aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
authorTimur Iskhodzhanov <timurrrr@google.com>2013-02-27 13:46:31 +0000
committerTimur Iskhodzhanov <timurrrr@google.com>2013-02-27 13:46:31 +0000
commit1d4fff5551c2347010b955b4337a2aa7d65a050e (patch)
tree23af51dbdbd07e651243307dbf3f1defb03c0ea8 /lib/CodeGen
parent0cc798f29d489140dd81b558e9c052e9a83cce39 (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.cpp6
-rw-r--r--lib/CodeGen/CGCXXABI.cpp9
-rw-r--r--lib/CodeGen/CGCXXABI.h10
-rw-r--r--lib/CodeGen/CGClass.cpp99
-rw-r--r--lib/CodeGen/CGVTables.cpp8
-rw-r--r--lib/CodeGen/CodeGenFunction.h7
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp25
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp86
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,