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: [PR debug/47106] account used vars only once


On Feb  7, 2011, Richard Guenther <richard.guenther@gmail.com> wrote:

> The referenced_var_lookup interface change is ok.

After much hacking and testing, I have a patchset that works (no
regressions) and that I'm happy with.

I've broken it up into preparation patches with interface changes, the
aactual change, one independent bug fix, some additional improvements
that I regard as slightly risky, but that have survived multiple
bootstrap cycles (-O1 and -O3 in addition to -O2, on i686 and x86_64),
and some additional patches I used for testing and for verifying that
the estimated stack sizes are unchanged from the current method, when
debug info is not enabled (when it is, variables retained in lexical
blocks for debug information only used to inflate the estimate, but now
they no longer do)

On Feb  7, 2011, Jan Hubicka <hubicka@ucw.cz> wrote:

>> 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?

SRA, indeed.

On Feb  8, 2011, Richard Guenther <richard.guenther@gmail.com> wrote:

> Yes, we can have cycles and no referenced vars in the callee.  But
> we won't inline that callee (as it isn't in SSA form), so we can just
> as well skip looking at its estimated stack frame size.

Excellent!

On Feb  8, 2011, Jan Hubicka <hubicka@ucw.cz> wrote:

> Functions checking inline parameters (check_inline_limits etc.) are done only
> after in_ssa_p check is done, so we should be safe here.

Yup.

> (with exception of disregard inline limits, you can move that check
> later but any value of that flag is OK since we won't do anything with
> the call)

I hadn't realized what this note was about before now.  I hit the
problem of processing functions in the wrong order, breaking pr42632.c,
which is why I introduced a new pass, compute_inlinable, at the point
the initial compute_inline_params was.  I tried not calling
compute_inlinable from within compute_inline_parameters, but I found out
inlinable changed, or had to be computed separately, or something like
that.  What I didn't try was to replace the explicit call of
compute_inline_parameters in cgraph_process_new_functions with
compute_inlinable.  From the failures I observed, it now occurs to me
that this might be what I was missing.  Anyhow, this patch works, but if
you'd rather I make this other change, I will.


Anyhow, here is the patch set.

Interface changes:

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.

Index: gcc/tree-flow.h
===================================================================
--- gcc/tree-flow.h.orig	2011-02-10 04:20:23.466643733 -0200
+++ gcc/tree-flow.h	2011-02-10 04:23:07.004150142 -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-10 04:20:23.160650315 -0200
+++ gcc/tree-dfa.c	2011-02-10 04:23:06.417162741 -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-10 04:20:22.943654959 -0200
+++ gcc/tree-flow-inline.h	2011-02-10 04:23:05.289186749 -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-10 04:20:22.823657516 -0200
+++ gcc/gimple-pretty-print.c	2011-02-10 04:20:27.672553932 -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-10 04:20:23.046652755 -0200
+++ gcc/tree-into-ssa.c	2011-02-10 04:23:06.064170211 -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-10 04:20:23.302647274 -0200
+++ gcc/tree-ssa.c	2011-02-10 04:23:06.817154171 -0200
@@ -1930,7 +1930,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-10 04:20:22.688660397 -0200
+++ gcc/cfgexpand.c	2011-02-10 04:23:00.395291314 -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;
for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/47106
	PR debug/47402
	* tree-flow.h (FOR_EACH_REFERENCED_VAR): Add FN argument.
	Adjust all users.  Pass FN to...
	* tree-flow-inline.h (first_referenced_var): ... this.  Add
	fn argument.
	* ipa-struct-reorg.c: Adjust.
	* tree-dfa.c: Adjust.
	* tree-into-ssa.c: Adjust.
	* tree-sra.c: Adjust.
	* tree-ssa-alias.c: Adjust.
	* tree-ssa-live.c: Adjust.
	* tree-ssa.c: Adjust.
	* tree-ssanames.c: Adjust.
	* tree-tailcall.c: Adjust.

Index: gcc/tree-flow.h
===================================================================
--- gcc/tree-flow.h.orig	2011-02-10 04:20:27.617555109 -0200
+++ gcc/tree-flow.h	2011-02-10 04:20:29.087522610 -0200
@@ -314,9 +314,9 @@ typedef struct
    to the hashtable while using this macro.  Doing so may cause it to behave
    erratically.  */
 
-#define FOR_EACH_REFERENCED_VAR(VAR, ITER) \
-  for ((VAR) = first_referenced_var (&(ITER)); \
-       !end_referenced_vars_p (&(ITER)); \
+#define FOR_EACH_REFERENCED_VAR(FN, VAR, ITER)		\
+  for ((VAR) = first_referenced_var ((FN), &(ITER));	\
+       !end_referenced_vars_p (&(ITER));		\
        (VAR) = next_referenced_var (&(ITER)))
 
 extern tree referenced_var_lookup (struct function *, unsigned int);
Index: gcc/tree-flow-inline.h
===================================================================
--- gcc/tree-flow-inline.h.orig	2011-02-10 04:20:27.650554402 -0200
+++ gcc/tree-flow-inline.h	2011-02-10 04:22:33.508865705 -0200
@@ -112,10 +112,10 @@ referenced_var (unsigned int uid)
    referenced_vars hashtable, and return that variable.  */
 
 static inline tree
-first_referenced_var (referenced_var_iterator *iter)
+first_referenced_var (struct function *fn, referenced_var_iterator *iter)
 {
   return (tree) first_htab_element (&iter->hti,
-				    gimple_referenced_vars (cfun));
+				    gimple_referenced_vars (fn));
 }
 
 /* Return true if we have hit the end of the referenced variables ITER is
Index: gcc/ipa-struct-reorg.c
===================================================================
--- gcc/ipa-struct-reorg.c.orig	2011-02-10 04:20:21.457686677 -0200
+++ gcc/ipa-struct-reorg.c	2011-02-10 04:20:29.142522529 -0200
@@ -2712,7 +2712,7 @@ create_new_local_vars (void)
   new_local_vars = htab_create (num_referenced_vars,
 				new_var_hash, new_var_eq, NULL);
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       if (!is_global_var (var))
 	create_new_var (var, new_local_vars);
Index: gcc/tree-dfa.c
===================================================================
--- gcc/tree-dfa.c.orig	2011-02-10 04:20:27.635554720 -0200
+++ gcc/tree-dfa.c	2011-02-10 04:20:29.157522207 -0200
@@ -218,7 +218,7 @@ dump_referenced_vars (FILE *file)
   fprintf (file, "\nReferenced variables in %s: %u\n\n",
 	   get_name (current_function_decl), (unsigned) num_referenced_vars);
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       fprintf (file, "Variable: ");
       dump_variable (file, var);
@@ -400,7 +400,7 @@ collect_dfa_stats (struct dfa_stats_d *d
   memset ((void *)dfa_stats_p, 0, sizeof (struct dfa_stats_d));
 
   /* Count all the variable annotations.  */
-  FOR_EACH_REFERENCED_VAR (var, vi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, vi)
     if (var_ann (var))
       dfa_stats_p->num_var_anns++;
 
Index: gcc/tree-into-ssa.c
===================================================================
--- gcc/tree-into-ssa.c.orig	2011-02-10 04:20:27.726552777 -0200
+++ gcc/tree-into-ssa.c	2011-02-10 04:20:29.185521611 -0200
@@ -1156,7 +1156,7 @@ insert_phi_nodes (bitmap_head *dfs)
      differences but no UID ordering differences.  */
 
   vars = BITMAP_ALLOC (NULL);
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       struct def_blocks_d *def_map;
 
@@ -1573,7 +1573,7 @@ dump_currdefs (FILE *file)
   tree var;
 
   fprintf (file, "\n\nCurrent reaching definitions\n\n");
-  FOR_EACH_REFERENCED_VAR (var, i)
+  FOR_EACH_REFERENCED_VAR (cfun, var, i)
     if (SYMS_TO_RENAME (cfun) == NULL
 	|| bitmap_bit_p (SYMS_TO_RENAME (cfun), DECL_UID (var)))
       {
@@ -2313,7 +2313,7 @@ init_ssa_renamer (void)
   def_blocks = htab_create (num_referenced_vars, def_blocks_hash,
                             def_blocks_eq, def_blocks_free);
 
-  FOR_EACH_REFERENCED_VAR(var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     set_current_def (var, NULL_TREE);
 }
 
Index: gcc/tree-sra.c
===================================================================
--- gcc/tree-sra.c.orig	2011-02-10 04:20:21.083694687 -0200
+++ gcc/tree-sra.c	2011-02-10 04:20:29.221520842 -0200
@@ -1540,7 +1540,7 @@ find_var_candidates (void)
   referenced_var_iterator rvi;
   bool ret = false;
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       if (TREE_CODE (var) != VAR_DECL && TREE_CODE (var) != PARM_DECL)
         continue;
Index: gcc/tree-ssa-alias.c
===================================================================
--- gcc/tree-ssa-alias.c.orig	2011-02-10 04:20:20.624704633 -0200
+++ gcc/tree-ssa-alias.c	2011-02-10 04:20:29.243520372 -0200
@@ -364,7 +364,7 @@ dump_alias_info (FILE *file)
 
   fprintf (file, "Aliased symbols\n\n");
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       if (may_be_aliased (var))
 	dump_variable (file, var);
Index: gcc/tree-ssa-live.c
===================================================================
--- gcc/tree-ssa-live.c.orig	2011-02-10 04:20:20.850699713 -0200
+++ gcc/tree-ssa-live.c	2011-02-10 04:20:29.261519988 -0200
@@ -705,7 +705,7 @@ remove_unused_locals (void)
   mark_scope_block_unused (DECL_INITIAL (current_function_decl));
 
   /* Assume all locals are unused.  */
-  FOR_EACH_REFERENCED_VAR (t, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, t, rvi)
     clear_is_used (t);
 
   /* Walk the CFG marking all referenced symbols.  */
@@ -821,7 +821,7 @@ remove_unused_locals (void)
     }
 
   /* Remove unused variables from REFERENCED_VARs.  */
-  FOR_EACH_REFERENCED_VAR (t, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, t, rvi)
     if (!is_global_var (t)
 	&& TREE_CODE (t) != PARM_DECL
 	&& TREE_CODE (t) != RESULT_DECL
Index: gcc/tree-ssa.c
===================================================================
--- gcc/tree-ssa.c.orig	2011-02-10 04:20:27.751552245 -0200
+++ gcc/tree-ssa.c	2011-02-10 04:20:29.279519603 -0200
@@ -1157,7 +1157,7 @@ delete_tree_ssa (void)
   tree var;
 
   /* Remove annotations from every referenced local variable.  */
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       if (is_global_var (var))
 	continue;
Index: gcc/tree-ssanames.c
===================================================================
--- gcc/tree-ssanames.c.orig	2011-02-10 04:20:20.484707352 -0200
+++ gcc/tree-ssanames.c	2011-02-10 04:20:29.292519326 -0200
@@ -340,7 +340,7 @@ release_dead_ssa_names (void)
 
   /* Current defs point to various dead SSA names that in turn point to
      eventually dead variables so a bunch of memory is held live.  */
-  FOR_EACH_REFERENCED_VAR (t, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, t, rvi)
     set_current_def (t, NULL);
   /* Now release the freelist.  */
   for (t = FREE_SSANAMES (cfun); t; t = next)
Index: gcc/tree-tailcall.c
===================================================================
--- gcc/tree-tailcall.c.orig	2011-02-10 04:20:20.349710447 -0200
+++ gcc/tree-tailcall.c	2011-02-10 04:20:29.306519026 -0200
@@ -481,7 +481,7 @@ find_tail_calls (basic_block bb, struct 
 
   /* Make sure the tail invocation of this function does not refer
      to local variables.  */
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       if (TREE_CODE (var) != PARM_DECL
 	  && auto_var_in_fn_p (var, cfun->decl)
@@ -889,7 +889,7 @@ add_virtual_phis (void)
      this, we cannot do much better than to rebuild the ssa form for
      possibly affected virtual ssa names from scratch.  */
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       if (!is_gimple_reg (var) && gimple_default_def (cfun, var) != NULL_TREE)
 	mark_sym_for_renaming (var);
for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/47106
	PR debug/47402
	* tree-inline.h (estimated_stack_frame_size): Take cgraph node
	rather than decl.
	* cfgexpand.c (estimated_stack_frame_size): Likewise.
	* ipa-inline.c (compute_inline_parameters): Adjust.

Index: gcc/tree-inline.h
===================================================================
--- gcc/tree-inline.h.orig	2011-02-10 04:20:18.394752112 -0200
+++ gcc/tree-inline.h	2011-02-10 04:20:34.606405625 -0200
@@ -188,6 +188,6 @@ extern tree remap_decl (tree decl, copy_
 extern tree remap_type (tree type, copy_body_data *id);
 extern gimple_seq copy_gimple_seq_and_replace_locals (gimple_seq seq);
 
-extern HOST_WIDE_INT estimated_stack_frame_size (tree);
+extern HOST_WIDE_INT estimated_stack_frame_size (struct cgraph_node *);
 
 #endif /* GCC_TREE_INLINE_H */
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c.orig	2011-02-10 04:20:27.785551518 -0200
+++ gcc/cfgexpand.c	2011-02-10 04:22:53.918429701 -0200
@@ -1366,24 +1366,25 @@ fini_vars_expansion (void)
   stack_vars_alloc = stack_vars_num = 0;
 }
 
-/* Make a fair guess for the size of the stack frame of the decl
-   passed.  This doesn't have to be exact, the result is only used
-   in the inline heuristics.  So we don't want to run the full stack
-   var packing algorithm (which is quadratic in the number of stack
-   vars).  Instead, we calculate the total size of all stack vars.
-   This turns out to be a pretty fair estimate -- packing of stack
-   vars doesn't happen very often.  */
+/* Make a fair guess for the size of the stack frame of the function
+   in NODE.  This doesn't have to be exact, the result is only used in
+   the inline heuristics.  So we don't want to run the full stack var
+   packing algorithm (which is quadratic in the number of stack vars).
+   Instead, we calculate the total size of all stack vars.  This turns
+   out to be a pretty fair estimate -- packing of stack vars doesn't
+   happen very often.  */
 
 HOST_WIDE_INT
-estimated_stack_frame_size (tree decl)
+estimated_stack_frame_size (struct cgraph_node *node)
 {
   HOST_WIDE_INT size = 0;
   size_t i;
   tree var, outer_block = DECL_INITIAL (current_function_decl);
   unsigned ix;
   tree old_cur_fun_decl = current_function_decl;
-  current_function_decl = decl;
-  push_cfun (DECL_STRUCT_FUNCTION (decl));
+
+  current_function_decl = node->decl;
+  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
 
   init_vars_expansion ();
 
Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c.orig	2011-02-10 04:20:18.579748152 -0200
+++ gcc/ipa-inline.c	2011-02-10 04:22:57.573351625 -0200
@@ -1982,9 +1982,8 @@ compute_inline_parameters (struct cgraph
 
   gcc_assert (!node->global.inlined_to);
 
-  /* Estimate the stack size for the function.  But not at -O0
-     because estimated_stack_frame_size is a quadratic problem.  */
-  self_stack_size = optimize ? estimated_stack_frame_size (node->decl) : 0;
+  /* Estimate the stack size for the function if we're optimizing.  */
+  self_stack_size = optimize ? estimated_stack_frame_size (node) : 0;
   inline_summary (node)->estimated_self_stack_size = self_stack_size;
   node->global.estimated_stack_size = self_stack_size;
   node->global.stack_frame_offset = 0;
for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/47106
	PR debug/47402
	* cgraph.h (compute_inline_parameters): Return void.
	* ipa-inline.c (compute_inline_parameters): Adjust.

Index: gcc/cgraph.h
===================================================================
--- gcc/cgraph.h.orig	2011-02-10 04:20:17.504771074 -0200
+++ gcc/cgraph.h	2011-02-10 04:21:08.306685881 -0200
@@ -769,7 +769,7 @@ varpool_next_static_initializer (struct 
 
 /* In ipa-inline.c  */
 void cgraph_clone_inlined_nodes (struct cgraph_edge *, bool, bool);
-unsigned int compute_inline_parameters (struct cgraph_node *);
+void compute_inline_parameters (struct cgraph_node *);
 
 
 /* Create a new static variable of type TYPE.  */
Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c.orig	2011-02-10 04:20:34.655404759 -0200
+++ gcc/ipa-inline.c	2011-02-10 04:22:54.129425181 -0200
@@ -1975,7 +1975,7 @@ estimate_function_body_sizes (struct cgr
 }
 
 /* Compute parameters of functions used by inliner.  */
-unsigned int
+void
 compute_inline_parameters (struct cgraph_node *node)
 {
   HOST_WIDE_INT self_stack_size;
@@ -2013,7 +2013,6 @@ compute_inline_parameters (struct cgraph
   /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
   node->global.time = inline_summary (node)->self_time;
   node->global.size = inline_summary (node)->self_size;
-  return 0;
 }
 
 
The patch that fixes the problem, using referenced_vars to estimate
stack sizes.

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

	PR debug/47106
	PR debug/47402
	* cfgexpand.c (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.  Test src_fn
	rather than cfun.  Drop redundant get_var_ann.
	(setup_one_parameter): Drop redundant get_var_ann.
	(declare_return_variable): Likewise.
	(copy_decl_for_dup_finish): Mark VAR_DECLs referenced in src_fn.
	(copy_arguments_for_versioning): Drop redundant get_var_ann.
	* tree-pass.h (pass_inlinable): Declare.
	* passes.c (init_optimization_passes): Move first
	pass_inline_parameters after pass_referenced_vars.  Add
	pass_inlinable where it was before.
	* ipa-inline.c (compute_inlinable): New, split out of...
	(compute_inline_parameters): ... this.  Quit if referenced_vars
	are not available.
	(compute_inlinable_for_current, pass_inlinable): New.
	(pass_inline_parameters): Require PROP_referenced_vars.
	* cgraphunit.c (cgraph_process_new_functions): Don't run
	compute_inline_parameters explicitly.

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

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

Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c.orig	2011-02-11 13:42:37.430636412 -0200
+++ gcc/cfgexpand.c	2011-02-11 13:42:40.067581306 -0200
@@ -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,23 +1355,17 @@ estimated_stack_frame_size (struct cgrap
 {
   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;
+  struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
 
   current_function_decl = node->decl;
-  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+  push_cfun (fn);
 
-  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 (fn));
+  FOR_EACH_REFERENCED_VAR (fn, 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-11 13:42:38.454614859 -0200
+++ gcc/tree-inline.c	2011-02-11 13:42:40.122579711 -0200
@@ -312,13 +312,17 @@ remap_decl (tree decl, copy_body_data *i
 	    walk_tree (&DECL_QUALIFIER (t), copy_tree_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))
-	{
-	  get_var_ann (t);
-	  add_referenced_var (t);
-	}
+      if ((TREE_CODE (t) == VAR_DECL
+	   || TREE_CODE (t) == RESULT_DECL
+	   || TREE_CODE (t) == PARM_DECL)
+	  && id->src_fn && DECL_STRUCT_FUNCTION (id->src_fn)
+	  && gimple_referenced_vars (DECL_STRUCT_FUNCTION (id->src_fn))
+	  /* We don't want to mark as referenced VAR_DECLs that were
+	     not marked as such in the src function.  */
+	  && (TREE_CODE (decl) != VAR_DECL
+	      || referenced_var_lookup (DECL_STRUCT_FUNCTION (id->src_fn),
+					DECL_UID (decl))))
+	add_referenced_var (t);
       return t;
     }
 
@@ -2547,10 +2551,7 @@ setup_one_parameter (copy_body_data *id,
 
   /* We're actually using the newly-created var.  */
   if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
-    {
-      get_var_ann (var);
-      add_referenced_var (var);
-    }
+    add_referenced_var (var);
 
   /* Declare this new variable.  */
   DECL_CHAIN (var) = *vars;
@@ -2857,10 +2858,7 @@ declare_return_variable (copy_body_data 
 
   var = copy_result_decl_to_var (result, id);
   if (gimple_in_ssa_p (cfun))
-    {
-      get_var_ann (var);
-      add_referenced_var (var);
-    }
+    add_referenced_var (var);
 
   DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
 
@@ -2896,10 +2894,7 @@ declare_return_variable (copy_body_data 
     {
       tree temp = create_tmp_var (TREE_TYPE (result), "retvalptr");
       if (gimple_in_ssa_p (id->src_cfun))
-	{
-	  get_var_ann (temp);
-	  add_referenced_var (temp);
-	}
+	add_referenced_var (temp);
       insert_decl_map (id, result, temp);
       /* When RESULT_DECL is in SSA form, we need to use it's default_def
 	 SSA_NAME.  */
@@ -4753,6 +4748,14 @@ copy_decl_for_dup_finish (copy_body_data
        new function.  */
     DECL_CONTEXT (copy) = id->dst_fn;
 
+  if (TREE_CODE (decl) == VAR_DECL
+      /* C++ clones functions during parsing, before
+	 referenced_vars.  */
+      && 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;
 }
 
@@ -4864,7 +4867,6 @@ copy_arguments_for_versioning (tree orig
 	   as temporary variable later in function, the uses will be
 	   replaced by local variable.  */
 	tree var = copy_decl_to_var (arg, id);
-	get_var_ann (var);
 	add_referenced_var (var);
 	insert_decl_map (id, arg, var);
         /* Declare this new variable.  */
Index: gcc/passes.c
===================================================================
--- gcc/passes.c.orig	2011-02-11 13:42:38.255618853 -0200
+++ gcc/passes.c	2011-02-11 13:42:40.146579235 -0200
@@ -729,7 +729,7 @@ 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);
+  NEXT_PASS (pass_inlinable);
   *p = NULL;
 
   /* Interprocedural optimization passes.  */
@@ -747,12 +747,8 @@ init_optimization_passes (void)
       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_inline_parameters);
       NEXT_PASS (pass_early_inline);
       NEXT_PASS (pass_all_early_optimizations);
 	{
Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c.orig	2011-02-11 13:42:37.859627265 -0200
+++ gcc/ipa-inline.c	2011-02-11 13:42:55.655254908 -0200
@@ -1974,21 +1974,10 @@ estimate_function_body_sizes (struct cgr
   inline_summary (node)->size_inlining_benefit = size_inlining_benefit;
 }
 
-/* Compute parameters of functions used by inliner.  */
-void
-compute_inline_parameters (struct cgraph_node *node)
+/* Determine whether node is inlinable.  */
+static void
+compute_inlinable (struct cgraph_node *node)
 {
-  HOST_WIDE_INT self_stack_size;
-
-  gcc_assert (!node->global.inlined_to);
-
-  /* Estimate the stack size for the function if we're optimizing.  */
-  self_stack_size = optimize ? estimated_stack_frame_size (node) : 0;
-  inline_summary (node)->estimated_self_stack_size = self_stack_size;
-  node->global.estimated_stack_size = self_stack_size;
-  node->global.stack_frame_offset = 0;
-
-  /* Can this function be inlined at all?  */
   node->local.inlinable = tree_inlinable_function_p (node->decl);
 
   /* Inlinable functions always can change signature.  */
@@ -1998,7 +1987,7 @@ compute_inline_parameters (struct cgraph
     {
       struct cgraph_edge *e;
 
-      /* Functions calling builtlin_apply can not change signature.  */
+      /* Functions calling builtin_apply can not change signature.  */
       for (e = node->callees; e; e = e->next_callee)
 	if (DECL_BUILT_IN (e->callee->decl)
 	    && DECL_BUILT_IN_CLASS (e->callee->decl) == BUILT_IN_NORMAL
@@ -2006,9 +1995,33 @@ compute_inline_parameters (struct cgraph
 	  break;
       node->local.can_change_signature = !e;
     }
+
   if (node->local.inlinable && !node->local.disregard_inline_limits)
     node->local.disregard_inline_limits
       = DECL_DISREGARD_INLINE_LIMITS (node->decl);
+}
+
+/* Compute parameters of functions used by inliner.  */
+void
+compute_inline_parameters (struct cgraph_node *node)
+{
+  HOST_WIDE_INT self_stack_size;
+
+  gcc_assert (!node->global.inlined_to);
+
+  compute_inlinable (node);
+
+  /* A function won't be considered for inlining before we put it in
+     SSA form and compute referenced_vars.  */
+  if (!gimple_referenced_vars (DECL_STRUCT_FUNCTION (node->decl)))
+    return;
+
+  /* Estimate the stack size for the function if we're optimizing.  */
+  self_stack_size = optimize ? estimated_stack_frame_size (node) : 0;
+  inline_summary (node)->estimated_self_stack_size = self_stack_size;
+  node->global.estimated_stack_size = self_stack_size;
+  node->global.stack_frame_offset = 0;
+
   estimate_function_body_sizes (node);
   /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
   node->global.time = inline_summary (node)->self_time;
@@ -2016,6 +2029,14 @@ compute_inline_parameters (struct cgraph
 }
 
 
+/* Determine whether current_function_decl is inlinable.  */
+static unsigned int
+compute_inlinable_for_current (void)
+{
+  compute_inlinable (cgraph_node (current_function_decl));
+  return 0;
+}
+
 /* Compute parameters of functions used by inliner using
    current_function_decl.  */
 static unsigned int
@@ -2025,6 +2046,25 @@ compute_inline_parameters_for_current (v
   return 0;
 }
 
+struct gimple_opt_pass pass_inlinable =
+{
+ {
+  GIMPLE_PASS,
+  "inlinable",				/* name */
+  NULL,					/* gate */
+  compute_inlinable_for_current,	/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  TV_INLINE_HEURISTICS,			/* tv_id */
+  0,					/* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  0					/* todo_flags_finish */
+ }
+};
+
 struct gimple_opt_pass pass_inline_parameters =
 {
  {
@@ -2036,7 +2076,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-11 13:42:38.057623032 -0200
+++ gcc/cgraphunit.c	2011-02-11 13:42:40.211577872 -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/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-11 13:42:40.236577347 -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 ());
+}
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h.orig	2011-02-11 13:42:37.641631793 -0200
+++ gcc/tree-pass.h	2011-02-11 13:42:40.249577075 -0200
@@ -572,6 +572,7 @@ extern struct rtl_opt_pass pass_final;
 extern struct rtl_opt_pass pass_rtl_seqabstr;
 extern struct gimple_opt_pass pass_release_ssa_names;
 extern struct gimple_opt_pass pass_early_inline;
+extern struct gimple_opt_pass pass_inlinable;
 extern struct gimple_opt_pass pass_inline_parameters;
 extern struct gimple_opt_pass pass_all_early_optimizations;
 extern struct gimple_opt_pass pass_update_address_taken;
This patch fixes a latent bug: when estimating function sizes/times, we
use functions that access current_function_decl, without always having
set it up to the function being estimated.

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

	PR debug/47106
	PR debug/47402
	* ipa-inline.c (estimate_function_body_sizes): Set
	current_function_decl while visiting stmts.

Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c.orig	2011-02-10 04:21:20.234431070 -0200
+++ gcc/ipa-inline.c	2011-02-10 04:22:42.115681759 -0200
@@ -1901,12 +1901,20 @@ estimate_function_body_sizes (struct cgr
   tree arg;
   int freq;
   tree funtype = TREE_TYPE (node->decl);
+  tree saved_current_function_decl = current_function_decl;
 
   if (dump_file)
     fprintf (dump_file, "Analyzing function body size: %s\n",
 	     cgraph_node_name (node));
 
   gcc_assert (my_function && my_function->cfg);
+  /* ??? estimate_num_insns may indirectly call
+     decl_address_invariant_p which tests current_function_decl.  We
+     should probably somehow arrange for decl_address_ip_invariant_p
+     to be called instead.  Leaving current_function_decl NULL would
+     probably have the same effect, but setting current_function_decl
+     we get a more accurate estimate.  */
+  current_function_decl = node->decl;
   FOR_EACH_BB_FN (bb, my_function)
     {
       freq = compute_call_stmt_bb_frequency (node->decl, bb);
@@ -1937,6 +1945,7 @@ estimate_function_body_sizes (struct cgr
 	  gcc_assert (size >= 0);
 	}
     }
+  current_function_decl = saved_current_function_decl;
   time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
   time_inlining_benefit = ((time_inlining_benefit + CGRAPH_FREQ_BASE)
   			   / (CGRAPH_FREQ_BASE * 2));
These two patches remove unnecessary setting up of cfun and
current_function_decl.

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

	PR debug/47106
	PR debug/47402
	* cfgexpand.c (estimated_stack_frame_size): Don't change cfun
	or decl.

Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c.orig	2011-02-10 04:21:20.149432887 -0200
+++ gcc/cfgexpand.c	2011-02-10 04:22:38.177765967 -0200
@@ -1356,13 +1356,9 @@ estimated_stack_frame_size (struct cgrap
   HOST_WIDE_INT size = 0;
   size_t i;
   tree var;
-  tree old_cur_fun_decl = current_function_decl;
   referenced_var_iterator rvi;
   struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
 
-  current_function_decl = node->decl;
-  push_cfun (fn);
-
   gcc_checking_assert (gimple_referenced_vars (fn));
   FOR_EACH_REFERENCED_VAR (fn, var, rvi)
     size += expand_one_var (var, true, false);
@@ -1376,8 +1372,6 @@ estimated_stack_frame_size (struct cgrap
       size += account_stack_vars ();
       fini_vars_expansion ();
     }
-  pop_cfun ();
-  current_function_decl = old_cur_fun_decl;
   return size;
 }
 
for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/47106
	PR debug/47402
	* ipa-inline.c (analyze_function): Don't change cfun or decl.

Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c.orig	2011-02-11 13:43:19.016764097 -0200
+++ gcc/ipa-inline.c	2011-02-11 13:43:19.317757985 -0200
@@ -2110,17 +2110,11 @@ inline_indirect_intraprocedural_analysis
 static void
 analyze_function (struct cgraph_node *node)
 {
-  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
-  current_function_decl = node->decl;
-
   compute_inline_parameters (node);
   /* FIXME: We should remove the optimize check after we ensure we never run
      IPA passes when not optimizng.  */
   if (flag_indirect_inlining && optimize)
     inline_indirect_intraprocedural_analysis (node);
-
-  current_function_decl = NULL;
-  pop_cfun ();
 }
 
 /* Called when new function is inserted to callgraph late.  */

Are the above ok to install?  All regstrapped on x86_64-linux-gnu and
i686-pc-linux-gnu, and also bootstrapped with -O1 and -O3, besides the
tests described below.


This FTR patch makes sure the previous two patches are safe, at least
inasmuchas they ensure we don't unconditionally dereferenced cfun or
current_function_decl within these functions.  It wasn't enough,
however, to detect the problem in function size/time estimation.  That
required comparing the output of the compiler with and without the
patches that dropped cfun overriding.  There was only one difference in
stage3-like builds, in ada/trans.o, and that was fixed with the patch
that set current_function_decl while estimating function body sizes and
times.

FTR and testing only, not to be installed.

Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c.orig	2011-02-11 13:43:19.174760996 -0200
+++ gcc/cfgexpand.c	2011-02-11 13:43:28.071574474 -0200
@@ -1358,6 +1358,10 @@ estimated_stack_frame_size (struct cgrap
   tree var;
   referenced_var_iterator rvi;
   struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
+  tree save = current_function_decl;
+
+  push_cfun (NULL);
+  current_function_decl = NULL;
 
   gcc_checking_assert (gimple_referenced_vars (fn));
   FOR_EACH_REFERENCED_VAR (fn, var, rvi)
@@ -1372,6 +1376,10 @@ estimated_stack_frame_size (struct cgrap
       size += account_stack_vars ();
       fini_vars_expansion ();
     }
+
+  current_function_decl = save;
+  pop_cfun ();
+
   return size;
 }
 
Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c.orig	2011-02-11 13:43:19.317757985 -0200
+++ gcc/ipa-inline.c	2011-02-11 13:43:28.101573846 -0200
@@ -2015,6 +2015,7 @@ void
 compute_inline_parameters (struct cgraph_node *node)
 {
   HOST_WIDE_INT self_stack_size;
+  tree save = current_function_decl;
 
   gcc_assert (!node->global.inlined_to);
 
@@ -2025,6 +2026,9 @@ compute_inline_parameters (struct cgraph
   if (!gimple_referenced_vars (DECL_STRUCT_FUNCTION (node->decl)))
     return;
 
+  push_cfun (NULL);
+  current_function_decl = NULL;
+
   /* Estimate the stack size for the function if we're optimizing.  */
   self_stack_size = optimize ? estimated_stack_frame_size (node) : 0;
   inline_summary (node)->estimated_self_stack_size = self_stack_size;
@@ -2035,6 +2039,9 @@ compute_inline_parameters (struct cgraph
   /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
   node->global.time = inline_summary (node)->self_time;
   node->global.size = inline_summary (node)->self_size;
+
+  current_function_decl = save;
+  pop_cfun ();
 }
 
 
@@ -2110,11 +2117,17 @@ inline_indirect_intraprocedural_analysis
 static void
 analyze_function (struct cgraph_node *node)
 {
+  push_cfun (NULL);
+  current_function_decl = NULL;
+
   compute_inline_parameters (node);
   /* FIXME: We should remove the optimize check after we ensure we never run
      IPA passes when not optimizng.  */
   if (flag_indirect_inlining && optimize)
     inline_indirect_intraprocedural_analysis (node);
+
+  current_function_decl = NULL;
+  pop_cfun ();
 }
 
 /* Called when new function is inserted to callgraph late.  */
Index: gcc/tree-flow-inline.h
===================================================================
--- gcc/tree-flow-inline.h.orig	2011-02-11 13:42:17.880046107 -0200
+++ gcc/tree-flow-inline.h	2011-02-11 13:43:28.118573489 -0200
@@ -114,6 +114,7 @@ referenced_var (unsigned int uid)
 static inline tree
 first_referenced_var (struct function *fn, referenced_var_iterator *iter)
 {
+  gcc_checking_assert (!cfun || fn == cfun);
   return (tree) first_htab_element (&iter->hti,
 				    gimple_referenced_vars (fn));
 }
Finally, this FTR patch was used to compare the stack size estimations
of the current (trunk) approach and the one introduced with this
patchset.  No messages printed in stage2 host for a bootstrap-debug
build (no -g), indicating no differences; plenty printed during stage3
(with -g), always lower counts.

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

	PR debug/47106
	PR debug/47402
	* cfgexpand.c (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.  Test src_fn
	rather than cfun.  Drop redundant get_var_ann.
	(setup_one_parameter): Drop redundant get_var_ann.
	(declare_return_variable): Likewise.
	(copy_decl_for_dup_finish): Mark VAR_DECLs referenced in src_fn.
	(copy_arguments_for_versioning): Drop redundant get_var_ann.
	* tree-pass.h (pass_inlinable): Declare.
	* passes.c (init_optimization_passes): Move first
	pass_inline_parameters after pass_referenced_vars.  Add
	pass_inlinable where it was before.
	* ipa-inline.c (compute_inlinable): New, split out of...
	(compute_inline_parameters): ... this.  Quit if referenced_vars
	are not available.
	(compute_inlinable_for_current, pass_inlinable): New.
	(pass_inline_parameters): Require PROP_referenced_vars.
	* cgraphunit.c (cgraph_process_new_functions): Don't run
	compute_inline_parameters explicitly.

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

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

Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c.orig	2011-02-11 13:42:37.430636412 -0200
+++ gcc/cfgexpand.c	2011-02-11 13:42:40.067581306 -0200
@@ -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,23 +1355,17 @@ estimated_stack_frame_size (struct cgrap
 {
   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;
+  struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
 
   current_function_decl = node->decl;
-  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+  push_cfun (fn);
 
-  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 (fn));
+  FOR_EACH_REFERENCED_VAR (fn, 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-11 13:42:38.454614859 -0200
+++ gcc/tree-inline.c	2011-02-11 13:42:40.122579711 -0200
@@ -312,13 +312,17 @@ remap_decl (tree decl, copy_body_data *i
 	    walk_tree (&DECL_QUALIFIER (t), copy_tree_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))
-	{
-	  get_var_ann (t);
-	  add_referenced_var (t);
-	}
+      if ((TREE_CODE (t) == VAR_DECL
+	   || TREE_CODE (t) == RESULT_DECL
+	   || TREE_CODE (t) == PARM_DECL)
+	  && id->src_fn && DECL_STRUCT_FUNCTION (id->src_fn)
+	  && gimple_referenced_vars (DECL_STRUCT_FUNCTION (id->src_fn))
+	  /* We don't want to mark as referenced VAR_DECLs that were
+	     not marked as such in the src function.  */
+	  && (TREE_CODE (decl) != VAR_DECL
+	      || referenced_var_lookup (DECL_STRUCT_FUNCTION (id->src_fn),
+					DECL_UID (decl))))
+	add_referenced_var (t);
       return t;
     }
 
@@ -2547,10 +2551,7 @@ setup_one_parameter (copy_body_data *id,
 
   /* We're actually using the newly-created var.  */
   if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
-    {
-      get_var_ann (var);
-      add_referenced_var (var);
-    }
+    add_referenced_var (var);
 
   /* Declare this new variable.  */
   DECL_CHAIN (var) = *vars;
@@ -2857,10 +2858,7 @@ declare_return_variable (copy_body_data 
 
   var = copy_result_decl_to_var (result, id);
   if (gimple_in_ssa_p (cfun))
-    {
-      get_var_ann (var);
-      add_referenced_var (var);
-    }
+    add_referenced_var (var);
 
   DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
 
@@ -2896,10 +2894,7 @@ declare_return_variable (copy_body_data 
     {
       tree temp = create_tmp_var (TREE_TYPE (result), "retvalptr");
       if (gimple_in_ssa_p (id->src_cfun))
-	{
-	  get_var_ann (temp);
-	  add_referenced_var (temp);
-	}
+	add_referenced_var (temp);
       insert_decl_map (id, result, temp);
       /* When RESULT_DECL is in SSA form, we need to use it's default_def
 	 SSA_NAME.  */
@@ -4753,6 +4748,14 @@ copy_decl_for_dup_finish (copy_body_data
        new function.  */
     DECL_CONTEXT (copy) = id->dst_fn;
 
+  if (TREE_CODE (decl) == VAR_DECL
+      /* C++ clones functions during parsing, before
+	 referenced_vars.  */
+      && 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;
 }
 
@@ -4864,7 +4867,6 @@ copy_arguments_for_versioning (tree orig
 	   as temporary variable later in function, the uses will be
 	   replaced by local variable.  */
 	tree var = copy_decl_to_var (arg, id);
-	get_var_ann (var);
 	add_referenced_var (var);
 	insert_decl_map (id, arg, var);
         /* Declare this new variable.  */
Index: gcc/passes.c
===================================================================
--- gcc/passes.c.orig	2011-02-11 13:42:38.255618853 -0200
+++ gcc/passes.c	2011-02-11 13:42:40.146579235 -0200
@@ -729,7 +729,7 @@ 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);
+  NEXT_PASS (pass_inlinable);
   *p = NULL;
 
   /* Interprocedural optimization passes.  */
@@ -747,12 +747,8 @@ init_optimization_passes (void)
       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_inline_parameters);
       NEXT_PASS (pass_early_inline);
       NEXT_PASS (pass_all_early_optimizations);
 	{
Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c.orig	2011-02-11 13:42:37.859627265 -0200
+++ gcc/ipa-inline.c	2011-02-11 13:42:55.655254908 -0200
@@ -1974,21 +1974,10 @@ estimate_function_body_sizes (struct cgr
   inline_summary (node)->size_inlining_benefit = size_inlining_benefit;
 }
 
-/* Compute parameters of functions used by inliner.  */
-void
-compute_inline_parameters (struct cgraph_node *node)
+/* Determine whether node is inlinable.  */
+static void
+compute_inlinable (struct cgraph_node *node)
 {
-  HOST_WIDE_INT self_stack_size;
-
-  gcc_assert (!node->global.inlined_to);
-
-  /* Estimate the stack size for the function if we're optimizing.  */
-  self_stack_size = optimize ? estimated_stack_frame_size (node) : 0;
-  inline_summary (node)->estimated_self_stack_size = self_stack_size;
-  node->global.estimated_stack_size = self_stack_size;
-  node->global.stack_frame_offset = 0;
-
-  /* Can this function be inlined at all?  */
   node->local.inlinable = tree_inlinable_function_p (node->decl);
 
   /* Inlinable functions always can change signature.  */
@@ -1998,7 +1987,7 @@ compute_inline_parameters (struct cgraph
     {
       struct cgraph_edge *e;
 
-      /* Functions calling builtlin_apply can not change signature.  */
+      /* Functions calling builtin_apply can not change signature.  */
       for (e = node->callees; e; e = e->next_callee)
 	if (DECL_BUILT_IN (e->callee->decl)
 	    && DECL_BUILT_IN_CLASS (e->callee->decl) == BUILT_IN_NORMAL
@@ -2006,9 +1995,33 @@ compute_inline_parameters (struct cgraph
 	  break;
       node->local.can_change_signature = !e;
     }
+
   if (node->local.inlinable && !node->local.disregard_inline_limits)
     node->local.disregard_inline_limits
       = DECL_DISREGARD_INLINE_LIMITS (node->decl);
+}
+
+/* Compute parameters of functions used by inliner.  */
+void
+compute_inline_parameters (struct cgraph_node *node)
+{
+  HOST_WIDE_INT self_stack_size;
+
+  gcc_assert (!node->global.inlined_to);
+
+  compute_inlinable (node);
+
+  /* A function won't be considered for inlining before we put it in
+     SSA form and compute referenced_vars.  */
+  if (!gimple_referenced_vars (DECL_STRUCT_FUNCTION (node->decl)))
+    return;
+
+  /* Estimate the stack size for the function if we're optimizing.  */
+  self_stack_size = optimize ? estimated_stack_frame_size (node) : 0;
+  inline_summary (node)->estimated_self_stack_size = self_stack_size;
+  node->global.estimated_stack_size = self_stack_size;
+  node->global.stack_frame_offset = 0;
+
   estimate_function_body_sizes (node);
   /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
   node->global.time = inline_summary (node)->self_time;
@@ -2016,6 +2029,14 @@ compute_inline_parameters (struct cgraph
 }
 
 
+/* Determine whether current_function_decl is inlinable.  */
+static unsigned int
+compute_inlinable_for_current (void)
+{
+  compute_inlinable (cgraph_node (current_function_decl));
+  return 0;
+}
+
 /* Compute parameters of functions used by inliner using
    current_function_decl.  */
 static unsigned int
@@ -2025,6 +2046,25 @@ compute_inline_parameters_for_current (v
   return 0;
 }
 
+struct gimple_opt_pass pass_inlinable =
+{
+ {
+  GIMPLE_PASS,
+  "inlinable",				/* name */
+  NULL,					/* gate */
+  compute_inlinable_for_current,	/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  TV_INLINE_HEURISTICS,			/* tv_id */
+  0,					/* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  0					/* todo_flags_finish */
+ }
+};
+
 struct gimple_opt_pass pass_inline_parameters =
 {
  {
@@ -2036,7 +2076,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-11 13:42:38.057623032 -0200
+++ gcc/cgraphunit.c	2011-02-11 13:42:40.211577872 -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/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-11 13:42:40.236577347 -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 ());
+}
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h.orig	2011-02-11 13:42:37.641631793 -0200
+++ gcc/tree-pass.h	2011-02-11 13:42:40.249577075 -0200
@@ -572,6 +572,7 @@ extern struct rtl_opt_pass pass_final;
 extern struct rtl_opt_pass pass_rtl_seqabstr;
 extern struct gimple_opt_pass pass_release_ssa_names;
 extern struct gimple_opt_pass pass_early_inline;
+extern struct gimple_opt_pass pass_inlinable;
 extern struct gimple_opt_pass pass_inline_parameters;
 extern struct gimple_opt_pass pass_all_early_optimizations;
 extern struct gimple_opt_pass pass_update_address_taken;

-- 
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

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