[AArch64] Fix wrong-code bug in right-shift SISD patterns
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>
Fri, 20 Feb 2015 14:05:51 +0000 (14:05 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Fri, 20 Feb 2015 14:05:51 +0000 (14:05 +0000)
* config/aarch64/aarch64.md (*aarch64_lshr_sisd_or_int_<mode>3):
Mark operand 0 as earlyclobber in 2nd alternative.
(1st define_split below *aarch64_lshr_sisd_or_int_<mode>3):
Write negated shift amount into QI lowpart operand 0 and use it
in the shift step.
(2nd define_split below *aarch64_lshr_sisd_or_int_<mode>3): Likewise.

* gcc.target/aarch64/sisd-shft-neg_1.c: New test.

From-SVN: r220860

gcc/ChangeLog
gcc/config/aarch64/aarch64.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/sisd-shft-neg_1.c [new file with mode: 0644]

index a899997e8eb97d850da0ba98d1f126fe98814dc1..32cc757278b41bb3901139c3f458334c8a6863ff 100644 (file)
@@ -1,3 +1,12 @@
+2015-02-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * config/aarch64/aarch64.md (*aarch64_lshr_sisd_or_int_<mode>3):
+       Mark operand 0 as earlyclobber in 2nd alternative.
+       (1st define_split below *aarch64_lshr_sisd_or_int_<mode>3):
+       Write negated shift amount into QI lowpart operand 0 and use it
+       in the shift step.
+       (2nd define_split below *aarch64_lshr_sisd_or_int_<mode>3): Likewise.
+
 2015-02-20  Bernd Schmidt  <bernds@codesourcery.com>
 
        * cgraph.h (clone_function_name_1): Declare.
index 1f4169ee76e7f3f321e5ed7a4d0f08b54ee3bf17..8f157ce2901362222da27011452095a46e4bf30d 100644 (file)
 
 ;; 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>")))]
            (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
            (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 2409cfb0fa7e788e30e0f52864b92989e57a5310..65310fd081d6aea2fcef786a13c165b7ee36a247 100644 (file)
@@ -1,3 +1,7 @@
+2015-02-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       * gcc.target/aarch64/sisd-shft-neg_1.c: New test.
+
 2015-02-20  Georg-Johann Lay  <avr@gjlay.de>
 
        PR target/64452
diff --git a/gcc/testsuite/gcc.target/aarch64/sisd-shft-neg_1.c b/gcc/testsuite/gcc.target/aarch64/sisd-shft-neg_1.c
new file mode 100644 (file)
index 0000000..c091657
--- /dev/null
@@ -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;
+}
+