mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[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
This commit is contained in:
parent
2978e175d1
commit
2523ca13cf
@ -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<CallInst>(I->getUser());
|
||||
assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
|
||||
@ -84,7 +98,17 @@ static bool lowerObjCCall(Function &F, const char *NewFn,
|
||||
SmallVector<Value *, 8> 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();
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user