https://gcc.gnu.org/g:a3b4c732f41fd627722df998ebb4c082ada20971
commit r17-3901-ga3b4c732f41fd627722df998ebb4c082ada20971 Author: Dominic P <[email protected]> Date: Sun Aug 2 11:56:04 2026 +0100 arm: Missing barrier for cmp_exch rel/acq [PR96056] An __atomic_compare_exchange with a success memory order of RELEASE and a failure memory order of ACQUIRE requires release ordering on the store path and acquire ordering on the (load-only) fail path. This is a well-formed combination: the two orders govern different sub-operations, and since C++17 the failure order need only avoid RELEASE/ACQ_REL and is otherwise unconstrained relative to the success order. arm_expand_compare_and_swap promotes the success model to ACQ_REL for this case so that both the release and the acquire orderings are preserved, but the promotion was gated on TARGET_HAVE_LDACQ. On ARMv6/ARMv7, which lack load-acquire/store-release instructions, the ordering is instead provided by explicit DMB barriers derived solely from the success memory model in arm_split_compare_and_swap. Without the promotion the success model stayed RELEASE, so need_atomic_barrier_p emitted only the pre (release) barrier and dropped the post (acquire) barrier. The fail path was therefore left with no acquire barrier, allowing later memory accesses to be reordered before the failed CAS load and violating the requested acquire semantics. For armv7-a the wrong sequence was: dmb ish .L2: ldrex r2, [r3] cmp r2, r0 bne .L3 strex ip, r1, [r3] cmp ip, #0 bne .L2 .L3: <- fall-through, no acquire barrier Remove the TARGET_HAVE_LDACQ guard so the promotion, and hence the trailing acquire barrier, is applied on all targets. ARMv8 LDACQ targets are unaffected: they already promoted and continue to emit ldaex/stlex with no DMB. Assisted-by: Claude Opus 5 (Anthropic) gcc/ChangeLog: PR target/96056 * config/arm/arm.cc (arm_expand_compare_and_swap): Always promote mod_s to ACQ_REL for the RELEASE/ACQUIRE combination. gcc/testsuite/ChangeLog: PR target/96056 * gcc.target/arm/atomic-comp-swap-release-acquire-4.c: New test. Signed-off-by: Dominic P <[email protected]> Diff: --- gcc/config/arm/arm.cc | 4 +--- .../gcc.target/arm/atomic-comp-swap-release-acquire-4.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index 0bc66abe238b..33b64995442f 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -31367,9 +31367,7 @@ arm_expand_compare_and_swap (rtx operands[]) /* Normally the succ memory model must be stronger than fail, but in the unlikely event of fail being ACQUIRE and succ being RELEASE we need to promote succ to ACQ_REL so that we don't lose the acquire semantics. */ - - if (TARGET_HAVE_LDACQ - && is_mm_acquire (memmodel_from_int (INTVAL (mod_f))) + if (is_mm_acquire (memmodel_from_int (INTVAL (mod_f))) && is_mm_release (memmodel_from_int (INTVAL (mod_s)))) mod_s = GEN_INT (MEMMODEL_ACQ_REL); diff --git a/gcc/testsuite/gcc.target/arm/atomic-comp-swap-release-acquire-4.c b/gcc/testsuite/gcc.target/arm/atomic-comp-swap-release-acquire-4.c new file mode 100644 index 000000000000..b80242d640be --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/atomic-comp-swap-release-acquire-4.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_arch_v7a_ok } */ +/* { dg-options "-O2 -fno-ipa-icf" } */ +/* { dg-add-options arm_arch_v7a } */ + +#include "../aarch64/atomic-comp-swap-release-acquire.x" + +/* { dg-final { scan-assembler-not "ldaex" } } */ +/* { dg-final { scan-assembler-not "stlex" } } */ +/* { dg-final { scan-assembler-times "dmb\tish" 8 } } */
