From 4c40d98ab7acf5f27fa89b17bd8fc0ef7683df37 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 31 Aug 2010 07:33:07 +0000 Subject: [PATCH] Teach IR generation to return 'this' from constructors and destructors under the ARM ABI. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112588 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCXX.cpp | 26 ++++++ lib/CodeGen/CGCXXABI.h | 69 +++++++++++++- lib/CodeGen/CGCall.cpp | 46 +++++---- lib/CodeGen/CGDeclCXX.cpp | 3 +- lib/CodeGen/CGExpr.cpp | 3 +- lib/CodeGen/CGExprCXX.cpp | 1 + lib/CodeGen/CGExprConstant.cpp | 1 + lib/CodeGen/CGExprScalar.cpp | 1 + lib/CodeGen/CGRTTI.cpp | 7 +- lib/CodeGen/CGVTT.cpp | 3 +- lib/CodeGen/CGVTables.cpp | 36 ++++--- lib/CodeGen/CodeGenFunction.cpp | 47 ++-------- lib/CodeGen/CodeGenFunction.h | 13 ++- lib/CodeGen/CodeGenModule.cpp | 15 +-- lib/CodeGen/CodeGenModule.h | 5 +- lib/CodeGen/CodeGenTypes.h | 6 +- lib/CodeGen/ItaniumCXXABI.cpp | 161 ++++++++++++++++++++++++++++++++ lib/CodeGen/MicrosoftCXXABI.cpp | 28 ++++++ test/CodeGenCXX/arm.cpp | 86 ++++++++++++++++- 19 files changed, 455 insertions(+), 102 deletions(-) diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 94378b79e6..fbea42065b 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -410,3 +410,29 @@ bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { // Fake answer. return true; } + +void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params) { + const CXXMethodDecl *MD = cast(CGF.CurGD.getDecl()); + + // FIXME: I'm not entirely sure I like using a fake decl just for code + // generation. Maybe we can come up with a better way? + ImplicitParamDecl *ThisDecl + = ImplicitParamDecl::Create(CGM.getContext(), 0, MD->getLocation(), + &CGM.getContext().Idents.get("this"), + MD->getThisType(CGM.getContext())); + Params.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); + getThisDecl(CGF) = ThisDecl; +} + +void CGCXXABI::EmitThisParam(CodeGenFunction &CGF) { + /// Initialize the 'this' slot. + assert(getThisDecl(CGF) && "no 'this' variable for function"); + getThisValue(CGF) + = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getThisDecl(CGF)), + "this"); +} + +void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, + RValue RV, QualType ResultType) { + CGF.EmitReturnOfRValue(RV, ResultType); +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 25110eb3b8..b87d6c0259 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -15,19 +15,23 @@ #ifndef CLANG_CODEGEN_CXXABI_H #define CLANG_CODEGEN_CXXABI_H +#include "CodeGenFunction.h" + namespace llvm { class Constant; class Type; class Value; + + template class SmallVectorImpl; } namespace clang { class CastExpr; + class CXXConstructorDecl; + class CXXDestructorDecl; class CXXMethodDecl; class CXXRecordDecl; class FieldDecl; - class MemberPointerType; - class QualType; namespace CodeGen { class CodeGenFunction; @@ -41,6 +45,28 @@ protected: CGCXXABI(CodeGenModule &CGM) : CGM(CGM) {} +protected: + ImplicitParamDecl *&getThisDecl(CodeGenFunction &CGF) { + return CGF.CXXThisDecl; + } + llvm::Value *&getThisValue(CodeGenFunction &CGF) { + return CGF.CXXThisValue; + } + + ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) { + return CGF.CXXVTTDecl; + } + llvm::Value *&getVTTValue(CodeGenFunction &CGF) { + return CGF.CXXVTTValue; + } + + /// Build a parameter variable suitable for 'this'. + void BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params); + + /// Perform prolog initialization of the parameter variable suitable + /// for 'this' emitted by BuildThisParam. + void EmitThisParam(CodeGenFunction &CGF); + public: virtual ~CGCXXABI(); @@ -99,6 +125,45 @@ public: EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Value *MemPtr, const MemberPointerType *MPT); + + /// 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. + /// + /// If there are ever any ABIs where the implicit parameters are + /// intermixed with the formal parameters, we can address those + /// then. + virtual void BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) = 0; + + /// 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). + virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) = 0; + + /// Build the ABI-specific portion of the parameter list for a + /// function. This generally involves a 'this' parameter and + /// 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. + virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params) = 0; + + /// Emit the ABI-specific prolog for the function. + virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; + + virtual void EmitReturnFromThunk(CodeGenFunction &CGF, + RValue RV, QualType ResultType); }; /// Creates an instance of a C++ ABI class. diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 4c48d631ab..6072c1c499 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "CGCall.h" +#include "CGCXXABI.h" #include "ABIInfo.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" @@ -126,29 +127,32 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, CXXCtorType Type) { llvm::SmallVector ArgTys; - - // Add the 'this' pointer. ArgTys.push_back(GetThisType(Context, D->getParent())); + CanQualType ResTy = Context.VoidTy; - // Check if we need to add a VTT parameter (which has type void **). - if (Type == Ctor_Base && D->getParent()->getNumVBases() != 0) - ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); + TheCXXABI.BuildConstructorSignature(D, Type, ResTy, ArgTys); - return ::getFunctionInfo(*this, ArgTys, GetFormalType(D)); + CanQual FTP = GetFormalType(D); + + // Add the formal parameters. + for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) + ArgTys.push_back(FTP->getArgType(i)); + + return getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, CXXDtorType Type) { - llvm::SmallVector ArgTys; - - // Add the 'this' pointer. + llvm::SmallVector ArgTys; ArgTys.push_back(GetThisType(Context, D->getParent())); - - // Check if we need to add a VTT parameter (which has type void **). - if (Type == Dtor_Base && D->getParent()->getNumVBases() != 0) - ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); + CanQualType ResTy = Context.VoidTy; + + TheCXXABI.BuildDestructorSignature(D, Type, ResTy, ArgTys); - return ::getFunctionInfo(*this, ArgTys, GetFormalType(D)); + CanQual FTP = GetFormalType(D); + assert(FTP->getNumArgs() == 0 && "dtor with formal parameters"); + + return getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { @@ -659,12 +663,18 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic); } -const llvm::Type * -CodeGenTypes::GetFunctionTypeForVTable(const CXXMethodDecl *MD) { +const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); const FunctionProtoType *FPT = MD->getType()->getAs(); - if (!VerifyFuncTypeComplete(FPT)) - return GetFunctionType(getFunctionInfo(MD), FPT->isVariadic(), false); + if (!VerifyFuncTypeComplete(FPT)) { + const CGFunctionInfo *Info; + if (isa(MD)) + Info = &getFunctionInfo(cast(MD), GD.getDtorType()); + else + Info = &getFunctionInfo(MD); + return GetFunctionType(*Info, FPT->isVariadic(), false); + } return llvm::OpaqueType::get(getLLVMContext()); } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index e0bd3a7c88..e2f197522b 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/Intrinsics.h" @@ -350,7 +351,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics; llvm::SmallString<256> GuardVName; - CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); + CGM.getCXXABI().getMangleContext().mangleGuardVariable(&D, GuardVName); // Create the guard variable. llvm::GlobalVariable *GuardVariable = diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index f6cf5920be..a676333f49 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -14,6 +14,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "CGCall.h" +#include "CGCXXABI.h" #include "CGRecordLayout.h" #include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" @@ -160,7 +161,7 @@ CreateReferenceTemporary(CodeGenFunction& CGF, QualType Type, if (const VarDecl *VD = dyn_cast_or_null(InitializedDecl)) { if (VD->hasGlobalStorage()) { llvm::SmallString<256> Name; - CGF.CGM.getMangleContext().mangleReferenceTemporary(VD, Name); + CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Name); const llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 61831543b4..34d7a764b2 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "llvm/Intrinsics.h" using namespace clang; diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index a3a1feaff2..9c31c2a3d5 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -13,6 +13,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGRecordLayout.h" #include "clang/AST/APValue.h" diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index dd881350c6..fd77a67606 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 2a90b3736f..680b2ba027 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenModule.h" +#include "CGCXXABI.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Frontend/CodeGenOptions.h" @@ -65,7 +66,7 @@ public: llvm::Constant *BuildName(QualType Ty, bool Hidden, llvm::GlobalVariable::LinkageTypes Linkage) { llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *OGV = CGM.getModule().getNamedGlobal(Name); @@ -164,7 +165,7 @@ public: llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { // Mangle the RTTI name. llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); // Look for an existing global. @@ -518,7 +519,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { // Check if we've already emitted an RTTI descriptor for this type. llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name); diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 61c74230e1..56acfc8480 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenModule.h" +#include "CGCXXABI.h" #include "clang/AST/RecordLayout.h" using namespace clang; using namespace CodeGen; @@ -373,7 +374,7 @@ CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, return 0; llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVTT(RD, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXVTT(RD, OutName); llvm::StringRef Name = OutName.str(); D1(printf("vtt %s\n", RD->getNameAsCString())); diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 22701c2f69..bed4670f7f 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -13,6 +13,7 @@ #include "CodeGenModule.h" #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" #include "clang/Frontend/CodeGenOptions.h" @@ -2409,12 +2410,12 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, // Compute the mangled name. llvm::SmallString<256> Name; if (const CXXDestructorDecl* DD = dyn_cast(MD)) - getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), Thunk.This, - Name); + getCXXABI().getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), + Thunk.This, Name); else - getMangleContext().mangleThunk(MD, Thunk, Name); + getCXXABI().getMangleContext().mangleThunk(MD, Thunk, Name); - const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(MD); + const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD); return GetOrCreateLLVMFunction(Name, Ty, GD); } @@ -2522,13 +2523,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, // CodeGenFunction::GenerateCode. // Create the implicit 'this' parameter declaration. - CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, - MD->getLocation(), - &getContext().Idents.get("this"), - ThisType); - - // Add the 'this' parameter. - FunctionArgs.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); + CurGD = GD; + CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResultType, FunctionArgs); // Add the rest of the parameters. for (FunctionDecl::param_const_iterator I = MD->param_begin(), @@ -2540,6 +2536,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation()); + CGM.getCXXABI().EmitInstanceFunctionProlog(*this); + // Adjust the 'this' pointer if necessary. llvm::Value *AdjustedThisPtr = PerformTypeAdjustment(*this, LoadCXXThis(), @@ -2563,7 +2561,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, // Get our callee. const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(GD), FPT->isVariadic()); llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); @@ -2623,7 +2621,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, } if (!ResultType->isVoidType() && Slot.isNull()) - EmitReturnOfRValue(RV, ResultType); + CGM.getCXXABI().EmitReturnFromThunk(CGF, RV, ResultType); FinishFunction(); @@ -2637,7 +2635,6 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) { llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk); - const CXXMethodDecl *MD = cast(GD.getDecl()); // Strip off a bitcast if we got one back. if (llvm::ConstantExpr *CE = dyn_cast(Entry)) { @@ -2648,7 +2645,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) // There's already a declaration with the same name, check if it has the same // type or if we need to replace it. if (cast(Entry)->getType()->getElementType() != - CGM.getTypes().GetFunctionTypeForVTable(MD)) { + CGM.getTypes().GetFunctionTypeForVTable(GD)) { llvm::GlobalValue *OldThunkFn = cast(Entry); // If the types mismatch then we have to rewrite the definition. @@ -2867,8 +2864,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, NextVTableThunkIndex++; } else { - const CXXMethodDecl *MD = cast(GD.getDecl()); - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(MD); + const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD); Init = CGM.GetAddrOfFunction(GD, Ty); } @@ -2935,7 +2931,7 @@ GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name, llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVTable(RD, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, OutName); llvm::StringRef Name = OutName.str(); ComputeVTableRelatedInformation(RD, true); @@ -2995,8 +2991,8 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, // Get the mangled construction vtable name. llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8, - Base.getBase(), OutName); + CGM.getCXXABI().getMangleContext(). + mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8, Base.getBase(), OutName); llvm::StringRef Name = OutName.str(); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 13ad034a0d..51d084e1d3 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -13,6 +13,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CGCXXABI.h" #include "CGDebugInfo.h" #include "CGException.h" #include "clang/Basic/TargetInfo.h" @@ -48,7 +49,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) Exceptions = getContext().getLangOptions().Exceptions; CatchUndefined = getContext().getLangOptions().CatchUndefined; - CGM.getMangleContext().startNewFunction(); + CGM.getCXXABI().getMangleContext().startNewFunction(); } ASTContext &CodeGenFunction::getContext() const { @@ -56,17 +57,6 @@ ASTContext &CodeGenFunction::getContext() const { } -llvm::Value *CodeGenFunction::GetAddrOfLocalVar(const VarDecl *VD) { - llvm::Value *Res = LocalDeclMap[VD]; - assert(Res && "Invalid argument to GetAddrOfLocalVar(), no decl!"); - return Res; -} - -llvm::Constant * -CodeGenFunction::GetAddrOfStaticLocalVar(const VarDecl *BVD) { - return cast(GetAddrOfLocalVar(BVD)); -} - const llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) { return CGM.getTypes().ConvertTypeForMem(T); } @@ -289,10 +279,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, EmitStartEHSpec(CurCodeDecl); EmitFunctionProlog(*CurFnInfo, CurFn, Args); - if (CXXThisDecl) - CXXThisValue = Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this"); - if (CXXVTTDecl) - CXXVTTValue = Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt"); + if (D && isa(D) && cast(D)->isInstance()) + CGM.getCXXABI().EmitInstanceFunctionProlog(*this); // If any of the arguments have a variably modified type, make sure to // emit the type size. @@ -336,30 +324,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { DebugInfo = CGM.getDebugInfo(); FunctionArgList Args; + QualType ResTy = FD->getResultType(); CurGD = GD; - if (const CXXMethodDecl *MD = dyn_cast(FD)) { - if (MD->isInstance()) { - // Create the implicit 'this' decl. - // FIXME: I'm not entirely sure I like using a fake decl just for code - // generation. Maybe we can come up with a better way? - CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, - FD->getLocation(), - &getContext().Idents.get("this"), - MD->getThisType(getContext())); - Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); - - // Check if we need a VTT parameter as well. - if (CodeGenVTables::needsVTTParameter(GD)) { - // FIXME: The comment about using a fake decl above applies here too. - QualType T = getContext().getPointerType(getContext().VoidPtrTy); - CXXVTTDecl = - ImplicitParamDecl::Create(getContext(), 0, FD->getLocation(), - &getContext().Idents.get("vtt"), T); - Args.push_back(std::make_pair(CXXVTTDecl, CXXVTTDecl->getType())); - } - } - } + if (isa(FD) && cast(FD)->isInstance()) + CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args); if (FD->getNumParams()) { const FunctionProtoType* FProto = FD->getType()->getAs(); @@ -374,7 +343,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); // Emit the standard function prologue. - StartFunction(GD, FD->getResultType(), Fn, Args, BodyRange.getBegin()); + StartFunction(GD, ResTy, Fn, Args, BodyRange.getBegin()); // Generate the body of the function. if (isa(FD)) diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f54a0113e7..fc741f8ef0 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -70,6 +70,7 @@ namespace CodeGen { class CGFunctionInfo; class CGRecordLayout; class CGBlockInfo; + class CGCXXABI; /// A branch fixup. These are required when emitting a goto to a /// label which hasn't been emitted yet. The goto is optimistically @@ -406,6 +407,8 @@ public: class CodeGenFunction : public BlockFunction { CodeGenFunction(const CodeGenFunction&); // DO NOT IMPLEMENT void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT + + friend class CGCXXABI; public: /// A jump destination is an abstract label, branching to which may /// require a jump out through normal cleanups. @@ -1034,10 +1037,16 @@ public: void StartBlock(const char *N); /// GetAddrOfStaticLocalVar - Return the address of a static local variable. - llvm::Constant *GetAddrOfStaticLocalVar(const VarDecl *BVD); + llvm::Constant *GetAddrOfStaticLocalVar(const VarDecl *BVD) { + return cast(GetAddrOfLocalVar(BVD)); + } /// GetAddrOfLocalVar - Return the address of a local variable. - llvm::Value *GetAddrOfLocalVar(const VarDecl *VD); + llvm::Value *GetAddrOfLocalVar(const VarDecl *VD) { + llvm::Value *Res = LocalDeclMap[VD]; + assert(Res && "Invalid argument to GetAddrOfLocalVar(), no decl!"); + return Res; + } /// getAccessedFieldNo - Given an encoded value and a result number, return /// the input field number being accessed. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index d8e12e7cb9..d125b370a0 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -15,6 +15,7 @@ #include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "CGCall.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "Mangle.h" #include "TargetInfo.h" @@ -287,7 +288,7 @@ llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { if (!Str.empty()) return Str; - if (!getMangleContext().shouldMangleDeclName(ND)) { + if (!getCXXABI().getMangleContext().shouldMangleDeclName(ND)) { IdentifierInfo *II = ND->getIdentifier(); assert(II && "Attempt to mangle unnamed decl."); @@ -297,13 +298,13 @@ llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { llvm::SmallString<256> Buffer; if (const CXXConstructorDecl *D = dyn_cast(ND)) - getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Buffer); + getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Buffer); else if (const CXXDestructorDecl *D = dyn_cast(ND)) - getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Buffer); + getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Buffer); else if (const BlockDecl *BD = dyn_cast(ND)) - getMangleContext().mangleBlock(GD, BD, Buffer); + getCXXABI().getMangleContext().mangleBlock(GD, BD, Buffer); else - getMangleContext().mangleName(ND, Buffer); + getCXXABI().getMangleContext().mangleName(ND, Buffer); // Allocate space for the mangled name. size_t Length = Buffer.size(); @@ -317,7 +318,7 @@ llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { void CodeGenModule::getMangledName(GlobalDecl GD, MangleBuffer &Buffer, const BlockDecl *BD) { - getMangleContext().mangleBlock(GD, BD, Buffer.getBuffer()); + getCXXABI().getMangleContext().mangleBlock(GD, BD, Buffer.getBuffer()); } llvm::GlobalValue *CodeGenModule::GetGlobalValue(llvm::StringRef Name) { @@ -1294,7 +1295,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { const FunctionDecl *D = cast(GD.getDecl()); const llvm::FunctionType *Ty = getTypes().GetFunctionType(GD); - getMangleContext().mangleInitDiscriminator(); + getCXXABI().getMangleContext().mangleInitDiscriminator(); // Get or create the prototype for the function. llvm::Constant *Entry = GetAddrOfFunction(GD, Ty); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index cd00f438c8..cabff9e1ca 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -22,7 +22,6 @@ #include "CGCall.h" #include "CGCXX.h" #include "CGVTables.h" -#include "CGCXXABI.h" #include "CodeGenTypes.h" #include "GlobalDecl.h" #include "Mangle.h" @@ -71,6 +70,7 @@ namespace clang { namespace CodeGen { class CodeGenFunction; + class CGCXXABI; class CGDebugInfo; class CGObjCRuntime; class MangleBuffer; @@ -243,9 +243,6 @@ public: const LangOptions &getLangOptions() const { return Features; } llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } - MangleContext &getMangleContext() { - return ABI.getMangleContext(); - } CodeGenVTables &getVTables() { return VTables; } Diagnostic &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index dac235f823..1fc2153fca 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -141,7 +141,7 @@ public: /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable, /// given a CXXMethodDecl. If the method to has an incomplete return type, /// and/or incomplete argument types, this will return the opaque type. - const llvm::Type *GetFunctionTypeForVTable(const CXXMethodDecl *MD); + const llvm::Type *GetFunctionTypeForVTable(GlobalDecl GD); const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const; @@ -171,7 +171,9 @@ public: const CGFunctionInfo &getFunctionInfo(CanQual Ty, bool IsRecursive = false); - // getFunctionInfo - Get the function info for a member function. + /// getFunctionInfo - Get the function info for a member function of + /// the given type. This is used for calls through member function + /// pointers. const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 354e72fbd0..920b833b25 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -87,11 +87,55 @@ public: llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Value *Addr, const MemberPointerType *MPT); + + void BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys); + + void BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys); + + void BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params); + + void EmitInstanceFunctionProlog(CodeGenFunction &CGF); }; class ARMCXXABI : public ItaniumCXXABI { public: ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {} + + void BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys); + + void BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys); + + void BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params); + + void EmitInstanceFunctionProlog(CodeGenFunction &CGF); + + void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy); + + +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()); + return ((isa(MD) && GD.getDtorType() != Dtor_Deleting) || + (isa(MD))); + } }; } @@ -586,3 +630,120 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) { return MPT->getPointeeType()->isFunctionType(); } + +/// The generic ABI passes 'this', plus a VTT if it's initializing a +/// base subobject. +void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + ASTContext &Context = CGM.getContext(); + + // '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, + llvm::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, + CXXDtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + ASTContext &Context = CGM.getContext(); + + // '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, + llvm::SmallVectorImpl &ArgTys) { + ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys); + + if (Type != Dtor_Deleting) + ResTy = ArgTys[0]; +} + +void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params) { + /// Create the 'this' variable. + BuildThisParam(CGF, Params); + + const CXXMethodDecl *MD = cast(CGF.CurGD.getDecl()); + assert(MD->isInstance()); + + // Check if we need a VTT parameter as well. + if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) { + ASTContext &Context = CGF.getContext(); + + // FIXME: avoid the fake decl + QualType T = Context.getPointerType(Context.VoidPtrTy); + ImplicitParamDecl *VTTDecl + = ImplicitParamDecl::Create(Context, 0, MD->getLocation(), + &Context.Idents.get("vtt"), T); + Params.push_back(std::make_pair(VTTDecl, VTTDecl->getType())); + getVTTDecl(CGF) = VTTDecl; + } +} + +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].second; +} + +void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { + /// Initialize the 'this' slot. + EmitThisParam(CGF); + + /// Initialize the 'vtt' slot if needed. + if (getVTTDecl(CGF)) { + getVTTValue(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 (HasThisReturn(CGF.CurGD)) + CGF.Builder.CreateStore(CGF.LoadCXXThis(), CGF.ReturnValue); +} + +void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, + RValue RV, QualType ResultType) { + if (!isa(CGF.CurGD.getDecl())) + return ItaniumCXXABI::EmitReturnFromThunk(CGF, RV, ResultType); + + // Destructor thunks in the ARM ABI have indeterminate results. + const llvm::Type *T = + cast(CGF.ReturnValue->getType())->getElementType(); + RValue Undef = RValue::get(llvm::UndefValue::get(T)); + return ItaniumCXXABI::EmitReturnFromThunk(CGF, Undef, ResultType); +} diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index f894f662ac..b718cf74c5 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -117,6 +117,34 @@ public: MicrosoftMangleContext &getMangleContext() { return MangleCtx; } + + void BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + // 'this' is already in place + // TODO: 'for base' flag + } + + void BuildDestructorSignature(const CXXDestructorDecl *Ctor, + CXXDtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + // 'this' is already in place + // TODO: 'for base' flag + } + + void BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params) { + BuildThisParam(CGF, Params); + // TODO: 'for base' flag + } + + void EmitInstanceFunctionProlog(CodeGenFunction &CGF) { + EmitThisParam(CGF); + // TODO: 'for base' flag + } }; } diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp index 1d4085ca23..b4c8c835e4 100644 --- a/test/CodeGenCXX/arm.cpp +++ b/test/CodeGenCXX/arm.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple=thumbv7-apple-darwin3.0.0-iphoneos -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=thumbv7-apple-darwin3.0.0-iphoneos -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - -fexceptions | FileCheck %s class foo { public: @@ -13,7 +13,89 @@ public: // The global dtor needs the right calling conv with -fno-use-cxa-atexit // rdar://7817590 +// Checked at end of file. bar baz; +// Destructors and constructors must return this. +namespace test1 { + void foo(); + + struct A { + A(int i) { foo(); } + ~A() { foo(); } + void bar() { foo(); } + }; + + // CHECK: define void @_ZN5test14testEv() + void test() { + // CHECK: [[AV:%.*]] = alloca [[A:%.*]], align 1 + // CHECK: call [[A]]* @_ZN5test11AC1Ei([[A]]* [[AV]], i32 10) + // CHECK: invoke void @_ZN5test11A3barEv([[A]]* [[AV]]) + // CHECK: call [[A]]* @_ZN5test11AD1Ev([[A]]* [[AV]]) + // CHECK: ret void + A a = 10; + a.bar(); + } + + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* + // CHECK: [[RET:%.*]] = alloca [[A]]*, align 4 + // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 + // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] + // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] + // CHECK: store [[A]]* [[THIS1]], [[A]]** [[RET]] + // CHECK: call [[A]]* @_ZN5test11AC2Ei( + // CHECK: [[THIS2:%.*]] = load [[A]]** [[RET]] + // CHECK: ret [[A]]* [[THIS2]] + + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* + // CHECK: [[RET:%.*]] = alloca [[A]]*, align 4 + // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 + // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] + // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] + // CHECK: store [[A]]* [[THIS1]], [[A]]** [[RET]] + // CHECK: call [[A]]* @_ZN5test11AD2Ev( + // CHECK: [[THIS2:%.*]] = load [[A]]** [[RET]] + // CHECK: ret [[A]]* [[THIS2]] +} + +// Awkward virtual cases. +namespace test2 { + void foo(); + + struct A { + int x; + + A(int); + virtual ~A() { foo(); } + }; + + struct B { + int y; + int z; + + B(int); + virtual ~B() { foo(); } + }; + + struct C : A, virtual B { + int q; + + C(int i) : A(i), B(i) { foo(); } + ~C() { foo(); } + }; + + void test() { + C c = 10; + } + + // CHECK: define linkonce_odr [[C:%.*]]* @_ZTv0_n12_N5test21CD1Ev( + // CHECK: call [[C]]* @_ZN5test21CD1Ev( + // CHECK: ret [[C]]* undef + + // CHECK: define linkonce_odr void @_ZTv0_n12_N5test21CD0Ev( + // CHECK: call void @_ZN5test21CD0Ev( + // CHECK: ret void +} + // CHECK: @_GLOBAL__D_a() -// CHECK: call void @_ZN3barD1Ev(%class.bar* @baz) +// CHECK: call %class.bar* @_ZN3barD1Ev(%class.bar* @baz) -- 2.40.0