Hi

In aarch64 backend of google/4.9 branch, the split pattern for insn
aarch64_lshr_sisd_or_int_<mode>3 destroys one of the source operands,
causes the later usage of the operand get a wrong value (google bug
17907351).

The bug has been fixed in trunk by r220860. This patch backports it to
google/4.9 branch. It passed regression test on aarch64-qemu.

OK for google/4.9?

thanks
Guozhi Wei


Index: config/aarch64/aarch64.md
===================================================================
--- config/aarch64/aarch64.md (revision 224524)
+++ config/aarch64/aarch64.md (working copy)
@@ -2786,7 +2786,7 @@

 ;; Logical right shift using SISD or Integer instruction
 (define_insn "*aarch64_lshr_sisd_or_int_<mode>3"
-  [(set (match_operand:GPI 0 "register_operand" "=w,w,r")
+  [(set (match_operand:GPI 0 "register_operand" "=w,&w,r")
         (lshiftrt:GPI
           (match_operand:GPI 1 "register_operand" "w,w,r")
           (match_operand:QI 2 "aarch64_reg_or_shift_imm_<mode>"
"Us<cmode>,w,rUs<cmode>")))]
@@ -2805,11 +2805,13 @@
            (match_operand:DI 1 "aarch64_simd_register")
            (match_operand:QI 2 "aarch64_simd_register")))]
   "TARGET_SIMD && reload_completed"
-  [(set (match_dup 2)
+  [(set (match_dup 3)
         (unspec:QI [(match_dup 2)] UNSPEC_SISD_NEG))
    (set (match_dup 0)
-        (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_SISD_USHL))]
-  ""
+        (unspec:DI [(match_dup 1) (match_dup 3)] UNSPEC_SISD_USHL))]
+  {
+    operands[3] = gen_lowpart (QImode, operands[0]);
+  }
 )

 (define_split
@@ -2818,11 +2820,13 @@
            (match_operand:SI 1 "aarch64_simd_register")
            (match_operand:QI 2 "aarch64_simd_register")))]
   "TARGET_SIMD && reload_completed"
-  [(set (match_dup 2)
+  [(set (match_dup 3)
         (unspec:QI [(match_dup 2)] UNSPEC_SISD_NEG))
    (set (match_dup 0)
-        (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_USHL_2S))]
-  ""
+        (unspec:SI [(match_dup 1) (match_dup 3)] UNSPEC_USHL_2S))]
+  {
+    operands[3] = gen_lowpart (QImode, operands[0]);
+  }
 )

 ;; Arithmetic right shift using SISD or Integer instruction
Index: testsuite/gcc.target/aarch64/sisd-shft-neg_1.c
===================================================================
--- testsuite/gcc.target/aarch64/sisd-shft-neg_1.c (revision 0)
+++ testsuite/gcc.target/aarch64/sisd-shft-neg_1.c (working copy)
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-inline" } */
+
+extern void abort (void);
+
+#define force_simd_si(v) asm volatile ("mov %s0, %1.s[0]" :"=w" (v) :"w" (v) :)
+
+unsigned int
+shft_add (unsigned int a, unsigned int b)
+{
+  unsigned int c;
+
+  force_simd_si (a);
+  force_simd_si (b);
+  c = a >> b;
+  force_simd_si (c);
+
+  return c + b;
+}
+
+int
+main (void)
+{
+  unsigned int i = 0;
+  unsigned int a = 0xdeadbeef;
+
+  for (i = 0; i < 32; i++)
+  {
+    unsigned int exp = (a / (1 << i) + i);
+    unsigned int got = shft_add (a, i);
+
+    if (exp != got)
+      abort ();
+  }
+
+  return 0;
+}
+

Reply via email to