Hi!

The following testcase is miscompiled on i686-linux at -O3.
The bug is in DSE record_store, which for group_id < 0 uses mem_addr
set to result of get_addr (base->val_rtx) (plus optional offset),
which is fine for canon_true_dependence with other MEMs in that function,
but we also store that address in store_info.  The problem is if later on
e.g. some read uses the same e.g. hard register as get_addr returned, but
that register contains at that later point a different value. 
canon_true_dependence then happily returns the read does not alias the
store, although it might.
The fix is to store the VALUE (plus optional offset) into
store_info->mem_addr instead, then at some later insn when get_addr is
called on it it will either return the same register or expression (if it
has not changed), or some different one otherwise.

Bootstrapped/regtested on x86_64-linux and i686-linux, I've additionally
performed instrumented x86_64-linux and i686-linux bootstraps/regtests,
which recorded number of locally_deleted and globally_deleted from each
function, once without this patch, once with it.  Across both 64-bit and
32-bit bootstrap/regtest, both unpatched and patched had the same number
151999 of globally_deleted, and unpatched had 74828 locally_deleted, while
patched 74849 locally_deleted.  Thus the patch should in addition to
actually fixing a real bug not really decrease number of DSEd stores
significant way, but sometimes even improve it.

Ok for trunk?

2016-01-15  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/68955
        * dse.c (record_store): For group_id < 0, ensure mem_addr is not
        result of get_addr.

        * gcc.dg/torture/pr68955.c: New test.

--- gcc/dse.c.jj        2016-01-04 14:55:51.000000000 +0100
+++ gcc/dse.c   2016-01-15 19:25:31.323384174 +0100
@@ -1653,6 +1653,15 @@ record_store (rtx body, bb_info_t bb_inf
   insn_info->store_rec = store_info;
   store_info->mem = mem;
   store_info->alias_set = spill_alias_set;
+  if (spill_alias_set == 0 && group_id < 0)
+    {
+      /* Ensure we store address with VALUE in it, instead of result of
+        get_addr on it, otherwise if the registers in get_addr change,
+        we will not notice possible aliasing.  */
+      mem_addr = base->val_rtx;
+      if (offset)
+       mem_addr = plus_constant (get_address_mode (mem), mem_addr, offset);
+    }
   store_info->mem_addr = mem_addr;
   store_info->cse_base = base;
   if (width > HOST_BITS_PER_WIDE_INT)
--- gcc/testsuite/gcc.dg/torture/pr68955.c.jj   2016-01-15 19:32:00.347979523 
+0100
+++ gcc/testsuite/gcc.dg/torture/pr68955.c      2016-01-15 19:31:39.000000000 
+0100
@@ -0,0 +1,41 @@
+/* PR rtl-optimization/68955 */
+/* { dg-do run } */
+/* { dg-output "ONE1ONE" } */
+
+int a, b, c, d, g, m;
+int i[7][7][5] = { { { 5 } }, { { 5 } },
+                  { { 5 }, { 5 }, { 5 }, { 5 }, { 5 }, { -1 } } };
+static int j = 11;
+short e, f, h, k, l;
+
+static void
+foo ()
+{
+  for (; e < 5; e++)
+    for (h = 3; h; h--)
+      {
+       for (g = 1; g < 6; g++)
+         {
+           m = c == 0 ? b : b / c;
+           i[e][1][e] = i[1][1][1] | (m & l) && f;
+         }
+       for (k = 0; k < 6; k++)
+         {
+           for (d = 0; d < 6; d++)
+             i[1][e][h] = i[h][k][e] >= l;
+           i[e + 2][h + 3][e] = 6 & l;
+           i[2][1][2] = a;
+           for (; j < 5;)
+             for (;;)
+               ;
+         }
+      }
+}
+
+int
+main ()
+{
+  foo ();
+  __builtin_printf ("ONE%dONE\n", i[1][0][2]);
+  return 0;
+}

        Jakub

Reply via email to