From: Stephen Lin Date: Tue, 18 Jun 2013 17:00:49 +0000 (+0000) Subject: CodeGen: Have 'this'-returning constructors and destructors to take advantage of... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d4c0cd07641681de6ed12164aa7a4495ab4b18e5;p=clang CodeGen: Have 'this'-returning constructors and destructors to take advantage of the new backend 'returned' attribute. The backend will now use the generic 'returned' attribute to form tail calls where possible, as well as avoid save-restores of 'this' in some cases (specifically the cases that matter for the ARM C++ ABI). This patch also reverts a prior front-end only partial implementation of these optimizations, since it's no longer required. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184205 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index f64a633d25..899e5e7b25 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -97,8 +97,12 @@ public: return *MangleCtx; } - /// Returns true if the given instance method is one of the - /// kinds that the ABI says returns 'this'. + /// Returns true if the given constructor or destructor is one of the + /// kinds that the ABI says returns 'this' (only applies when called + /// non-virtually for destructors). + /// + /// There currently is no way to indicate if a destructor returns 'this' + /// when called virtually, and code generation does not support the case. virtual bool HasThisReturn(GlobalDecl GD) const { return false; } /// Returns true if the given record type should be returned indirectly. @@ -214,10 +218,10 @@ public: const CXXRecordDecl *BaseClassDecl) = 0; /// Build the signature of the given constructor variant by adding - /// any required parameters. For convenience, ResTy has been - /// initialized to 'void', and ArgTys has been initialized with the - /// type of 'this' (although this may be changed by the ABI) and - /// will have the formal parameters added to it afterwards. + /// any required parameters. For convenience, ArgTys has been initialized + /// with the type of 'this' and ResTy has been initialized with the type of + /// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise + /// (although both may be changed by the ABI). /// /// If there are ever any ABIs where the implicit parameters are /// intermixed with the formal parameters, we can address those @@ -230,9 +234,10 @@ public: virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF); /// Build the signature of the given destructor variant by adding - /// any required parameters. For convenience, ResTy has been - /// initialized to 'void' and ArgTys has been initialized with the - /// type of 'this' (although this may be changed by the ABI). + /// any required parameters. For convenience, ArgTys has been initialized + /// with the type of 'this' and ResTy has been initialized with the type of + /// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise + /// (although both may be changed by the ABI). virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor, CXXDtorType T, CanQualType &ResTy, @@ -243,7 +248,8 @@ public: /// possibly some extra data for constructors and destructors. /// /// ABIs may also choose to override the return type, which has been - /// initialized with the formal return type of the function. + /// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or + /// the formal return type of the function otherwise. virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, FunctionArgList &Params) = 0; @@ -252,13 +258,14 @@ public: virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; /// 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, - llvm::Value *This, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd) = 0; + virtual RValue EmitConstructorCall(CodeGenFunction &CGF, + const CXXConstructorDecl *D, + CXXCtorType Type, + bool ForVirtualBase, bool Delegating, + ReturnValueSlot ReturnValue, + llvm::Value *This, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) = 0; /// Emit the ABI-specific virtual destructor call. virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF, diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 80446393d5..f74ae39120 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -200,7 +200,10 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D, CXXCtorType ctorKind) { SmallVector argTypes; argTypes.push_back(GetThisType(Context, D->getParent())); - CanQualType resultType = Context.VoidTy; + + GlobalDecl GD(D, ctorKind); + CanQualType resultType = + TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy; TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes); @@ -225,7 +228,10 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D, CXXDtorType dtorKind) { SmallVector argTypes; argTypes.push_back(GetThisType(Context, D->getParent())); - CanQualType resultType = Context.VoidTy; + + GlobalDecl GD(D, dtorKind); + CanQualType resultType = + TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy; TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes); @@ -1633,18 +1639,6 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { 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(ThisArg)) && - Bitcast->getOperand(0) == This) - return true; - return false; -} - void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc) { // Functions with no result always return void. @@ -1741,19 +1735,6 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, 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(&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(); if (!RetDbgLoc.isUnknown()) Ret->setDebugLoc(RetDbgLoc); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 9d08d1c7f7..88f5cf9e6b 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1661,11 +1661,9 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, } // Non-trivial constructors are handled in an ABI-specific manner. - 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; + CGM.getCXXABI().EmitConstructorCall(*this, D, Type, + ForVirtualBase, Delegating, + ReturnValueSlot(), This, ArgBeg, ArgEnd); } void @@ -1757,9 +1755,6 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType); EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType), Callee, ReturnValueSlot(), DelegateArgs, Ctor); - if (CGM.getCXXABI().HasThisReturn(CurGD) && - CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType))) - CalleeWithThisReturn = Callee; } namespace { @@ -1826,9 +1821,6 @@ 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/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index b1072b4721..d1168770dd 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -287,8 +287,9 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk) { const CXXMethodDecl *MD = cast(GD.getDecl()); const FunctionProtoType *FPT = MD->getType()->getAs(); - QualType ResultType = FPT->getResultType(); QualType ThisType = MD->getThisType(getContext()); + QualType ResultType = + CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType(); FunctionArgList FunctionArgs; diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 297fc655e4..e8469e6480 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -42,8 +42,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) AutoreleaseResult(false), BlockInfo(0), BlockPointer(0), LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1), FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0), - DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0), - DidCallStackSave(false), + DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), NumReturnExprs(0), NumSimpleReturnExprs(0), CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), @@ -662,8 +661,12 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, QualType ResTy = FD->getResultType(); CurGD = GD; - if (isa(FD) && cast(FD)->isInstance()) + const CXXMethodDecl *MD; + if ((MD = dyn_cast(FD)) && MD->isInstance()) { + if (CGM.getCXXABI().HasThisReturn(GD)) + ResTy = MD->getThisType(getContext()); CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args); + } for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) Args.push_back(FD->getParamDecl(i)); @@ -672,10 +675,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); CurEHLocation = BodyRange.getEnd(); - // 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. StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin()); @@ -727,9 +726,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, // Emit the standard function epilogue. 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 // a quick pass now to see if we can. diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 508e6a4ec3..9071e07ac9 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -798,10 +798,6 @@ 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/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 824d2a0466..d76fee5c84 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -717,6 +717,14 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, if (!IsIncompleteFunction) SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F); + if (getCXXABI().HasThisReturn(GD)) { + llvm::Type *RetTy = F->getReturnType(); + assert(!F->arg_empty() && + F->arg_begin()->getType()->canLosslesslyBitCastTo(RetTy) && + "unexpected this return"); + F->addAttribute(1, llvm::Attribute::Returned); + } + // Only a few attributes are set on declarations; these may later be // overridden by a definition. diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 6cf95b5ce9..7228400738 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -119,13 +119,14 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, - const CXXConstructorDecl *D, - CXXCtorType Type, bool ForVirtualBase, - bool Delegating, - llvm::Value *This, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd); + RValue EmitConstructorCall(CodeGenFunction &CGF, + const CXXConstructorDecl *D, + CXXCtorType Type, + bool ForVirtualBase, bool Delegating, + ReturnValueSlot ReturnValue, + llvm::Value *This, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd); RValue EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, @@ -165,21 +166,11 @@ class ARMCXXABI : public ItaniumCXXABI { public: ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {} - void BuildConstructorSignature(const CXXConstructorDecl *Ctor, - CXXCtorType T, - CanQualType &ResTy, - SmallVectorImpl &ArgTys); - - void BuildDestructorSignature(const CXXDestructorDecl *Dtor, - CXXDtorType T, - CanQualType &ResTy, - SmallVectorImpl &ArgTys); - - void BuildInstanceFunctionParams(CodeGenFunction &CGF, - QualType &ResTy, - FunctionArgList &Params); - - void EmitInstanceFunctionProlog(CodeGenFunction &CGF); + bool HasThisReturn(GlobalDecl GD) const { + return (isa(GD.getDecl()) || ( + isa(GD.getDecl()) && + GD.getDtorType() != Dtor_Deleting)); + } void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy); @@ -191,15 +182,6 @@ public: QualType ElementType); llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, CharUnits cookieSize); - - /// \brief Returns true if the given instance method is one of the - /// kinds that the ARM ABI says returns 'this'. - 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))); - } }; } @@ -754,22 +736,14 @@ void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, SmallVectorImpl &ArgTys) { ASTContext &Context = getContext(); - // 'this' is already there. + // 'this' parameter is already there, as well as 'this' return if + // HasThisReturn(GlobalDecl(Ctor, Type)) is true // Check if we need to add a VTT parameter (which has type void **). if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0) ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); } -/// The ARM ABI does the same as the Itanium ABI, but returns 'this'. -void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, - CXXCtorType Type, - CanQualType &ResTy, - SmallVectorImpl &ArgTys) { - ItaniumCXXABI::BuildConstructorSignature(Ctor, Type, ResTy, ArgTys); - ResTy = ArgTys[0]; -} - /// The generic ABI passes 'this', plus a VTT if it's destroying a /// base subobject. void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, @@ -778,25 +752,14 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, SmallVectorImpl &ArgTys) { ASTContext &Context = getContext(); - // 'this' is already there. + // 'this' parameter is already there, as well as 'this' return if + // HasThisReturn(GlobalDecl(Dtor, Type)) is true // Check if we need to add a VTT parameter (which has type void **). if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0) ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); } -/// The ARM ABI does the same as the Itanium ABI, but returns 'this' -/// for non-deleting destructors. -void ARMCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, - CXXDtorType Type, - CanQualType &ResTy, - SmallVectorImpl &ArgTys) { - ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys); - - if (Type != Dtor_Deleting) - ResTy = ArgTys[0]; -} - void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, FunctionArgList &Params) { @@ -820,16 +783,6 @@ void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, } } -void ARMCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, - QualType &ResTy, - FunctionArgList &Params) { - ItaniumCXXABI::BuildInstanceFunctionParams(CGF, ResTy, Params); - - // Return 'this' from certain constructors and destructors. - if (HasThisReturn(CGF.CurGD)) - ResTy = Params[0]->getType(); -} - void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { /// Initialize the 'this' slot. EmitThisParam(CGF); @@ -840,21 +793,24 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)), "vtt"); } -} -void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { - ItaniumCXXABI::EmitInstanceFunctionProlog(CGF); - - /// Initialize the return slot to 'this' at the start of the - /// function. + /// If this is a function that the ABI specifies returns 'this', initialize + /// the return slot to 'this' at the start of the function. + /// + /// Unlike the setting of return types, this is done within the ABI + /// implementation instead of by clients of CGCXXABI because: + /// 1) getThisValue is currently protected + /// 2) in theory, an ABI could implement 'this' returns some other way; + /// HasThisReturn only specifies a contract, not the implementation if (HasThisReturn(CGF.CurGD)) CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); } -llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, +RValue ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, - CXXCtorType Type, bool ForVirtualBase, - bool Delegating, + CXXCtorType Type, + bool ForVirtualBase, bool Delegating, + ReturnValueSlot ReturnValue, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { @@ -864,9 +820,8 @@ llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); // FIXME: Provide a source location here. - CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, - VTT, VTTTy, ArgBeg, ArgEnd); - return Callee; + return CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValue, + This, VTT, VTTTy, ArgBeg, ArgEnd); } RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 1bb2c55f55..e6eca28b29 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -28,6 +28,8 @@ class MicrosoftCXXABI : public CGCXXABI { public: MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {} + bool HasThisReturn(GlobalDecl GD) const; + bool isReturnTypeIndirect(const CXXRecordDecl *RD) const { // Structures that are not C++03 PODs are always indirect. return !RD->isPOD(); @@ -71,13 +73,14 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, - const CXXConstructorDecl *D, - CXXCtorType Type, bool ForVirtualBase, - bool Delegating, - llvm::Value *This, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd); + RValue EmitConstructorCall(CodeGenFunction &CGF, + const CXXConstructorDecl *D, + CXXCtorType Type, + bool ForVirtualBase, bool Delegating, + ReturnValueSlot ReturnValue, + llvm::Value *This, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd); RValue EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, @@ -124,7 +127,6 @@ public: llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, CharUnits cookieSize); - static bool needThisReturn(GlobalDecl GD); private: llvm::Constant *getZeroInt() { @@ -299,19 +301,15 @@ MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF, return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase); } -bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) { - const CXXMethodDecl* MD = cast(GD.getDecl()); - return isa(MD); +bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const { + return isa(GD.getDecl()); } void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy, SmallVectorImpl &ArgTys) { - // 'this' is already in place - - // Ctor returns this ptr - ResTy = ArgTys[0]; + // 'this' parameter and 'this' return are already in place const CXXRecordDecl *Class = Ctor->getParent(); if (Class->getNumVBases()) { @@ -346,6 +344,7 @@ void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, CanQualType &ResTy, SmallVectorImpl &ArgTys) { // 'this' is already in place + // TODO: 'for base' flag if (Type == Dtor_Deleting) { @@ -366,9 +365,6 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, FunctionArgList &Params) { BuildThisParam(CGF, Params); - if (needThisReturn(CGF.CurGD)) { - ResTy = Params[0]->getType(); - } ASTContext &Context = getContext(); const CXXMethodDecl *MD = cast(CGF.CurGD.getDecl()); @@ -393,9 +389,17 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { EmitThisParam(CGF); - if (needThisReturn(CGF.CurGD)) { + + /// If this is a function that the ABI specifies returns 'this', initialize + /// the return slot to 'this' at the start of the function. + /// + /// Unlike the setting of return types, this is done within the ABI + /// implementation instead of by clients of CGCXXABI because: + /// 1) getThisValue is currently protected + /// 2) in theory, an ABI could implement 'this' returns some other way; + /// HasThisReturn only specifies a contract, not the implementation + if (HasThisReturn(CGF.CurGD)) CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); - } const CXXMethodDecl *MD = cast(CGF.CurGD.getDecl()); if (isa(MD) && MD->getParent()->getNumVBases()) { @@ -417,11 +421,13 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { } } -llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, - const CXXConstructorDecl *D, - CXXCtorType Type, bool ForVirtualBase, - bool Delegating, - llvm::Value *This, +RValue MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, + const CXXConstructorDecl *D, + CXXCtorType Type, + bool ForVirtualBase, + bool Delegating, + ReturnValueSlot ReturnValue, + llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { assert(Type == Ctor_Complete || Type == Ctor_Base); @@ -435,10 +441,9 @@ llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, } // FIXME: Provide a source location here. - CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, - ImplicitParam, ImplicitParamTy, - ArgBeg, ArgEnd); - return Callee; + return CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValue, + This, ImplicitParam, ImplicitParamTy, + ArgBeg, ArgEnd); } RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp index 48f2f00840..5578b2ab2b 100644 --- a/test/CodeGenCXX/arm.cpp +++ b/test/CodeGenCXX/arm.cpp @@ -52,19 +52,19 @@ namespace test1 { a.bar(); } - // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* returned %this, i32 %i) unnamed_addr // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] - // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei( - // CHECK: ret [[A]]* [[THIS2]] + // CHECK: {{%.*}} = call [[A]]* @_ZN5test11AC2Ei( + // CHECK: ret [[A]]* [[THIS1]] - // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* returned %this) unnamed_addr // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] - // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev( - // CHECK: ret [[A]]* [[THIS2]] + // CHECK: {{%.*}} = call [[A]]* @_ZN5test11AD2Ev( + // CHECK: ret [[A]]* [[THIS1]] } // Awkward virtual cases. diff --git a/test/CodeGenCXX/constructor-destructor-return-this.cpp b/test/CodeGenCXX/constructor-destructor-return-this.cpp index 1ff922de60..eb7cd3d73f 100644 --- a/test/CodeGenCXX/constructor-destructor-return-this.cpp +++ b/test/CodeGenCXX/constructor-destructor-return-this.cpp @@ -1,60 +1,120 @@ -//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s +//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-unknown-linux | FileCheck --check-prefix=CHECKGEN %s +//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck --check-prefix=CHECKARM %s +//RUN: %clang_cc1 %s -emit-llvm -o - -DPR12784_WORKAROUND -triple=x86_64-pc-win32 -cxx-abi microsoft | FileCheck --check-prefix=CHECKMS %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 +// FIXME: Add checks to ensure that Microsoft destructors do not return 'this' +// once PR12784 is resolved -// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr -// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev( -// CHECK-NEXT: ret [[A]] [[THIS1]] +// Make sure we attach the 'returned' attribute to the 'this' parameter of +// constructors and destructors which return this (and only these cases) -// 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]] +class A { +public: + A(); + ~A(); -// 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]] +private: + int x_; +}; -class TimerBase { +class B : public A { public: - TimerBase(); - virtual ~TimerBase(); + B(int *i); + ~B(); + +private: + int *i_; }; -template class Timer : public TimerBase { -public: - typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*); +B::B(int *i) : i_(i) { } +#ifndef PR12784_WORKAROUND +B::~B() { } +#endif - Timer(TimerFiredClass* o, TimerFiredFunction f) - : m_object(o), m_function(f) { } +// CHECKGEN: define void @_ZN1BC1EPi(%class.B* %this, i32* %i) +// CHECKGEN: define void @_ZN1BC2EPi(%class.B* %this, i32* %i) +// CHECKGEN: define void @_ZN1BD1Ev(%class.B* %this) +// CHECKGEN: define void @_ZN1BD2Ev(%class.B* %this) -private: - virtual void fired() { (m_object->*m_function)(this); } +// CHECKARM: define %class.B* @_ZN1BC1EPi(%class.B* returned %this, i32* %i) +// CHECKARM: define %class.B* @_ZN1BC2EPi(%class.B* returned %this, i32* %i) +// CHECKARM: define %class.B* @_ZN1BD1Ev(%class.B* returned %this) +// CHECKARM: define %class.B* @_ZN1BD2Ev(%class.B* returned %this) + +// CHECKMS: define %class.B* @"\01??0B@@QEAA@PEAH@Z"(%class.B* returned %this, i32* %i) - TimerFiredClass* m_object; - TimerFiredFunction m_function; +class C : public A, public B { +public: + C(int *i, char *c); + virtual ~C(); +private: + char *c_; }; -class ObjectCache { +C::C(int *i, char *c) : B(i), c_(c) { } +#ifndef PR12784_WORKAROUND +C::~C() { } +#endif + +// CHECKGEN: define void @_ZN1CC1EPiPc(%class.C* %this, i32* %i, i8* %c) +// CHECKGEN: define void @_ZN1CC2EPiPc(%class.C* %this, i32* %i, i8* %c) +// CHECKGEN: define void @_ZN1CD0Ev(%class.C* %this) +// CHECKGEN: define void @_ZN1CD1Ev(%class.C* %this) +// CHECKGEN: define void @_ZN1CD2Ev(%class.C* %this) + +// CHECKARM: define %class.C* @_ZN1CC1EPiPc(%class.C* returned %this, i32* %i, i8* %c) +// CHECKARM: define %class.C* @_ZN1CC2EPiPc(%class.C* returned %this, i32* %i, i8* %c) +// CHECKARM: define void @_ZN1CD0Ev(%class.C* %this) +// CHECKARM: define %class.C* @_ZN1CD1Ev(%class.C* returned %this) +// CHECKARM: define %class.C* @_ZN1CD2Ev(%class.C* returned %this) + +// CHECKMS: define %class.C* @"\01??0C@@QEAA@PEAHPEAD@Z"(%class.C* returned %this, i32* %i, i8* %c) + +class D : public virtual A { public: - explicit ObjectCache(); - ~ObjectCache(); + D(); + ~D(); +}; -private: - Timer m_notificationPostTimer; +#ifndef PR12784_WORKAROUND +D::D() { } +D::~D() { } +#endif + +// CHECKGEN: define void @_ZN1DC1Ev(%class.D* %this) +// CHECKGEN: define void @_ZN1DC2Ev(%class.D* %this, i8** %vtt) +// CHECKGEN: define void @_ZN1DD1Ev(%class.D* %this) +// CHECKGEN: define void @_ZN1DD2Ev(%class.D* %this, i8** %vtt) + +// CHECKARM: define %class.D* @_ZN1DC1Ev(%class.D* returned %this) +// CHECKARM: define %class.D* @_ZN1DC2Ev(%class.D* returned %this, i8** %vtt) +// CHECKARM: define %class.D* @_ZN1DD1Ev(%class.D* returned %this) +// CHECKARM: define %class.D* @_ZN1DD2Ev(%class.D* returned %this, i8** %vtt) + +class E { +public: + E(); + virtual ~E(); }; -inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { } -inline ObjectCache::~ObjectCache() { } +E* gete(); -ObjectCache *test() { - ObjectCache *dd = new ObjectCache(); - return dd; +void test_destructor() { + E* e1 = new E(); + E* e2 = gete(); + e1->~E(); + e2->~E(); } + +// CHECKARM: define void @_Z15test_destructorv() + +// CHECKARM: {{%.*}} = call %class.E* @_ZN1EC1Ev(%class.E* + +// Verify that virtual calls to destructors are not marked with a 'returned' +// this parameter at the call site... +// CHECKARM: [[VFN:%.*]] = getelementptr inbounds %class.E* (%class.E*)** +// CHECKARM: [[THUNK:%.*]] = load %class.E* (%class.E*)** [[VFN]] +// CHECKARM: call %class.E* [[THUNK]](%class.E* + +// ...but static calls create declarations with 'returned' this +// CHECKARM: declare %class.E* @_ZN1EC1Ev(%class.E* returned) diff --git a/test/CodeGenCXX/copy-constructor-elim-2.cpp b/test/CodeGenCXX/copy-constructor-elim-2.cpp index 4ff877516b..b1447040e6 100644 --- a/test/CodeGenCXX/copy-constructor-elim-2.cpp +++ b/test/CodeGenCXX/copy-constructor-elim-2.cpp @@ -21,7 +21,7 @@ namespace no_elide_base { Derived(const Other &O); }; - // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr + // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* returned %this, %"struct.no_elide_base::Other"* %O) unnamed_addr Derived::Derived(const Other &O) // CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv // CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_ diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp index 864540d425..2c2f162540 100644 --- a/test/CodeGenCXX/microsoft-abi-structors.cpp +++ b/test/CodeGenCXX/microsoft-abi-structors.cpp @@ -15,7 +15,7 @@ class A { void no_constructor_destructor_infinite_recursion() { A a; -// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* %this) +// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* returned %this) // CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4 // CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4 // CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]] @@ -34,7 +34,7 @@ struct B { // Tests that we can define constructors outside the class (PR12784). B::B() { - // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* %this) + // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* returned %this) // CHECK: ret } @@ -136,7 +136,7 @@ struct B : A { }; B::B() { - // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* %this) + // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* returned %this) // CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}}) // CHECK: ret } @@ -146,7 +146,7 @@ struct C : virtual A { }; C::C() { - // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %this, i32 %is_most_derived) + // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* returned %this, i32 %is_most_derived) // TODO: make sure this works in the Release build too; // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] @@ -175,7 +175,7 @@ struct D : C { }; D::D() { - // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* %this, i32 %is_most_derived) unnamed_addr + // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* returned %this, i32 %is_most_derived) unnamed_addr // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0 @@ -196,7 +196,7 @@ struct E : virtual C { }; E::E() { - // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* %this, i32 %is_most_derived) unnamed_addr + // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* returned %this, i32 %is_most_derived) unnamed_addr // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0