backport: re PR tree-optimization/82060 (ICE in refs_may_alias_p_1 with devirtualization enabled)

2017-12-15  Richard Biener  <rguenther@suse.de>

	Backport from mainline
	PR tree-optimization/82060
	* tree-ssa-pre.c (eliminate_dom_walker::before_dom_children):
	Move devirtualization after stmt folding and before EH/AB/noreturn
	cleanup to get the stmt refs canonicalized.  Use a bool instead
	of gimple_modified_p since that doesn't work for NOPs.  Schedule
	NOPs generated by folding for removal.

	* g++.dg/torture/pr82060.C: New testcase.

From-SVN: r255682
This commit is contained in:
Richard Biener 2017-12-15 10:12:08 +00:00 committed by Richard Biener
parent c49c3117e3
commit 2c44df49aa
4 changed files with 102 additions and 46 deletions

View File

@ -1,3 +1,13 @@
2017-12-15 Richard Biener <rguenther@suse.de>
Backport from mainline
PR tree-optimization/82060
* tree-ssa-pre.c (eliminate_dom_walker::before_dom_children):
Move devirtualization after stmt folding and before EH/AB/noreturn
cleanup to get the stmt refs canonicalized. Use a bool instead
of gimple_modified_p since that doesn't work for NOPs. Schedule
NOPs generated by folding for removal.
2017-12-15 Richard Biener <rguenther@suse.de> 2017-12-15 Richard Biener <rguenther@suse.de>
Backport from mainline Backport from mainline

View File

@ -1,3 +1,9 @@
2017-12-15 Richard Biener <rguenther@suse.de>
Backport from mainline
PR tree-optimization/82060
* g++.dg/torture/pr82060.C: New testcase.
2017-12-15 Sudakshina Das <sudi.das@arm.com> 2017-12-15 Sudakshina Das <sudi.das@arm.com>
* gcc.target/arm/armv8_2-fp16-move-2.c: Remove dg-add-options. * gcc.target/arm/armv8_2-fp16-move-2.c: Remove dg-add-options.

View File

@ -0,0 +1,32 @@
// { dg-do compile }
struct A
{
char a[1]; // must be char array
};
struct B
{
A& a() { return ma; } // must be accessed through a getter
A ma;
};
struct C
{
B& b() { return mb; } // must be accessed through a getter
B mb;
};
struct D
{
virtual A getA() = 0; // must be virtual
};
void
foo(D& d) // The D object must not be created locally
// (so that getA implementation is not known at compile time?)
{
C c;
for (;;) // must be in a loop
c.b().a() = d.getA();
}

View File

@ -4566,6 +4566,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
/* If we didn't replace the whole stmt (or propagate the result /* If we didn't replace the whole stmt (or propagate the result
into all uses), replace all uses on this stmt with their into all uses), replace all uses on this stmt with their
leaders. */ leaders. */
bool modified = false;
use_operand_p use_p; use_operand_p use_p;
ssa_op_iter iter; ssa_op_iter iter;
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
@ -4587,7 +4588,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
|| !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime)))) || !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))))
{ {
propagate_value (use_p, sprime); propagate_value (use_p, sprime);
gimple_set_modified (stmt, true); modified = true;
if (TREE_CODE (sprime) == SSA_NAME if (TREE_CODE (sprime) == SSA_NAME
&& !is_gimple_debug (stmt)) && !is_gimple_debug (stmt))
gimple_set_plf (SSA_NAME_DEF_STMT (sprime), gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
@ -4595,8 +4596,34 @@ eliminate_dom_walker::before_dom_children (basic_block b)
} }
} }
/* Fold the stmt if modified, this canonicalizes MEM_REFs we propagated
into which is a requirement for the IPA devirt machinery. */
gimple *old_stmt = stmt;
if (modified)
{
/* If a formerly non-invariant ADDR_EXPR is turned into an
invariant one it was on a separate stmt. */
if (gimple_assign_single_p (stmt)
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
if (is_gimple_call (stmt))
{
/* ??? Only fold calls inplace for now, this may create new
SSA names which in turn will confuse free_scc_vn SSA name
release code. */
fold_stmt_inplace (&gsi);
}
else
{
fold_stmt (&gsi);
stmt = gsi_stmt (gsi);
}
}
/* Visit indirect calls and turn them into direct calls if /* Visit indirect calls and turn them into direct calls if
possible using the devirtualization machinery. */ possible using the devirtualization machinery. Do this before
checking for required EH/abnormal/noreturn cleanup as devird
may expose more of those. */
if (gcall *call_stmt = dyn_cast <gcall *> (stmt)) if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
{ {
tree fn = gimple_call_fn (call_stmt); tree fn = gimple_call_fn (call_stmt);
@ -4605,24 +4632,21 @@ eliminate_dom_walker::before_dom_children (basic_block b)
&& virtual_method_call_p (fn)) && virtual_method_call_p (fn))
{ {
tree otr_type = obj_type_ref_class (fn); tree otr_type = obj_type_ref_class (fn);
unsigned HOST_WIDE_INT otr_tok
= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (fn));
tree instance; tree instance;
ipa_polymorphic_call_context context (current_function_decl, fn, stmt, &instance); ipa_polymorphic_call_context context (current_function_decl,
fn, stmt, &instance);
context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn),
otr_type, stmt);
bool final; bool final;
vec <cgraph_node *> targets
context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt);
vec <cgraph_node *>targets
= possible_polymorphic_call_targets (obj_type_ref_class (fn), = possible_polymorphic_call_targets (obj_type_ref_class (fn),
tree_to_uhwi otr_tok, context, &final);
(OBJ_TYPE_REF_TOKEN (fn)),
context,
&final);
if (dump_file) if (dump_file)
dump_possible_polymorphic_call_targets (dump_file, dump_possible_polymorphic_call_targets (dump_file,
obj_type_ref_class (fn), obj_type_ref_class (fn),
tree_to_uhwi otr_tok, context);
(OBJ_TYPE_REF_TOKEN (fn)),
context);
if (final && targets.length () <= 1 && dbg_cnt (devirt)) if (final && targets.length () <= 1 && dbg_cnt (devirt))
{ {
tree fn; tree fn;
@ -4632,7 +4656,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE); fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
if (dump_enabled_p ()) if (dump_enabled_p ())
{ {
location_t loc = gimple_location_safe (stmt); location_t loc = gimple_location (stmt);
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
"converting indirect call to " "converting indirect call to "
"function %s\n", "function %s\n",
@ -4654,38 +4678,22 @@ eliminate_dom_walker::before_dom_children (basic_block b)
} }
} }
if (gimple_modified_p (stmt)) if (modified)
{ {
/* If a formerly non-invariant ADDR_EXPR is turned into an /* When changing a call into a noreturn call, cfg cleanup
invariant one it was on a separate stmt. */ is needed to fix up the noreturn call. */
if (gimple_assign_single_p (stmt) if (!was_noreturn
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR) && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt)); el_to_fixup.safe_push (stmt);
gimple *old_stmt = stmt; /* When changing a condition or switch into one we know what
if (is_gimple_call (stmt)) edge will be executed, schedule a cfg cleanup. */
{ if ((gimple_code (stmt) == GIMPLE_COND
/* ??? Only fold calls inplace for now, this may create new && (gimple_cond_true_p (as_a <gcond *> (stmt))
SSA names which in turn will confuse free_scc_vn SSA name || gimple_cond_false_p (as_a <gcond *> (stmt))))
release code. */ || (gimple_code (stmt) == GIMPLE_SWITCH
fold_stmt_inplace (&gsi); && TREE_CODE (gimple_switch_index
/* When changing a call into a noreturn call, cfg cleanup (as_a <gswitch *> (stmt))) == INTEGER_CST))
is needed to fix up the noreturn call. */ el_todo |= TODO_cleanup_cfg;
if (!was_noreturn && gimple_call_noreturn_p (stmt))
el_to_fixup.safe_push (stmt);
}
else
{
fold_stmt (&gsi);
stmt = gsi_stmt (gsi);
if ((gimple_code (stmt) == GIMPLE_COND
&& (gimple_cond_true_p (as_a <gcond *> (stmt))
|| gimple_cond_false_p (as_a <gcond *> (stmt))))
|| (gimple_code (stmt) == GIMPLE_SWITCH
&& TREE_CODE (gimple_switch_index (
as_a <gswitch *> (stmt)))
== INTEGER_CST))
el_todo |= TODO_cleanup_cfg;
}
/* If we removed EH side-effects from the statement, clean /* If we removed EH side-effects from the statement, clean
its EH information. */ its EH information. */
if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)) if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))