From a9a3781df81a8a630e5d233efbc8b15b24ddd1dd Mon Sep 17 00:00:00 2001 From: Francis Visoiu Mistrih Date: Wed, 6 Nov 2019 17:09:55 -0800 Subject: [PATCH] [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 --- llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp | 26 +++++++++++++++++++++- .../PreISelIntrinsicLowering/objc-arc.ll | 10 ++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp index 0d2f6f9..79d0c80 100644 --- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp +++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/PreISelIntrinsicLowering.h" +#include "llvm/Analysis/ObjCARCInstKind.h" #include "llvm/CodeGen/Passes.h" #include "llvm/IR/Function.h" #include "llvm/IR/Intrinsics.h" @@ -56,6 +57,17 @@ static bool lowerLoadRelative(Function &F) { return Changed; } +// ObjCARC has knowledge about whether an obj-c runtime function needs to be +// always tail-called or never tail-called. +static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) { + objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F); + if (objcarc::IsAlwaysTail(Kind)) + return CallInst::TCK_Tail; + else if (objcarc::IsNeverTail(Kind)) + return CallInst::TCK_NoTail; + return CallInst::TCK_None; +} + static bool lowerObjCCall(Function &F, const char *NewFn, bool setNonLazyBind = false) { if (F.use_empty()) @@ -75,6 +87,8 @@ static bool lowerObjCCall(Function &F, const char *NewFn, } } + CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F); + for (auto I = F.use_begin(), E = F.use_end(); I != E;) { auto *CI = cast(I->getUser()); assert(CI->getCalledFunction() && "Cannot lower an indirect call!"); @@ -84,7 +98,17 @@ static bool lowerObjCCall(Function &F, const char *NewFn, SmallVector Args(CI->arg_begin(), CI->arg_end()); CallInst *NewCI = Builder.CreateCall(FCache, Args); NewCI->setName(CI->getName()); - NewCI->setTailCallKind(CI->getTailCallKind()); + + // Try to set the most appropriate TailCallKind based on both the current + // attributes and the ones that we could get from ObjCARC's special + // knowledge of the runtime functions. + // + // std::max respects both requirements of notail and tail here: + // * notail on either the call or from ObjCARC becomes notail + // * tail on either side is stronger than none, but not notail + CallInst::TailCallKind TCK = CI->getTailCallKind(); + NewCI->setTailCallKind(std::max(TCK, OverridingTCK)); + if (!CI->use_empty()) CI->replaceAllUsesWith(NewCI); CI->eraseFromParent(); diff --git a/llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll b/llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll index 8b7d11e..5ff620a 100644 --- a/llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll +++ b/llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll @@ -7,7 +7,7 @@ define i8* @test_objc_autorelease(i8* %arg0) { ; CHECK-LABEL: test_objc_autorelease ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = call i8* @objc_autorelease(i8* %arg0) +; CHECK-NEXT: %0 = notail call i8* @objc_autorelease(i8* %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.autorelease(i8* %arg0) @@ -37,7 +37,7 @@ entry: define i8* @test_objc_autoreleaseReturnValue(i8* %arg0) { ; CHECK-LABEL: test_objc_autoreleaseReturnValue ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = call i8* @objc_autoreleaseReturnValue(i8* %arg0) +; CHECK-NEXT: %0 = tail call i8* @objc_autoreleaseReturnValue(i8* %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %arg0) @@ -117,7 +117,7 @@ entry: define i8* @test_objc_retain(i8* %arg0) { ; CHECK-LABEL: test_objc_retain ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = call i8* @objc_retain(i8* %arg0) +; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.retain(i8* %arg0) @@ -147,7 +147,7 @@ entry: define i8* @test_objc_retainAutoreleasedReturnValue(i8* %arg0) { ; CHECK-LABEL: test_objc_retainAutoreleasedReturnValue ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %arg0) +; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %arg0) @@ -187,7 +187,7 @@ entry: define i8* @test_objc_unsafeClaimAutoreleasedReturnValue(i8* %arg0) { ; CHECK-LABEL: test_objc_unsafeClaimAutoreleasedReturnValue ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %arg0) +; CHECK-NEXT: %0 = tail call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %arg0) -- 2.7.4