Skip to content

Commit 4450780

Browse files
committed
[ObjC][ARC] Ignore lifetime markers between *ReturnValue calls
When eliminating a pair of `llvm.objc.autoreleaseReturnValue` followed by `llvm.objc.retainAutoreleasedReturnValue` we need to make sure that the instructions in between are safe to ignore. Other than bitcasts and useless GEPs, it's also safe to ignore lifetime markers for both static allocas (lifetime.start/lifetime.end) and dynamic allocas (stacksave/stackrestore). These get added by the inliner as part of the return sequence and can prevent the transformation from happening in practice. Differential Revision: https://reviews.llvm.org/D69833 (cherry picked from commit 47d1029)
1 parent 759e043 commit 4450780

File tree

2 files changed

+28
-5
lines changed

2 files changed

+28
-5
lines changed

llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,33 @@ void ObjCARCOpt::getAnalysisUsage(AnalysisUsage &AU) const {
588588
AU.setPreservesCFG();
589589
}
590590

591+
static bool isSafeBetweenRVCalls(const Instruction *I) {
592+
if (IsNoopInstruction(I))
593+
return true;
594+
595+
auto *CB = dyn_cast<CallBase>(I);
596+
if (!CB)
597+
return false;
598+
599+
Intrinsic::ID IID = CB->getIntrinsicID();
600+
if (IID == Intrinsic::not_intrinsic)
601+
return false;
602+
603+
switch (IID) {
604+
case Intrinsic::lifetime_start:
605+
case Intrinsic::lifetime_end:
606+
// The inliner adds new lifetime markers as part of the return sequence,
607+
// which should be skipped when looking for paired return RV call.
608+
LLVM_FALLTHROUGH;
609+
case Intrinsic::stacksave:
610+
case Intrinsic::stackrestore:
611+
// If the inlined code contains dynamic allocas, the above applies as well.
612+
return true;
613+
default:
614+
return false;
615+
}
616+
}
617+
591618
/// Turn objc_retainAutoreleasedReturnValue into objc_retain if the operand is
592619
/// not a return value. Or, if it can be paired with an
593620
/// objc_autoreleaseReturnValue, delete the pair and return true.
@@ -634,7 +661,7 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {
634661
if (I != Begin) {
635662
do
636663
--I;
637-
while (I != Begin && IsNoopInstruction(&*I));
664+
while (I != Begin && isSafeBetweenRVCalls(&*I));
638665
if (GetBasicARCInstKind(&*I) == ARCInstKind::AutoreleaseRV &&
639666
EquivalentArgs.count(GetArgRCIdentityRoot(&*I))) {
640667
Changed = true;

llvm/test/Transforms/ObjCARC/post-inlining.ll

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ declare void @llvm.lifetime.end.p0i8(i64, i8*)
7676
; CHECK: entry:
7777
; CHECK-NEXT: %obj = alloca i8
7878
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* %obj)
79-
; CHECK-NEXT: %0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i)
8079
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* %obj)
81-
; CHECK-NEXT: %1 = tail call i8* @llvm.objc.retain(i8* %call.i)
8280
; CHECK-NEXT: ret i8* %call.i
8381
; CHECK-NEXT: }
8482
define i8* @testLifetime(i8* %call.i) {
@@ -100,9 +98,7 @@ declare void @llvm.stackrestore(i8*)
10098
; CHECK: entry:
10199
; CHECK-NEXT: %save = tail call i8* @llvm.stacksave()
102100
; CHECK-NEXT: %obj = alloca i8, i8 %arg
103-
; CHECK-NEXT: %0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i)
104101
; CHECK-NEXT: call void @llvm.stackrestore(i8* %save)
105-
; CHECK-NEXT: %1 = tail call i8* @llvm.objc.retain(i8* %call.i)
106102
; CHECK-NEXT: ret i8* %call.i
107103
; CHECK-NEXT: }
108104
define i8* @testStack(i8* %call.i, i8 %arg) {

0 commit comments

Comments
 (0)