Skip to content

Commit a9a3781

Browse files
committed
[ObjC] Override TailCallKind when lowering objc intrinsics
The tail-call-kind-ness is known by the ObjCARC analysis and can be enforced while lowering the intrinsics to calls. This allows us to get the requested tail calls at -O0 without trying to preserve the attributes throughout passes that change code even at -O0 ,like the Always Inliner, where the ObjCOpt pass doesn't run. Differential Revision: https://reviews.llvm.org/D69980
1 parent 135a493 commit a9a3781

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "llvm/CodeGen/PreISelIntrinsicLowering.h"
15+
#include "llvm/Analysis/ObjCARCInstKind.h"
1516
#include "llvm/CodeGen/Passes.h"
1617
#include "llvm/IR/Function.h"
1718
#include "llvm/IR/Intrinsics.h"
@@ -56,6 +57,17 @@ static bool lowerLoadRelative(Function &F) {
5657
return Changed;
5758
}
5859

60+
// ObjCARC has knowledge about whether an obj-c runtime function needs to be
61+
// always tail-called or never tail-called.
62+
static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) {
63+
objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F);
64+
if (objcarc::IsAlwaysTail(Kind))
65+
return CallInst::TCK_Tail;
66+
else if (objcarc::IsNeverTail(Kind))
67+
return CallInst::TCK_NoTail;
68+
return CallInst::TCK_None;
69+
}
70+
5971
static bool lowerObjCCall(Function &F, const char *NewFn,
6072
bool setNonLazyBind = false) {
6173
if (F.use_empty())
@@ -75,6 +87,8 @@ static bool lowerObjCCall(Function &F, const char *NewFn,
7587
}
7688
}
7789

90+
CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F);
91+
7892
for (auto I = F.use_begin(), E = F.use_end(); I != E;) {
7993
auto *CI = cast<CallInst>(I->getUser());
8094
assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
@@ -84,7 +98,17 @@ static bool lowerObjCCall(Function &F, const char *NewFn,
8498
SmallVector<Value *, 8> Args(CI->arg_begin(), CI->arg_end());
8599
CallInst *NewCI = Builder.CreateCall(FCache, Args);
86100
NewCI->setName(CI->getName());
87-
NewCI->setTailCallKind(CI->getTailCallKind());
101+
102+
// Try to set the most appropriate TailCallKind based on both the current
103+
// attributes and the ones that we could get from ObjCARC's special
104+
// knowledge of the runtime functions.
105+
//
106+
// std::max respects both requirements of notail and tail here:
107+
// * notail on either the call or from ObjCARC becomes notail
108+
// * tail on either side is stronger than none, but not notail
109+
CallInst::TailCallKind TCK = CI->getTailCallKind();
110+
NewCI->setTailCallKind(std::max(TCK, OverridingTCK));
111+
88112
if (!CI->use_empty())
89113
CI->replaceAllUsesWith(NewCI);
90114
CI->eraseFromParent();

llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
define i8* @test_objc_autorelease(i8* %arg0) {
88
; CHECK-LABEL: test_objc_autorelease
99
; CHECK-NEXT: entry
10-
; CHECK-NEXT: %0 = call i8* @objc_autorelease(i8* %arg0)
10+
; CHECK-NEXT: %0 = notail call i8* @objc_autorelease(i8* %arg0)
1111
; CHECK-NEXT: ret i8* %0
1212
entry:
1313
%0 = call i8* @llvm.objc.autorelease(i8* %arg0)
@@ -37,7 +37,7 @@ entry:
3737
define i8* @test_objc_autoreleaseReturnValue(i8* %arg0) {
3838
; CHECK-LABEL: test_objc_autoreleaseReturnValue
3939
; CHECK-NEXT: entry
40-
; CHECK-NEXT: %0 = call i8* @objc_autoreleaseReturnValue(i8* %arg0)
40+
; CHECK-NEXT: %0 = tail call i8* @objc_autoreleaseReturnValue(i8* %arg0)
4141
; CHECK-NEXT: ret i8* %0
4242
entry:
4343
%0 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %arg0)
@@ -117,7 +117,7 @@ entry:
117117
define i8* @test_objc_retain(i8* %arg0) {
118118
; CHECK-LABEL: test_objc_retain
119119
; CHECK-NEXT: entry
120-
; CHECK-NEXT: %0 = call i8* @objc_retain(i8* %arg0)
120+
; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %arg0)
121121
; CHECK-NEXT: ret i8* %0
122122
entry:
123123
%0 = call i8* @llvm.objc.retain(i8* %arg0)
@@ -147,7 +147,7 @@ entry:
147147
define i8* @test_objc_retainAutoreleasedReturnValue(i8* %arg0) {
148148
; CHECK-LABEL: test_objc_retainAutoreleasedReturnValue
149149
; CHECK-NEXT: entry
150-
; CHECK-NEXT: %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %arg0)
150+
; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %arg0)
151151
; CHECK-NEXT: ret i8* %0
152152
entry:
153153
%0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %arg0)
@@ -187,7 +187,7 @@ entry:
187187
define i8* @test_objc_unsafeClaimAutoreleasedReturnValue(i8* %arg0) {
188188
; CHECK-LABEL: test_objc_unsafeClaimAutoreleasedReturnValue
189189
; CHECK-NEXT: entry
190-
; CHECK-NEXT: %0 = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %arg0)
190+
; CHECK-NEXT: %0 = tail call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %arg0)
191191
; CHECK-NEXT: ret i8* %0
192192
entry:
193193
%0 = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %arg0)

0 commit comments

Comments
 (0)