[RFA][PR rtl-optimization/70263] Fix creation of new REG_EQUIV notes

Jeff Law law@redhat.com
Thu Mar 17 18:21:00 GMT 2016



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
-------------- next part --------------
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  <law@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.lu@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  <law@redhat.com>
+
+	PR rtl-optimization/70263
+	* gcc.c-torture/compile/pr70263.c: New test.
+
 2016-03-17  H.J. Lu  <hongjiu.lu@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);
+}
+


More information about the Gcc-patches mailing list