Hi!

The following testcase is miscompiled on powerpc64le-linux.
As mentioned in the PR, the problem is with a REG_EQUAL note which
expand_mult_const attaches to:

(insn 17 16 18 2 (set (reg:SI 140)
        (plus:SI (subreg:SI (reg:HI 138) 0)
            (subreg:SI (reg:HI 136) 0))) "pr89679.c":16:3 -1
     (expr_list:REG_EQUAL (mult:SI (subreg:SI (reg:HI 136) 0)
            (const_int 257 [0x101]))
        (nil)))

The REG_EQUAL here is only approximate, as the operation is done on
SImode and using paradoxical subregs, so the upper bits can be anything,
only the low part of the SImode reg is guaranteed to be
equal to low part of the REG_EQUAL note.

Later on fwprop propagates separately into the insn PATTERN and into the
REG_EQUAL note and we end up with:

(insn 17 6 19 2 (set (reg:SI 140)
        (const_int -1 [0xffffffffffffffff])) "pr89679.c":16:3 494 
{*movsi_internal1}
     (expr_list:REG_DEAD (reg:HI 138 [ c ])
        (expr_list:REG_DEAD (reg:HI 136 [ c ])
            (expr_list:REG_EQUAL (const_int 65535 [0xffff])
                (nil)))))

which is clearly invalid, as it is never equal rather than always.
Later on CSE uses the REG_EQUAL note and miscompiles the testcase.

Below is one patch, more in the spirit of
https://gcc.gnu.org/ml/gcc-patches/2016-04/msg00418.html
where we refuse to add REG_EQUAL note in that case.

Attached is another variant, which keeps it around just in case something
would make use of it, but makes sure we don't fwprop into such REG_EQUAL
notes replacing a paradoxical subreg in there with something else.

Both patches were bootstrapped/regtested on
{x86_64,i686,powerpc64le,s390x,aarch64}-linux, ok for trunk (which one)?

2019-03-13  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/89679
        * expmed.c (expand_mult_const): Don't add a REG_EQUAL note if it
        would contain a paradoxical SUBREG.

        * gcc.dg/pr89679.c: New test.

--- gcc/expmed.c.jj     2019-01-10 11:43:14.387377695 +0100
+++ gcc/expmed.c        2019-03-12 17:38:55.286511666 +0100
@@ -3356,13 +3356,20 @@ expand_mult_const (machine_mode mode, rt
              tem = gen_lowpart (nmode, op0);
            }
 
-         insn = get_last_insn ();
-         wide_int wval_so_far
-           = wi::uhwi (val_so_far,
-                       GET_MODE_PRECISION (as_a <scalar_mode> (nmode)));
-         rtx c = immed_wide_int_const (wval_so_far, nmode);
-         set_dst_reg_note (insn, REG_EQUAL, gen_rtx_MULT (nmode, tem, c),
-                           accum_inner);
+         /* Don't add a REG_EQUAL note if tem is a paradoxical SUBREG.
+            In that case, only the low bits of accum would be guaranteed to
+            be equal to the content of the REG_EQUAL note, the upper bits
+            can be anything.  */
+         if (!paradoxical_subreg_p (tem))
+           {
+             insn = get_last_insn ();
+             wide_int wval_so_far
+               = wi::uhwi (val_so_far,
+                           GET_MODE_PRECISION (as_a <scalar_mode> (nmode)));
+             rtx c = immed_wide_int_const (wval_so_far, nmode);
+             set_dst_reg_note (insn, REG_EQUAL, gen_rtx_MULT (nmode, tem, c),
+                               accum_inner);
+           }
        }
     }
 
--- gcc/testsuite/gcc.dg/pr89679.c.jj   2019-02-22 00:02:11.718740936 +0100
+++ gcc/testsuite/gcc.dg/pr89679.c      2019-03-12 18:08:07.240502975 +0100
@@ -0,0 +1,26 @@
+/* PR rtl-optimization/89679 */
+/* { dg-do run } */
+/* { dg-options "-Og -frerun-cse-after-loop -fno-tree-fre" } */
+
+unsigned short g;
+
+void
+foo (unsigned long long x)
+{
+  if (x != 0xffff)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+#if __SIZEOF_SHORT__ == 2 && __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+  unsigned short d = 0;
+  unsigned long long x, c = ~0;
+  c = c >> d;
+  __builtin_memset (&d, c, 2);
+  x = d + g;
+  foo (x);
+#endif
+  return 0;
+}

        Jakub
2019-03-13  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/89679
        * fwprop.c (forward_propagate_and_simplify): Don't propagate into
        paradoxical SUBREGs in REG_EQUAL notes.

        * gcc.dg/pr89679.c: New test.

--- gcc/fwprop.c.jj     2019-01-01 12:37:21.190908780 +0100
+++ gcc/fwprop.c        2019-03-12 17:24:14.623863160 +0100
@@ -1327,7 +1327,12 @@ forward_propagate_and_simplify (df_ref u
     {
       rtx note = find_reg_note (use_insn, REG_EQUAL, NULL_RTX);
       if (DF_REF_FLAGS (use) & DF_REF_IN_NOTE)
-       loc = &XEXP (note, 0);
+       {
+         loc = &XEXP (note, 0);
+         /* Don't simplify a paradoxical SUBREG in a REG_EQUAL note.  */
+         if (paradoxical_subreg_p (DF_REF_REG (use)))
+           return false;
+       }
       else
        loc = &SET_SRC (use_set);
 
--- gcc/testsuite/gcc.dg/pr89679.c.jj   2019-02-22 00:02:11.718740936 +0100
+++ gcc/testsuite/gcc.dg/pr89679.c      2019-03-12 18:08:07.240502975 +0100
@@ -0,0 +1,26 @@
+/* PR rtl-optimization/89679 */
+/* { dg-do run } */
+/* { dg-options "-Og -frerun-cse-after-loop -fno-tree-fre" } */
+
+unsigned short g;
+
+void
+foo (unsigned long long x)
+{
+  if (x != 0xffff)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+#if __SIZEOF_SHORT__ == 2 && __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+  unsigned short d = 0;
+  unsigned long long x, c = ~0;
+  c = c >> d;
+  __builtin_memset (&d, c, 2);
+  x = d + g;
+  foo (x);
+#endif
+  return 0;
+}

Reply via email to