diff mbox

[PR,debug/47106] account used vars only once

Message ID ord3n4qb4b.fsf@livre.localdomain
State New
Headers show

Commit Message

Alexandre Oliva Feb. 7, 2011, 12:31 p.m. UTC
On Feb  4, 2011, Alexandre Oliva <aoliva@redhat.com> wrote:

> That isn't enough.  We often attempt to estimate the stack size of a
> function before we as much as put it in SSA form (let alone compute
> referenced_vras), while processing other functions.

> if we switch to referenced_vars only, we have to figure out how to
> rearrange the passes so that we make reasonable estimates.

Like this.  This has completed bootstrap and is almost done building
target libs on amd64-linux-gnu.  Ok to install if it passes regression
testing?

I've used a patch to report differences in the computation of stack
size, and in nearly all cases the size goes down, but there are
exceptions in which it goes up by 4 or 8 bytes.  I'll run a full
bootstrap with that patch once I'm done with testing and summarize the
results.

Comments

Jan Hubicka Feb. 7, 2011, 4:02 p.m. UTC | #1
> On Feb  4, 2011, Alexandre Oliva <aoliva@redhat.com> wrote:
> 
> > That isn't enough.  We often attempt to estimate the stack size of a
> > function before we as much as put it in SSA form (let alone compute
> > referenced_vras), while processing other functions.

This should happen only because compute_inline_parameters is scheduled too early.
Moving it just before early_inline pass should do the trick.

Honza
Jan Hubicka Feb. 7, 2011, 4:09 p.m. UTC | #2
> Index: gcc/ipa-inline.c
> ===================================================================
> --- gcc/ipa-inline.c.orig	2011-02-07 09:23:31.554084216 -0200
> +++ gcc/ipa-inline.c	2011-02-07 09:25:20.570774611 -0200
> @@ -1794,7 +1794,7 @@ cgraph_early_inlining (void)
>  
>    cfun->always_inline_functions_inlined = true;
>  
> -  return todo;
> +  return todo | execute_fixup_cfg ();

Fixup_cfg exists to update function body after properties of other functions
it calls was changed (and originally also some EH edges was removed after
inlining, but this was fixed some time ago).
If you go for splitting early otimizatoin queue, you need to schedule fixup_cfg
as first of early lowered passes, or any invocation of verify_cfg would fail
until early inliner is run.
> Index: gcc/cgraphunit.c
> ===================================================================
> --- gcc/cgraphunit.c.orig	2011-02-07 09:23:31.962071817 -0200
> +++ gcc/cgraphunit.c	2011-02-07 09:25:20.590774004 -0200
> @@ -246,7 +246,6 @@ cgraph_process_new_functions (void)
>  	    cgraph_analyze_function (node);
>  	  push_cfun (DECL_STRUCT_FUNCTION (fndecl));
>  	  current_function_decl = fndecl;
> -	  compute_inline_parameters (node);

Hmm, this is because both ipa-sra and ipa-split take care to compute inliner parameters
themselves?
If you go for this, you probably should arrange also new function inserted by -fprofile-generate
to be processed by compute_inline_parameters.  We never inline those, but we should not get
uninitialized fields there since they are used for cost metrics of ipa-cp, too.

Honza
Alexandre Oliva Feb. 7, 2011, 10:33 p.m. UTC | #3
On Feb  7, 2011, Jan Hubicka <hubicka@ucw.cz> wrote:

> If you go for splitting early otimizatoin queue, you need to schedule
> fixup_cfg as first of early lowered passes, or any invocation of
> verify_cfg would fail until early inliner is run.

That might work as well, but I probably won't investigate further, since
the approach of splitting the passes is undesirable and probably too
destabilizing at this point.

>> Index: gcc/cgraphunit.c
>> ===================================================================
>> --- gcc/cgraphunit.c.orig	2011-02-07 09:23:31.962071817 -0200
>> +++ gcc/cgraphunit.c	2011-02-07 09:25:20.590774004 -0200
>> @@ -246,7 +246,6 @@ cgraph_process_new_functions (void)
>> cgraph_analyze_function (node);
>> push_cfun (DECL_STRUCT_FUNCTION (fndecl));
>> current_function_decl = fndecl;
>> -	  compute_inline_parameters (node);

> Hmm, this is because both ipa-sra and ipa-split take care to compute
> inliner parameters themselves?

No, it's just because the early passes called below now include the
pass that computes inline parameters.
Alexandre Oliva Feb. 7, 2011, 10:35 p.m. UTC | #4
On Feb  7, 2011, Jan Hubicka <hubicka@ucw.cz> wrote:

>> On Feb  4, 2011, Alexandre Oliva <aoliva@redhat.com> wrote:
>> 
>> > That isn't enough.  We often attempt to estimate the stack size of a
>> > function before we as much as put it in SSA form (let alone compute
>> > referenced_vras), while processing other functions.

> This should happen only because compute_inline_parameters is scheduled
> too early.  Moving it just before early_inline pass should do the
> trick.

I tried that.  It didn't work, we still tried to estimate the stack size
of functions that hadn't been put in SSA form and had referenced_vars
computed.
Jan Hubicka Feb. 7, 2011, 11:58 p.m. UTC | #5
> On Feb  7, 2011, Jan Hubicka <hubicka@ucw.cz> wrote:
> 
> >> On Feb  4, 2011, Alexandre Oliva <aoliva@redhat.com> wrote:
> >> 
> >> > That isn't enough.  We often attempt to estimate the stack size of a
> >> > function before we as much as put it in SSA form (let alone compute
> >> > referenced_vras), while processing other functions.
> 
> > This should happen only because compute_inline_parameters is scheduled
> > too early.  Moving it just before early_inline pass should do the
> > trick.
> 
> I tried that.  It didn't work, we still tried to estimate the stack size
> of functions that hadn't been put in SSA form and had referenced_vars
> computed.

From where we did so?
Honza
> 
> -- 
> Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
> You must be the change you wish to see in the world. -- Gandhi
> Be Free! -- http://FSFLA.org/   FSF Latin America board member
> Free Software Evangelist      Red Hat Brazil Compiler Engineer
diff mbox

Patch

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/47106
	PR debug/47402
	* tree-flow.h (referenced_var_lookup): Add fn parameter.
	Adjust all callers.
	* tree-dfa.c (referenced_var_lookup): Use fn instead of cfun.
	* tree-flow-inline.h: Adjust.
	* gimple-pretty-print.c: Adjust.
	* tree-into-ssa.c: Adjust.
	* tree-ssa.c: Adjust.
	* cfgexpand.c: Adjust.
	(account_used_vars_for_block): Remove.
	(estimated_stack_frame_size): Use referenced vars.
	* tree-inline.c (remap_decl): Only mark VAR_DECLs as referenced
	that were referenced in the original function.
	(copy_decl_for_dup_finish): Likewise.
	* tree-optimize.c (pass_early_lowering_passes): New.
	(pass_early_lowered_passes): New.
	* tree-pass.h (pass_early_lowering_passes): Declare.
	(pass_early_lowered_passes): Declare.
	* passes.c (init_optimization_passes): Introduce
	pass_early_lowering_passes and pass_early_lowered_passes.
	Move first pass_inline_parameters into the latter.
	(execute_ipa_pass_list): Adjust so PLUGIN_EARLY_GIMPLE_PASSES get
	called at the same spots.
	* ipa-inline.c (cgraph_early_inlining): Fixup cfg.
	(pass_inline_parameters): Require PROP_referenced_vars.
	* cgraphunit.c (cgraph_process_new_functions): Don't run
	compute_inline_parameters explicitly.
	* predict.c (gate_estimate_probability): Skip for already-guessed
	versioned functions.

for  gcc/testsuite/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/47106
	PR debug/47402
	* g++.dg/debug/pr47106.C: New.

Index: gcc/tree-flow.h
===================================================================
--- gcc/tree-flow.h.orig	2011-02-07 09:23:32.698049422 -0200
+++ gcc/tree-flow.h	2011-02-07 09:25:20.342781531 -0200
@@ -319,7 +319,7 @@  typedef struct
        !end_referenced_vars_p (&(ITER)); \
        (VAR) = next_referenced_var (&(ITER)))
 
-extern tree referenced_var_lookup (unsigned int);
+extern tree referenced_var_lookup (struct function *, unsigned int);
 extern bool referenced_var_check_and_insert (tree);
 #define num_referenced_vars htab_elements (gimple_referenced_vars (cfun))
 
Index: gcc/tree-dfa.c
===================================================================
--- gcc/tree-dfa.c.orig	2011-02-07 09:23:32.112067191 -0200
+++ gcc/tree-dfa.c	2011-02-07 09:25:20.391780043 -0200
@@ -488,12 +488,12 @@  find_referenced_vars_in (gimple stmt)
    variable.  */
 
 tree
-referenced_var_lookup (unsigned int uid)
+referenced_var_lookup (struct function *fn, unsigned int uid)
 {
   tree h;
   struct tree_decl_minimal in;
   in.uid = uid;
-  h = (tree) htab_find_with_hash (gimple_referenced_vars (cfun), &in, uid);
+  h = (tree) htab_find_with_hash (gimple_referenced_vars (fn), &in, uid);
   return h;
 }
 
Index: gcc/tree-flow-inline.h
===================================================================
--- gcc/tree-flow-inline.h.orig	2011-02-07 09:23:31.268092772 -0200
+++ gcc/tree-flow-inline.h	2011-02-07 09:25:20.476777464 -0200
@@ -103,7 +103,7 @@  next_htab_element (htab_iterator *hti)
 static inline tree
 referenced_var (unsigned int uid)
 {
-  tree var = referenced_var_lookup (uid);
+  tree var = referenced_var_lookup (cfun, uid);
   gcc_assert (var || uid == 0);
   return var;
 }
Index: gcc/gimple-pretty-print.c
===================================================================
--- gcc/gimple-pretty-print.c.orig	2011-02-07 09:23:30.988101348 -0200
+++ gcc/gimple-pretty-print.c	2011-02-07 09:25:20.438778618 -0200
@@ -542,7 +542,7 @@  pp_points_to_solution (pretty_printer *b
       pp_string (buffer, "{ ");
       EXECUTE_IF_SET_IN_BITMAP (pt->vars, 0, i, bi)
 	{
-	  tree var = referenced_var_lookup (i);
+	  tree var = referenced_var_lookup (cfun, i);
 	  if (var)
 	    {
 	      dump_generic_node (buffer, var, 0, dump_flags, false);
Index: gcc/tree-into-ssa.c
===================================================================
--- gcc/tree-into-ssa.c.orig	2011-02-07 09:23:31.697080038 -0200
+++ gcc/tree-into-ssa.c	2011-02-07 09:25:20.500776736 -0200
@@ -1469,7 +1469,7 @@  dump_decl_set (FILE *file, bitmap set)
 
       EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi)
 	{
-	  tree var = referenced_var_lookup (i);
+	  tree var = referenced_var_lookup (cfun, i);
 	  if (var)
 	    print_generic_expr (file, var, 0);
 	  else
Index: gcc/tree-ssa.c
===================================================================
--- gcc/tree-ssa.c.orig	2011-02-07 09:23:32.553053907 -0200
+++ gcc/tree-ssa.c	2011-02-07 09:25:20.526775945 -0200
@@ -1902,7 +1902,7 @@  maybe_optimize_var (tree var, bitmap add
 
   /* If the variable is not in the list of referenced vars then we
      do not need to touch it nor can we rename it.  */
-  if (!referenced_var_lookup (DECL_UID (var)))
+  if (!referenced_var_lookup (cfun, DECL_UID (var)))
     return false;
 
   if (TREE_ADDRESSABLE (var)
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c.orig	2011-02-07 09:23:30.841105782 -0200
+++ gcc/cfgexpand.c	2011-02-07 09:25:20.326782016 -0200
@@ -520,7 +520,7 @@  update_alias_info_with_stack_vars (void)
 	     for -O0 where we are preserving even unreferenced variables.  */
 	  gcc_assert (DECL_P (decl)
 		      && (!optimize
-			  || referenced_var_lookup (DECL_UID (decl))));
+			  || referenced_var_lookup (cfun, DECL_UID (decl))));
 	  bitmap_set_bit (part, uid);
 	  *((bitmap *) pointer_map_insert (decls_to_partitions,
 					   (void *)(size_t) uid)) = part;
@@ -1311,30 +1311,6 @@  create_stack_guard (void)
   crtl->stack_protect_guard = guard;
 }
 
-/* A subroutine of expand_used_vars.  Walk down through the BLOCK tree
-   expanding variables.  Those variables that can be put into registers
-   are allocated pseudos; those that can't are put on the stack.
-
-   TOPLEVEL is true if this is the outermost BLOCK.  */
-
-static HOST_WIDE_INT
-account_used_vars_for_block (tree block, bool toplevel)
-{
-  tree t;
-  HOST_WIDE_INT size = 0;
-
-  /* Expand all variables at this level.  */
-  for (t = BLOCK_VARS (block); t ; t = DECL_CHAIN (t))
-    if (var_ann (t) && is_used_p (t))
-      size += expand_one_var (t, toplevel, false);
-
-  /* Expand all variables at containing levels.  */
-  for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t))
-    size += account_used_vars_for_block (t, false);
-
-  return size;
-}
-
 /* Prepare for expanding variables.  */
 static void
 init_vars_expansion (void)
@@ -1379,22 +1355,18 @@  estimated_stack_frame_size (tree decl)
 {
   HOST_WIDE_INT size = 0;
   size_t i;
-  tree var, outer_block = DECL_INITIAL (current_function_decl);
-  unsigned ix;
+  tree var;
   tree old_cur_fun_decl = current_function_decl;
+  referenced_var_iterator rvi;
+
+  gcc_checking_assert (gimple_referenced_vars (cfun));
+
   current_function_decl = decl;
   push_cfun (DECL_STRUCT_FUNCTION (decl));
 
-  init_vars_expansion ();
-
-  FOR_EACH_LOCAL_DECL (cfun, ix, var)
-    {
-      /* TREE_USED marks local variables that do not appear in lexical
-	 blocks.  We don't want to expand those that do twice.  */
-      if (TREE_USED (var))
-        size += expand_one_var (var, true, false);
-    }
-  size += account_used_vars_for_block (outer_block, true);
+  gcc_checking_assert (gimple_referenced_vars (cfun));
+  FOR_EACH_REFERENCED_VAR (var, rvi)
+    size += expand_one_var (var, true, false);
 
   if (stack_vars_num > 0)
     {
Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c.orig	2011-02-07 09:23:32.407058212 -0200
+++ gcc/tree-inline.c	2011-02-07 09:25:20.376780499 -0200
@@ -317,7 +317,11 @@  remap_decl (tree decl, copy_body_data *i
 	      || TREE_CODE (t) == RESULT_DECL || TREE_CODE (t) == PARM_DECL))
 	{
 	  get_var_ann (t);
-	  add_referenced_var (t);
+	  if (TREE_CODE (decl) != VAR_DECL
+	      || !gimple_referenced_vars (DECL_STRUCT_FUNCTION (id->src_fn))
+	      || referenced_var_lookup (DECL_STRUCT_FUNCTION (id->src_fn),
+					DECL_UID (decl)))
+	    add_referenced_var (t);
 	}
       return t;
     }
@@ -4753,6 +4757,13 @@  copy_decl_for_dup_finish (copy_body_data
        new function.  */
     DECL_CONTEXT (copy) = id->dst_fn;
 
+  if (TREE_CODE (decl) == VAR_DECL
+      && gimple_referenced_vars (cfun)
+      && gimple_referenced_vars (DECL_STRUCT_FUNCTION (id->src_fn))
+      && referenced_var_lookup (DECL_STRUCT_FUNCTION (id->src_fn),
+				DECL_UID (decl)))
+    add_referenced_var (copy);
+
   return copy;
 }
 
Index: gcc/tree-optimize.c
===================================================================
--- gcc/tree-optimize.c.orig	2011-02-07 09:23:33.152035632 -0200
+++ gcc/tree-optimize.c	2011-02-07 09:25:20.538775583 -0200
@@ -101,6 +101,44 @@  execute_all_early_local_passes (void)
   return 0;
 }
 
+struct simple_ipa_opt_pass pass_early_lowering_passes =
+{
+ {
+  SIMPLE_IPA_PASS,
+  "*early_lowering",			/* name */
+  gate_all_early_local_passes,		/* gate */
+  NULL,					/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  TV_EARLY_LOCAL,			/* tv_id */
+  0,					/* properties_required */
+  PROP_referenced_vars,			/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  0	 				/* todo_flags_finish */
+ }
+};
+
+struct simple_ipa_opt_pass pass_early_lowered_passes =
+{
+ {
+  SIMPLE_IPA_PASS,
+  "*early_lowered",			/* name */
+  gate_all_early_local_passes,		/* gate */
+  NULL,					/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  TV_EARLY_LOCAL,			/* tv_id */
+  PROP_referenced_vars,			/* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  0	 				/* todo_flags_finish */
+ }
+};
+
 struct simple_ipa_opt_pass pass_early_local_passes =
 {
  {
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h.orig	2011-02-07 09:23:31.407088633 -0200
+++ gcc/tree-pass.h	2011-02-07 09:25:20.550775218 -0200
@@ -452,6 +452,8 @@  extern struct simple_ipa_opt_pass pass_i
 extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility;
 extern struct simple_ipa_opt_pass pass_ipa_tree_profile;
 
+extern struct simple_ipa_opt_pass pass_early_lowering_passes;
+extern struct simple_ipa_opt_pass pass_early_lowered_passes;
 extern struct simple_ipa_opt_pass pass_early_local_passes;
 
 extern struct ipa_opt_pass_d pass_ipa_whole_program_visibility;
Index: gcc/passes.c
===================================================================
--- gcc/passes.c.orig	2011-02-07 09:23:32.266062537 -0200
+++ gcc/passes.c	2011-02-07 09:25:20.462777888 -0200
@@ -729,7 +729,6 @@  init_optimization_passes (void)
   NEXT_PASS (pass_build_cfg);
   NEXT_PASS (pass_warn_function_return);
   NEXT_PASS (pass_build_cgraph_edges);
-  NEXT_PASS (pass_inline_parameters);
   *p = NULL;
 
   /* Interprocedural optimization passes.  */
@@ -739,51 +738,59 @@  init_optimization_passes (void)
   NEXT_PASS (pass_early_local_passes);
     {
       struct opt_pass **p = &pass_early_local_passes.pass.sub;
-      NEXT_PASS (pass_fixup_cfg);
-      NEXT_PASS (pass_init_datastructures);
-      NEXT_PASS (pass_expand_omp);
-
-      NEXT_PASS (pass_referenced_vars);
-      NEXT_PASS (pass_build_ssa);
-      NEXT_PASS (pass_lower_vector);
-      NEXT_PASS (pass_early_warn_uninitialized);
-      /* Note that it is not strictly necessary to schedule an early
-	 inline pass here.  However, some test cases (e.g.,
-	 g++.dg/other/p334435.C g++.dg/other/i386-1.C) expect extern
-	 inline functions to be inlined even at -O0.  This does not
-	 happen during the first early inline pass.  */
-      NEXT_PASS (pass_rebuild_cgraph_edges);
-      NEXT_PASS (pass_early_inline);
-      NEXT_PASS (pass_all_early_optimizations);
-	{
-	  struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
-	  NEXT_PASS (pass_remove_cgraph_callee_edges);
-	  NEXT_PASS (pass_rename_ssa_copies);
-	  NEXT_PASS (pass_ccp);
-	  NEXT_PASS (pass_forwprop);
-	  /* pass_build_ealias is a dummy pass that ensures that we
-	     execute TODO_rebuild_alias at this point.  Re-building
-	     alias information also rewrites no longer addressed
-	     locals into SSA form if possible.  */
-	  NEXT_PASS (pass_build_ealias);
-	  NEXT_PASS (pass_sra_early);
-	  NEXT_PASS (pass_copy_prop);
-	  NEXT_PASS (pass_merge_phi);
-	  NEXT_PASS (pass_cd_dce);
-	  NEXT_PASS (pass_early_ipa_sra);
-	  NEXT_PASS (pass_tail_recursion);
-	  NEXT_PASS (pass_convert_switch);
-          NEXT_PASS (pass_cleanup_eh);
-          NEXT_PASS (pass_profile);
-          NEXT_PASS (pass_local_pure_const);
-	  /* Split functions creates parts that are not run through
-	     early optimizations again.  It is thus good idea to do this
-	     late.  */
-          NEXT_PASS (pass_split_functions);
+      NEXT_PASS (pass_early_lowering_passes);
+        {
+	  struct opt_pass **p = &pass_early_lowering_passes.pass.sub;
+	  NEXT_PASS (pass_fixup_cfg);
+	  NEXT_PASS (pass_init_datastructures);
+	  NEXT_PASS (pass_expand_omp);
+
+	  /* We have to run this pass for all functions before we go into
+	     early local passes, particularly pass_inline_parameters, that
+	     relies on referenced_vars being already computed.  */
+	  NEXT_PASS (pass_referenced_vars);
+
+	  NEXT_PASS (pass_build_ssa);
+	  NEXT_PASS (pass_lower_vector);
+	  NEXT_PASS (pass_early_warn_uninitialized);
+	  NEXT_PASS (pass_rebuild_cgraph_edges);
+	}
+      NEXT_PASS (pass_early_lowered_passes);
+        {
+	  struct opt_pass **p = &pass_early_lowered_passes.pass.sub;
+	  NEXT_PASS (pass_inline_parameters);
+	  NEXT_PASS (pass_early_inline);
+	  NEXT_PASS (pass_all_early_optimizations);
+	  {
+	    struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
+	    NEXT_PASS (pass_remove_cgraph_callee_edges);
+	    NEXT_PASS (pass_rename_ssa_copies);
+	    NEXT_PASS (pass_ccp);
+	    NEXT_PASS (pass_forwprop);
+	    /* pass_build_ealias is a dummy pass that ensures that we
+	       execute TODO_rebuild_alias at this point.  Re-building
+	       alias information also rewrites no longer addressed
+	       locals into SSA form if possible.  */
+	    NEXT_PASS (pass_build_ealias);
+	    NEXT_PASS (pass_sra_early);
+	    NEXT_PASS (pass_copy_prop);
+	    NEXT_PASS (pass_merge_phi);
+	    NEXT_PASS (pass_cd_dce);
+	    NEXT_PASS (pass_early_ipa_sra);
+	    NEXT_PASS (pass_tail_recursion);
+	    NEXT_PASS (pass_convert_switch);
+	    NEXT_PASS (pass_cleanup_eh);
+	    NEXT_PASS (pass_profile);
+	    NEXT_PASS (pass_local_pure_const);
+	    /* Split functions creates parts that are not run through
+	       early optimizations again.  It is thus good idea to do this
+	       late.  */
+	    NEXT_PASS (pass_split_functions);
+	  }
+	  NEXT_PASS (pass_release_ssa_names);
+	  NEXT_PASS (pass_rebuild_cgraph_edges);
+	  NEXT_PASS (pass_inline_parameters);
 	}
-      NEXT_PASS (pass_release_ssa_names);
-      NEXT_PASS (pass_rebuild_cgraph_edges);
-      NEXT_PASS (pass_inline_parameters);
     }
   NEXT_PASS (pass_ipa_tree_profile);
     {
@@ -1927,18 +1934,20 @@  execute_ipa_pass_list (struct opt_pass *
       gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
       if (execute_one_pass (pass) && pass->sub)
 	{
+	  if (pass == &pass_early_local_passes.pass)
+	    invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
+
 	  if (pass->sub->type == GIMPLE_PASS)
-	    {
-	      invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
-	      do_per_function_toporder ((void (*)(void *))execute_pass_list,
-					pass->sub);
-	      invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
-	    }
+	    do_per_function_toporder ((void (*)(void *))execute_pass_list,
+				      pass->sub);
 	  else if (pass->sub->type == SIMPLE_IPA_PASS
 		   || pass->sub->type == IPA_PASS)
 	    execute_ipa_pass_list (pass->sub);
 	  else
 	    gcc_unreachable ();
+
+	  if (pass == &pass_early_local_passes.pass)
+	    invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
 	}
       gcc_assert (!current_function_decl);
       cgraph_process_new_functions ();
Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c.orig	2011-02-07 09:23:31.554084216 -0200
+++ gcc/ipa-inline.c	2011-02-07 09:25:20.570774611 -0200
@@ -1794,7 +1794,7 @@  cgraph_early_inlining (void)
 
   cfun->always_inline_functions_inlined = true;
 
-  return todo;
+  return todo | execute_fixup_cfg ();
 }
 
 struct gimple_opt_pass pass_early_inline =
@@ -2044,7 +2044,7 @@  struct gimple_opt_pass pass_inline_param
   NULL,					/* next */
   0,					/* static_pass_number */
   TV_INLINE_HEURISTICS,			/* tv_id */
-  0,	                                /* properties_required */
+  PROP_referenced_vars,	                /* properties_required */
   0,					/* properties_provided */
   0,					/* properties_destroyed */
   0,					/* todo_flags_start */
Index: gcc/cgraphunit.c
===================================================================
--- gcc/cgraphunit.c.orig	2011-02-07 09:23:31.962071817 -0200
+++ gcc/cgraphunit.c	2011-02-07 09:25:20.590774004 -0200
@@ -246,7 +246,6 @@  cgraph_process_new_functions (void)
 	    cgraph_analyze_function (node);
 	  push_cfun (DECL_STRUCT_FUNCTION (fndecl));
 	  current_function_decl = fndecl;
-	  compute_inline_parameters (node);
 	  if ((cgraph_state == CGRAPH_STATE_IPA_SSA
 	      && !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
 	      /* When not optimizing, be sure we run early local passes anyway
Index: gcc/predict.c
===================================================================
--- gcc/predict.c.orig	2011-02-07 09:23:31.828075834 -0200
+++ gcc/predict.c	2011-02-07 09:53:09.096282921 -0200
@@ -2266,6 +2266,11 @@  compute_function_frequency (void)
 static bool
 gate_estimate_probability (void)
 {
+  /* Functions cloned for versioning get profile information from
+     the original functions.  */
+  if (profile_status != PROFILE_ABSENT)
+    return false;
+
   return flag_guess_branch_prob;
 }
 
Index: gcc/testsuite/g++.dg/debug/pr47106.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/g++.dg/debug/pr47106.C	2011-02-07 09:25:20.420779164 -0200
@@ -0,0 +1,37 @@ 
+// { dg-do compile }
+// { dg-options "-O -fpartial-inlining -flto -fconserve-stack -fcompare-debug" }
+
+void end (int, int) __attribute__ ((__noreturn__));
+
+struct S
+{
+  int i;
+  S *s;
+};
+
+inline bool f (S *s)
+{
+  if (!s->s)
+    end (0, 0);
+  return s->s == s;
+}
+
+inline bool
+baz (S s1, S)
+{
+  while (f (&s1));
+}
+
+inline bool
+bar (S s1, S s2, S)
+{
+  baz (s1, s2);
+}
+
+S getS ();
+
+bool
+foo ()
+{
+  bar (getS (), getS (), getS ());
+}