[llvm] [ObjCARC] Optimize loadWeak across copyWeak and moveWeak (PR #218417)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 24 07:02:14 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: AZero13 (AZero13)
<details>
<summary>Changes</summary>
Previously, the backward scan for redundant weak loads maintained its tracked pointer locally within the instruction-visitation loop. If it encountered a CopyWeak or MoveWeak operating on the tracked pointer, it conservatively aborted the scan (goto clobbered).
---
Full diff: https://github.com/llvm/llvm-project/pull/218417.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp (+20-5)
- (modified) llvm/test/Transforms/ObjCARC/weak.ll (+64)
``````````diff
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index f92e5bbdf0111..c62283605f03d 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -2096,6 +2096,7 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
// within the same block. Theoretically, we could do memdep-style non-local
// analysis too, but that would want caching. A better approach would be to
// use the technique that EarlyCSE uses.
+ Value *Arg = cast<CallInst>(Inst)->getArgOperand(0);
inst_iterator Current = std::prev(I);
BasicBlock *CurrentBB = &*Current.getBasicBlockIterator();
for (BasicBlock::iterator B = CurrentBB->begin(),
@@ -2110,7 +2111,6 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
// with that one.
CallInst *Call = cast<CallInst>(Inst);
CallInst *EarlierCall = cast<CallInst>(EarlierInst);
- Value *Arg = Call->getArgOperand(0);
Value *EarlierArg = EarlierCall->getArgOperand(0);
switch (PA.getAA()->alias(Arg, EarlierArg)) {
case AliasResult::MustAlias:
@@ -2140,7 +2140,6 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
// replace this load's value with the stored value.
CallInst *Call = cast<CallInst>(Inst);
CallInst *EarlierCall = cast<CallInst>(EarlierInst);
- Value *Arg = Call->getArgOperand(0);
Value *EarlierArg = EarlierCall->getArgOperand(0);
switch (PA.getAA()->alias(Arg, EarlierArg)) {
case AliasResult::MustAlias:
@@ -2165,9 +2164,25 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
break;
}
case ARCInstKind::MoveWeak:
- case ARCInstKind::CopyWeak:
- // TOOD: Grab the copied value.
- goto clobbered;
+ case ARCInstKind::CopyWeak: {
+ CallInst *EarlierCall = cast<CallInst>(EarlierInst);
+ Value *EarlierDest = EarlierCall->getArgOperand(0);
+ Value *EarlierSrc = EarlierCall->getArgOperand(1);
+ switch (PA.getAA()->alias(Arg, EarlierDest)) {
+ case AliasResult::MustAlias:
+ Arg = EarlierSrc;
+ break;
+ case AliasResult::MayAlias:
+ case AliasResult::PartialAlias:
+ goto clobbered;
+ case AliasResult::NoAlias:
+ if (EarlierClass == ARCInstKind::MoveWeak &&
+ PA.getAA()->alias(Arg, EarlierSrc) != AliasResult::NoAlias)
+ goto clobbered;
+ break;
+ }
+ break;
+ }
case ARCInstKind::AutoreleasepoolPush:
case ARCInstKind::None:
case ARCInstKind::IntrinsicUser:
diff --git a/llvm/test/Transforms/ObjCARC/weak.ll b/llvm/test/Transforms/ObjCARC/weak.ll
index db63847c8f6c9..3339ca79bd5ac 100644
--- a/llvm/test/Transforms/ObjCARC/weak.ll
+++ b/llvm/test/Transforms/ObjCARC/weak.ll
@@ -58,3 +58,67 @@ entry:
ret void
}
+
+declare void @use_pointer(ptr)
+
+; Test that copyWeak enables eliminating a redundant loadWeak.
+define void @test_copyweak(ptr %src, ptr %dest, ptr %val) {
+; CHECK-LABEL: @test_copyweak(
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.storeWeak(ptr [[SRC:%.*]], ptr [[VAL:%.*]])
+; CHECK-NEXT: call void @llvm.objc.copyWeak(ptr [[DEST:%.*]], ptr [[SRC]])
+; CHECK-NEXT: call void @use_pointer(ptr [[VAL]])
+; CHECK-NEXT: ret void
+;
+ call ptr @llvm.objc.storeWeak(ptr %src, ptr %val)
+ call void @llvm.objc.copyWeak(ptr %dest, ptr %src)
+ %x = call ptr @llvm.objc.loadWeak(ptr %dest)
+ call void @use_pointer(ptr %x)
+ ret void
+}
+
+; Test that moveWeak enables eliminating a redundant loadWeak.
+define void @test_moveweak(ptr %src, ptr %dest, ptr %val) {
+; CHECK-LABEL: @test_moveweak(
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.storeWeak(ptr [[SRC:%.*]], ptr [[VAL:%.*]])
+; CHECK-NEXT: call void @llvm.objc.moveWeak(ptr [[DEST:%.*]], ptr [[SRC]])
+; CHECK-NEXT: call void @use_pointer(ptr [[VAL]])
+; CHECK-NEXT: ret void
+;
+ call ptr @llvm.objc.storeWeak(ptr %src, ptr %val)
+ call void @llvm.objc.moveWeak(ptr %dest, ptr %src)
+ %x = call ptr @llvm.objc.loadWeak(ptr %dest)
+ call void @use_pointer(ptr %x)
+ ret void
+}
+
+; Test that moveWeak clobbers a load from its source.
+define void @test_moveweak_clobber(ptr %src, ptr %dest, ptr %val) {
+; CHECK-LABEL: @test_moveweak_clobber(
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.storeWeak(ptr [[SRC:%.*]], ptr [[VAL:%.*]])
+; CHECK-NEXT: call void @llvm.objc.moveWeak(ptr [[DEST:%.*]], ptr [[SRC]])
+; CHECK-NEXT: [[X:%.*]] = call ptr @llvm.objc.loadWeak(ptr [[SRC]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: ret void
+;
+ call ptr @llvm.objc.storeWeak(ptr %src, ptr %val)
+ call void @llvm.objc.moveWeak(ptr %dest, ptr %src)
+ %x = call ptr @llvm.objc.loadWeak(ptr %src)
+ call void @use_pointer(ptr %x)
+ ret void
+}
+
+; Test that copyWeak does NOT clobber a load from its source.
+define void @test_copyweak_no_clobber(ptr %src, ptr %dest, ptr %val) {
+; CHECK-LABEL: @test_copyweak_no_clobber(
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.objc.storeWeak(ptr [[SRC:%.*]], ptr [[VAL:%.*]])
+; CHECK-NEXT: call void @llvm.objc.copyWeak(ptr [[DEST:%.*]], ptr [[SRC]])
+; CHECK-NEXT: [[X:%.*]] = call ptr @llvm.objc.loadWeak(ptr [[SRC]])
+; CHECK-NEXT: call void @use_pointer(ptr [[X]])
+; CHECK-NEXT: ret void
+;
+ call ptr @llvm.objc.storeWeak(ptr %src, ptr %val)
+ call void @llvm.objc.copyWeak(ptr %dest, ptr %src)
+ %x = call ptr @llvm.objc.loadWeak(ptr %src)
+ call void @use_pointer(ptr %x)
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/218417
More information about the llvm-commits
mailing list