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;
+}

Reply via email to