aarch64: Fix up *aarch64_bfxilsi_uxtw [PR98853]
authorJakub Jelinek <jakub@redhat.com>
Wed, 27 Jan 2021 19:35:21 +0000 (20:35 +0100)
committerJakub Jelinek <jakub@redhat.com>
Wed, 27 Jan 2021 19:35:21 +0000 (20:35 +0100)
The https://gcc.gnu.org/legacy-ml/gcc-patches/2018-07/msg01895.html
patch that introduced this pattern claimed:
Would generate:

combine_balanced_int:
        bfxil   w0, w1, 0, 16
        uxtw    x0, w0
        ret

But with this patch generates:

combine_balanced_int:
        bfxil   w0, w1, 0, 16
        ret
and it is indeed what it should generate, but it doesn't do that,
it emits bfxil  x0, x1, 0, 16
instead which doesn't zero extend from 32 to 64 bits, but preserves
the bits from the destination register.

2021-01-27  Jakub Jelinek  <jakub@redhat.com>

PR target/98853
* config/aarch64/aarch64.md (*aarch64_bfxilsi_uxtw): Use
%w0, %w1 and %2 instead of %0, %1 and %2.

* gcc.c-torture/execute/pr98853-1.c: New test.
* gcc.c-torture/execute/pr98853-2.c: New test.

gcc/config/aarch64/aarch64.md
gcc/testsuite/gcc.c-torture/execute/pr98853-1.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/pr98853-2.c [new file with mode: 0644]

index 45d9c6ac45a23c0e3133aef38c812a8d8738004f..e5990765b270b692965f67f2b7390a4470c21bd1 100644 (file)
     {
       case 0:
        operands[3] = GEN_INT (ctz_hwi (~INTVAL (operands[3])));
-       return "bfxil\\t%0, %1, 0, %3";
+       return "bfxil\\t%w0, %w1, 0, %3";
       case 1:
        operands[3] = GEN_INT (ctz_hwi (~INTVAL (operands[4])));
-       return "bfxil\\t%0, %2, 0, %3";
+       return "bfxil\\t%w0, %w2, 0, %3";
       default:
        gcc_unreachable ();
     }
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr98853-1.c b/gcc/testsuite/gcc.c-torture/execute/pr98853-1.c
new file mode 100644 (file)
index 0000000..b5a3786
--- /dev/null
@@ -0,0 +1,21 @@
+/* PR target/98853 */
+
+#if __SIZEOF_INT__ == 4 && __SIZEOF_LONG_LONG__ == 8 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+__attribute__((__noipa__)) unsigned long long
+foo (unsigned x, unsigned long long y, unsigned long long z)
+{
+  __builtin_memcpy (2 + (char *) &x, 2 + (char *) &y, 2);
+  return x + z;
+}
+#endif
+
+int
+main ()
+{
+#if __SIZEOF_INT__ == 4 && __SIZEOF_LONG_LONG__ == 8 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+  if (foo (0x44444444U, 0x1111111111111111ULL, 0x2222222222222222ULL)
+      != 0x2222222233336666ULL)
+    __builtin_abort ();
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr98853-2.c b/gcc/testsuite/gcc.c-torture/execute/pr98853-2.c
new file mode 100644 (file)
index 0000000..2a3b0f2
--- /dev/null
@@ -0,0 +1,19 @@
+/* PR target/98853 */
+
+#if __SIZEOF_INT__ == 4 && __SIZEOF_LONG_LONG__ == 8
+__attribute__((noipa)) unsigned long long
+foo (unsigned long long x, unsigned int y)
+{
+  return ((unsigned) x & 0xfffe0000U) | (y & 0x1ffff);
+}
+#endif
+
+int
+main ()
+{
+#if __SIZEOF_INT__ == 4 && __SIZEOF_LONG_LONG__ == 8
+  if (foo (0xdeadbeefcaf2babeULL, 0xdeaffeedU) != 0x00000000caf3feedULL)
+    __builtin_abort ();
+#endif
+  return 0;
+}