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]

Re: IPA merge 4: SSA inliner


Hi,
this is variant of patch I ended up comitting after further testing with
SSA enabled.  There are four minor additional changes for problems I
noticed:
 1) remap_ssa_name originally worked hard to duplicate type of SSA_NAME
 instead of copying it from SSA_NAME_VAR.  This even breaks sanity
 checking on fortran where the types differ slightly (ie they are
 noop_conversion but not equivalent).  This didn't reproduce on IPA
 branch because I didn't merged this extra gimple checker in yet.
 2) copy_cfg_body used to produce copy of cfun of the inlined function
 for no good reason.  This was omision from original cleanups to merge
 of CFG inliner (that originally did so in the attempt to accomondate
 recursive inlining) and started to reproduce as an corruption in histogram
 tables (a since copy was updated, but not the original) in profiled
 bootstrap with IPA-SSA (and would probably reproduce without IPA-SSA on some
 testcases too).  I also dropped a comment why we are not ready to
 verify SSA and statements just after inlining and need fixup_cfg pass
 first.  (I have plans to tie this into PM so this can be done, but it
 needs little further work)
 3) declare_return_value took as an argument &retval just to produce
 folded *&retval in most cases. This is a trivial waste and it strikes
 wrong to see ADDR_EXPR of SSA_NAME in debugger even if it is a temporary
 situation.
 4) copy_bb called gimplify_stmt but in case gimplifier gimplified
 something it confused itself not expecting statement_list in the stmt.
 This is again latent bug that could probably reproduce on mainline with
 some particularly evil testcase as an missed EH info.

All these changes are rather obvious, so I've re-tested the patch on
both mainline and mainline with IPA-SSA and comitted. 

Thank you,

Index: ChangeLog
===================================================================
*** ChangeLog	(revision 120259)
--- ChangeLog	(working copy)
***************
*** 1,3 ****
--- 1,23 ----
+ 2006-12-29  Jan Hubicka  <jh@suse.cz>
+ 
+ 	* 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; use return_slot instead of
+ 	address of return slot of argument to avoid folding back and forth.
+ 	(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.
+ 
  2006-12-29  Marcin Dalecki  <martin@dalecki.de>
  
  	* doc/invoke.texi: Replace no longer supported -fno-strength-reduce
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 120259)
--- tree-inline.c	(working copy)
*************** Boston, MA 02110-1301, USA.  */
*** 50,55 ****
--- 50,56 ----
  #include "pointer-set.h"
  #include "ipa-prop.h"
  #include "value-prof.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
*** 141,146 ****
--- 142,191 ----
  		       (splay_tree_value) value);
  }
  
+ /* Construct new SSA name for old NAME. ID is the inline context.  */
+ 
+ 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 is not copied yet. We do that
+      in copy_bb.  */
+   new = remap_decl (SSA_NAME_VAR (name), id);
+   /* We might've substituted constant or another SSA_NAME for
+      the variable. 
+ 
+      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.  */
+   if ((TREE_CODE (new) == VAR_DECL || TREE_CODE (new) == PARM_DECL)
+       && (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)))
+ 	{
+ 	  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);
+       TREE_TYPE (new) = TREE_TYPE (SSA_NAME_VAR (new));
+     }
+   else
+     insert_decl_map (id, name, new);
+   return new;
+ }
+ 
  /* Remap DECL during the copying of the BLOCK tree for the function.  */
  
  tree
*************** remap_decl (tree decl, copy_body_data *i
*** 188,193 ****
--- 233,254 ----
  	    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 = gimple_default_def (id->src_cfun, decl);
+ 	  get_var_ann (t);
+ 	  if (TREE_CODE (decl) != PARM_DECL && def)
+ 	    {
+ 	      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
*** 500,505 ****
--- 561,572 ----
  	  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
*** 621,626 ****
--- 688,698 ----
        /* 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
*** 718,791 ****
  	    gimplify_stmt (&stmt);
  
            bsi_insert_after (&copy_bsi, stmt, BSI_NEW_STMT);
! 	  call = get_call_expr_in (stmt);
! 	  /* We're duplicating a CALL_EXPR.  Find any corresponding
! 	     callgraph edges and update or duplicate them.  */
! 	  if (call && (decl = get_callee_fndecl (call)))
  	    {
! 	      struct cgraph_node *node;
! 	      struct cgraph_edge *edge;
! 	     
! 	      switch (id->transform_call_graph_edges)
  		{
! 		case CB_CGE_DUPLICATE:
! 		  edge = cgraph_edge (id->src_node, orig_stmt);
! 		  if (edge)
! 		    cgraph_clone_edge (edge, id->dst_node, stmt,
! 				       REG_BR_PROB_BASE, 1, true);
! 		  break;
! 
! 		case CB_CGE_MOVE_CLONES:
! 		  for (node = id->dst_node->next_clone;
! 		       node;
! 		       node = node->next_clone)
  		    {
! 		      edge = cgraph_edge (node, orig_stmt);
! 		      gcc_assert (edge);
! 		      cgraph_set_call_stmt (edge, stmt);
! 		    }
! 		  /* FALLTHRU */
  
! 		case CB_CGE_MOVE:
! 		  edge = cgraph_edge (id->dst_node, orig_stmt);
! 		  if (edge)
! 		    cgraph_set_call_stmt (edge, stmt);
! 		  break;
  
! 		default:
! 		  gcc_unreachable ();
  		}
! 	    }
! 	  /* If you think we can abort here, you are wrong.
! 	     There is no region 0 in tree land.  */
! 	  gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt)
! 		      != 0);
  
! 	  if (tree_could_throw_p (stmt))
! 	    {
! 	      int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
! 	      /* Add an entry for the copied tree in the EH hashtable.
! 		 When cloning or versioning, use the hashtable in
! 		 cfun, and just copy the EH number.  When inlining, use the
! 		 hashtable in the caller, and adjust the region number.  */
! 	      if (region > 0)
! 		add_stmt_to_eh_region (stmt, region + id->eh_region_offset);
! 
! 	      /* If this tree doesn't have a region associated with it,
! 		 and there is a "current region,"
! 		 then associate this tree with the current region
! 		 and add edges associated with this region.  */
! 	      if ((lookup_stmt_eh_region_fn (id->src_cfun,
! 					     orig_stmt) <= 0
! 		   && id->eh_region > 0)
! 		  && tree_could_throw_p (stmt))
! 		add_stmt_to_eh_region (stmt, id->eh_region);
  	    }
  	}
      }
    return copy_basic_block;
  }
  
  /* 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.  */
--- 790,921 ----
  	    gimplify_stmt (&stmt);
  
            bsi_insert_after (&copy_bsi, stmt, BSI_NEW_STMT);
! 
! 	  /* Process new statement.  gimplify_stmt possibly turned statement
! 	     into multiple statements, we need to process all of them.  */
! 	  while (!bsi_end_p (copy_bsi))
  	    {
! 	      stmt = bsi_stmt (copy_bsi);
! 	      call = get_call_expr_in (stmt);
! 	      /* We're duplicating a CALL_EXPR.  Find any corresponding
! 		 callgraph edges and update or duplicate them.  */
! 	      if (call && (decl = get_callee_fndecl (call)))
  		{
! 		  struct cgraph_node *node;
! 		  struct cgraph_edge *edge;
! 		 
! 		  switch (id->transform_call_graph_edges)
  		    {
! 		    case CB_CGE_DUPLICATE:
! 		      edge = cgraph_edge (id->src_node, orig_stmt);
! 		      if (edge)
! 			cgraph_clone_edge (edge, id->dst_node, stmt,
! 					   REG_BR_PROB_BASE, 1, true);
! 		      break;
! 
! 		    case CB_CGE_MOVE_CLONES:
! 		      for (node = id->dst_node->next_clone;
! 			   node;
! 			   node = node->next_clone)
! 			{
! 			  edge = cgraph_edge (node, orig_stmt);
! 			  gcc_assert (edge);
! 			  cgraph_set_call_stmt (edge, stmt);
! 			}
! 		      /* FALLTHRU */
! 
! 		    case CB_CGE_MOVE:
! 		      edge = cgraph_edge (id->dst_node, orig_stmt);
! 		      if (edge)
! 			cgraph_set_call_stmt (edge, stmt);
! 		      break;
  
! 		    default:
! 		      gcc_unreachable ();
! 		    }
! 		}
! 	      /* If you think we can abort here, you are wrong.
! 		 There is no region 0 in tree land.  */
! 	      gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt)
! 			  != 0);
  
! 	      if (tree_could_throw_p (stmt))
! 		{
! 		  int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
! 		  /* Add an entry for the copied tree in the EH hashtable.
! 		     When cloning or versioning, use the hashtable in
! 		     cfun, and just copy the EH number.  When inlining, use the
! 		     hashtable in the caller, and adjust the region number.  */
! 		  if (region > 0)
! 		    add_stmt_to_eh_region (stmt, region + id->eh_region_offset);
! 
! 		  /* If this tree doesn't have a region associated with it,
! 		     and there is a "current region,"
! 		     then associate this tree with the current region
! 		     and add edges associated with this region.  */
! 		  if ((lookup_stmt_eh_region_fn (id->src_cfun,
! 						 orig_stmt) <= 0
! 		       && id->eh_region > 0)
! 		      && 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;
  
! 		   find_new_referenced_vars (bsi_stmt_ptr (copy_bsi));
! 		   FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_DEF)
! 		    if (TREE_CODE (def) == SSA_NAME)
! 		      SSA_NAME_DEF_STMT (def) = stmt;
! 		}
! 	      bsi_next (&copy_bsi);
  	    }
+ 	  copy_bsi = bsi_last (copy_basic_block);
  	}
      }
    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 dominator relation
+    across EH edges from basic block within inlined functions destinating
+    to landging pads in function we inline into.
+ 
+    The function mark PHI_RESULT of such PHI nodes for renaming; it is
+    safe the EH edges are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI
+    must be set.  This means, that there will be no overlapping live ranges
+    for the underlying symbol.
+ 
+    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
*** 825,830 ****
--- 955,962 ----
  
        copy_stmt = bsi_stmt (bsi);
        update_stmt (copy_stmt);
+       if (gimple_in_ssa_p (cfun))
+         mark_symbols_for_renaming (copy_stmt);
        /* Do this before the possible split_block.  */
        bsi_next (&bsi);
  
*************** copy_edges_for_bb (basic_block bb, int c
*** 847,857 ****
--- 979,1032 ----
  	       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 are copied, some blocks
+    was possibly split 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)
*** 863,868 ****
--- 1038,1104 ----
    return remap_decl (decl, (copy_body_data *) data);
  }
  
+ /* Build struct function and associated datastructures for the new clone
+    NEW_FNDECL to be build.  CALLEE_FNDECL is the original */
+ 
+ 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);
+   VALUE_HISTOGRAMS (new_cfun) = NULL;
+   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
*** 873,887 ****
    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 =
!     (struct function *) ggc_alloc_cleared (sizeof (struct function));
    basic_block bb;
    tree new_fndecl = NULL;
    int count_scale, frequency_scale;
  
    if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
      count_scale = (REG_BR_PROB_BASE * count
--- 1109,1119 ----
    tree callee_fndecl = id->src_fn;
    /* Original cfun for the callee, doesn't change.  */
    struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
!   struct function *cfun_to_copy;
    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,966 ****
    gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
  	      (DECL_STRUCT_FUNCTION (callee_fndecl)));
  
!   *cfun_to_copy = *DECL_STRUCT_FUNCTION (callee_fndecl);
  
-   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;
  }
--- 1135,1181 ----
    gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
  	      (DECL_STRUCT_FUNCTION (callee_fndecl)));
  
!   cfun_to_copy = id->src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl);
  
  
    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,
*** 1017,1029 ****
    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.
--- 1232,1248 ----
    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,
*** 1047,1052 ****
--- 1266,1276 ----
       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,
*** 1085,1105 ****
    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 GIMPLE_MODIFY_STMT, not INIT_EXPR here so that we
  	 keep our trees in gimple form.  */
!       init_stmt = build2 (GIMPLE_MODIFY_STMT, 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
--- 1309,1362 ----
    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
+ 	  || is_gimple_min_invariant (rhs)))
+     {
+       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 GIMPLE_MODIFY_STMT, 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 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), def, rhs);
! 	  SSA_NAME_DEF_STMT (def) = init_stmt;
! 	  SSA_NAME_IS_DEFAULT_DEF (def) = 0;
! 	  set_default_def (var, NULL);
! 	}
!       else
!         init_stmt = build2 (GIMPLE_MODIFY_STMT, 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,
*** 1110,1121 ****
  	  && (!is_gimple_cast (rhs)
  	      || !is_gimple_val (TREE_OPERAND (rhs, 0))))
  	  || !is_gimple_reg (var))
! 	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);
      }
  }
  
--- 1367,1395 ----
  	  && (!is_gimple_cast (rhs)
  	      || !is_gimple_val (TREE_OPERAND (rhs, 0))))
  	  || !is_gimple_reg (var))
! 	{
!           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_symbols_for_renaming (bsi_stmt (bsi));
      }
  }
  
*************** initialize_inlined_parameters (copy_body
*** 1170,1186 ****
     The USE_STMT is filled to contain a use of the declaration to
     indicate the return value of the function.
  
!    RETURN_SLOT_ADDR, if non-null, was a fake parameter that
!    took the address of the result.  MODIFY_DEST, if non-null, was the LHS of
!    the GIMPLE_MODIFY_STMT to which this call is the RHS.
  
     The return value is a (possibly null) value that is the result of the
     function as seen by the callee.  *USE_P is a (possibly null) value that
     holds the result as seen by the caller.  */
  
  static tree
! declare_return_variable (copy_body_data *id, tree return_slot_addr,
! 			 tree modify_dest, tree *use_p)
  {
    tree callee = id->src_fn;
    tree caller = id->dst_fn;
--- 1444,1460 ----
     The USE_STMT is filled to contain a use of the declaration to
     indicate the return value of the function.
  
!    RETURN_SLOT, if non-null is place where to store the result.  It
!    is set only for CALL_EXPR_RETURN_SLOT_OPT.  MODIFY_DEST, if non-null,
!    was the LHS of the GIMPLE_MODIFY_STMT to which this call is the RHS.
  
     The return value is a (possibly null) value that is the result of the
     function as seen by the callee.  *USE_P is a (possibly null) value that
     holds the result as seen by the caller.  */
  
  static tree
! declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
! 			 tree *use_p)
  {
    tree callee = id->src_fn;
    tree caller = id->dst_fn;
*************** declare_return_variable (copy_body_data 
*** 1199,1213 ****
  
    /* If there was a return slot, then the return value is the
       dereferenced address of that object.  */
!   if (return_slot_addr)
      {
!       /* The front end shouldn't have used both return_slot_addr and
  	 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
             || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
  	  && !DECL_GIMPLE_REG_P (result)
--- 1473,1521 ----
  
    /* If there was a return slot, then the return value is the
       dereferenced address of that object.  */
!   if (return_slot)
      {
!       /* The front end shouldn't have used both return_slot and
  	 a modify expression.  */
        gcc_assert (!modify_dest);
        if (DECL_BY_REFERENCE (result))
! 	{
! 	  tree return_slot_addr = build_fold_addr_expr (return_slot);
! 	  STRIP_USELESS_TYPE_CONVERSION (return_slot_addr);
! 
! 	  /* We are going to construct *&return_slot and we can't do that
! 	     for variables believed to be not addressable. 
! 
! 	     FIXME: This check possibly can match, because values returned
! 	     via return slot optimization are not believed to have address
! 	     taken by alias analysis.  */
! 	  gcc_assert (TREE_CODE (return_slot) != SSA_NAME);
! 	  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 (return_slot, &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
! 	{
! 	  var = return_slot;
! 	  gcc_assert (TREE_CODE (var) != SSA_NAME);
! 	}
        if ((TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
             || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
  	  && !DECL_GIMPLE_REG_P (result)
*************** declare_return_variable (copy_body_data 
*** 1221,1227 ****
    gcc_assert (!TREE_ADDRESSABLE (callee_type));
  
    /* Attempt to avoid creating a new temporary variable.  */
!   if (modify_dest)
      {
        bool use_it = false;
  
--- 1529,1536 ----
    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 
*** 1270,1275 ****
--- 1579,1589 ----
    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
*** 1938,1944 ****
    tree fn;
    splay_tree st;
    tree args;
!   tree return_slot_addr;
    tree modify_dest;
    location_t saved_location;
    struct cgraph_edge *cg_edge;
--- 2252,2258 ----
    tree fn;
    splay_tree st;
    tree args;
!   tree return_slot;
    tree modify_dest;
    location_t saved_location;
    struct cgraph_edge *cg_edge;
*************** expand_call_inline (basic_block bb, tree
*** 2095,2100 ****
--- 2409,2415 ----
    /* Record the function we are about to inline.  */
    id->src_fn = fn;
    id->src_node = cg_edge->callee;
+   id->src_cfun = DECL_STRUCT_FUNCTION (fn);
  
    initialize_inlined_parameters (id, args, TREE_OPERAND (t, 2), fn, bb);
  
*************** expand_call_inline (basic_block bb, tree
*** 2108,2114 ****
    gcc_assert (TREE_CODE (DECL_INITIAL (fn)) == BLOCK);
  
    /* Find the lhs to which the result of this call is assigned.  */
!   return_slot_addr = NULL;
    if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
      {
        modify_dest = GIMPLE_STMT_OPERAND (stmt, 0);
--- 2423,2429 ----
    gcc_assert (TREE_CODE (DECL_INITIAL (fn)) == BLOCK);
  
    /* Find the lhs to which the result of this call is assigned.  */
!   return_slot = NULL;
    if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
      {
        modify_dest = GIMPLE_STMT_OPERAND (stmt, 0);
*************** expand_call_inline (basic_block bb, tree
*** 2123,2130 ****
  	TREE_NO_WARNING (modify_dest) = 1;
        if (CALL_EXPR_RETURN_SLOT_OPT (t))
  	{
! 	  return_slot_addr = build_fold_addr_expr (modify_dest);
! 	  STRIP_USELESS_TYPE_CONVERSION (return_slot_addr);
  	  modify_dest = NULL;
  	}
      }
--- 2438,2444 ----
  	TREE_NO_WARNING (modify_dest) = 1;
        if (CALL_EXPR_RETURN_SLOT_OPT (t))
  	{
! 	  return_slot = modify_dest;
  	  modify_dest = NULL;
  	}
      }
*************** expand_call_inline (basic_block bb, tree
*** 2132,2138 ****
      modify_dest = NULL;
  
    /* Declare the return variable for the function.  */
!   declare_return_variable (id, return_slot_addr,
  			   modify_dest, &use_retvar);
  
    /* This is it.  Duplicate the callee body.  Assume callee is
--- 2446,2452 ----
      modify_dest = NULL;
  
    /* Declare the return variable for the function.  */
!   declare_return_variable (id, return_slot,
  			   modify_dest, &use_retvar);
  
    /* This is it.  Duplicate the callee body.  Assume callee is
*************** expand_call_inline (basic_block bb, tree
*** 2164,2175 ****
    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);
--- 2478,2521 ----
    if (use_retvar && (TREE_CODE (bsi_stmt (stmt_bsi)) != CALL_EXPR))
      {
        *tp = use_retvar;
+       if (gimple_in_ssa_p (cfun))
+ 	{
+           update_stmt (stmt);
+           mark_symbols_for_renaming (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) == GIMPLE_MODIFY_STMT
! 	  && TREE_CODE (GIMPLE_STMT_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)
*** 2290,2296 ****
       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
--- 2636,2658 ----
       as inlining loops might increase the maximum.  */
    if (ENTRY_BLOCK_PTR->count)
      counts_to_freqs ();
!   if (gimple_in_ssa_p (cfun))
!     {
!       /* We make no attempts to keep dominance info up-to-date.  */
!       free_dominance_info (CDI_DOMINATORS);
!       free_dominance_info (CDI_POST_DOMINATORS);
!       delete_unreachable_blocks ();
!       update_ssa (TODO_update_ssa);
!       fold_cond_expr_cond ();
!       if (need_ssa_update_p ())
!         update_ssa (TODO_update_ssa);
!     }
!   else
!     fold_cond_expr_cond ();
!   /* It would be nice to check SSA/CFG/statement consistency here, but it is
!      not possible yet - the IPA passes might make various functions to not
!      throw and they don't care to proactively update local EH info.  This is
!      done later in fixup_cfg pass that also execute the verification.  */
  }
  
  /* FN is a function that has a complete body, and CLONE is a function whose
*************** tree_function_versioning (tree old_decl,
*** 2782,2788 ****
    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;
--- 3144,3150 ----
    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,
*** 2828,2833 ****
--- 3190,3201 ----
    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,
*** 2871,2892 ****
        }
    
    /* 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);
--- 3239,3246 ----
        }
    
    /* 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,
*** 2894,2906 ****
        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;
  }
  
--- 3248,3267 ----
        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);
+     }
+   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]