This fixes issues in GIMPLE and RTL code-hoisting which ignore const/pure calls when determining whether it is safe to hoist a possibly trapping memory reference across it.
The GIMPLE side of the fix handles this similar to regular operations where we avoid hoisting possibly trapping ones over a call that might not return. The RTL side of the fix makes sure to not handle RTL_LOOPING_CONST_OR_PURE_CALL_P like pure or const calls but mark blocks with such calls in block_with_calls. Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2019-04-09 Richard Biener <rguent...@suse.de> PR tree-optimization/90020 * tree-ssa-sccvn.c (vn_reference_may_trap): New function. * tree-ssa-sccvn.h (vn_reference_may_trap): Declare. * tree-ssa-pre.c (compute_avail): Use it to not put possibly trapping references after a call that might not return into EXP_GEN. * gcse.c (compute_hash_table_work): Do not elide marking a block containing a call if the call might not return. * gcc.dg/torture/pr90020.c: New testcase. Index: gcc/tree-ssa-sccvn.c =================================================================== --- gcc/tree-ssa-sccvn.c (revision 270223) +++ gcc/tree-ssa-sccvn.c (working copy) @@ -4766,6 +4766,57 @@ vn_nary_may_trap (vn_nary_op_t nary) return false; } +/* Return true if the reference operation REF may trap. */ + +bool +vn_reference_may_trap (vn_reference_t ref) +{ + switch (ref->operands[0].opcode) + { + case MODIFY_EXPR: + case CALL_EXPR: + /* We do not handle calls. */ + case ADDR_EXPR: + /* And toplevel address computations never trap. */ + return false; + default:; + } + + vn_reference_op_t op; + unsigned i; + FOR_EACH_VEC_ELT (ref->operands, i, op) + { + switch (op->opcode) + { + case WITH_SIZE_EXPR: + case TARGET_MEM_REF: + /* Always variable. */ + return true; + case COMPONENT_REF: + if (op->op1 && TREE_CODE (op->op1) == SSA_NAME) + return true; + break; + case ARRAY_RANGE_REF: + case ARRAY_REF: + if (TREE_CODE (op->op0) == SSA_NAME) + return true; + break; + case MEM_REF: + /* Nothing interesting in itself, the base is separate. */ + break; + /* The following are the address bases. */ + case SSA_NAME: + return true; + case ADDR_EXPR: + if (op->op0) + return tree_could_trap_p (TREE_OPERAND (op->op0, 0)); + return false; + default:; + } + } + return false; +} + eliminate_dom_walker::eliminate_dom_walker (cdi_direction direction, bitmap inserted_exprs_) : dom_walker (direction), do_pre (inserted_exprs_ != NULL), Index: gcc/tree-ssa-sccvn.h =================================================================== --- gcc/tree-ssa-sccvn.h (revision 270223) +++ gcc/tree-ssa-sccvn.h (working copy) @@ -243,6 +243,7 @@ vn_reference_t vn_reference_insert_piece bool vn_nary_op_eq (const_vn_nary_op_t const vno1, const_vn_nary_op_t const vno2); bool vn_nary_may_trap (vn_nary_op_t); +bool vn_reference_may_trap (vn_reference_t); bool vn_reference_eq (const_vn_reference_t const, const_vn_reference_t const); unsigned int get_max_value_id (void); unsigned int get_next_value_id (void); Index: gcc/tree-ssa-pre.c =================================================================== --- gcc/tree-ssa-pre.c (revision 270223) +++ gcc/tree-ssa-pre.c (working copy) @@ -3931,6 +3931,13 @@ compute_avail (void) continue; } + /* If the REFERENCE traps and there was a preceding + point in the block that might not return avoid + adding the reference to EXP_GEN. */ + if (BB_MAY_NOTRETURN (block) + && vn_reference_may_trap (ref)) + continue; + /* If the value of the reference is not invalidated in this block until it is computed, add the expression to EXP_GEN. */ Index: gcc/gcse.c =================================================================== --- gcc/gcse.c (revision 270223) +++ gcc/gcse.c (working copy) @@ -1532,7 +1532,8 @@ compute_hash_table_work (struct gcse_has 0, regno, hrsi) record_last_reg_set_info (insn, regno); - if (! RTL_CONST_OR_PURE_CALL_P (insn)) + if (! RTL_CONST_OR_PURE_CALL_P (insn) + || RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)) record_last_mem_set_info (insn); } Index: gcc/testsuite/gcc.dg/torture/pr90020.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr90020.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/pr90020.c (working copy) @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-require-weak "" } */ + +void __attribute__((noinline,noclone)) +check (int i) +{ + if (i == 0) + __builtin_exit (0); +} + +int i; +extern int x __attribute__((weak)); + +int main(int argc, char **argv) +{ + if (argc) + { + check (i); + return x; + } + else + { + check (i); + return x-1; + } + return 0; +}