Commit e910a9b1 by Richard Biener Committed by Richard Biener

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

2017-09-04  Richard Biener  <rguenther@suse.de>

	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: r251650
parent 76b0cbf8
2017-09-04 Richard Biener <rguenther@suse.de>
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-09-04 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
......
2017-09-04 Richard Biener <rguenther@suse.de>
PR tree-optimization/82060
* g++.dg/torture/pr82060.C: New testcase.
2017-09-04 Alexander Monakov <amonakov@ispras.ru>
PR rtl-optimization/57448
......
// { 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();
}
......@@ -4592,6 +4592,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
/* If we didn't replace the whole stmt (or propagate the result
into all uses), replace all uses on this stmt with their
leaders. */
bool modified = false;
use_operand_p use_p;
ssa_op_iter iter;
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
......@@ -4613,7 +4614,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
|| !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))))
{
propagate_value (use_p, sprime);
gimple_set_modified (stmt, true);
modified = true;
if (TREE_CODE (sprime) == SSA_NAME
&& !is_gimple_debug (stmt))
gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
......@@ -4621,8 +4622,56 @@ 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));
gimple_stmt_iterator prev = gsi;
gsi_prev (&prev);
if (fold_stmt (&gsi))
{
/* fold_stmt may have created new stmts inbetween
the previous stmt and the folded stmt. Mark
all defs created there as varying to not confuse
the SCCVN machinery as we're using that even during
elimination. */
if (gsi_end_p (prev))
prev = gsi_start_bb (b);
else
gsi_next (&prev);
if (gsi_stmt (prev) != gsi_stmt (gsi))
do
{
tree def;
ssa_op_iter dit;
FOR_EACH_SSA_TREE_OPERAND (def, gsi_stmt (prev),
dit, SSA_OP_ALL_DEFS)
/* As existing DEFs may move between stmts
we have to guard VN_INFO_GET. */
if (! has_VN_INFO (def))
VN_INFO_GET (def)->valnum = def;
if (gsi_stmt (prev) == gsi_stmt (gsi))
break;
gsi_next (&prev);
}
while (1);
}
stmt = gsi_stmt (gsi);
/* In case we folded the stmt away schedule the NOP for removal. */
if (gimple_nop_p (stmt))
el_to_remove.safe_push (stmt);
}
/* 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))
{
tree fn = gimple_call_fn (call_stmt);
......@@ -4631,24 +4680,21 @@ eliminate_dom_walker::before_dom_children (basic_block b)
&& virtual_method_call_p (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;
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;
context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt);
vec <cgraph_node *>targets
vec <cgraph_node *> targets
= possible_polymorphic_call_targets (obj_type_ref_class (fn),
tree_to_uhwi
(OBJ_TYPE_REF_TOKEN (fn)),
context,
&final);
otr_tok, context, &final);
if (dump_file)
dump_possible_polymorphic_call_targets (dump_file,
obj_type_ref_class (fn),
tree_to_uhwi
(OBJ_TYPE_REF_TOKEN (fn)),
context);
otr_tok, context);
if (final && targets.length () <= 1 && dbg_cnt (devirt))
{
tree fn;
......@@ -4658,7 +4704,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
if (dump_enabled_p ())
{
location_t loc = gimple_location_safe (stmt);
location_t loc = gimple_location (stmt);
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
"converting indirect call to "
"function %s\n",
......@@ -4675,50 +4721,13 @@ eliminate_dom_walker::before_dom_children (basic_block b)
== void_type_node))
gimple_call_set_fntype (call_stmt, TREE_TYPE (fn));
maybe_remove_unused_call_args (cfun, call_stmt);
gimple_set_modified (stmt, true);
modified = true;
}
}
}
if (gimple_modified_p (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));
gimple *old_stmt = stmt;
gimple_stmt_iterator prev = gsi;
gsi_prev (&prev);
if (fold_stmt (&gsi))
{
/* fold_stmt may have created new stmts inbetween
the previous stmt and the folded stmt. Mark
all defs created there as varying to not confuse
the SCCVN machinery as we're using that even during
elimination. */
if (gsi_end_p (prev))
prev = gsi_start_bb (b);
else
gsi_next (&prev);
if (gsi_stmt (prev) != gsi_stmt (gsi))
do
{
tree def;
ssa_op_iter dit;
FOR_EACH_SSA_TREE_OPERAND (def, gsi_stmt (prev),
dit, SSA_OP_ALL_DEFS)
/* As existing DEFs may move between stmts
we have to guard VN_INFO_GET. */
if (! has_VN_INFO (def))
VN_INFO_GET (def)->valnum = def;
if (gsi_stmt (prev) == gsi_stmt (gsi))
break;
gsi_next (&prev);
}
while (1);
}
stmt = gsi_stmt (gsi);
/* When changing a call into a noreturn call, cfg cleanup
is needed to fix up the noreturn call. */
if (!was_noreturn
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment