This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
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