EmitBlock(AfterFor, true);
}
+/// 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) {
+ if (!CGVtableInfo::needsVTTParameter(GD)) {
+ // This constructor/destructor does not need a VTT parameter.
+ return 0;
+ }
+
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent();
+ const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
+
+ llvm::Value *VTT;
+
+ uint64_t SubVTTIndex =
+ CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base);
+ assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
+
+ if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) {
+ // A VTT parameter was passed to the constructor, use it.
+ VTT = CGF.LoadCXXVTT();
+ VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
+ } else {
+ // We're the complete constructor, so get the VTT by name.
+ VTT = CGF.CGM.getVtableInfo().getVTT(RD);
+ VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
+ }
+
+ return VTT;
+}
+
+
/// EmitClassMemberwiseCopy - This routine generates code to copy a class
/// object from SrcValue to DestValue. Copying can be either a bitwise copy
/// or via a copy constructor call.
llvm::Value *Dest, llvm::Value *Src,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl, QualType Ty) {
+ CXXCtorType CtorType = Ctor_Complete;
+
if (ClassDecl) {
Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
/*NullCheckValue=*/false);
Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
/*NullCheckValue=*/false);
+
+ // We want to call the base constructor.
+ CtorType = Ctor_Base;
}
if (BaseClassDecl->hasTrivialCopyConstructor()) {
EmitAggregateCopy(Dest, Src, Ty);
if (CXXConstructorDecl *BaseCopyCtor =
BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
- Ctor_Complete);
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, CtorType);
CallArgList CallArgs;
// Push the this (Dest) ptr.
CallArgs.push_back(std::make_pair(RValue::get(Dest),
BaseCopyCtor->getThisType(getContext())));
+ // Push the VTT parameter, if necessary.
+ if (llvm::Value *VTT =
+ GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType))) {
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
+ CallArgs.push_back(std::make_pair(RValue::get(VTT), T));
+ }
+
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType()));
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8);
V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo());
- // FIXME: This should always use Ctor_Base as the ctor type! (But that
- // causes crashes in tests.)
CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
- CtorType, V,
+ Ctor_Base, V,
BaseInit->const_arg_begin(),
BaseInit->const_arg_end());
}
return m;
}
+
void
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CXXCtorType Type,
return;
}
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type));
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
- EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, ArgBeg, ArgEnd);
+ EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
}
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
llvm::Value *This) {
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type));
llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
- CallArgList Args;
-
- // Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This),
- DD->getThisType(getContext())));
-
- // Add a VTT parameter if necessary.
- // FIXME: This should not be a dummy null parameter!
- if (Type == Dtor_Base && DD->getParent()->getNumVBases() != 0) {
- QualType T = getContext().getPointerType(getContext().VoidPtrTy);
-
- Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T));
- }
-
- // FIXME: We should try to share this code with EmitCXXMemberCall.
-
- QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
- ReturnValueSlot(), Args, DD);
+ EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
}
llvm::Value *
// Store address point
Builder.CreateStore(VtableAddressPoint, VtableField);
}
+
+llvm::Value *CodeGenFunction::LoadCXXVTT() {
+ assert((isa<CXXConstructorDecl>(CurFuncDecl) ||
+ isa<CXXDestructorDecl>(CurFuncDecl)) &&
+ "Must be in a C++ ctor or dtor to load the vtt parameter");
+
+ return Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt");
+}
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
+ llvm::Value *VTT,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
assert(MD->isInstance() &&
Args.push_back(std::make_pair(RValue::get(This),
MD->getThisType(getContext())));
+ // If there is a VTT parameter, emit it.
+ if (VTT) {
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
+ Args.push_back(std::make_pair(RValue::get(VTT), T));
+ }
+
// And the rest of the call args
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
Callee = CGM.GetAddrOfFunction(MD, Ty);
}
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
+ return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
CE->arg_begin(), CE->arg_end());
}
else
Callee = CGM.GetAddrOfFunction(MD, Ty);
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
+ return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
E->arg_begin() + 1, E->arg_end());
}
/*isVariadic=*/false);
llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
- EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, 0, 0);
+ EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
+ 0, 0);
// The dtor took care of deleting the object.
ShouldCallDelete = false;
return VtableComponents;
}
- llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getVBIndex()
{ return VBIndex; }
SavedAdjustmentsVectorTy &getSavedAdjustments()
llvm::Constant *ClassVtbl;
llvm::LLVMContext &VMContext;
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+
+ bool GenerateDefinition;
+
/// BuildVtablePtr - Build up a referene to the given secondary vtable
llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable,
const CXXRecordDecl *VtableClass,
// FIXME: Slightly too many of these for __ZTT8test8_B2
llvm::Constant *init;
if (BaseMorallyVirtual)
- init = BuildVtablePtr(vtbl, VtblClass, RD, Offset);
+ init = GenerateDefinition ?
+ BuildVtablePtr(vtbl, VtblClass, RD, Offset) : 0;
else {
- init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset);
+ init = GenerateDefinition ?
+ CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset) : 0;
subvtbl = init;
subVtblClass = Base;
- init = BuildVtablePtr(init, Class, Base, BaseOffset);
+ init = GenerateDefinition ?
+ BuildVtablePtr(init, Class, Base, BaseOffset) : 0;
}
Inits.push_back(init);
}
// First comes the primary virtual table pointer...
if (MorallyVirtual) {
- Vtable = ClassVtbl;
+ Vtable = GenerateDefinition ? ClassVtbl : 0;
VtableClass = Class;
} else {
- Vtable = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset);
+ Vtable = GenerateDefinition ?
+ CGM.getVtableInfo().getCtorVtable(Class, RD, Offset) : 0;
VtableClass = RD;
}
- llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset);
+ llvm::Constant *Init = GenerateDefinition ?
+ BuildVtablePtr(Vtable, VtableClass, RD, Offset) : 0;
Inits.push_back(Init);
// then the secondary VTTs....
continue;
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+
+ // Remember the sub-VTT index.
+ SubVTTIndicies[Base] = Inits.size();
+
BuildVTT(Base, BaseOffset, MorallyVirtual);
}
}
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
if (i->isVirtual() && !SeenVBase.count(Base)) {
+ // Remember the sub-VTT index.
+ SubVTTIndicies[Base] = Inits.size();
+
SeenVBase.insert(Base);
uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
BuildVTT(Base, BaseOffset, true);
public:
VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
- CodeGenModule &cgm)
+ CodeGenModule &cgm, bool GenerateDefinition)
: Inits(inits), Class(c), CGM(cgm),
BLayout(cgm.getContext().getASTRecordLayout(c)),
AddressPoints(*cgm.AddressPoints[c]),
- VMContext(cgm.getModule().getContext()) {
+ VMContext(cgm.getModule().getContext()),
+ GenerateDefinition(GenerateDefinition) {
// First comes the primary virtual table pointer for the complete class...
ClassVtbl = CGM.getVtableInfo().getVtable(Class);
- Inits.push_back(BuildVtablePtr(ClassVtbl, Class, Class, 0));
+ llvm::Constant *Init = GenerateDefinition ?
+ BuildVtablePtr(ClassVtbl, Class, Class, 0) : 0;
+ Inits.push_back(Init);
// then the secondary VTTs...
SecondaryVTTs(Class);
// and last, the virtual VTTs.
VirtualVTTs(Class);
}
+
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() {
+ return SubVTTIndicies;
+ }
};
}
llvm::GlobalVariable *
CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
const CXXRecordDecl *RD) {
// Only classes that have virtual bases need a VTT.
if (RD->getNumVBases() == 0)
CGM.getMangleContext().mangleCXXVTT(RD, OutName);
llvm::StringRef Name = OutName.str();
-
D1(printf("vtt %s\n", RD->getNameAsCString()));
- std::vector<llvm::Constant *> inits;
- VTTBuilder b(inits, RD, CGM);
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV == 0 || GV->isDeclaration()) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
-
- llvm::Constant *Init = llvm::ConstantArray::get(Type, inits);
-
- llvm::GlobalVariable *VTT =
- new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
- Linkage, Init, Name);
- CGM.setGlobalVisibility(VTT, RD);
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder b(inits, RD, CGM, GenerateDefinition);
+
+ const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
+ llvm::Constant *Init = 0;
+ if (GenerateDefinition)
+ Init = llvm::ConstantArray::get(Type, inits);
+
+ llvm::GlobalVariable *OldGV = GV;
+ GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
+ Linkage, Init, Name);
+ CGM.setGlobalVisibility(GV, RD);
+
+ if (OldGV) {
+ GV->takeName(OldGV);
+ llvm::Constant *NewPtr =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtr);
+ OldGV->eraseFromParent();
+ }
+ }
- return VTT;
+ return GV;
}
void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
}
Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0);
- GenerateVTT(Linkage, RD);
+ GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
}
llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
LayoutClass, RD, Offset);
}
+llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) {
+ return GenerateVTT(llvm::GlobalValue::ExternalLinkage,
+ /*GenerateDefinition=*/false, RD);
+
+}
+
+
void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const CXXRecordDecl *RD = MD->getParent();
// We don't have the right key function.
if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
return;
-
- // If the key function is a destructor, we only want to emit the vtable
- // once, so do it for the complete destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete)
- return;
- } else {
- // If there is no key function, we only want to emit the vtable if we are
- // emitting a constructor.
- if (!isa<CXXConstructorDecl>(MD) || GD.getCtorType() != Ctor_Complete)
- return;
}
llvm::GlobalVariable::LinkageTypes Linkage;
}
}
+bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // We don't have any virtual bases, just return early.
+ if (!MD->getParent()->getNumVBases())
+ return false;
+
+ // Check if we have a base constructor.
+ if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
+ return true;
+
+ // Check if we have a base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return true;
+
+ return false;
+}
+
+uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Base) {
+ ClassPairTy ClassPair(RD, Base);
+
+ SubVTTIndiciesTy::iterator I =
+ SubVTTIndicies.find(ClassPair);
+ if (I != SubVTTIndicies.end())
+ return I->second;
+
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false);
+
+ for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ Builder.getSubVTTIndicies().begin(),
+ E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
+ // Insert all indices.
+ ClassPairTy ClassPair(RD, I->first);
+
+ SubVTTIndicies.insert(std::make_pair(ClassPair, I->second));
+ }
+
+ I = SubVTTIndicies.find(ClassPair);
+ assert(I != SubVTTIndicies.end() && "Did not find index!");
+
+ return I->second;
+}
SavedAdjustmentsTy SavedAdjustments;
llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords;
+ typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesTy;
+ SubVTTIndiciesTy SubVTTIndicies;
+
/// getNumVirtualFunctionPointers - Return the number of virtual function
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
const CXXRecordDecl *RD, uint64_t Offset);
llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
const CXXRecordDecl *RD);
public:
CGVtableInfo(CodeGenModule &CGM)
: CGM(CGM) { }
+ /// needsVTTParameter - Return whether the given global decl needs a VTT
+ /// parameter, which it does if it's a base constructor or destructor with
+ /// virtual bases.
+ static bool needsVTTParameter(GlobalDecl GD);
+
+ /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
+ /// given record decl.
+ uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base);
+
/// getMethodVtableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
const CXXRecordDecl *Class,
uint64_t Offset);
+ llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD);
void MaybeEmitVtable(GlobalDecl GD);
};
}
}
-static bool NeedsVTTParameter(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // We don't have any virtual bases, just return early.
- if (!MD->getParent()->getNumVBases())
- return false;
-
- // Check if we have a base constructor.
- if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
- return true;
-
- // Check if we have a base destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
- return true;
-
- return false;
-}
-
-void CodeGenFunction::GenerateCode(GlobalDecl GD,
- llvm::Function *Fn) {
+void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
// Check if we should generate debug info for this function.
Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
// Check if we need a VTT parameter as well.
- if (NeedsVTTParameter(GD)) {
+ if (CGVtableInfo::needsVTTParameter(GD)) {
// FIXME: The comment about using a fake decl above applies here too.
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
CXXVTTDecl =
/// generating code for an C++ member function.
llvm::Value *LoadCXXThis();
+ /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
+ /// virtual bases.
+ llvm::Value *LoadCXXVTT();
+
/// GetAddressOfBaseClass - This function will add the necessary delta to the
/// load of 'this' and returns address of the base class.
// FIXME. This currently only does a derived to non-virtual base conversion.
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
+ llvm::Value *VTT,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
delete node;
}
-// CHECK-LP64: __ZN4NodeIP12BinomialNodeIiEEC1Ev:
+// CHECK-LP64: __ZN4NodeIP12BinomialNodeIiEEC2Ev:
// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEEC1Ev:
// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED1Ev:
-// CHECK-LP32: __ZN4NodeIP12BinomialNodeIiEEC1Ev:
+// CHECK-LP32: __ZN4NodeIP12BinomialNodeIiEEC2Ev:
// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEEC1Ev:
// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED1Ev:
struct B : public A {};
B x;
-// CHECK: call void @_ZN1AC1Ei
+// CHECK: call void @_ZN1AC2Ei
virtual ~B();
};
+// Complete dtor.
+// CHECK: define void @_ZN1BD1Ev
+// CHECK: call void @_ZN1AD2Ev
+
// Deleting dtor.
// CHECK: define void @_ZN1BD0Ev
// CHECK: call void @_ZN1AD2Ev
// check: call void @_ZdlPv
-// Complete dtor.
-// CHECK: define void @_ZN1BD1Ev
-// CHECK: call void @_ZN1AD2Ev
-
// Base dtor.
// CHECK: define void @_ZN1BD2Ev
// CHECK: call void @_ZN1AD2Ev