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