This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

IPA merge 4: SSA inliner


Hi,
this patch updates inliner to deal with SSA (so it now can handle both SSA and
non-SSA gimple.  This is quite natural to do, since SSA is more an extension of
IL than different one and also needed for -O0 inlining).  The SSA code is
unused now, since we are not quite ready to reorder the pass queue (with my
passmanager patch, one can do it and get crashes on testcases with static
variables, I have patch for static variables in queue), however I am sending
it, so we can parallelize the efforts and as example how SSA updating on IPA
level looks like now.

Some interesting stuff:

 1) Inserting SSA body into SSA body is basically easy, since dominator
    tree change little.  SSA names for automatic variables in outer function
    don't need to change, most of SSA in internal function doesn't either.
    
    So the basic idea is to have remap_ssa_name producing new SSA names for
    copied ones and new copy_phis_for_bb re-creating PHI nodes in the copied
    body according to the original PHIs.
 2) For virtual operands I simply trigger rebuild of SSA of everything
    mentioned.  The scheme outlined above doesn't work for static variables
    touched by both inlined and callee functions since we need to merge
    SSA form built on those.
 3) SSA names for return decls are stripped away and SSA form is rebuilt.
    This should be fine since there ought to be only one name as we have
    single return_stmt.  We however might break SSA from otherwise in the case
    function returned partially uninitialized return value
 4) SSA operands are copy/constant propagated by inliner.  Inliner always
    constant propagated in order to get "const" declared arguments right.
    We can easilly do more, but it also tend to uncover latent bugs.
    I did little measurements on tramp3d and not doing the constant/copy
    prop increases number of SSA names built by 30%, so I think it is worthwhile
    (and it also makes it easier to inline callbacks)
 5) EH edges comming from inlined function body to landing paths within outer
    function cause troubles since PHI nodes can be associated with the landing
    pads.  I discussed this with Rth on the summit and we concluded it is safe
    to to rebuild SSA on those symbols: since they have PHIs on abnormal edges
    we don't have overlapping liveranges.
    I have some alternate plans if we ever decide to make EH edges redirectable
    (basically one can feed in the PHI argument of edge comming from original
    call to be replaced to the specific landing pad, but it is not always
    present so way we build EH cfg would have to be tweaked)
 6) Problematic are also return values returned via slot.  These variables
    do have address taken (technically to pass to inlined function) but we
    don't model it properly in the outer function, so they might be in SSA form
    and we might have issues with partly initialized return values.

    I think we should properly mark them as having address taken at least
    pre-inline.  This is not included in this patch, I just added assert that
    this assumption is true, we can deal with this incrementally I hope.

Bootstrapped/regtested i686-linux and bootstrapped x86_64-linux with some
additional changes to operate on SSA form.
OK?

Honza

	* tree-inline.c (remap_ssa_name): New function.
	(remap_decl): Update SSA datastructures for DECLs.
	(copy_body_r): Deal with SSA_NAMEs; add referenced global vars.
	(copy_bb): Set SSA_NAME def stmts.
	(update_ssa_acorss_eh_edges): New function.
	(copy_edge_for_bb): Call it; mark new vars for renaming.
	(copy_phis_for_bb): New function.
	(initialize_cfun): Break out from ...
	(copy_cfg_body): ... here; maintain AUX map for both directions;
	call SSA updating workers.
	(setup_one_parameter): Do propagation across SSA form.
	(declare_return_variable): Work on SSA.
	(expand_call_inline): Update SSA from on return values.
	(optimize_inline_calls): Do sanity checking, dead blocks removal,
	update SSA form.
	(tree_function_verioning): Update initialize_cfun.
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 119454)
--- tree-inline.c	(working copy)
*************** Boston, MA 02110-1301, USA.  */
*** 49,54 ****
--- 49,55 ----
  #include "debug.h"
  #include "pointer-set.h"
  #include "ipa-prop.h"
+ #include "tree-pass.h"
  
  /* I'm not real happy about this, but we need to handle gimple and
     non-gimple trees.  */
*************** insert_decl_map (copy_body_data *id, tre
*** 140,145 ****
--- 141,190 ----
  		       (splay_tree_value) value);
  }
  
+ /* Construct new SSA name for old one.  */
+ 
+ static tree
+ remap_ssa_name (tree name, copy_body_data *id)
+ {
+   tree new;
+   splay_tree_node n;
+ 
+   gcc_assert (TREE_CODE (name) == SSA_NAME);
+ 
+   n = splay_tree_lookup (id->decl_map, (splay_tree_key) name);
+   if (n)
+     return (tree) n->value;
+ 
+   /* Do not set DEF_STMT yet as statement might not get copied.  */
+   new = remap_decl (SSA_NAME_VAR (name), id);
+   /* We might've substituted constant or another SSA_NAME for
+      the variable.  */
+   if ((TREE_CODE (new) == VAR_DECL || TREE_CODE (new) == PARM_DECL)
+       /* Replace the SSA name representing RESULT_DECL by variable during
+ 	 inlining:  this saves us from need to introduce PHI node in a case
+ 	 return value is just partly initialized.  */
+       && (TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL
+ 	  || !id->transform_return_to_modify))
+     {
+       new = make_ssa_name (new, NULL);
+       insert_decl_map (id, name, new);
+       if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name))
+ 	  /* When inlining, parameters are replaced by initialized vars.  */
+ 	  && (TREE_CODE (new) == PARM_DECL || TREE_CODE (name) != PARM_DECL))
+ 	{
+ 	  SSA_NAME_DEF_STMT (new) = build_empty_stmt ();
+ 	  if (gimple_default_def (id->src_cfun, SSA_NAME_VAR (name)) == name)
+ 	    set_default_def (SSA_NAME_VAR (new), new);
+ 	}
+       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new)
+ 	= SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
+     }
+   else
+     insert_decl_map (id, name, new);
+   TREE_TYPE (new) = remap_type (TREE_TYPE (name), id);
+   return new;
+ }
+ 
  /* Remap DECL during the copying of the BLOCK tree for the function.  */
  
  tree
*************** remap_decl (tree decl, copy_body_data *i
*** 187,192 ****
--- 232,255 ----
  	    walk_tree (&DECL_QUALIFIER (t), copy_body_r, id, NULL);
  	}
  
+       if (cfun && gimple_in_ssa_p (cfun)
+ 	  && (TREE_CODE (t) == VAR_DECL
+ 	      || TREE_CODE (t) == RESULT_DECL || TREE_CODE (t) == PARM_DECL))
+ 	{
+ 	  tree def;
+ 
+ 	  get_var_ann (t);
+ 	  if (TREE_CODE (decl) != PARM_DECL
+ 	      && (def = gimple_default_def (id->src_cfun, decl)))
+ 	    {
+ 	      tree map = remap_ssa_name (def, id);
+ 	      /* Watch out RESULT_DECLs whose SSA names map directly
+ 		 to them.  */
+ 	      if (TREE_CODE (map) == SSA_NAME)
+ 	        set_default_def (t, map);
+ 	    }
+ 	  add_referenced_var (t);
+ 	}
        return t;
      }
  
*************** copy_body_r (tree *tp, int *walk_subtree
*** 499,504 ****
--- 562,573 ----
  	  return (tree) (void *)1;
  	}
      }
+   else if (TREE_CODE (*tp) == SSA_NAME)
+     {
+       *tp = remap_ssa_name (*tp, id);
+       *walk_subtrees = 0;
+       return NULL;
+     }
  
    /* Local variables and labels need to be replaced by equivalent
       variables.  We don't want to copy static variables; there's only
*************** copy_body_r (tree *tp, int *walk_subtree
*** 620,625 ****
--- 689,699 ----
        /* Here is the "usual case".  Copy this tree node, and then
  	 tweak some special cases.  */
        copy_tree_r (tp, walk_subtrees, NULL);
+ 
+       /* Global variables we didn't seen yet needs to go into referenced
+ 	 vars.  */
+       if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL)
+ 	add_referenced_var (*tp);
         
        /* If EXPR has block defined, map it to newly constructed block.
           When inlining we want EXPRs without block appear in the block
*************** copy_bb (copy_body_data *id, basic_block
*** 777,787 ****
--- 851,906 ----
  		  && tree_could_throw_p (stmt))
  		add_stmt_to_eh_region (stmt, id->eh_region);
  	    }
+ 	  if (gimple_in_ssa_p (cfun))
+ 	    {
+ 	       ssa_op_iter i;
+ 	       tree def;
+ 
+ 	       FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_DEF)
+ 		if (TREE_CODE (def) == SSA_NAME)
+ 		  SSA_NAME_DEF_STMT (def) = stmt;
+ 	    }
  	}
      }
    return copy_basic_block;
  }
  
+ /* Inserting Single Entry Multiple Exit region in SSA form into code in SSA
+    form is quite easy, since dominator relationship for old basic blocks does
+    not change.
+ 
+    There is however exception where inlining might change dominatorships across
+    EH edges from basic block within inlined functions destinating to landging
+    pads in function we inline into.
+ 
+    It is safe to mark PHI_RESULT of such PHI nodes for renaming; the EH edges
+    are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI must be set.
+    This might change in future if we allow redirecting of EH edges and
+    we might want to change way build CFG pre-inlining to include
+    all the possible edges then.  */
+ static void
+ update_ssa_across_eh_edges (basic_block bb)
+ {
+   edge e;
+   edge_iterator ei;
+ 
+   FOR_EACH_EDGE (e, ei, bb->succs)
+     if (!e->dest->aux
+ 	|| ((basic_block)e->dest->aux)->index == ENTRY_BLOCK)
+       {
+ 	tree phi;
+ 
+ 	gcc_assert (e->flags & EDGE_EH);
+ 	for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
+ 	  {
+ 	    gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
+ 			(PHI_RESULT (phi)));
+ 	    mark_sym_for_renaming
+ 	      (SSA_NAME_VAR (PHI_RESULT (phi)));
+ 	  }
+       }
+ }
+ 
  /* Copy edges from BB into its copy constructed earlier, scale profile
     accordingly.  Edges will be taken care of later.  Assume aux
     pointers to point to the copies of each BB.  */
*************** copy_edges_for_bb (basic_block bb, int c
*** 821,826 ****
--- 940,947 ----
  
        copy_stmt = bsi_stmt (bsi);
        update_stmt (copy_stmt);
+       if (gimple_in_ssa_p (cfun))
+         mark_new_vars_to_rename (copy_stmt);
        /* Do this before the possible split_block.  */
        bsi_next (&bsi);
  
*************** copy_edges_for_bb (basic_block bb, int c
*** 843,853 ****
--- 964,1016 ----
  	       right at this point; split_block doesn't care.  */
  	    {
  	      edge e = split_block (new_bb, copy_stmt);
+ 
  	      new_bb = e->dest;
+ 	      new_bb->aux = e->src->aux;
  	      bsi = bsi_start (new_bb);
  	    }
  
             make_eh_edges (copy_stmt);
+ 
+ 	   if (gimple_in_ssa_p (cfun))
+ 	     update_ssa_across_eh_edges (bb_for_stmt (copy_stmt));
+ 	}
+     }
+ }
+ 
+ /* Copy the PHIs.  All blocks and edges was copied, some blocks
+    was possibly splited and new outgoing EH edges inserted.
+    BB points to the block of original function and AUX pointers links
+    the original and newly copied blocks.  */
+ static void
+ copy_phis_for_bb (basic_block bb, copy_body_data *id)
+ {
+   basic_block new_bb = bb->aux;
+   edge_iterator ei;
+   tree phi;
+ 
+   for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+     {
+       tree res = PHI_RESULT (phi);
+       tree new_res = res;
+       tree new_phi;
+       edge new_edge;
+ 
+       if (is_gimple_reg (res))
+ 	{
+ 	  walk_tree (&new_res, copy_body_r, id, NULL);
+ 	  SSA_NAME_DEF_STMT (new_res)
+ 	    = new_phi = create_phi_node (new_res, new_bb);
+ 	  FOR_EACH_EDGE (new_edge, ei, new_bb->preds)
+ 	    {
+ 	      edge old_edge = find_edge (new_edge->src->aux, bb);
+ 	      tree arg = PHI_ARG_DEF_FROM_EDGE (phi, old_edge);
+ 	      tree new_arg = arg;
+ 
+ 	      walk_tree (&new_arg, copy_body_r, id, NULL);
+ 	      gcc_assert (new_arg);
+ 	      add_phi_arg (new_phi, new_arg, new_edge);
+ 	    }
  	}
      }
  }
*************** remap_decl_1 (tree decl, void *data)
*** 859,864 ****
--- 1022,1086 ----
    return remap_decl (decl, (copy_body_data *) data);
  }
  
+ /* Build struct function and associated datastructures for the new clone
+    to be build.  */
+ static void
+ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count,
+ 		 int frequency)
+ {
+   struct function *new_cfun
+      = (struct function *) ggc_alloc_cleared (sizeof (struct function));
+   struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
+   int count_scale, frequency_scale;
+ 
+   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
+     count_scale = (REG_BR_PROB_BASE * count
+ 		   / ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count);
+   else
+     count_scale = 1;
+ 
+   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency)
+     frequency_scale = (REG_BR_PROB_BASE * frequency
+ 		       /
+ 		       ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency);
+   else
+     frequency_scale = count_scale;
+ 
+   /* Register specific tree functions.  */
+   tree_register_cfg_hooks ();
+   *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
+   new_cfun->unexpanded_var_list = NULL;
+   new_cfun->cfg = NULL;
+   new_cfun->decl = new_fndecl /*= copy_node (callee_fndecl)*/;
+   new_cfun->ib_boundaries_block = NULL;
+   DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
+   push_cfun (new_cfun);
+   init_empty_tree_cfg ();
+ 
+   ENTRY_BLOCK_PTR->count =
+     (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
+      REG_BR_PROB_BASE);
+   ENTRY_BLOCK_PTR->frequency =
+     (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
+      frequency_scale / REG_BR_PROB_BASE);
+   EXIT_BLOCK_PTR->count =
+     (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
+      REG_BR_PROB_BASE);
+   EXIT_BLOCK_PTR->frequency =
+     (EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
+      frequency_scale / REG_BR_PROB_BASE);
+   if (src_cfun->eh)
+     init_eh_for_function ();
+ 
+   if (src_cfun->gimple_df)
+     {
+       init_tree_ssa ();
+       cfun->gimple_df->in_ssa_p = true;
+       init_ssa_operands ();
+     }
+   pop_cfun ();
+ }
+ 
  /* Make a copy of the body of FN so that it can be inserted inline in
     another function.  Walks FN via CFG, returns new fndecl.  */
  
*************** copy_cfg_body (copy_body_data * id, gcov
*** 869,876 ****
    tree callee_fndecl = id->src_fn;
    /* Original cfun for the callee, doesn't change.  */
    struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
-   /* Copy, built by this function.  */
-   struct function *new_cfun;
    /* Place to copy from; when a copy of the function was saved off earlier,
       use that instead of the main copy.  */
    struct function *cfun_to_copy =
--- 1091,1096 ----
*************** copy_cfg_body (copy_body_data * id, gcov
*** 878,883 ****
--- 1098,1104 ----
    basic_block bb;
    tree new_fndecl = NULL;
    int count_scale, frequency_scale;
+   int last;
  
    if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
      count_scale = (REG_BR_PROB_BASE * count
*************** copy_cfg_body (copy_body_data * id, gcov
*** 903,962 ****
  
    id->src_cfun = cfun_to_copy;
  
-   /* If requested, create new basic_block_info and label_to_block_maps.
-      Otherwise, insert our new blocks and labels into the existing cfg.  */
-   if (id->transform_new_cfg)
-     {
-       new_cfun =
- 	(struct function *) ggc_alloc_cleared (sizeof (struct function));
-       *new_cfun = *DECL_STRUCT_FUNCTION (callee_fndecl);
-       new_cfun->cfg = NULL;
-       new_cfun->decl = new_fndecl = copy_node (callee_fndecl);
-       new_cfun->ib_boundaries_block = NULL;
-       DECL_STRUCT_FUNCTION (new_fndecl) = new_cfun;
-       push_cfun (new_cfun);
-       init_empty_tree_cfg ();
- 
-       ENTRY_BLOCK_PTR->count =
- 	(ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
- 	 REG_BR_PROB_BASE);
-       ENTRY_BLOCK_PTR->frequency =
- 	(ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
- 	 frequency_scale / REG_BR_PROB_BASE);
-       EXIT_BLOCK_PTR->count =
- 	(EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count * count_scale /
- 	 REG_BR_PROB_BASE);
-       EXIT_BLOCK_PTR->frequency =
- 	(EXIT_BLOCK_PTR_FOR_FUNCTION (src_cfun)->frequency *
- 	 frequency_scale / REG_BR_PROB_BASE);
- 
-       entry_block_map = ENTRY_BLOCK_PTR;
-       exit_block_map = EXIT_BLOCK_PTR;
-     }
  
    ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = entry_block_map;
    EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = exit_block_map;
  
    /* Duplicate any exception-handling regions.  */
    if (cfun->eh)
      {
-       if (id->transform_new_cfg)
-         init_eh_for_function ();
        id->eh_region_offset
  	= duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
  				0, id->eh_region);
      }
    /* Use aux pointers to map the original blocks to copy.  */
    FOR_EACH_BB_FN (bb, cfun_to_copy)
!     bb->aux = copy_bb (id, bb, frequency_scale, count_scale);
    /* Now that we've duplicated the blocks, duplicate their edges.  */
    FOR_ALL_BB_FN (bb, cfun_to_copy)
      copy_edges_for_bb (bb, count_scale);
    FOR_ALL_BB_FN (bb, cfun_to_copy)
!     bb->aux = NULL;
! 
!   if (id->transform_new_cfg)
!     pop_cfun ();
  
    return new_fndecl;
  }
--- 1124,1168 ----
  
    id->src_cfun = cfun_to_copy;
  
  
    ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = entry_block_map;
    EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy)->aux = exit_block_map;
+   entry_block_map->aux = ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy);
+   exit_block_map->aux = EXIT_BLOCK_PTR_FOR_FUNCTION (cfun_to_copy);
  
    /* Duplicate any exception-handling regions.  */
    if (cfun->eh)
      {
        id->eh_region_offset
  	= duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
  				0, id->eh_region);
      }
    /* Use aux pointers to map the original blocks to copy.  */
    FOR_EACH_BB_FN (bb, cfun_to_copy)
!     {
!       basic_block new = copy_bb (id, bb, frequency_scale, count_scale);
!       bb->aux = new;
!       new->aux = bb;
!     }
! 
!   last = n_basic_blocks;
    /* Now that we've duplicated the blocks, duplicate their edges.  */
    FOR_ALL_BB_FN (bb, cfun_to_copy)
      copy_edges_for_bb (bb, count_scale);
+   if (gimple_in_ssa_p (cfun))
+     FOR_ALL_BB_FN (bb, cfun_to_copy)
+       copy_phis_for_bb (bb, id);
    FOR_ALL_BB_FN (bb, cfun_to_copy)
!     {
!       ((basic_block)bb->aux)->aux = NULL;
!       bb->aux = NULL;
!     }
!   /* Zero out AUX fields of newly created block during EH edge
!      insertion. */
!   for (; last < n_basic_blocks; last++)
!     BASIC_BLOCK (last)->aux = NULL;
!   entry_block_map->aux = NULL;
!   exit_block_map->aux = NULL;
  
    return new_fndecl;
  }
*************** setup_one_parameter (copy_body_data *id,
*** 1013,1025 ****
    tree init_stmt;
    tree var;
    tree var_sub;
! 
!   /* If the parameter is never assigned to, we may not need to
!      create a new variable here at all.  Instead, we may be able
!      to just use the argument value.  */
    if (TREE_READONLY (p)
        && !TREE_ADDRESSABLE (p)
!       && value && !TREE_SIDE_EFFECTS (value))
      {
        /* We may produce non-gimple trees by adding NOPs or introduce
  	 invalid sharing when operand is not really constant.
--- 1219,1235 ----
    tree init_stmt;
    tree var;
    tree var_sub;
!   tree rhs = value ? fold_convert (TREE_TYPE (p), value) : NULL;
!   tree def = (gimple_in_ssa_p (cfun)
! 	      ? gimple_default_def (id->src_cfun, p) : NULL);
! 
!   /* If the parameter is never assigned to, has no SSA_NAMEs created,
!      we may not need to create a new variable here at all.  Instead, we may
!      be able to just use the argument value.  */
    if (TREE_READONLY (p)
        && !TREE_ADDRESSABLE (p)
!       && value && !TREE_SIDE_EFFECTS (value)
!       && !def)
      {
        /* We may produce non-gimple trees by adding NOPs or introduce
  	 invalid sharing when operand is not really constant.
*************** setup_one_parameter (copy_body_data *id,
*** 1043,1048 ****
--- 1253,1263 ----
       here since the type of this decl must be visible to the calling
       function.  */
    var = copy_decl_to_var (p, id);
+   if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
+     {
+       get_var_ann (var);
+       add_referenced_var (var);
+     }
  
    /* See if the frontend wants to pass this by invisible reference.  If
       so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
*************** setup_one_parameter (copy_body_data *id,
*** 1081,1101 ****
    if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
      TREE_READONLY (var) = 0;
  
    /* Initialize this VAR_DECL from the equivalent argument.  Convert
       the argument to the proper type in case it was promoted.  */
    if (value)
      {
-       tree rhs = fold_convert (TREE_TYPE (var), value);
        block_stmt_iterator bsi = bsi_last (bb);
  
        if (rhs == error_mark_node)
! 	return;
  
        STRIP_USELESS_TYPE_CONVERSION (rhs);
  
        /* We want to use MODIFY_EXPR, not INIT_EXPR here so that we
  	 keep our trees in gimple form.  */
!       init_stmt = build2 (MODIFY_EXPR, TREE_TYPE (var), var, rhs);
  
        /* If we did not create a gimple value and we did not create a gimple
  	 cast of a gimple value, then we will need to gimplify INIT_STMTS
--- 1296,1350 ----
    if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
      TREE_READONLY (var) = 0;
  
+   /* If there is no setup required and we are in SSA, take the easy route
+      replacing all SSA names representing the function parameter by the
+      SSA name passed to function.
+ 
+      We need to construct map for the variable anyway as it might be used
+      in different SSA names when parameter is set in function.
+ 
+      FIXME: This usually kills the last connection in between inlined
+      function parameter and the actual value in debug info.  Can we do
+      better here?  If we just inserted the statement, copy propagation
+      would kill it anyway as it always did in older versions of GCC.
+ 
+      We might want to introduce a notion that single SSA_NAME might
+      represent multiple variables for purposes of debugging. */
+   if (gimple_in_ssa_p (cfun) && rhs && def && is_gimple_reg (p)
+       && (TREE_CODE (rhs) == SSA_NAME
+ 	  /* Replacing &""[0] has interesting side effects.  Exclude ADDR_EXPRs
+ 	     now.  */
+ 	  || (is_gimple_min_invariant (rhs) && TREE_CODE (rhs) != ADDR_EXPR)))
+     {
+       insert_decl_map (id, def, rhs);
+       return;
+     }
+ 
    /* Initialize this VAR_DECL from the equivalent argument.  Convert
       the argument to the proper type in case it was promoted.  */
    if (value)
      {
        block_stmt_iterator bsi = bsi_last (bb);
  
        if (rhs == error_mark_node)
! 	{
!   	  insert_decl_map (id, p, var_sub);
! 	  return;
! 	}
  
        STRIP_USELESS_TYPE_CONVERSION (rhs);
  
        /* We want to use MODIFY_EXPR, not INIT_EXPR here so that we
  	 keep our trees in gimple form.  */
!       if (def && gimple_in_ssa_p (cfun) && is_gimple_reg (p))
! 	{
! 	  def = remap_ssa_name (def, id);
!           init_stmt = build2 (MODIFY_EXPR, TREE_TYPE (var), def, rhs);
! 	  SSA_NAME_DEF_STMT (def) = init_stmt;
! 	  set_default_def (var, NULL);
! 	}
!       else
!         init_stmt = build2 (MODIFY_EXPR, TREE_TYPE (var), var, rhs);
  
        /* If we did not create a gimple value and we did not create a gimple
  	 cast of a gimple value, then we will need to gimplify INIT_STMTS
*************** setup_one_parameter (copy_body_data *id,
*** 1105,1116 ****
        if (!is_gimple_val (rhs)
  	  && (!is_gimple_cast (rhs)
  	      || !is_gimple_val (TREE_OPERAND (rhs, 0))))
! 	gimplify_stmt (&init_stmt);
  
        /* If VAR represents a zero-sized variable, it's possible that the
  	 assignment statment may result in no gimple statements.  */
        if (init_stmt)
          bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
      }
  }
  
--- 1354,1382 ----
        if (!is_gimple_val (rhs)
  	  && (!is_gimple_cast (rhs)
  	      || !is_gimple_val (TREE_OPERAND (rhs, 0))))
! 	{
!           tree_stmt_iterator i;
! 
! 	  push_gimplify_context ();
! 	  gimplify_stmt (&init_stmt);
! 	  if (gimple_in_ssa_p (cfun)
!               && init_stmt && TREE_CODE (init_stmt) == STATEMENT_LIST)
! 	    {
! 	      /* The replacement can expose previously unreferenced
! 		 variables.  */
! 	      for (i = tsi_start (init_stmt); !tsi_end_p (i); tsi_next (&i))
! 		find_new_referenced_vars (tsi_stmt_ptr (i));
! 	     }
! 	  pop_gimplify_context (NULL);
! 	}
  
        /* If VAR represents a zero-sized variable, it's possible that the
  	 assignment statment may result in no gimple statements.  */
        if (init_stmt)
          bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
+       if (gimple_in_ssa_p (cfun))
+ 	for (;!bsi_end_p (bsi); bsi_next (&bsi))
+ 	  mark_new_vars_to_rename (bsi_stmt (bsi));
      }
  }
  
*************** declare_return_variable (copy_body_data 
*** 1200,1208 ****
  	 a modify expression.  */
        gcc_assert (!modify_dest);
        if (DECL_BY_REFERENCE (result))
! 	var = return_slot_addr;
        else
! 	var = build_fold_indirect_ref (return_slot_addr);
        if (TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
  	  && !DECL_COMPLEX_GIMPLE_REG_P (result)
  	  && DECL_P (var))
--- 1466,1518 ----
  	 a modify expression.  */
        gcc_assert (!modify_dest);
        if (DECL_BY_REFERENCE (result))
! 	{
! 	  /* The address might be folded to direct assignment already.  */
! 	  if (TREE_CODE (return_slot_addr) == ADDR_EXPR)
! 	    {
! 	      tree base_var = TREE_OPERAND (return_slot_addr, 0);
! 
! 	      /* FIXME: rewriting random variables in SSA form is going
! 		 to cause missoptimizations once we start optimizing. 
! 
! 		 Should structures that are initialized via return_slot_addr
! 		 be marked as TREE_ADDRESSABLE at least before inlining?
! 		 (technically they do have address taken, but we know it
! 		 is pretty safe in function call context as the address is
! 		 used only to write return value)  */
! 	      if (TREE_CODE (base_var) == SSA_NAME)
! 		{
! 		  base_var = SSA_NAME_VAR (base_var);
! 		  gcc_assert (TREE_ADDRESSABLE (base_var));
! 		}
! 	      if (gimple_in_ssa_p (cfun))
! 		{
! 		  HOST_WIDE_INT bitsize;
! 		  HOST_WIDE_INT bitpos;
! 		  tree offset;
! 		  enum machine_mode mode;
! 		  int unsignedp;
! 		  int volatilep;
! 		  tree base;
! 		  base = get_inner_reference (base_var, &bitsize, &bitpos,
! 					      &offset,
! 					      &mode, &unsignedp, &volatilep,
! 					      false);
! 		  if (TREE_CODE (base) == INDIRECT_REF)
! 		    base = TREE_OPERAND (base, 0);
! 		  if (TREE_CODE (base) == SSA_NAME)
! 		    base = SSA_NAME_VAR (base);
! 		  mark_sym_for_renaming (base);
! 		}
! 	    }
! 	  var = return_slot_addr;
! 	}
        else
! 	{
! 	  if (gimple_in_ssa_p (cfun))
! 	    mark_sym_for_renaming (TREE_OPERAND (return_slot_addr, 0));
! 	  var = build_fold_indirect_ref (return_slot_addr);
! 	}
        if (TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
  	  && !DECL_COMPLEX_GIMPLE_REG_P (result)
  	  && DECL_P (var))
*************** declare_return_variable (copy_body_data 
*** 1215,1221 ****
    gcc_assert (!TREE_ADDRESSABLE (callee_type));
  
    /* Attempt to avoid creating a new temporary variable.  */
!   if (modify_dest)
      {
        bool use_it = false;
  
--- 1525,1532 ----
    gcc_assert (!TREE_ADDRESSABLE (callee_type));
  
    /* Attempt to avoid creating a new temporary variable.  */
!   if (modify_dest
!       && TREE_CODE (modify_dest) != SSA_NAME)
      {
        bool use_it = false;
  
*************** declare_return_variable (copy_body_data 
*** 1263,1268 ****
--- 1574,1584 ----
    gcc_assert (TREE_CODE (TYPE_SIZE_UNIT (callee_type)) == INTEGER_CST);
  
    var = copy_result_decl_to_var (result, id);
+   if (gimple_in_ssa_p (cfun))
+     {
+       get_var_ann (var);
+       add_referenced_var (var);
+     }
  
    DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
    DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list
*************** expand_call_inline (basic_block bb, tree
*** 2155,2166 ****
    if (use_retvar && (TREE_CODE (bsi_stmt (stmt_bsi)) != CALL_EXPR))
      {
        *tp = use_retvar;
        maybe_clean_or_replace_eh_stmt (stmt, stmt);
      }
    else
      /* We're modifying a TSI owned by gimple_expand_calls_inline();
         tsi_delink() will leave the iterator in a sane state.  */
!     bsi_remove (&stmt_bsi, true);
  
    if (purge_dead_abnormal_edges)
      tree_purge_dead_abnormal_call_edges (return_block);
--- 2471,2514 ----
    if (use_retvar && (TREE_CODE (bsi_stmt (stmt_bsi)) != CALL_EXPR))
      {
        *tp = use_retvar;
+       if (gimple_in_ssa_p (cfun))
+ 	{
+           update_stmt (stmt);
+           mark_new_vars_to_rename (stmt);
+ 	}
        maybe_clean_or_replace_eh_stmt (stmt, stmt);
      }
    else
      /* We're modifying a TSI owned by gimple_expand_calls_inline();
         tsi_delink() will leave the iterator in a sane state.  */
!     {
!       /* Handle case of inlining function that miss return statement so return value becomes
!          undefined.  */
!       if (TREE_CODE (stmt) == MODIFY_EXPR
! 	  && TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME)
! 	{
! 	  tree name = TREE_OPERAND (stmt, 0);
! 	  tree var = SSA_NAME_VAR (TREE_OPERAND (stmt, 0));
! 	  tree def = gimple_default_def (cfun, var);
! 
! 	  /* If the variable is used undefined, make this name undefined via
! 	     move.  */
! 	  if (def)
! 	    {
! 	      TREE_OPERAND (stmt, 1) = def;
! 	      update_stmt (stmt);
! 	    }
! 	  /* Otherwise make this variable undefined.  */
! 	  else
! 	    {
! 	      bsi_remove (&stmt_bsi, true);
! 	      set_default_def (var, name);
! 	      SSA_NAME_DEF_STMT (name) = build_empty_stmt ();
! 	    }
! 	}
!       else
!         bsi_remove (&stmt_bsi, true);
!     }
  
    if (purge_dead_abnormal_edges)
      tree_purge_dead_abnormal_call_edges (return_block);
*************** optimize_inline_calls (tree fn)
*** 2281,2287 ****
       as inlining loops might increase the maximum.  */
    if (ENTRY_BLOCK_PTR->count)
      counts_to_freqs ();
!   fold_cond_expr_cond ();
  }
  
  /* FN is a function that has a complete body, and CLONE is a function whose
--- 2629,2650 ----
       as inlining loops might increase the maximum.  */
    if (ENTRY_BLOCK_PTR->count)
      counts_to_freqs ();
!   if (gimple_in_ssa_p (cfun))
!     {
!       delete_unreachable_blocks ();
!       update_ssa (TODO_update_ssa);
! #ifdef ENABLE_CHECKING
!       verify_ssa (true);
! #endif
!       fold_cond_expr_cond ();
!       cleanup_tree_cfg ();
!       if (need_ssa_update_p ())
!         update_ssa (TODO_update_ssa);
!       free_dominance_info (CDI_DOMINATORS);
!       free_dominance_info (CDI_POST_DOMINATORS);
!     }
!   else
!     fold_cond_expr_cond ();
  }
  
  /* FN is a function that has a complete body, and CLONE is a function whose
*************** tree_function_versioning (tree old_decl,
*** 2769,2775 ****
    struct cgraph_node *old_version_node;
    struct cgraph_node *new_version_node;
    copy_body_data id;
!   tree p, new_fndecl;
    unsigned i;
    struct ipa_replace_map *replace_info;
    basic_block old_entry_block;
--- 3132,3138 ----
    struct cgraph_node *old_version_node;
    struct cgraph_node *new_version_node;
    copy_body_data id;
!   tree p;
    unsigned i;
    struct ipa_replace_map *replace_info;
    basic_block old_entry_block;
*************** tree_function_versioning (tree old_decl,
*** 2815,2820 ****
--- 3178,3189 ----
    id.transform_lang_insert_block = false;
  
    current_function_decl = new_decl;
+   old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
+     (DECL_STRUCT_FUNCTION (old_decl));
+   initialize_cfun (new_decl, old_decl,
+ 		   old_entry_block->count,
+ 		   old_entry_block->frequency);
+   push_cfun (DECL_STRUCT_FUNCTION (new_decl));
    
    /* Copy the function's static chain.  */
    p = DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl;
*************** tree_function_versioning (tree old_decl,
*** 2858,2879 ****
        }
    
    /* Copy the Function's body.  */
!   old_entry_block = ENTRY_BLOCK_PTR_FOR_FUNCTION
!     (DECL_STRUCT_FUNCTION (old_decl));
!   new_fndecl = copy_body (&id,
! 			  old_entry_block->count,
! 			  old_entry_block->frequency, NULL, NULL);
    
-   DECL_SAVED_TREE (new_decl) = DECL_SAVED_TREE (new_fndecl);
- 
-   DECL_STRUCT_FUNCTION (new_decl)->cfg =
-     DECL_STRUCT_FUNCTION (new_fndecl)->cfg;
-   DECL_STRUCT_FUNCTION (new_decl)->eh = DECL_STRUCT_FUNCTION (new_fndecl)->eh;
-   DECL_STRUCT_FUNCTION (new_decl)->ib_boundaries_block =
-     DECL_STRUCT_FUNCTION (new_fndecl)->ib_boundaries_block;
-   DECL_STRUCT_FUNCTION (new_decl)->last_label_uid =
-     DECL_STRUCT_FUNCTION (new_fndecl)->last_label_uid;
- 
    if (DECL_RESULT (old_decl) != NULL_TREE)
      {
        tree *res_decl = &DECL_RESULT (old_decl);
--- 3227,3234 ----
        }
    
    /* Copy the Function's body.  */
!   copy_body (&id, old_entry_block->count, old_entry_block->frequency, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR);
    
    if (DECL_RESULT (old_decl) != NULL_TREE)
      {
        tree *res_decl = &DECL_RESULT (old_decl);
*************** tree_function_versioning (tree old_decl,
*** 2881,2893 ****
        lang_hooks.dup_lang_specific_decl (DECL_RESULT (new_decl));
      }
    
-   current_function_decl = NULL;
    /* Renumber the lexical scoping (non-code) blocks consecutively.  */
    number_blocks (new_decl);
  
    /* Clean up.  */
    splay_tree_delete (id.decl_map);
    fold_cond_expr_cond ();
    return;
  }
  
--- 3236,3258 ----
        lang_hooks.dup_lang_specific_decl (DECL_RESULT (new_decl));
      }
    
    /* Renumber the lexical scoping (non-code) blocks consecutively.  */
    number_blocks (new_decl);
  
    /* Clean up.  */
    splay_tree_delete (id.decl_map);
    fold_cond_expr_cond ();
+   if (gimple_in_ssa_p (cfun))
+     {
+       update_ssa (TODO_update_ssa);
+ #ifdef ENABLE_CHECKING
+       verify_ssa (true);
+ #endif
+     }
+   free_dominance_info (CDI_DOMINATORS);
+   free_dominance_info (CDI_POST_DOMINATORS);
+   pop_cfun ();
+   current_function_decl = NULL;
    return;
  }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]