[llvm] 63cb3e5 - [ObjCARC] Don't sink objc_retain past atomic writes (#184113)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 30 06:47:36 PDT 2026
Author: Marina Taylor
Date: 2026-03-30T14:47:31+01:00
New Revision: 63cb3e55e7f1d0bc7609f2fcbad0516e9eff32b7
URL: https://github.com/llvm/llvm-project/commit/63cb3e55e7f1d0bc7609f2fcbad0516e9eff32b7
DIFF: https://github.com/llvm/llvm-project/commit/63cb3e55e7f1d0bc7609f2fcbad0516e9eff32b7.diff
LOG: [ObjCARC] Don't sink objc_retain past atomic writes (#184113)
The atomic may cause another thread to objc_release the pointer, so
consider these instructions as potentially decrementing refcounts.
This patch is a synthesis of several AI models' outputs, as well as work
by David Kilzer.
Co-authored-by: David Kilzer <ddkilzer at apple.com>
Assisted-by: claude
rdar://152185192
Added:
llvm/test/Transforms/ObjCARC/sink-past-atomic.ll
Modified:
llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
index b4cc00033e720..ae9f9ad0d3bac 100644
--- a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
+++ b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
@@ -67,7 +67,15 @@ bool llvm::objcarc::CanDecrementRefCount(const Instruction *Inst,
const Value *Ptr,
ProvenanceAnalysis &PA,
ARCInstKind Class) {
- // First perform a quick check if Class can not touch ref counts.
+ // Atomic stores, RMW, and CmpXchg may make a pointer visible to another
+ // thread, which could release it. Treat such instructions as potentially
+ // decrementing refcounts.
+ if (const auto *SI = dyn_cast<StoreInst>(Inst); SI && SI->isAtomic())
+ return true;
+ if (isa<AtomicRMWInst>(Inst) || isa<AtomicCmpXchgInst>(Inst))
+ return true;
+
+ // Perform a quick check if Class can not touch ref counts.
if (!CanDecrementRefCount(Class))
return false;
diff --git a/llvm/test/Transforms/ObjCARC/sink-past-atomic.ll b/llvm/test/Transforms/ObjCARC/sink-past-atomic.ll
new file mode 100644
index 0000000000000..6cf285c801ed5
--- /dev/null
+++ b/llvm/test/Transforms/ObjCARC/sink-past-atomic.ll
@@ -0,0 +1,49 @@
+; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
+
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+declare ptr @llvm.objc.retain(ptr)
+declare void @llvm.objc.release(ptr)
+
+; Retain must not sink past atomicrmw.
+define void @test_atomicrmw(ptr %obj, ptr %atomic_slot) {
+; CHECK-LABEL: @test_atomicrmw
+; CHECK: call ptr @llvm.objc.retain
+; CHECK: atomicrmw
+entry:
+ %obj_as_int = ptrtoint ptr %obj to i64
+ %retained = call ptr @llvm.objc.retain(ptr %obj)
+ %old_value = atomicrmw xchg ptr %atomic_slot, i64 %obj_as_int monotonic, align 8
+ %old_obj = inttoptr i64 %old_value to ptr
+ call void @llvm.objc.release(ptr %old_obj)
+ call void @llvm.objc.release(ptr %obj)
+ ret void
+}
+
+; Retain must not sink past cmpxchg.
+define void @test_cmpxchg(ptr %obj, ptr %atomic_slot, i64 %expected) {
+; CHECK-LABEL: @test_cmpxchg
+; CHECK: call ptr @llvm.objc.retain
+; CHECK: cmpxchg
+entry:
+ %obj_as_int = ptrtoint ptr %obj to i64
+ %retained = call ptr @llvm.objc.retain(ptr %obj)
+ %res = cmpxchg ptr %atomic_slot, i64 %expected, i64 %obj_as_int monotonic monotonic, align 8
+ %old_int = extractvalue { i64, i1 } %res, 0
+ %old_obj = inttoptr i64 %old_int to ptr
+ call void @llvm.objc.release(ptr %old_obj)
+ call void @llvm.objc.release(ptr %obj)
+ ret void
+}
+
+; Retain must not sink past an atomic store.
+define void @test_atomic_store(ptr %obj, ptr %slot) {
+; CHECK-LABEL: @test_atomic_store
+; CHECK: call ptr @llvm.objc.retain
+; CHECK: store atomic
+entry:
+ %retained = call ptr @llvm.objc.retain(ptr %obj)
+ store atomic ptr %obj, ptr %slot monotonic, align 8
+ call void @llvm.objc.release(ptr %obj)
+ ret void
+}
More information about the llvm-commits
mailing list