Hi!

We miscompile the following testcase, because first we add
a mem/v into the hash table (which should not happen), later on
during merge_equiv_classes a new element for that mem/v is added
and doesn't even have in_memory set (because HASH failed with do_not_record
but nothing checked it) and later on this results in that memory not being
properly invalidated.

The initial problem is that if SET_DEST (sets[i].rtl) is a volatile mem,
but we have a known value at that memory, we compute initially
sets[i].dest_hash as hash value of the known value.  That doesn't result
into do_not_record, and when we recompute actual hash value for the MEM,
we ignore the do_not_record flag.

I've tested it also with logging when did this trigger, and in both
bootstraps it triggered only on the new testcase and in 64-bit build of
libstdc++-v3/testsuite/29_atomics/atomic_flag/test_and_set/explicit-hle.cc.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk?

2015-02-02  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/64756
        * cse.c (cse_insn): If dest != SET_DEST (sets[i].rtl) and
        HASH (SET_DEST (sets[i].rtl), mode) computation sets do_not_record,
        invalidate and do not record it.

        * gcc.c-torture/execute/pr64756.c: New test.

--- gcc/cse.c.jj        2015-01-23 20:49:11.000000000 +0100
+++ gcc/cse.c   2015-02-02 11:51:57.508084360 +0100
@@ -5521,7 +5521,22 @@ cse_insn (rtx_insn *insn)
        }
 
       if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl))
-       sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+       {
+         do_not_record = 0;
+         sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+         if (do_not_record)
+           {
+             rtx dst = SET_DEST (sets[i].rtl);
+             if (REG_P (dst) || GET_CODE (dst) == SUBREG)
+               invalidate (dst, VOIDmode);
+             else if (MEM_P (dst))
+               invalidate (dst, VOIDmode);
+             else if (GET_CODE (dst) == STRICT_LOW_PART
+                      || GET_CODE (dst) == ZERO_EXTRACT)
+               invalidate (XEXP (dst, 0), GET_MODE (dst));
+             sets[i].rtl = 0;
+           }
+       }
 
 #ifdef HAVE_cc0
       /* If setting CC0, record what it was set to, or a constant, if it
--- gcc/testsuite/gcc.c-torture/execute/pr64756.c.jj    2015-02-02 
11:53:06.903882851 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr64756.c       2015-02-02 
11:52:53.000000000 +0100
@@ -0,0 +1,30 @@
+/* PR rtl-optimization/64756 */
+
+int a, *tmp, **c = &tmp;
+volatile int d;
+static int *volatile *e = &tmp;
+unsigned int f;
+
+static void
+fn1 (int *p)
+{
+  int g;
+  for (; f < 1; f++)
+    for (g = 1; g >= 0; g--)
+      {
+       d || d;
+       *c = p;
+
+       if (tmp != &a)
+         __builtin_abort ();
+
+       *e = 0;
+      }
+}
+
+int
+main ()
+{
+  fn1 (&a);
+  return 0;
+}

        Jakub

Reply via email to