[llvm] [AA] Use the cmpxchg merged ordering in getModRefInfo (PR #210545)
Justin Lebar via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 19 09:45:16 PDT 2026
https://github.com/jlebar updated https://github.com/llvm/llvm-project/pull/210545
>From ff0b51209b819640177ffad5991420c353ee806a Mon Sep 17 00:00:00 2001
From: Justin Lebar <justin.lebar at gmail.com>
Date: Sat, 18 Jul 2026 20:29:08 +0000
Subject: [PATCH] [AA] Use the cmpxchg merged ordering in getModRefInfo
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When a cmpxchg's address is NoAlias with the queried location,
getModRefInfo still reports sync effects if the cmpxchg is stronger than
monotonic, since an ordered operation constrains code motion around
locations it never accesses. But it tested only the success ordering,
and the failure ordering can be stronger (cmpxchg ... monotonic acquire
is valid IR), so such a cmpxchg looked freely reorderable to every AA
user.
The LoadStoreVectorizer turns that into a miscompile:
define <2 x i32> @f(ptr %p, ptr noalias %flag) {
%p.1 = getelementptr i8, ptr %p, i64 4
%v0 = load i32, ptr %p, align 8
%old = cmpxchg ptr %flag, i32 0, i32 0 monotonic acquire, align 4
%v1 = load i32, ptr %p.1, align 4
...
$ opt -passes=load-store-vectorizer
%1 = load <2 x i32>, ptr %p, align 8 ; both words above the cmpxchg
%old = cmpxchg ptr %flag, i32 0, i32 0 monotonic acquire, align 4
A failed cmpxchg is an acquire read of %flag here, so a consumer that
observes a producer's release-store of *%flag == 1 is guaranteed to see
its earlier store to %p.1 — but the rewritten code loads %p.1 without
waiting for the acquire. On x86 (where the compiler did the reordering,
not the hardware) a pthread litmus test of this idiom sees a stale %p.1
in ~2.5M of 3M rounds; with this fix, zero.
Check the merged ordering, i.e. the stronger of the two.
---
llvm/lib/Analysis/AliasAnalysis.cpp | 2 +-
llvm/test/Analysis/BasicAA/atomics.ll | 8 ++++++--
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index c7984c35e87ae..a04bab051f218 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -610,7 +610,7 @@ ModRefInfo AAResults::getModRefInfo(const AtomicCmpXchgInst *CX,
// it.
if (AR == AliasResult::NoAlias) {
// Synchronization effects may affect locations that do not alias.
- if (isStrongerThanMonotonic(CX->getSuccessOrdering()))
+ if (isStrongerThanMonotonic(CX->getMergedOrdering()))
return getSyncEffects(this, Loc, AAQI);
return ModRefInfo::NoModRef;
}
diff --git a/llvm/test/Analysis/BasicAA/atomics.ll b/llvm/test/Analysis/BasicAA/atomics.ll
index ab0556ddf62c2..b3001be0f4063 100644
--- a/llvm/test/Analysis/BasicAA/atomics.ll
+++ b/llvm/test/Analysis/BasicAA/atomics.ll
@@ -64,8 +64,10 @@ define void @alloca_no_escape(ptr %x) {
; CHECK: Both ModRef: Ptr: i32* %x <-> %1 = atomicrmw add ptr %x, i32 1 acq_rel, align 4
; CHECK: Both ModRef: Ptr: i32* %a <-> %2 = cmpxchg ptr %x, i32 0, i32 1 acq_rel monotonic, align 4
; CHECK: Both ModRef: Ptr: i32* %x <-> %2 = cmpxchg ptr %x, i32 0, i32 1 acq_rel monotonic, align 4
-; CHECK: Both ModRef: Ptr: i32* %a <-> %3 = load atomic i32, ptr %x acquire, align 4
-; CHECK: Both ModRef: Ptr: i32* %x <-> %3 = load atomic i32, ptr %x acquire, align 4
+; CHECK: Both ModRef: Ptr: i32* %a <-> %3 = cmpxchg ptr %x, i32 0, i32 1 monotonic acquire, align 4
+; CHECK: Both ModRef: Ptr: i32* %x <-> %3 = cmpxchg ptr %x, i32 0, i32 1 monotonic acquire, align 4
+; CHECK: Both ModRef: Ptr: i32* %a <-> %4 = load atomic i32, ptr %x acquire, align 4
+; CHECK: Both ModRef: Ptr: i32* %x <-> %4 = load atomic i32, ptr %x acquire, align 4
; CHECK: Both ModRef: Ptr: i32* %a <-> store atomic i32 0, ptr %x release, align 4
; CHECK: Both ModRef: Ptr: i32* %x <-> store atomic i32 0, ptr %x release, align 4
define void @alloca_escape_after(ptr %x) {
@@ -75,6 +77,8 @@ define void @alloca_escape_after(ptr %x) {
fence release
atomicrmw add ptr %x, i32 1 acq_rel
cmpxchg ptr %x, i32 0, i32 1 acq_rel monotonic
+ ; The failure ordering counts too: monotonic/acquire is an acquire operation.
+ cmpxchg ptr %x, i32 0, i32 1 monotonic acquire
load atomic i32, ptr %x acquire, align 4
store atomic i32 0, ptr %x release, align 4
More information about the llvm-commits
mailing list