]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
aarch64: Fix TImode __sync_*_compare_and_exchange expansion with LSE [PR114310]
authorJakub Jelinek <jakub@redhat.com>
Thu, 14 Mar 2024 13:09:20 +0000 (14:09 +0100)
committerJakub Jelinek <jakub@redhat.com>
Fri, 15 Mar 2024 23:28:39 +0000 (00:28 +0100)
The following testcase ICEs with LSE atomics.
The problem is that the @atomic_compare_and_swap<mode> expander uses
aarch64_reg_or_zero predicate for the desired operand, which is fine,
given that for most of the modes and even for TImode in some cases
it can handle zero immediate just fine, but the TImode
@aarch64_compare_and_swap<mode>_lse just uses register_operand for
that operand instead, again intentionally so, because the casp,
caspa, caspl and caspal instructions need to use a pair of consecutive
registers for the operand and xzr is just one register and we can't
just store zero into the link register to emulate pair of zeros.

So, the following patch fixes that by forcing the newval operand into
a register for the TImode LSE case.

2024-03-14  Jakub Jelinek  <jakub@redhat.com>

PR target/114310
* config/aarch64/aarch64.cc (aarch64_expand_compare_and_swap): For
TImode force newval into a register.

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

(cherry picked from commit 9349aefa1df7ae36714b7b9f426ad46e314892d1)

gcc/config/aarch64/aarch64.cc
gcc/testsuite/gcc.dg/pr114310.c [new file with mode: 0644]

index f546c48ae2d2bad2e34c6b72e5e3e30aba3c3bd6..f6d14cd791a5da0f3fd5ca348ec8cd6c37e6b401 100644 (file)
@@ -23081,6 +23081,8 @@ aarch64_expand_compare_and_swap (rtx operands[])
         rval = copy_to_mode_reg (r_mode, oldval);
       else
        emit_move_insn (rval, gen_lowpart (r_mode, oldval));
+      if (mode == TImode)
+       newval = force_reg (mode, newval);
 
       emit_insn (gen_aarch64_compare_and_swap_lse (mode, rval, mem,
                                                   newval, mod_s));
diff --git a/gcc/testsuite/gcc.dg/pr114310.c b/gcc/testsuite/gcc.dg/pr114310.c
new file mode 100644 (file)
index 0000000..55edd80
--- /dev/null
@@ -0,0 +1,20 @@
+/* PR target/114310 */
+/* { dg-do run { target int128 } } */
+
+volatile __attribute__((aligned (sizeof (__int128_t)))) __int128_t v = 10;
+
+int
+main ()
+{
+#if __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
+  if (__sync_val_compare_and_swap (&v, (__int128_t) 10, (__int128_t) 0) != 10)
+    __builtin_abort ();
+  if (__sync_val_compare_and_swap (&v, (__int128_t) 10, (__int128_t) 15) != 0)
+    __builtin_abort ();
+  if (__sync_val_compare_and_swap (&v, (__int128_t) 0, (__int128_t) 42) != 0)
+    __builtin_abort ();
+  if (__sync_val_compare_and_swap (&v, (__int128_t) 31, (__int128_t) 35) != 42)
+    __builtin_abort ();
+#endif
+  return 0;
+}