diff options
author | Timur Iskhodzhanov <timurrrr@google.com> | 2013-02-27 13:46:31 +0000 |
---|---|---|
committer | Timur Iskhodzhanov <timurrrr@google.com> | 2013-02-27 13:46:31 +0000 |
commit | 1d4fff5551c2347010b955b4337a2aa7d65a050e (patch) | |
tree | 23af51dbdbd07e651243307dbf3f1defb03c0ea8 /lib/CodeGen | |
parent | 0cc798f29d489140dd81b558e9c052e9a83cce39 (diff) |
Better support for constructors with -cxx-abi microsoft, partly fixes PR12784
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176186 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 10 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 99 | ||||
-rw-r--r-- | lib/CodeGen/CGVTables.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 7 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 25 | ||||
-rw-r--r-- | lib/CodeGen/MicrosoftCXXABI.cpp | 86 |
8 files changed, 200 insertions, 50 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 43813fefa1..983cb9224a 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -183,14 +183,16 @@ void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { // The constructor used for constructing this as a base class; // ignores virtual bases. - EmitGlobal(GlobalDecl(D, Ctor_Base)); + if (getTarget().getCXXABI().hasConstructorVariants()) + EmitGlobal(GlobalDecl(D, Ctor_Base)); } void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor, CXXCtorType ctorType) { // The complete constructor is equivalent to the base constructor // for classes with no virtual bases. Try to emit it as an alias. - if (ctorType == Ctor_Complete && + if (getTarget().getCXXABI().hasConstructorVariants() && + ctorType == Ctor_Complete && !ctor->getParent()->getNumVBases() && !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete), GlobalDecl(ctor, Ctor_Base))) diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index 91795b9ded..f9fea57ea6 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -248,3 +248,12 @@ llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) { E->path_begin(), E->path_end()); } + +llvm::BasicBlock *CGCXXABI::EmitCtorCompleteObjectHandler( + CodeGenFunction &CGF) { + if (CGM.getTarget().getCXXABI().hasConstructorVariants()) + llvm_unreachable("shouldn't be called in this ABI"); + + ErrorUnsupportedABI(CGF, "complete object detection in ctor"); + return 0; +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 4764247757..cdc87b70e5 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -185,6 +185,8 @@ public: CanQualType &ResTy, SmallVectorImpl<CanQualType> &ArgTys) = 0; + 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 @@ -207,6 +209,14 @@ public: /// Emit the ABI-specific prolog for the function. virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; + virtual void 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; + /// Emit the ABI-specific virtual destructor call. virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 05894465d2..ac2dada083 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -15,6 +15,7 @@ #include "CGDebugInfo.h" #include "CGRecordLayout.h" #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/RecordLayout.h" @@ -280,18 +281,16 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, return Value; } - -/// GetVTTParameter - Return the VTT parameter that should be passed to a -/// base constructor/destructor with virtual bases. -static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, - bool ForVirtualBase, - bool Delegating) { + +llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD, + bool ForVirtualBase, + bool Delegating) { if (!CodeGenVTables::needsVTTParameter(GD)) { // This constructor/destructor does not need a VTT parameter. return 0; } - const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent(); + const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurFuncDecl)->getParent(); const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent(); llvm::Value *VTT; @@ -300,34 +299,33 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, if (Delegating) { // If this is a delegating constructor call, just load the VTT. - return CGF.LoadCXXVTT(); + return LoadCXXVTT(); } else if (RD == Base) { // If the record matches the base, this is the complete ctor/dtor // variant calling the base variant in a class with virtual bases. - assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) && + assert(!CodeGenVTables::needsVTTParameter(CurGD) && "doing no-op VTT offset in base dtor/ctor?"); assert(!ForVirtualBase && "Can't have same class as virtual base!"); SubVTTIndex = 0; } else { - const ASTRecordLayout &Layout = - CGF.getContext().getASTRecordLayout(RD); + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); CharUnits BaseOffset = ForVirtualBase ? Layout.getVBaseClassOffset(Base) : Layout.getBaseClassOffset(Base); SubVTTIndex = - CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset)); + CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset)); assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); } - if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) { + if (CodeGenVTables::needsVTTParameter(CurGD)) { // A VTT parameter was passed to the constructor, use it. - VTT = CGF.LoadCXXVTT(); - VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex); + VTT = LoadCXXVTT(); + VTT = Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex); } else { // We're the complete constructor, so get the VTT by name. - VTT = CGF.CGM.getVTables().GetAddrOfVTT(RD); - VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex); + VTT = CGM.getVTables().GetAddrOfVTT(RD); + VTT = Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex); } return VTT; @@ -1103,27 +1101,46 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, const CXXRecordDecl *ClassDecl = CD->getParent(); - SmallVector<CXXCtorInitializer *, 8> MemberInitializers; - - for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), - E = CD->init_end(); - B != E; ++B) { - CXXCtorInitializer *Member = (*B); - - if (Member->isBaseInitializer()) { - EmitBaseInitializer(*this, ClassDecl, Member, CtorType); - } else { - assert(Member->isAnyMemberInitializer() && - "Delegating initializer on non-delegating constructor"); - MemberInitializers.push_back(Member); - } + CXXConstructorDecl::init_const_iterator B = CD->init_begin(), + E = CD->init_end(); + + llvm::BasicBlock *BaseCtorContinueBB = 0; + if (ClassDecl->getNumVBases() && + !CGM.getTarget().getCXXABI().hasConstructorVariants()) { + // The ABIs that don't have constructor variants need to put a branch + // before the virtual base initialization code. + BaseCtorContinueBB = CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this); + assert(BaseCtorContinueBB); + } + + // Virtual base initializers first. + for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) { + EmitBaseInitializer(*this, ClassDecl, *B, CtorType); + } + + if (BaseCtorContinueBB) { + // Complete object handler should continue to the remaining initializers. + Builder.CreateBr(BaseCtorContinueBB); + EmitBlock(BaseCtorContinueBB); + } + + // Then, non-virtual base initializers. + for (; B != E && (*B)->isBaseInitializer(); B++) { + assert(!(*B)->isBaseVirtual()); + EmitBaseInitializer(*this, ClassDecl, *B, CtorType); } InitializeVTablePointers(ClassDecl); + // And finally, initialize class members. ConstructorMemcpyizer CM(*this, CD, Args); - for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) - CM.addMemberInitializer(MemberInitializers[I]); + for (; B != E; B++) { + CXXCtorInitializer *Member = (*B); + assert(!Member->isBaseInitializer()); + assert(Member->isAnyMemberInitializer() && + "Delegating initializer on non-delegating constructor"); + CM.addMemberInitializer(Member); + } CM.finish(); } @@ -1622,6 +1639,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, Parent->getLocation()); } + // If this is a trivial constructor, just emit what's needed. if (D->isTrivial()) { if (ArgBeg == ArgEnd) { // Trivial default constructor, no codegen required. @@ -1641,14 +1659,9 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, return; } - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase, - Delegating); - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); - - // FIXME: Provide a source location here. - EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, - VTT, getContext().getPointerType(getContext().VoidPtrTy), - ArgBeg, ArgEnd); + // Non-trivial constructors are handled in an ABI-specific manner. + CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase, + Delegating, This, ArgBeg, ArgEnd); } void @@ -1718,7 +1731,7 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, ++I; // vtt - if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType), + if (llvm::Value *VTT = GetVTTParameter(GlobalDecl(Ctor, CtorType), /*ForVirtualBase=*/false, /*Delegating=*/true)) { QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); @@ -1792,7 +1805,7 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, bool ForVirtualBase, bool Delegating, llvm::Value *This) { - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type), + llvm::Value *VTT = GetVTTParameter(GlobalDecl(DD, Type), ForVirtualBase, Delegating); llvm::Value *Callee = 0; if (getLangOpts().AppleKext) diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 73a69b141d..b7ddc97a8a 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -813,8 +813,12 @@ CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) { EmitVTableDefinition(VTable, Linkage, RD); if (RD->getNumVBases()) { - llvm::GlobalVariable *VTT = GetAddrOfVTT(RD); - EmitVTTDefinition(VTT, Linkage, RD); + if (!CGM.getTarget().getCXXABI().isMicrosoft()) { + llvm::GlobalVariable *VTT = GetAddrOfVTT(RD); + EmitVTTDefinition(VTT, Linkage, RD); + } else { + // FIXME: Emit vbtables here. + } } // If this is the magic class __cxxabiv1::__fundamental_type_info, diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 880b82e924..6cb0b3304e 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1818,6 +1818,13 @@ public: const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl); + /// GetVTTParameter - Return the VTT parameter that should be passed to a + /// base constructor/destructor with virtual bases. + /// FIXME: VTTs are Itanium ABI-specific, so the definition should move + /// to ItaniumCXXABI.cpp together with all the references to VTT. + llvm::Value *GetVTTParameter(GlobalDecl GD, bool ForVirtualBase, + bool Delegating); + void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index bb2c93befc..7b1d8098aa 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -112,6 +112,14 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); + void 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 EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, @@ -826,6 +834,23 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); } +void ItaniumCXXABI::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) { + llvm::Value *VTT = CGF.GetVTTParameter(GlobalDecl(D, Type), ForVirtualBase, + Delegating); + QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy); + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); + + // FIXME: Provide a source location here. + CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, + VTT, VTTTy, ArgBeg, ArgEnd); +} + RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 6c9a6fdd61..fb6b86d878 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -42,6 +42,8 @@ public: CanQualType &ResTy, SmallVectorImpl<CanQualType> &ArgTys); + llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF); + void BuildDestructorSignature(const CXXDestructorDecl *Ctor, CXXDtorType Type, CanQualType &ResTy, @@ -53,6 +55,14 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); + void 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 EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, @@ -120,9 +130,36 @@ void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, CanQualType &ResTy, SmallVectorImpl<CanQualType> &ArgTys) { // 'this' is already in place - // TODO: 'for base' flag + // Ctor returns this ptr ResTy = ArgTys[0]; + + const CXXRecordDecl *Class = Ctor->getParent(); + if (Class->getNumVBases()) { + // Constructors of classes with virtual bases take an implicit parameter. + ArgTys.push_back(CGM.getContext().IntTy); + } +} + +llvm::BasicBlock *MicrosoftCXXABI::EmitCtorCompleteObjectHandler( + CodeGenFunction &CGF) { + llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF); + assert(IsMostDerivedClass && + "ctor for a class with virtual bases must have an implicit parameter"); + llvm::Value *IsCompleteObject + = CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object"); + + llvm::BasicBlock *CallVbaseCtorsBB = CGF.createBasicBlock("ctor.init_vbases"); + llvm::BasicBlock *SkipVbaseCtorsBB = CGF.createBasicBlock("ctor.skip_vbases"); + CGF.Builder.CreateCondBr(IsCompleteObject, + CallVbaseCtorsBB, SkipVbaseCtorsBB); + + CGF.EmitBlock(CallVbaseCtorsBB); + // FIXME: emit vbtables somewhere around here. + + // CGF will put the base ctor calls in this basic block for us later. + + return SkipVbaseCtorsBB; } void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, @@ -153,9 +190,18 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, if (needThisReturn(CGF.CurGD)) { ResTy = Params[0]->getType(); } - if (IsDeletingDtor(CGF.CurGD)) { - ASTContext &Context = getContext(); + ASTContext &Context = getContext(); + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); + if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) { + ImplicitParamDecl *IsMostDerived + = ImplicitParamDecl::Create(Context, 0, + CGF.CurGD.getDecl()->getLocation(), + &Context.Idents.get("is_most_derived"), + Context.IntTy); + Params.push_back(IsMostDerived); + getStructorImplicitParamDecl(CGF) = IsMostDerived; + } else if (IsDeletingDtor(CGF.CurGD)) { ImplicitParamDecl *ShouldDelete = ImplicitParamDecl::Create(Context, 0, CGF.CurGD.getDecl()->getLocation(), @@ -171,6 +217,17 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { if (needThisReturn(CGF.CurGD)) { CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); } + + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); + if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) { + assert(getStructorImplicitParamDecl(CGF) && + "no implicit parameter for a constructor with virtual bases?"); + getStructorImplicitParamValue(CGF) + = CGF.Builder.CreateLoad( + CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)), + "is_most_derived"); + } + if (IsDeletingDtor(CGF.CurGD)) { assert(getStructorImplicitParamDecl(CGF) && "no implicit parameter for a deleting destructor?"); @@ -181,6 +238,29 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { } } +void MicrosoftCXXABI::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) { + assert(Type == Ctor_Complete || Type == Ctor_Base); + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Ctor_Complete); + + llvm::Value *ImplicitParam = 0; + QualType ImplicitParamTy; + if (D->getParent()->getNumVBases()) { + ImplicitParam = llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete); + ImplicitParamTy = getContext().IntTy; + } + + // FIXME: Provide a source location here. + CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, + ImplicitParam, ImplicitParamTy, + ArgBeg, ArgEnd); +} + RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, |