diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp new file mode 100644 index 0000000..61c7423 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp @@ -0,0 +1,487 @@ +//===--- CGVTT.cpp - Emit LLVM Code for C++ VTTs --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of VTTs (vtable tables). +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "clang/AST/RecordLayout.h" +using namespace clang; +using namespace CodeGen; + +#define D1(x) + +namespace { + +/// VTT builder - Class for building VTT layout information. +class VTTBuilder { + + CodeGenModule &CGM; + + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + typedef llvm::SmallVector<llvm::Constant *, 64> VTTComponentsVectorTy; + + /// VTTComponents - The VTT components. + VTTComponentsVectorTy VTTComponents; + + /// MostDerivedClassLayout - the AST record layout of the most derived class. + const ASTRecordLayout &MostDerivedClassLayout; + + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; + + typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; + + /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived + /// class. + llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies; + + /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of + /// all subobjects of the most derived class. + llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices; + + /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for + /// the VTT. + bool GenerateDefinition; + + /// GetAddrOfVTable - Returns the address of the vtable for the base class in + /// the given vtable class. + /// + /// \param AddressPoints - If the returned vtable is a construction vtable, + /// this will hold the address points for it. + llvm::Constant *GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual, + AddressPointsMapTy& AddressPoints); + + /// AddVTablePointer - Add a vtable pointer to the VTT currently being built. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + const AddressPointsMapTy& AddressPoints); + + /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base + /// subobject. + void LayoutSecondaryVTTs(BaseSubobject Base); + + /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers + /// for the given base subobject. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void LayoutSecondaryVirtualPointers(BaseSubobject Base, + bool BaseIsMorallyVirtual, + llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + const AddressPointsMapTy& AddressPoints, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers + /// for the given base subobject. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void LayoutSecondaryVirtualPointers(BaseSubobject Base, + llvm::Constant *VTable, + const AddressPointsMapTy& AddressPoints); + + /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the + /// given record decl. + void LayoutVirtualVTTs(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutVTT - Will lay out the VTT for the given subobject, including any + /// secondary VTTs, secondary virtual pointers and virtual VTTs. + void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual); + +public: + VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass, + bool GenerateDefinition); + + // getVTTComponents - Returns a reference to the VTT components. + const VTTComponentsVectorTy &getVTTComponents() const { + return VTTComponents; + } + + /// getSubVTTIndicies - Returns a reference to the sub-VTT indices. + const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const { + return SubVTTIndicies; + } + + /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary + /// virtual pointer indices. + const llvm::DenseMap<BaseSubobject, uint64_t> & + getSecondaryVirtualPointerIndices() const { + return SecondaryVirtualPointerIndices; + } + +}; + +VTTBuilder::VTTBuilder(CodeGenModule &CGM, + const CXXRecordDecl *MostDerivedClass, + bool GenerateDefinition) + : CGM(CGM), MostDerivedClass(MostDerivedClass), + MostDerivedClassLayout(CGM.getContext().getASTRecordLayout(MostDerivedClass)), + GenerateDefinition(GenerateDefinition) { + + // Lay out this VTT. + LayoutVTT(BaseSubobject(MostDerivedClass, 0), /*BaseIsVirtual=*/false); +} + +llvm::Constant * +VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual, + AddressPointsMapTy& AddressPoints) { + if (!GenerateDefinition) + return 0; + + if (Base.getBase() == MostDerivedClass) { + assert(Base.getBaseOffset() == 0 && + "Most derived class vtable must have a zero offset!"); + // This is a regular vtable. + return CGM.getVTables().GetAddrOfVTable(MostDerivedClass); + } + + return CGM.getVTables().GenerateConstructionVTable(MostDerivedClass, + Base, BaseIsVirtual, + AddressPoints); +} + +void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + const AddressPointsMapTy& AddressPoints) { + // Store the vtable pointer index if we're generating the primary VTT. + if (VTableClass == MostDerivedClass) { + assert(!SecondaryVirtualPointerIndices.count(Base) && + "A virtual pointer index already exists for this base subobject!"); + SecondaryVirtualPointerIndices[Base] = VTTComponents.size(); + } + + if (!GenerateDefinition) { + VTTComponents.push_back(0); + return; + } + + uint64_t AddressPoint; + if (VTableClass != MostDerivedClass) { + // The vtable is a construction vtable, look in the construction vtable + // address points. + AddressPoint = AddressPoints.lookup(Base); + assert(AddressPoint != 0 && "Did not find ctor vtable address point!"); + } else { + // Just get the address point for the regular vtable. + AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass); + assert(AddressPoint != 0 && "Did not find vtable address point!"); + } + + if (!AddressPoint) AddressPoint = 0; + + llvm::Value *Idxs[] = { + llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), + AddressPoint) + }; + + llvm::Constant *Init = + llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs, 2); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); + + VTTComponents.push_back(Init); +} + +void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { + const CXXRecordDecl *RD = Base.getBase(); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + // Don't layout virtual bases. + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + uint64_t BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + // Layout the VTT for this base. + LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); + } +} + +void +VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, + bool BaseIsMorallyVirtual, + llvm::Constant *VTable, + const CXXRecordDecl *VTableClass, + const AddressPointsMapTy& AddressPoints, + VisitedVirtualBasesSetTy &VBases) { + const CXXRecordDecl *RD = Base.getBase(); + + // We're not interested in bases that don't have virtual bases, and not + // morally virtual bases. + if (!RD->getNumVBases() && !BaseIsMorallyVirtual) + return; + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Itanium C++ ABI 2.6.2: + // Secondary virtual pointers are present for all bases with either + // virtual bases or virtual function declarations overridden along a + // virtual path. + // + // If the base class is not dynamic, we don't want to add it, nor any + // of its base classes. + if (!BaseDecl->isDynamicClass()) + continue; + + bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; + bool BaseDeclIsNonVirtualPrimaryBase = false; + uint64_t BaseOffset; + if (I->isVirtual()) { + // Ignore virtual bases that we've already visited. + if (!VBases.insert(BaseDecl)) + continue; + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + BaseDeclIsMorallyVirtual = true; + } else { + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); + + if (!Layout.getPrimaryBaseWasVirtual() && + Layout.getPrimaryBase() == BaseDecl) + BaseDeclIsNonVirtualPrimaryBase = true; + } + + // Itanium C++ ABI 2.6.2: + // Secondary virtual pointers: for each base class X which (a) has virtual + // bases or is reachable along a virtual path from D, and (b) is not a + // non-virtual primary base, the address of the virtual table for X-in-D + // or an appropriate construction virtual table. + if (!BaseDeclIsNonVirtualPrimaryBase && + (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) { + // Add the vtable pointer. + AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable, VTableClass, + AddressPoints); + } + + // And lay out the secondary virtual pointers for the base class. + LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset), + BaseDeclIsMorallyVirtual, VTable, + VTableClass, AddressPoints, VBases); + } +} + +void +VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, + llvm::Constant *VTable, + const AddressPointsMapTy& AddressPoints) { + VisitedVirtualBasesSetTy VBases; + LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false, + VTable, Base.getBase(), AddressPoints, VBases); +} + +void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Check if this is a virtual base. + if (I->isVirtual()) { + // Check if we've seen this base before. + if (!VBases.insert(BaseDecl)) + continue; + + uint64_t BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true); + } + + // We only need to layout virtual VTTs for this base if it actually has + // virtual bases. + if (BaseDecl->getNumVBases()) + LayoutVirtualVTTs(BaseDecl, VBases); + } +} + +void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { + const CXXRecordDecl *RD = Base.getBase(); + + // Itanium C++ ABI 2.6.2: + // An array of virtual table addresses, called the VTT, is declared for + // each class type that has indirect or direct virtual base classes. + if (RD->getNumVBases() == 0) + return; + + bool IsPrimaryVTT = Base.getBase() == MostDerivedClass; + + if (!IsPrimaryVTT) { + // Remember the sub-VTT index. + SubVTTIndicies[Base] = VTTComponents.size(); + } + + AddressPointsMapTy AddressPoints; + llvm::Constant *VTable = GetAddrOfVTable(Base, BaseIsVirtual, AddressPoints); + + // Add the primary vtable pointer. + AddVTablePointer(Base, VTable, RD, AddressPoints); + + // Add the secondary VTTs. + LayoutSecondaryVTTs(Base); + + // Add the secondary virtual pointers. + LayoutSecondaryVirtualPointers(Base, VTable, AddressPoints); + + // If this is the primary VTT, we want to lay out virtual VTTs as well. + if (IsPrimaryVTT) { + VisitedVirtualBasesSetTy VBases; + LayoutVirtualVTTs(Base.getBase(), VBases); + } +} + +} + +llvm::GlobalVariable * +CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, + const CXXRecordDecl *RD) { + // Only classes that have virtual bases need a VTT. + if (RD->getNumVBases() == 0) + return 0; + + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXVTT(RD, OutName); + llvm::StringRef Name = OutName.str(); + + D1(printf("vtt %s\n", RD->getNameAsCString())); + + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true); + if (GV == 0 || GV->isDeclaration()) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + + VTTBuilder Builder(CGM, RD, GenerateDefinition); + + const llvm::ArrayType *Type = + llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size()); + + llvm::Constant *Init = 0; + if (GenerateDefinition) + Init = llvm::ConstantArray::get(Type, Builder.getVTTComponents().data(), + Builder.getVTTComponents().size()); + + 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 GV; +} + +llvm::GlobalVariable *CodeGenVTables::getVTT(const CXXRecordDecl *RD) { + return GenerateVTT(llvm::GlobalValue::ExternalLinkage, + /*GenerateDefinition=*/false, RD); +} + +bool CodeGenVTables::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 CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD, + BaseSubobject Base) { + BaseSubobjectPairTy ClassSubobjectPair(RD, Base); + + SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair); + if (I != SubVTTIndicies.end()) + return I->second; + + VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); + + for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I = + Builder.getSubVTTIndicies().begin(), + E = Builder.getSubVTTIndicies().end(); I != E; ++I) { + // Insert all indices. + BaseSubobjectPairTy ClassSubobjectPair(RD, I->first); + + SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second)); + } + + I = SubVTTIndicies.find(ClassSubobjectPair); + assert(I != SubVTTIndicies.end() && "Did not find index!"); + + return I->second; +} + +uint64_t +CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, + BaseSubobject Base) { + SecondaryVirtualPointerIndicesMapTy::iterator I = + SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base)); + + if (I != SecondaryVirtualPointerIndices.end()) + return I->second; + + VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); + + // Insert all secondary vpointer indices. + for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I = + Builder.getSecondaryVirtualPointerIndices().begin(), + E = Builder.getSecondaryVirtualPointerIndices().end(); I != E; ++I) { + std::pair<const CXXRecordDecl *, BaseSubobject> Pair = + std::make_pair(RD, I->first); + + SecondaryVirtualPointerIndices.insert(std::make_pair(Pair, I->second)); + } + + I = SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base)); + assert(I != SecondaryVirtualPointerIndices.end() && "Did not find index!"); + + return I->second; +} + |