tree-optimization/93491 - avoid PRE of trapping calls across exits

This makes us avoid PREing calls that could trap across other
calls that might not return.  The PR88087 testcase has exactly
such case so I've refactored the testcase to contain a valid PRE.
I've also adjusted PRE to not consider pure calls possibly
not returning in line with what we do elsewhere.

Note we don't have a good idea whether a function always returns
normally or whether its body is known to never trap.  That's
something IPA could compute.

2021-09-01  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/93491
	* tree-ssa-pre.c (compute_avail): Set BB_MAY_NOTRETURN
	after processing the stmt itself.  Do not consider
	pure functions possibly not returning.  Properly avoid
	adding possibly trapping calls to EXP_GEN when there's
	a preceeding possibly not returning call.
	* tree-ssa-sccvn.c (vn_reference_may_trap): Conservatively
	not handle calls.

	* gcc.dg/torture/pr93491.c: New testcase.
	* gcc.dg/tree-ssa/pr88087.c: Change to valid PRE opportunity.
This commit is contained in:
Richard Biener 2021-09-01 11:49:39 +02:00
parent 153766ec83
commit 13a43a90ae
4 changed files with 60 additions and 16 deletions

View File

@ -0,0 +1,24 @@
/* { dg-do run } */
extern void exit (int);
__attribute__((noipa))
void f(int i)
{
exit(i);
}
__attribute__((const,noipa))
int g(int i)
{
return 1 / i;
}
int main()
{
while (1)
{
f(0);
f(g(0));
}
}

View File

@ -1,17 +1,17 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
/* { dg-options "-O2 -fno-code-hoisting -fdump-tree-pre-stats" } */
int f();
int d;
void c()
void c(int x)
{
for (;;)
{
f();
int (*fp)() __attribute__((const)) = (void *)f;
d = fp();
}
int (*fp)() __attribute__((const)) = (void *)f;
if (x)
d = fp ();
int tem = fp ();
f();
d = tem;
}
/* We shouldn't ICE and hoist the const call of fp out of the loop. */
/* We shouldn't ICE and PRE the const call. */
/* { dg-final { scan-tree-dump "Eliminated: 1" "pre" } } */

View File

@ -3957,6 +3957,7 @@ compute_avail (function *fun)
/* Now compute value numbers and populate value sets with all
the expressions computed in BLOCK. */
bool set_bb_may_notreturn = false;
for (gimple_stmt_iterator gsi = gsi_start_bb (block); !gsi_end_p (gsi);
gsi_next (&gsi))
{
@ -3965,6 +3966,12 @@ compute_avail (function *fun)
stmt = gsi_stmt (gsi);
if (set_bb_may_notreturn)
{
BB_MAY_NOTRETURN (block) = 1;
set_bb_may_notreturn = false;
}
/* Cache whether the basic-block has any non-visible side-effect
or control flow.
If this isn't a call or it is the last stmt in the
@ -3976,10 +3983,12 @@ compute_avail (function *fun)
that forbids hoisting possibly trapping expressions
before it. */
int flags = gimple_call_flags (stmt);
if (!(flags & ECF_CONST)
if (!(flags & (ECF_CONST|ECF_PURE))
|| (flags & ECF_LOOPING_CONST_OR_PURE)
|| stmt_can_throw_external (fun, stmt))
BB_MAY_NOTRETURN (block) = 1;
/* Defer setting of BB_MAY_NOTRETURN to avoid it
influencing the processing of the call itself. */
set_bb_may_notreturn = true;
}
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
@ -4030,11 +4039,16 @@ compute_avail (function *fun)
/* If the value of the call is not invalidated in
this block until it is computed, add the expression
to EXP_GEN. */
if (!gimple_vuse (stmt)
|| gimple_code
(SSA_NAME_DEF_STMT (gimple_vuse (stmt))) == GIMPLE_PHI
|| gimple_bb (SSA_NAME_DEF_STMT
(gimple_vuse (stmt))) != block)
if ((!gimple_vuse (stmt)
|| gimple_code
(SSA_NAME_DEF_STMT (gimple_vuse (stmt))) == GIMPLE_PHI
|| gimple_bb (SSA_NAME_DEF_STMT
(gimple_vuse (stmt))) != block)
/* If the REFERENCE traps and there was a preceding
point in the block that might not return avoid
adding the reference to EXP_GEN. */
&& (!BB_MAY_NOTRETURN (block)
|| !vn_reference_may_trap (ref)))
{
result = get_or_alloc_expr_for_reference
(ref, gimple_location (stmt));
@ -4220,6 +4234,11 @@ compute_avail (function *fun)
break;
}
}
if (set_bb_may_notreturn)
{
BB_MAY_NOTRETURN (block) = 1;
set_bb_may_notreturn = false;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{

View File

@ -5851,6 +5851,7 @@ vn_reference_may_trap (vn_reference_t ref)
case MODIFY_EXPR:
case CALL_EXPR:
/* We do not handle calls. */
return true;
case ADDR_EXPR:
/* And toplevel address computations never trap. */
return false;