for gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR debug/47106
PR debug/47402
* tree-flow.h (referenced_var_lookup): Add fn parameter.
Adjust all callers.
* tree-dfa.c (referenced_var_lookup): Use fn instead of cfun.
* tree-flow-inline.h: Adjust.
* gimple-pretty-print.c: Adjust.
* tree-into-ssa.c: Adjust.
* tree-ssa.c: Adjust.
* cfgexpand.c: Adjust.
(account_used_vars_for_block): Remove.
(estimated_stack_frame_size): Use referenced vars.
* tree-inline.c (remap_decl): Only mark VAR_DECLs as referenced
that were referenced in the original function.
(copy_decl_for_dup_finish): Likewise.
* tree-optimize.c (pass_early_lowering_passes): New.
(pass_early_lowered_passes): New.
* tree-pass.h (pass_early_lowering_passes): Declare.
(pass_early_lowered_passes): Declare.
* passes.c (init_optimization_passes): Introduce
pass_early_lowering_passes and pass_early_lowered_passes.
Move first pass_inline_parameters into the latter.
(execute_ipa_pass_list): Adjust so PLUGIN_EARLY_GIMPLE_PASSES get
called at the same spots.
* ipa-inline.c (cgraph_early_inlining): Fixup cfg.
(pass_inline_parameters): Require PROP_referenced_vars.
* cgraphunit.c (cgraph_process_new_functions): Don't run
compute_inline_parameters explicitly.
* predict.c (gate_estimate_probability): Skip for already-guessed
versioned functions.
for gcc/testsuite/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR debug/47106
PR debug/47402
* g++.dg/debug/pr47106.C: New.
===================================================================
@@ -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))
===================================================================
@@ -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;
}
===================================================================
@@ -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;
}
===================================================================
@@ -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);
===================================================================
@@ -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
===================================================================
@@ -1902,7 +1902,7 @@ maybe_optimize_var (tree var, bitmap add
/* If the variable is not in the list of referenced vars then we
do not need to touch it nor can we rename it. */
- if (!referenced_var_lookup (DECL_UID (var)))
+ if (!referenced_var_lookup (cfun, DECL_UID (var)))
return false;
if (TREE_ADDRESSABLE (var)
===================================================================
@@ -520,7 +520,7 @@ update_alias_info_with_stack_vars (void)
for -O0 where we are preserving even unreferenced variables. */
gcc_assert (DECL_P (decl)
&& (!optimize
- || referenced_var_lookup (DECL_UID (decl))));
+ || referenced_var_lookup (cfun, DECL_UID (decl))));
bitmap_set_bit (part, uid);
*((bitmap *) pointer_map_insert (decls_to_partitions,
(void *)(size_t) uid)) = part;
@@ -1311,30 +1311,6 @@ create_stack_guard (void)
crtl->stack_protect_guard = guard;
}
-/* A subroutine of expand_used_vars. Walk down through the BLOCK tree
- expanding variables. Those variables that can be put into registers
- are allocated pseudos; those that can't are put on the stack.
-
- TOPLEVEL is true if this is the outermost BLOCK. */
-
-static HOST_WIDE_INT
-account_used_vars_for_block (tree block, bool toplevel)
-{
- tree t;
- HOST_WIDE_INT size = 0;
-
- /* Expand all variables at this level. */
- for (t = BLOCK_VARS (block); t ; t = DECL_CHAIN (t))
- if (var_ann (t) && is_used_p (t))
- size += expand_one_var (t, toplevel, false);
-
- /* Expand all variables at containing levels. */
- for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t))
- size += account_used_vars_for_block (t, false);
-
- return size;
-}
-
/* Prepare for expanding variables. */
static void
init_vars_expansion (void)
@@ -1379,22 +1355,18 @@ estimated_stack_frame_size (tree decl)
{
HOST_WIDE_INT size = 0;
size_t i;
- tree var, outer_block = DECL_INITIAL (current_function_decl);
- unsigned ix;
+ tree var;
tree old_cur_fun_decl = current_function_decl;
+ referenced_var_iterator rvi;
+
+ gcc_checking_assert (gimple_referenced_vars (cfun));
+
current_function_decl = decl;
push_cfun (DECL_STRUCT_FUNCTION (decl));
- init_vars_expansion ();
-
- FOR_EACH_LOCAL_DECL (cfun, ix, var)
- {
- /* TREE_USED marks local variables that do not appear in lexical
- blocks. We don't want to expand those that do twice. */
- if (TREE_USED (var))
- size += expand_one_var (var, true, false);
- }
- size += account_used_vars_for_block (outer_block, true);
+ gcc_checking_assert (gimple_referenced_vars (cfun));
+ FOR_EACH_REFERENCED_VAR (var, rvi)
+ size += expand_one_var (var, true, false);
if (stack_vars_num > 0)
{
===================================================================
@@ -317,7 +317,11 @@ remap_decl (tree decl, copy_body_data *i
|| TREE_CODE (t) == RESULT_DECL || TREE_CODE (t) == PARM_DECL))
{
get_var_ann (t);
- add_referenced_var (t);
+ if (TREE_CODE (decl) != VAR_DECL
+ || !gimple_referenced_vars (DECL_STRUCT_FUNCTION (id->src_fn))
+ || referenced_var_lookup (DECL_STRUCT_FUNCTION (id->src_fn),
+ DECL_UID (decl)))
+ add_referenced_var (t);
}
return t;
}
@@ -4753,6 +4757,13 @@ copy_decl_for_dup_finish (copy_body_data
new function. */
DECL_CONTEXT (copy) = id->dst_fn;
+ if (TREE_CODE (decl) == VAR_DECL
+ && gimple_referenced_vars (cfun)
+ && gimple_referenced_vars (DECL_STRUCT_FUNCTION (id->src_fn))
+ && referenced_var_lookup (DECL_STRUCT_FUNCTION (id->src_fn),
+ DECL_UID (decl)))
+ add_referenced_var (copy);
+
return copy;
}
===================================================================
@@ -101,6 +101,44 @@ execute_all_early_local_passes (void)
return 0;
}
+struct simple_ipa_opt_pass pass_early_lowering_passes =
+{
+ {
+ SIMPLE_IPA_PASS,
+ "*early_lowering", /* name */
+ gate_all_early_local_passes, /* gate */
+ NULL, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_EARLY_LOCAL, /* tv_id */
+ 0, /* properties_required */
+ PROP_referenced_vars, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0 /* todo_flags_finish */
+ }
+};
+
+struct simple_ipa_opt_pass pass_early_lowered_passes =
+{
+ {
+ SIMPLE_IPA_PASS,
+ "*early_lowered", /* name */
+ gate_all_early_local_passes, /* gate */
+ NULL, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_EARLY_LOCAL, /* tv_id */
+ PROP_referenced_vars, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0 /* todo_flags_finish */
+ }
+};
+
struct simple_ipa_opt_pass pass_early_local_passes =
{
{
===================================================================
@@ -452,6 +452,8 @@ extern struct simple_ipa_opt_pass pass_i
extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility;
extern struct simple_ipa_opt_pass pass_ipa_tree_profile;
+extern struct simple_ipa_opt_pass pass_early_lowering_passes;
+extern struct simple_ipa_opt_pass pass_early_lowered_passes;
extern struct simple_ipa_opt_pass pass_early_local_passes;
extern struct ipa_opt_pass_d pass_ipa_whole_program_visibility;
===================================================================
@@ -729,7 +729,6 @@ init_optimization_passes (void)
NEXT_PASS (pass_build_cfg);
NEXT_PASS (pass_warn_function_return);
NEXT_PASS (pass_build_cgraph_edges);
- NEXT_PASS (pass_inline_parameters);
*p = NULL;
/* Interprocedural optimization passes. */
@@ -739,51 +738,59 @@ init_optimization_passes (void)
NEXT_PASS (pass_early_local_passes);
{
struct opt_pass **p = &pass_early_local_passes.pass.sub;
- NEXT_PASS (pass_fixup_cfg);
- NEXT_PASS (pass_init_datastructures);
- NEXT_PASS (pass_expand_omp);
-
- NEXT_PASS (pass_referenced_vars);
- NEXT_PASS (pass_build_ssa);
- NEXT_PASS (pass_lower_vector);
- NEXT_PASS (pass_early_warn_uninitialized);
- /* Note that it is not strictly necessary to schedule an early
- inline pass here. However, some test cases (e.g.,
- g++.dg/other/p334435.C g++.dg/other/i386-1.C) expect extern
- inline functions to be inlined even at -O0. This does not
- happen during the first early inline pass. */
- NEXT_PASS (pass_rebuild_cgraph_edges);
- NEXT_PASS (pass_early_inline);
- NEXT_PASS (pass_all_early_optimizations);
- {
- struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
- NEXT_PASS (pass_remove_cgraph_callee_edges);
- NEXT_PASS (pass_rename_ssa_copies);
- NEXT_PASS (pass_ccp);
- NEXT_PASS (pass_forwprop);
- /* pass_build_ealias is a dummy pass that ensures that we
- execute TODO_rebuild_alias at this point. Re-building
- alias information also rewrites no longer addressed
- locals into SSA form if possible. */
- NEXT_PASS (pass_build_ealias);
- NEXT_PASS (pass_sra_early);
- NEXT_PASS (pass_copy_prop);
- NEXT_PASS (pass_merge_phi);
- NEXT_PASS (pass_cd_dce);
- NEXT_PASS (pass_early_ipa_sra);
- NEXT_PASS (pass_tail_recursion);
- NEXT_PASS (pass_convert_switch);
- NEXT_PASS (pass_cleanup_eh);
- NEXT_PASS (pass_profile);
- NEXT_PASS (pass_local_pure_const);
- /* Split functions creates parts that are not run through
- early optimizations again. It is thus good idea to do this
- late. */
- NEXT_PASS (pass_split_functions);
+ NEXT_PASS (pass_early_lowering_passes);
+ {
+ struct opt_pass **p = &pass_early_lowering_passes.pass.sub;
+ NEXT_PASS (pass_fixup_cfg);
+ NEXT_PASS (pass_init_datastructures);
+ NEXT_PASS (pass_expand_omp);
+
+ /* We have to run this pass for all functions before we go into
+ early local passes, particularly pass_inline_parameters, that
+ relies on referenced_vars being already computed. */
+ NEXT_PASS (pass_referenced_vars);
+
+ NEXT_PASS (pass_build_ssa);
+ NEXT_PASS (pass_lower_vector);
+ NEXT_PASS (pass_early_warn_uninitialized);
+ NEXT_PASS (pass_rebuild_cgraph_edges);
+ }
+ NEXT_PASS (pass_early_lowered_passes);
+ {
+ struct opt_pass **p = &pass_early_lowered_passes.pass.sub;
+ NEXT_PASS (pass_inline_parameters);
+ NEXT_PASS (pass_early_inline);
+ NEXT_PASS (pass_all_early_optimizations);
+ {
+ struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
+ NEXT_PASS (pass_remove_cgraph_callee_edges);
+ NEXT_PASS (pass_rename_ssa_copies);
+ NEXT_PASS (pass_ccp);
+ NEXT_PASS (pass_forwprop);
+ /* pass_build_ealias is a dummy pass that ensures that we
+ execute TODO_rebuild_alias at this point. Re-building
+ alias information also rewrites no longer addressed
+ locals into SSA form if possible. */
+ NEXT_PASS (pass_build_ealias);
+ NEXT_PASS (pass_sra_early);
+ NEXT_PASS (pass_copy_prop);
+ NEXT_PASS (pass_merge_phi);
+ NEXT_PASS (pass_cd_dce);
+ NEXT_PASS (pass_early_ipa_sra);
+ NEXT_PASS (pass_tail_recursion);
+ NEXT_PASS (pass_convert_switch);
+ NEXT_PASS (pass_cleanup_eh);
+ NEXT_PASS (pass_profile);
+ NEXT_PASS (pass_local_pure_const);
+ /* Split functions creates parts that are not run through
+ early optimizations again. It is thus good idea to do this
+ late. */
+ NEXT_PASS (pass_split_functions);
+ }
+ NEXT_PASS (pass_release_ssa_names);
+ NEXT_PASS (pass_rebuild_cgraph_edges);
+ NEXT_PASS (pass_inline_parameters);
}
- NEXT_PASS (pass_release_ssa_names);
- NEXT_PASS (pass_rebuild_cgraph_edges);
- NEXT_PASS (pass_inline_parameters);
}
NEXT_PASS (pass_ipa_tree_profile);
{
@@ -1927,18 +1934,20 @@ execute_ipa_pass_list (struct opt_pass *
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
if (execute_one_pass (pass) && pass->sub)
{
+ if (pass == &pass_early_local_passes.pass)
+ invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
+
if (pass->sub->type == GIMPLE_PASS)
- {
- invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
- do_per_function_toporder ((void (*)(void *))execute_pass_list,
- pass->sub);
- invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
- }
+ do_per_function_toporder ((void (*)(void *))execute_pass_list,
+ pass->sub);
else if (pass->sub->type == SIMPLE_IPA_PASS
|| pass->sub->type == IPA_PASS)
execute_ipa_pass_list (pass->sub);
else
gcc_unreachable ();
+
+ if (pass == &pass_early_local_passes.pass)
+ invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
}
gcc_assert (!current_function_decl);
cgraph_process_new_functions ();
===================================================================
@@ -1794,7 +1794,7 @@ cgraph_early_inlining (void)
cfun->always_inline_functions_inlined = true;
- return todo;
+ return todo | execute_fixup_cfg ();
}
struct gimple_opt_pass pass_early_inline =
@@ -2044,7 +2044,7 @@ struct gimple_opt_pass pass_inline_param
NULL, /* next */
0, /* static_pass_number */
TV_INLINE_HEURISTICS, /* tv_id */
- 0, /* properties_required */
+ PROP_referenced_vars, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
===================================================================
@@ -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
===================================================================
@@ -2266,6 +2266,11 @@ compute_function_frequency (void)
static bool
gate_estimate_probability (void)
{
+ /* Functions cloned for versioning get profile information from
+ the original functions. */
+ if (profile_status != PROFILE_ABSENT)
+ return false;
+
return flag_guess_branch_prob;
}
===================================================================
@@ -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 ());
+}