update_equiv_regs will search for (set (MEM) (REG)) where the REG is only used in a single basic block and is always equivalent to the memory location in that block and if moving the store from its present location to the insn which sets REG would be safe. If those conditions are met, then it'll create a REG_EQUIV note on the initializing insn.

To implement the movement safety check above update_equiv_regs will call memref_used_between_p to see if anything potentially reads MEM between the insn that sets REG and the store to MEM. memref_used_between_p does a scan from the source insn (set REG) to the final insn (set MEM).

Normally that would be all fine and good.  In this test however we have

(set (MEM) (REG))
(set (REG) (...))

So the scan of the insn chain starting from the (set (REG)) insn will never find the (set (MEM)) insn and eventually segfaults.

[ REG is uninitialized when stored into MEM. ]

This patch does two things.

First, it changes memref_used_between_p to not fault, but instead assert that it finds the final insn.

Second, update_equiv_regs detects the case shown above where the MEM assignment comes before the REG assignment and avoids calling memref_used_between_p in that case.

update_equiv_regs is the only user of memref_used_between_p.

Bootstrapped and regression tested on x86_64-linux-gnu.  OK for the trunk?

Thanks,
Jeff
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b7711b8..8a10ec3 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2016-03-17  Jeff Law  <l...@redhat.com>
+
+       PR rtl-optimization/70263
+       * ira.c (memref_used_between_p): Assert we found END in the insn chain.
+       (update_equiv_regs): When trying to move a store to after the insn
+       that sets the source of the store, make sure the store occurs after
+       the insn that sets the source of the store.
+
 2016-03-17  H.J. Lu  <hongjiu...@intel.com>
 
        PR driver/70192
diff --git a/gcc/ira.c b/gcc/ira.c
index 062b8a4..ef9731e 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3225,13 +3225,18 @@ memref_referenced_p (rtx memref, rtx x)
 }
 
 /* TRUE if some insn in the range (START, END] references a memory location
-   that would be affected by a store to MEMREF.  */
+   that would be affected by a store to MEMREF.
+
+   Callers should not call this routine if START is after END in the
+   insn chain.  */
+
 static int
 memref_used_between_p (rtx memref, rtx_insn *start, rtx_insn *end)
 {
   rtx_insn *insn;
 
-  for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
+  for (insn = NEXT_INSN (start);
+       insn && insn != NEXT_INSN (end);
        insn = NEXT_INSN (insn))
     {
       if (!NONDEBUG_INSN_P (insn))
@@ -3245,6 +3250,7 @@ memref_used_between_p (rtx memref, rtx_insn *start, 
rtx_insn *end)
        return 1;
     }
 
+  gcc_assert (insn);
   return 0;
 }
 
@@ -3337,6 +3343,7 @@ update_equiv_regs (void)
   int loop_depth;
   bitmap cleared_regs;
   bool *pdx_subregs;
+  bitmap seen_insns;
 
   /* Use pdx_subregs to show whether a reg is used in a paradoxical
      subreg.  */
@@ -3606,11 +3613,14 @@ update_equiv_regs (void)
   /* A second pass, to gather additional equivalences with memory.  This needs
      to be done after we know which registers we are going to replace.  */
 
+  seen_insns = BITMAP_ALLOC (NULL);
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
       rtx set, src, dest;
       unsigned regno;
 
+      bitmap_set_bit (seen_insns, INSN_UID (insn));
+
       if (! INSN_P (insn))
        continue;
 
@@ -3646,7 +3656,8 @@ update_equiv_regs (void)
          && ! find_reg_note (XEXP (reg_equiv[regno].init_insns, 0),
                              REG_EQUIV, NULL_RTX)
          && ! contains_replace_regs (XEXP (dest, 0))
-         && ! pdx_subregs[regno])
+         && ! pdx_subregs[regno]
+         && ! bitmap_bit_p (seen_insns, INSN_UID (insn)))
        {
          rtx_insn *init_insn =
            as_a <rtx_insn *> (XEXP (reg_equiv[regno].init_insns, 0));
@@ -3664,6 +3675,7 @@ update_equiv_regs (void)
            }
        }
     }
+  BITMAP_FREE (seen_insns);
 
   cleared_regs = BITMAP_ALLOC (NULL);
   /* Now scan all regs killed in an insn to see if any of them are
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c59417e..800abbd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2016-03-17  Jeff Law  <l...@redhat.com>
+
+       PR rtl-optimization/70263
+       * gcc.c-torture/compile/pr70263.c: New test.
+
 2016-03-17  H.J. Lu  <hongjiu...@intel.com>
 
        PR driver/70192
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr70263.c 
b/gcc/testsuite/gcc.c-torture/compile/pr70263.c
new file mode 100644
index 0000000..d4bf280
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr70263.c
@@ -0,0 +1,11 @@
+int a[91];
+int b, c;
+void fn1() {
+  int n, m;
+  do {
+    a[c--];
+    a[--c] = m;
+    a[--m] = b;
+  } while (n);
+}
+

Reply via email to