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:
parent
153766ec83
commit
13a43a90ae
4 changed files with 60 additions and 16 deletions
24
gcc/testsuite/gcc.dg/torture/pr93491.c
Normal file
24
gcc/testsuite/gcc.dg/torture/pr93491.c
Normal 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));
|
||||
}
|
||||
}
|
|
@ -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" } } */
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue