From 2710ed8fd997be04ff447b8be2190f8fb34ac22b Mon Sep 17 00:00:00 2001 From: Manman Ren Date: Sat, 16 Mar 2013 00:11:09 +0000 Subject: [PATCH] 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. rdar://12818789 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177211 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCXXABI.h | 7 ++++++- lib/CodeGen/CGCall.cpp | 12 ++++++++++++ lib/CodeGen/CGClass.cpp | 17 +++++++++++++---- lib/CodeGen/CodeGenFunction.cpp | 5 +++++ lib/CodeGen/CodeGenFunction.h | 4 ++++ lib/CodeGen/ItaniumCXXABI.cpp | 11 ++++++----- lib/CodeGen/MicrosoftCXXABI.cpp | 5 +++-- test/CodeGenCXX/arm.cpp | 8 ++++---- 8 files changed, 53 insertions(+), 16 deletions(-) diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index cdc87b70e5..d0384ecc12 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -91,6 +91,10 @@ public: 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 /// type. virtual llvm::Type * @@ -209,7 +213,8 @@ public: /// Emit the ABI-specific prolog for the function. 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, CXXCtorType Type, bool ForVirtualBase, bool Delegating, diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 9e97bce6c3..6438ebf846 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -1705,6 +1705,18 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { llvm_unreachable("Invalid ABI kind for return argument"); } + // If this function returns 'this' and the last instruction is a CallInst + // that returns 'this', 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(&IP->back())) && + Callsite->getCalledFunction() == CalleeWithThisReturn) + // Create a bitcast of Callsite. + RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType()); + } llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid(); if (!RetDbgLoc.isUnknown()) Ret->setDebugLoc(RetDbgLoc); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 287d164cb9..2ececb0365 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1666,8 +1666,11 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, } // Non-trivial constructors are handled in an ABI-specific manner. - CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase, - Delegating, This, ArgBeg, ArgEnd); + llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type, + ForVirtualBase, Delegating, This, ArgBeg, ArgEnd); + if (CGM.getCXXABI().HasThisReturn(CurGD) && + CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type))) + CalleeWithThisReturn = Callee; } void @@ -1756,9 +1759,12 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, EmitDelegateCallArg(DelegateArgs, param); } + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType); EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType), - CGM.GetAddrOfCXXConstructor(Ctor, CtorType), - ReturnValueSlot(), DelegateArgs, Ctor); + Callee, ReturnValueSlot(), DelegateArgs, Ctor); + if (CGM.getCXXABI().HasThisReturn(CurGD) && + CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType))) + CalleeWithThisReturn = Callee; } namespace { @@ -1825,6 +1831,9 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This, VTT, getContext().getPointerType(getContext().VoidPtrTy), 0, 0); + if (CGM.getCXXABI().HasThisReturn(CurGD) && + CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type))) + CalleeWithThisReturn = Callee; } namespace { diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 27ef65fa94..98a63464f9 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -564,6 +564,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, SourceRange BodyRange; if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); + // Reset CalleeWithThisReturn. + CalleeWithThisReturn = 0; + // Emit the standard function prologue. StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin()); @@ -615,6 +618,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, // Emit the standard function epilogue. FinishFunction(BodyRange.getEnd()); + // Reset CalleeWithThisReturn. + CalleeWithThisReturn = 0; // If we haven't marked the function nothrow through other means, do // a quick pass now to see if we can. diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 55c21e80ee..19a4d571ee 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1131,6 +1131,10 @@ private: CGDebugInfo *DebugInfo; 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 /// calling llvm.stacksave for multiple VLAs in the same scope. bool DidCallStackSave; diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 8c7a759a43..17e83a18b9 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -112,7 +112,7 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - void EmitConstructorCall(CodeGenFunction &CGF, + llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, @@ -177,11 +177,11 @@ public: llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, CharUnits cookieSize); -private: /// \brief Returns true if the given instance method is one of the /// kinds that the ARM ABI says returns 'this'. - static bool HasThisReturn(GlobalDecl GD) { - const CXXMethodDecl *MD = cast(GD.getDecl()); + bool HasThisReturn(GlobalDecl GD) const { + const CXXMethodDecl *MD = dyn_cast_or_null(GD.getDecl()); + if (!MD) return false; return ((isa(MD) && GD.getDtorType() != Dtor_Deleting) || (isa(MD))); } @@ -834,7 +834,7 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); } -void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, +llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, @@ -849,6 +849,7 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, // FIXME: Provide a source location here. CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, VTT, VTTTy, ArgBeg, ArgEnd); + return Callee; } RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index fb6b86d878..85d926023f 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -55,7 +55,7 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - void EmitConstructorCall(CodeGenFunction &CGF, + llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, 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, CXXCtorType Type, bool ForVirtualBase, bool Delegating, @@ -259,6 +259,7 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd); + return Callee; } RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp index 3d3b147aa1..48f2f00840 100644 --- a/test/CodeGenCXX/arm.cpp +++ b/test/CodeGenCXX/arm.cpp @@ -56,15 +56,15 @@ namespace test1 { // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] - // CHECK: call [[A]]* @_ZN5test11AC2Ei( - // CHECK: ret [[A]]* [[THIS1]] + // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei( + // CHECK: ret [[A]]* [[THIS2]] // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] - // CHECK: call [[A]]* @_ZN5test11AD2Ev( - // CHECK: ret [[A]]* [[THIS1]] + // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev( + // CHECK: ret [[A]]* [[THIS2]] } // Awkward virtual cases. -- 2.40.0