From: Stephen Lin Date: Wed, 19 Jun 2013 23:23:19 +0000 (+0000) Subject: Revert r184205 and associated patches while investigating issue with broken buildbot... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=19cee1871e3986c79a4408813f029121e896f11c;p=platform%2Fupstream%2Fllvm.git Revert r184205 and associated patches while investigating issue with broken buildbot (possible interaction with LTO) llvm-svn: 184384 --- diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index cfcba09..04bc54b 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -97,12 +97,8 @@ public: return *MangleCtx; } - /// 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. + /// 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; } /// Returns true if the given record type should be returned indirectly. @@ -218,10 +214,10 @@ public: const CXXRecordDecl *BaseClassDecl) = 0; /// Build the signature of the given constructor variant by adding - /// 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). + /// 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. /// /// If there are ever any ABIs where the implicit parameters are /// intermixed with the formal parameters, we can address those @@ -235,10 +231,9 @@ public: const CXXRecordDecl *RD); /// Build the signature of the given destructor variant by adding - /// 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). + /// 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). virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor, CXXDtorType T, CanQualType &ResTy, @@ -249,8 +244,7 @@ public: /// possibly some extra data for constructors and destructors. /// /// ABIs may also choose to override the return type, which has been - /// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or - /// the formal return type of the function otherwise. + /// initialized with the formal return type of the function. virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, FunctionArgList &Params) = 0; @@ -259,20 +253,21 @@ public: virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; /// Emit the constructor call. Return the function that is called. - virtual void EmitConstructorCall(CodeGenFunction &CGF, + virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, - CXXCtorType Type, - bool ForVirtualBase, bool Delegating, + CXXCtorType Type, bool ForVirtualBase, + bool Delegating, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) = 0; /// Emit the ABI-specific virtual destructor call. - virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, - SourceLocation CallLoc, - llvm::Value *This) = 0; + virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF, + const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, + SourceLocation CallLoc, + ReturnValueSlot ReturnValue, + llvm::Value *This) = 0; /// Emit any tables needed to implement virtual inheritance. For Itanium, /// this emits virtual table tables. For the MSVC++ ABI, this emits virtual diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index f74ae39..8044639 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -200,10 +200,7 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D, CXXCtorType ctorKind) { SmallVector argTypes; argTypes.push_back(GetThisType(Context, D->getParent())); - - GlobalDecl GD(D, ctorKind); - CanQualType resultType = - TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy; + CanQualType resultType = Context.VoidTy; TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes); @@ -228,10 +225,7 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D, CXXDtorType dtorKind) { SmallVector argTypes; argTypes.push_back(GetThisType(Context, D->getParent())); - - GlobalDecl GD(D, dtorKind); - CanQualType resultType = - TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy; + CanQualType resultType = Context.VoidTy; TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes); @@ -1639,6 +1633,18 @@ 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. @@ -1735,6 +1741,19 @@ 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/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index cceae68..a32c152f 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1662,8 +1662,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 @@ -1755,6 +1758,9 @@ 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 { @@ -1821,6 +1827,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/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 438657a..60a70f8 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -280,15 +280,16 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, // We also don't emit a virtual call if the base expression has a record type // because then we know what the type is. bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod; - llvm::Value *Callee; + llvm::Value *Callee; if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) { - assert(CE->arg_begin() == CE->arg_end() && - "Destructor shouldn't have explicit parameters"); - assert(ReturnValue.isNull() && "Destructor shouldn't have return value"); if (UseVirtualCall) { - CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete, - CE->getExprLoc(), This); + assert(CE->arg_begin() == CE->arg_end() && + "Virtual destructor shouldn't have explicit parameters"); + return CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, + Dtor_Complete, + CE->getExprLoc(), + ReturnValue, This); } else { if (getLangOpts().AppleKext && MD->isVirtual() && @@ -301,16 +302,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, cast(DevirtualizedMethod); Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty); } - EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This, - /*ImplicitParam=*/0, QualType(), 0, 0); } - return RValue::get(0); - } - - if (const CXXConstructorDecl *Ctor = dyn_cast(MD)) { + } else if (const CXXConstructorDecl *Ctor = + dyn_cast(MD)) { Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty); } else if (UseVirtualCall) { - Callee = BuildVirtualCall(MD, This, Ty); + Callee = BuildVirtualCall(MD, This, Ty); } else { if (getLangOpts().AppleKext && MD->isVirtual() && @@ -1416,7 +1413,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF, // FIXME: Provide a source location here. CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting; CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType, - SourceLocation(), Ptr); + SourceLocation(), + ReturnValueSlot(), Ptr); if (UseGlobalDelete) { CGF.PopCleanupBlock(); diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 9c4a5e0..e15639d 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -287,9 +287,8 @@ 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/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index e8469e6..297fc65 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -42,7 +42,8 @@ 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), DidCallStackSave(false), + DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0), + DidCallStackSave(false), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), NumReturnExprs(0), NumSimpleReturnExprs(0), CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), @@ -661,12 +662,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, QualType ResTy = FD->getResultType(); CurGD = GD; - const CXXMethodDecl *MD; - if ((MD = dyn_cast(FD)) && MD->isInstance()) { - if (CGM.getCXXABI().HasThisReturn(GD)) - ResTy = MD->getThisType(getContext()); + if (isa(FD) && cast(FD)->isInstance()) CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args); - } for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) Args.push_back(FD->getParamDecl(i)); @@ -675,6 +672,10 @@ 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()); @@ -726,6 +727,9 @@ 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/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index b7e2086..7b18edf 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -798,6 +798,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/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 3298d5a..efff4b11 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -722,14 +722,6 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, if (!IsIncompleteFunction) SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F); - if (getCXXABI().HasThisReturn(GD)) { - assert(!F->arg_empty() && - F->arg_begin()->getType() - ->canLosslesslyBitCastTo(F->getReturnType()) && - "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/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 51c1dc5..36b3da5 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -119,17 +119,20 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - void EmitConstructorCall(CodeGenFunction &CGF, - const CXXConstructorDecl *D, CXXCtorType Type, - bool ForVirtualBase, bool Delegating, + 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); - void EmitVirtualDestructorCall(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, SourceLocation CallLoc, - llvm::Value *This); + RValue EmitVirtualDestructorCall(CodeGenFunction &CGF, + const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, + SourceLocation CallLoc, + ReturnValueSlot ReturnValue, + llvm::Value *This); void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD); @@ -165,11 +168,21 @@ class ARMCXXABI : public ItaniumCXXABI { public: ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {} - bool HasThisReturn(GlobalDecl GD) const { - return (isa(GD.getDecl()) || ( - isa(GD.getDecl()) && - GD.getDtorType() != Dtor_Deleting)); - } + 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); void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy); @@ -181,6 +194,15 @@ 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))); + } }; } @@ -735,14 +757,22 @@ void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, SmallVectorImpl &ArgTys) { ASTContext &Context = getContext(); - // 'this' parameter is already there, as well as 'this' return if - // HasThisReturn(GlobalDecl(Ctor, Type)) is true + // 'this' is already there. // 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, @@ -751,14 +781,25 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, SmallVectorImpl &ArgTys) { ASTContext &Context = getContext(); - // 'this' parameter is already there, as well as 'this' return if - // HasThisReturn(GlobalDecl(Dtor, Type)) is true + // 'this' is already there. // 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) { @@ -782,6 +823,16 @@ 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); @@ -792,23 +843,21 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)), "vtt"); } +} - /// 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 +void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { + ItaniumCXXABI::EmitInstanceFunctionProlog(CGF); + + /// Initialize the return slot to 'this' at the start of the + /// function. if (HasThisReturn(CGF.CurGD)) 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, + CXXCtorType Type, bool ForVirtualBase, + bool Delegating, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { @@ -818,15 +867,17 @@ void 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); + CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, + VTT, VTTTy, ArgBeg, ArgEnd); + return Callee; } -void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, - SourceLocation CallLoc, - llvm::Value *This) { +RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, + const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, + SourceLocation CallLoc, + ReturnValueSlot ReturnValue, + llvm::Value *This) { assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete); const CGFunctionInfo *FInfo @@ -834,8 +885,8 @@ void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo); llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty); - CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This, - /*ImplicitParam=*/0, QualType(), 0, 0); + return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This, + /*ImplicitParam=*/0, QualType(), 0, 0); } void ItaniumCXXABI::EmitVirtualInheritanceTables( diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 1dca209..1ff7946 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -30,8 +30,6 @@ 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(); @@ -76,17 +74,20 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - void EmitConstructorCall(CodeGenFunction &CGF, - const CXXConstructorDecl *D, CXXCtorType Type, - bool ForVirtualBase, bool Delegating, + 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); - - void EmitVirtualDestructorCall(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, SourceLocation CallLoc, - llvm::Value *This); + + RValue EmitVirtualDestructorCall(CodeGenFunction &CGF, + const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, + SourceLocation CallLoc, + ReturnValueSlot ReturnValue, + llvm::Value *This); void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD); @@ -129,6 +130,7 @@ public: llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, CharUnits cookieSize); + static bool needThisReturn(GlobalDecl GD); private: llvm::Constant *getZeroInt() { @@ -312,15 +314,19 @@ MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF, return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase); } -bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const { - return isa(GD.getDecl()); +bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) { + const CXXMethodDecl* MD = cast(GD.getDecl()); + return isa(MD); } void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy, SmallVectorImpl &ArgTys) { - // 'this' parameter and 'this' return are already in place + // 'this' is already in place + + // Ctor returns this ptr + ResTy = ArgTys[0]; const CXXRecordDecl *Class = Ctor->getParent(); if (Class->getNumVBases()) { @@ -378,7 +384,6 @@ void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, CanQualType &ResTy, SmallVectorImpl &ArgTys) { // 'this' is already in place - // TODO: 'for base' flag if (Type == Dtor_Deleting) { @@ -399,6 +404,9 @@ 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()); @@ -423,17 +431,9 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { EmitThisParam(CGF); - - /// 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)) + if (needThisReturn(CGF.CurGD)) { CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); + } const CXXMethodDecl *MD = cast(CGF.CurGD.getDecl()); if (isa(MD) && MD->getParent()->getNumVBases()) { @@ -455,10 +455,9 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { } } -void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, +llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, const CXXConstructorDecl *D, - CXXCtorType Type, - bool ForVirtualBase, + CXXCtorType Type, bool ForVirtualBase, bool Delegating, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, @@ -475,14 +474,17 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, // FIXME: Provide a source location here. CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, - ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd); + ImplicitParam, ImplicitParamTy, + ArgBeg, ArgEnd); + return Callee; } -void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, - SourceLocation CallLoc, - llvm::Value *This) { +RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, + const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, + SourceLocation CallLoc, + ReturnValueSlot ReturnValue, + llvm::Value *This) { assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete); // We have only one destructor in the vftable but can get both behaviors @@ -497,8 +499,8 @@ void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()), DtorType == Dtor_Deleting); - CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This, - ImplicitParam, Context.BoolTy, 0, 0); + return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This, + ImplicitParam, Context.BoolTy, 0, 0); } const VBTableVector & diff --git a/clang/test/CodeGenCXX/arm.cpp b/clang/test/CodeGenCXX/arm.cpp index 5578b2a..48f2f00 100644 --- a/clang/test/CodeGenCXX/arm.cpp +++ b/clang/test/CodeGenCXX/arm.cpp @@ -52,19 +52,19 @@ namespace test1 { a.bar(); } - // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* returned %this, i32 %i) unnamed_addr + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr // 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]]* returned %this) unnamed_addr + // 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. diff --git a/clang/test/CodeGenCXX/constructor-destructor-return-this.cpp b/clang/test/CodeGenCXX/constructor-destructor-return-this.cpp index 1e9a0ce..1ff922d 100644 --- a/clang/test/CodeGenCXX/constructor-destructor-return-this.cpp +++ b/clang/test/CodeGenCXX/constructor-destructor-return-this.cpp @@ -1,119 +1,60 @@ -//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 +//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s -// FIXME: Add checks to ensure that Microsoft destructors do not return 'this' -// once PR12784 is resolved +// 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 -// 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:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr +// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev( +// CHECK-NEXT: ret [[A]] [[THIS1]] -class A { -public: - A(); - ~A(); +// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this +// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E( +// CHECK-NEXT: ret [[A]] [[THIS1]] -private: - int x_; -}; +// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr +// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev( +// CHECK-NEXT: ret [[A]] [[THIS1]] -class B : public A { -public: - B(int *i); - ~B(); - -private: - int *i_; -}; +// 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]] -B::B(int *i) : i_(i) { } -#ifndef PR12784_WORKAROUND -B::~B() { } -#endif - -// 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) - -// 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) - -class C : public A, public B { +class TimerBase { public: - C(int *i, char *c); - virtual ~C(); -private: - char *c_; + TimerBase(); + virtual ~TimerBase(); }; -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 { +template class Timer : public TimerBase { public: - D(); - ~D(); -}; + typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*); -#ifndef PR12784_WORKAROUND -D::D() { } -D::~D() { } -#endif + Timer(TimerFiredClass* o, TimerFiredFunction f) + : m_object(o), m_function(f) { } -// 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) +private: + virtual void fired() { (m_object->*m_function)(this); } -// 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) + TimerFiredClass* m_object; + TimerFiredFunction m_function; +}; -class E { +class ObjectCache { public: - E(); - virtual ~E(); + explicit ObjectCache(); + ~ObjectCache(); + +private: + Timer m_notificationPostTimer; }; -E* gete(); +inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { } +inline ObjectCache::~ObjectCache() { } -void test_destructor() { - const E& e1 = E(); - E* e2 = gete(); - e2->~E(); +ObjectCache *test() { + ObjectCache *dd = new ObjectCache(); + return dd; } - -// CHECKARM: define void @_Z15test_destructorv() - -// 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: {{%.*}} = call %class.E* @_ZN1ED1Ev(%class.E* % - -// CHECKARM: declare %class.E* @_ZN1ED1Ev(%class.E* returned) diff --git a/clang/test/CodeGenCXX/copy-constructor-elim-2.cpp b/clang/test/CodeGenCXX/copy-constructor-elim-2.cpp index b144704..4ff8775 100644 --- a/clang/test/CodeGenCXX/copy-constructor-elim-2.cpp +++ b/clang/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"* returned %this, %"struct.no_elide_base::Other"* %O) unnamed_addr + // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %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/clang/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/clang/test/CodeGenCXX/copy-constructor-synthesis-2.cpp index 03c6633..d028a28 100644 --- a/clang/test/CodeGenCXX/copy-constructor-synthesis-2.cpp +++ b/clang/test/CodeGenCXX/copy-constructor-synthesis-2.cpp @@ -3,5 +3,5 @@ struct A { virtual void a(); }; A x(A& y) { return y; } -// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* {{.*}}%this, %struct.A*) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) diff --git a/clang/test/CodeGenCXX/default-constructor-template-member.cpp b/clang/test/CodeGenCXX/default-constructor-template-member.cpp index 2156964..0dd64df 100644 --- a/clang/test/CodeGenCXX/default-constructor-template-member.cpp +++ b/clang/test/CodeGenCXX/default-constructor-template-member.cpp @@ -5,7 +5,6 @@ struct B { A x; }; void a() { B b; } - // CHECK: call {{.*}} @_ZN1BC1Ev -// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* {{.*}}%this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* %this) unnamed_addr // CHECK: call {{.*}} @_ZN1AIiEC1Ev diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp index 03eae53..15a85c7 100644 --- a/clang/test/CodeGenCXX/mangle-template.cpp +++ b/clang/test/CodeGenCXX/mangle-template.cpp @@ -82,7 +82,7 @@ namespace test7 { X(U*, typename int_c<(meta::value + meta::value)>::type *) { } }; - // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE( + // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(%"struct.test7::X"* %this, double*, float*) unnamed_addr template X::X(double*, float*); } @@ -101,7 +101,7 @@ namespace test8 { template void f(int_c::type::value>) { } - // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE( + // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE template void f(int_c); } diff --git a/clang/test/CodeGenCXX/microsoft-abi-structors.cpp b/clang/test/CodeGenCXX/microsoft-abi-structors.cpp index 27c0006..9d4a1c5 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-structors.cpp +++ b/clang/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"* returned %this) +// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* %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"* returned %this) + // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* %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"* returned %this) + // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* %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"* returned %this, i32 %is_most_derived) + // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %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]] @@ -179,7 +179,7 @@ struct D : C { }; D::D() { - // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* returned %this, i32 %is_most_derived) unnamed_addr + // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* %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 @@ -204,7 +204,7 @@ struct E : virtual C { }; E::E() { - // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* returned %this, i32 %is_most_derived) unnamed_addr + // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* %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 diff --git a/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp b/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp index a8d4520b..2424d21 100644 --- a/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -18,34 +18,34 @@ int main() { // basic_iostream's complete dtor calls its base dtor, then its // virtual base's dtor. -// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr // CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev // CHECK: call {{.*}} @_ZN9basic_iosD2Ev // basic_iostream's base dtor calls its non-virtual base dtor. -// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* {{.*}}%this, i8** %vtt) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr // CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev // CHECK: } // basic_iostream's deleting dtor calls its complete dtor, then // operator delete(). -// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr // CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev // CHECK: call {{.*}} @_ZdlPv // basic_istream's complete dtor calls the base dtor, // then its virtual base's base dtor. -// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr // CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev // CHECK: call {{.*}} @_ZN9basic_iosD2Ev // basic_istream's deleting dtor calls the complete dtor, then // operator delete(). -// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr // CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev // CHECK: call {{.*}} @_ZdlPv // basic_istream's base dtor is a no-op. -// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* {{.*}}%this, i8** %vtt) unnamed_addr +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr // CHECK-NOT: call // CHECK: }