diff --git a/gcc/testsuite/gcc.dg/torture/pr93491.c b/gcc/testsuite/gcc.dg/torture/pr93491.c new file mode 100644 index 0000000000000000000000000000000000000000..2cb4c0ca7afe5da7fc5a13bb592682ddd65effb1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr93491.c @@ -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)); + } +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr88087.c b/gcc/testsuite/gcc.dg/tree-ssa/pr88087.c index d0061b61aedb0e11792f90ac81424b478b298aff..c48dba5bf21c339197d337b616f5fd71a08cd45e 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr88087.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr88087.c @@ -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" } } */ diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index ebe95cc6c73f0540db5986869f8d89816df470a4..769aadb2315ab39acab82d26397443e94a918d52 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -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)) { diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index bf87cee38573064e552ec04e4fc1b3ec37f0cc02..2357bbdbf9022c4ee540f97e323ad81073a3ec3e 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -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;