forked from OSchip/llvm-project
Exploit this-return of a callsite in a this-return function.
For constructors/desctructors that return 'this', if there exists a callsite that returns 'this' and is immediately before the return instruction, make sure we are using the return value from the callsite. We don't need to keep 'this' alive through the callsite. It also enables optimizations in the backend, such as tail call optimization. Updated from r177211. rdar://12818789 llvm-svn: 177541
This commit is contained in:
parent
7a8bb72a3a
commit
0175461296
|
@ -91,6 +91,10 @@ public:
|
||||||
return *MangleCtx;
|
return *MangleCtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the given instance method is one of the
|
||||||
|
/// kinds that the ABI says returns 'this'.
|
||||||
|
virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
|
||||||
|
|
||||||
/// Find the LLVM type used to represent the given member pointer
|
/// Find the LLVM type used to represent the given member pointer
|
||||||
/// type.
|
/// type.
|
||||||
virtual llvm::Type *
|
virtual llvm::Type *
|
||||||
|
@ -209,7 +213,8 @@ public:
|
||||||
/// Emit the ABI-specific prolog for the function.
|
/// Emit the ABI-specific prolog for the function.
|
||||||
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
|
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
|
||||||
|
|
||||||
virtual void EmitConstructorCall(CodeGenFunction &CGF,
|
/// Emit the constructor call. Return the function that is called.
|
||||||
|
virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType Type, bool ForVirtualBase,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
bool Delegating,
|
bool Delegating,
|
||||||
|
|
|
@ -1614,6 +1614,18 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether 'this' argument of a callsite matches 'this' of the caller.
|
||||||
|
static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) {
|
||||||
|
if (ThisArg == This)
|
||||||
|
return true;
|
||||||
|
// Check whether ThisArg is a bitcast of This.
|
||||||
|
llvm::BitCastInst *Bitcast;
|
||||||
|
if ((Bitcast = dyn_cast<llvm::BitCastInst>(ThisArg)) &&
|
||||||
|
Bitcast->getOperand(0) == This)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
|
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
|
||||||
// Functions with no result always return void.
|
// Functions with no result always return void.
|
||||||
if (ReturnValue == 0) {
|
if (ReturnValue == 0) {
|
||||||
|
@ -1705,6 +1717,19 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
|
||||||
llvm_unreachable("Invalid ABI kind for return argument");
|
llvm_unreachable("Invalid ABI kind for return argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this function returns 'this', the last instruction is a CallInst
|
||||||
|
// that returns 'this', and 'this' argument of the CallInst points to
|
||||||
|
// the same object as CXXThisValue, use the return value from the CallInst.
|
||||||
|
// We will not need to keep 'this' alive through the callsite. It also enables
|
||||||
|
// optimizations in the backend, such as tail call optimization.
|
||||||
|
if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {
|
||||||
|
llvm::BasicBlock *IP = Builder.GetInsertBlock();
|
||||||
|
llvm::CallInst *Callsite;
|
||||||
|
if (!IP->empty() && (Callsite = dyn_cast<llvm::CallInst>(&IP->back())) &&
|
||||||
|
Callsite->getCalledFunction() == CalleeWithThisReturn &&
|
||||||
|
checkThisPointer(Callsite->getOperand(0), CXXThisValue))
|
||||||
|
RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());
|
||||||
|
}
|
||||||
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
|
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
|
||||||
if (!RetDbgLoc.isUnknown())
|
if (!RetDbgLoc.isUnknown())
|
||||||
Ret->setDebugLoc(RetDbgLoc);
|
Ret->setDebugLoc(RetDbgLoc);
|
||||||
|
|
|
@ -1666,8 +1666,11 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-trivial constructors are handled in an ABI-specific manner.
|
// Non-trivial constructors are handled in an ABI-specific manner.
|
||||||
CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
|
llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
|
||||||
Delegating, This, ArgBeg, ArgEnd);
|
ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
|
||||||
|
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||||
|
CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
|
||||||
|
CalleeWithThisReturn = Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1756,9 +1759,12 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
|
||||||
EmitDelegateCallArg(DelegateArgs, param);
|
EmitDelegateCallArg(DelegateArgs, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
|
||||||
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
|
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
|
||||||
CGM.GetAddrOfCXXConstructor(Ctor, CtorType),
|
Callee, ReturnValueSlot(), DelegateArgs, Ctor);
|
||||||
ReturnValueSlot(), DelegateArgs, Ctor);
|
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||||
|
CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
|
||||||
|
CalleeWithThisReturn = Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -1825,6 +1831,9 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
|
||||||
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
|
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||||
VTT, getContext().getPointerType(getContext().VoidPtrTy),
|
VTT, getContext().getPointerType(getContext().VoidPtrTy),
|
||||||
0, 0);
|
0, 0);
|
||||||
|
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||||
|
CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
|
||||||
|
CalleeWithThisReturn = Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
@ -564,6 +564,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
|
||||||
SourceRange BodyRange;
|
SourceRange BodyRange;
|
||||||
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
|
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
|
||||||
|
|
||||||
|
// CalleeWithThisReturn keeps track of the last callee inside this function
|
||||||
|
// that returns 'this'. Before starting the function, we set it to null.
|
||||||
|
CalleeWithThisReturn = 0;
|
||||||
|
|
||||||
// Emit the standard function prologue.
|
// Emit the standard function prologue.
|
||||||
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
|
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
|
||||||
|
|
||||||
|
@ -615,6 +619,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
|
||||||
|
|
||||||
// Emit the standard function epilogue.
|
// Emit the standard function epilogue.
|
||||||
FinishFunction(BodyRange.getEnd());
|
FinishFunction(BodyRange.getEnd());
|
||||||
|
// CalleeWithThisReturn keeps track of the last callee inside this function
|
||||||
|
// that returns 'this'. After finishing the function, we set it to null.
|
||||||
|
CalleeWithThisReturn = 0;
|
||||||
|
|
||||||
// If we haven't marked the function nothrow through other means, do
|
// If we haven't marked the function nothrow through other means, do
|
||||||
// a quick pass now to see if we can.
|
// a quick pass now to see if we can.
|
||||||
|
|
|
@ -1131,6 +1131,10 @@ private:
|
||||||
CGDebugInfo *DebugInfo;
|
CGDebugInfo *DebugInfo;
|
||||||
bool DisableDebugInfo;
|
bool DisableDebugInfo;
|
||||||
|
|
||||||
|
/// If the current function returns 'this', use the field to keep track of
|
||||||
|
/// the callee that returns 'this'.
|
||||||
|
llvm::Value *CalleeWithThisReturn;
|
||||||
|
|
||||||
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
|
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
|
||||||
/// calling llvm.stacksave for multiple VLAs in the same scope.
|
/// calling llvm.stacksave for multiple VLAs in the same scope.
|
||||||
bool DidCallStackSave;
|
bool DidCallStackSave;
|
||||||
|
|
|
@ -112,7 +112,7 @@ public:
|
||||||
|
|
||||||
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||||
|
|
||||||
void EmitConstructorCall(CodeGenFunction &CGF,
|
llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType Type, bool ForVirtualBase,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
bool Delegating,
|
bool Delegating,
|
||||||
|
@ -177,11 +177,11 @@ public:
|
||||||
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
|
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
|
||||||
CharUnits cookieSize);
|
CharUnits cookieSize);
|
||||||
|
|
||||||
private:
|
|
||||||
/// \brief Returns true if the given instance method is one of the
|
/// \brief Returns true if the given instance method is one of the
|
||||||
/// kinds that the ARM ABI says returns 'this'.
|
/// kinds that the ARM ABI says returns 'this'.
|
||||||
static bool HasThisReturn(GlobalDecl GD) {
|
bool HasThisReturn(GlobalDecl GD) const {
|
||||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(GD.getDecl());
|
||||||
|
if (!MD) return false;
|
||||||
return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) ||
|
return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) ||
|
||||||
(isa<CXXConstructorDecl>(MD)));
|
(isa<CXXConstructorDecl>(MD)));
|
||||||
}
|
}
|
||||||
|
@ -834,7 +834,7 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||||
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType Type, bool ForVirtualBase,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
bool Delegating,
|
bool Delegating,
|
||||||
|
@ -849,6 +849,7 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
// FIXME: Provide a source location here.
|
// FIXME: Provide a source location here.
|
||||||
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||||
VTT, VTTTy, ArgBeg, ArgEnd);
|
VTT, VTTTy, ArgBeg, ArgEnd);
|
||||||
|
return Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
|
|
||||||
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||||
|
|
||||||
void EmitConstructorCall(CodeGenFunction &CGF,
|
llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType Type, bool ForVirtualBase,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
bool Delegating,
|
bool Delegating,
|
||||||
|
@ -238,7 +238,7 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType Type, bool ForVirtualBase,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
bool Delegating,
|
bool Delegating,
|
||||||
|
@ -259,6 +259,7 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||||
ImplicitParam, ImplicitParamTy,
|
ImplicitParam, ImplicitParamTy,
|
||||||
ArgBeg, ArgEnd);
|
ArgBeg, ArgEnd);
|
||||||
|
return Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
|
|
|
@ -56,15 +56,15 @@ namespace test1 {
|
||||||
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
||||||
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
||||||
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
||||||
// CHECK: call [[A]]* @_ZN5test11AC2Ei(
|
// CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(
|
||||||
// CHECK: ret [[A]]* [[THIS1]]
|
// CHECK: ret [[A]]* [[THIS2]]
|
||||||
|
|
||||||
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
|
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
|
||||||
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
||||||
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
||||||
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
||||||
// CHECK: call [[A]]* @_ZN5test11AD2Ev(
|
// CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(
|
||||||
// CHECK: ret [[A]]* [[THIS1]]
|
// CHECK: ret [[A]]* [[THIS2]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Awkward virtual cases.
|
// Awkward virtual cases.
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s
|
||||||
|
|
||||||
|
// For constructors/desctructors that return 'this', if there exists a callsite
|
||||||
|
// that returns 'this' and is immediately before the return instruction, make
|
||||||
|
// sure we are using the return value from the callsite.
|
||||||
|
// rdar://12818789
|
||||||
|
|
||||||
|
// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr
|
||||||
|
// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev(
|
||||||
|
// CHECK-NEXT: ret [[A]] [[THIS1]]
|
||||||
|
|
||||||
|
// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this
|
||||||
|
// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E(
|
||||||
|
// CHECK-NEXT: ret [[A]] [[THIS1]]
|
||||||
|
|
||||||
|
// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr
|
||||||
|
// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev(
|
||||||
|
// CHECK-NEXT: ret [[A]] [[THIS1]]
|
||||||
|
|
||||||
|
// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED2Ev([[A]] %this) unnamed_addr
|
||||||
|
// CHECK: [[THIS1:%.*]] = call [[B:%.*]] @_ZN9TimerBaseD2Ev(
|
||||||
|
// CHECK-NEXT: [[THIS2:%.*]] = bitcast [[B]] [[THIS1]] to [[A]]
|
||||||
|
// CHECK-NEXT: ret [[A]] [[THIS2]]
|
||||||
|
|
||||||
|
class TimerBase {
|
||||||
|
public:
|
||||||
|
TimerBase();
|
||||||
|
virtual ~TimerBase();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TimerFiredClass> class Timer : public TimerBase {
|
||||||
|
public:
|
||||||
|
typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*);
|
||||||
|
|
||||||
|
Timer(TimerFiredClass* o, TimerFiredFunction f)
|
||||||
|
: m_object(o), m_function(f) { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void fired() { (m_object->*m_function)(this); }
|
||||||
|
|
||||||
|
TimerFiredClass* m_object;
|
||||||
|
TimerFiredFunction m_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectCache {
|
||||||
|
public:
|
||||||
|
explicit ObjectCache();
|
||||||
|
~ObjectCache();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Timer<ObjectCache> m_notificationPostTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { }
|
||||||
|
inline ObjectCache::~ObjectCache() { }
|
||||||
|
|
||||||
|
ObjectCache *test() {
|
||||||
|
ObjectCache *dd = new ObjectCache();
|
||||||
|
return dd;
|
||||||
|
}
|
Loading…
Reference in New Issue