aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-03-14 14:09:20 +0100
committerJakub Jelinek <jakub@redhat.com>2024-06-20 15:07:37 +0200
commit0570303f818ed12ff28de0d258ebe4f6803ef7e0 (patch)
tree924915b8a57e5cc087fe74ae80a64b64b61661f8
parentf340e1fb0e0bbe5f2982f3f1025bb12fb910db41 (diff)
downloadgcc-0570303f818ed12ff28de0d258ebe4f6803ef7e0.zip
gcc-0570303f818ed12ff28de0d258ebe4f6803ef7e0.tar.gz
gcc-0570303f818ed12ff28de0d258ebe4f6803ef7e0.tar.bz2
aarch64: Fix TImode __sync_*_compare_and_exchange expansion with LSE [PR114310]
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.c (aarch64_expand_compare_and_swap): For TImode force newval into a register. * gcc.dg/pr114310.c: New test. (cherry picked from commit 9349aefa1df7ae36714b7b9f426ad46e314892d1)
-rw-r--r--gcc/config/aarch64/aarch64.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr114310.c20
2 files changed, 22 insertions, 0 deletions
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 4df7233..9ec09d9 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -21879,6 +21879,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
index 0000000..55edd80
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114310.c
@@ -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;
+}