diff options
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenVTables.cpp')
| -rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenVTables.cpp | 267 |
1 files changed, 237 insertions, 30 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp index 438b483ccb9c..af8f5ae2cc0a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp @@ -15,6 +15,7 @@ #include "CIRGenCXXABI.h" #include "CIRGenModule.h" #include "mlir/IR/Types.h" +#include "clang/AST/VTTBuilder.h" #include "clang/AST/VTableBuilder.h" #include "llvm/ADT/SmallVector.h" @@ -60,7 +61,7 @@ void CIRGenVTables::generateClassData(const CXXRecordDecl *rd) { assert(!cir::MissingFeatures::generateDebugInfo()); if (rd->getNumVBases()) - cgm.errorNYI(rd->getSourceRange(), "emitVirtualInheritanceTables"); + cgm.getCXXABI().emitVirtualInheritanceTables(rd); cgm.getCXXABI().emitVTableDefinitions(*this, rd); } @@ -76,12 +77,6 @@ mlir::Attribute CIRGenVTables::getVTableComponent( assert(!cir::MissingFeatures::vtableRelativeLayout()); switch (component.getKind()) { - case VTableComponent::CK_VCallOffset: - cgm.errorNYI("getVTableComponent: VCallOffset"); - return mlir::Attribute(); - case VTableComponent::CK_VBaseOffset: - cgm.errorNYI("getVTableComponent: VBaseOffset"); - return mlir::Attribute(); case VTableComponent::CK_CompleteDtorPointer: cgm.errorNYI("getVTableComponent: CompleteDtorPointer"); return mlir::Attribute(); @@ -92,6 +87,14 @@ mlir::Attribute CIRGenVTables::getVTableComponent( cgm.errorNYI("getVTableComponent: UnusedFunctionPointer"); return mlir::Attribute(); + case VTableComponent::CK_VCallOffset: + return builder.getConstPtrAttr(builder.getUInt8PtrTy(), + component.getVCallOffset().getQuantity()); + + case VTableComponent::CK_VBaseOffset: + return builder.getConstPtrAttr(builder.getUInt8PtrTy(), + component.getVBaseOffset().getQuantity()); + case VTableComponent::CK_OffsetToTop: return builder.getConstPtrAttr(builder.getUInt8PtrTy(), component.getOffsetToTop().getQuantity()); @@ -144,33 +147,28 @@ void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp, layout.getAddressPointIndices(); unsigned nextVTableThunkIndex = 0; - if (layout.getNumVTables() > 1) - cgm.errorNYI("emitVTableDefinitions: multiple vtables"); - - // We'll need a loop here to handle multiple vtables, but for now we only - // support one. - unsigned vtableIndex = 0; - size_t vtableStart = layout.getVTableOffset(vtableIndex); - size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex); - - // Build a ConstArrayAttr of the vtable components. - llvm::SmallVector<mlir::Attribute> components; - for (size_t componentIndex = vtableStart; componentIndex < vtableEnd; - ++componentIndex) { - components.push_back( - getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex, - addressPoints[vtableIndex], vtableHasLocalLinkage)); - } - mlir::MLIRContext *mlirContext = &cgm.getMLIRContext(); - // Create a ConstArrayAttr to hold the components. - auto arr = cir::ConstArrayAttr::get( - cir::ArrayType::get(componentType, components.size()), - mlir::ArrayAttr::get(mlirContext, components)); + SmallVector<mlir::Attribute> vtables; + for (auto [vtableIndex, addressPoint] : llvm::enumerate(addressPoints)) { + // Build a ConstArrayAttr of the vtable components. + size_t vtableStart = layout.getVTableOffset(vtableIndex); + size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex); + llvm::SmallVector<mlir::Attribute> components; + components.reserve(vtableEnd - vtableStart); + for (size_t componentIndex : llvm::seq(vtableStart, vtableEnd)) + components.push_back( + getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex, + addressPoint, vtableHasLocalLinkage)); + // Create a ConstArrayAttr to hold the components. + auto arr = cir::ConstArrayAttr::get( + cir::ArrayType::get(componentType, components.size()), + mlir::ArrayAttr::get(mlirContext, components)); + vtables.push_back(arr); + } // Create a ConstRecordAttr to hold the component array. - const auto members = mlir::ArrayAttr::get(mlirContext, {arr}); + const auto members = mlir::ArrayAttr::get(mlirContext, vtables); cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members); // Create a VTableAttr @@ -180,6 +178,66 @@ void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp, cgm.setInitializer(vtableOp, vtableAttr); } +cir::GlobalOp CIRGenVTables::generateConstructionVTable( + const CXXRecordDecl *rd, const BaseSubobject &base, bool baseIsVirtual, + cir::GlobalLinkageKind linkage, VTableAddressPointsMapTy &addressPoints) { + assert(!cir::MissingFeatures::generateDebugInfo()); + + std::unique_ptr<VTableLayout> vtLayout( + getItaniumVTableContext().createConstructionVTableLayout( + base.getBase(), base.getBaseOffset(), baseIsVirtual, rd)); + + // Add the address points. + addressPoints = vtLayout->getAddressPoints(); + + // Get the mangled construction vtable name. + SmallString<256> outName; + llvm::raw_svector_ostream out(outName); + cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext()) + .mangleCXXCtorVTable(rd, base.getBaseOffset().getQuantity(), + base.getBase(), out); + SmallString<256> name(outName); + + assert(!cir::MissingFeatures::vtableRelativeLayout()); + + cir::RecordType vtType = getVTableType(*vtLayout); + + // Construction vtable symbols are not part of the Itanium ABI, so we cannot + // guarantee that they actually will be available externally. Instead, when + // emitting an available_externally VTT, we provide references to an internal + // linkage construction vtable. The ABI only requires complete-object vtables + // to be the same for all instances of a type, not construction vtables. + if (linkage == cir::GlobalLinkageKind::AvailableExternallyLinkage) + linkage = cir::GlobalLinkageKind::InternalLinkage; + + llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtType); + mlir::Location loc = cgm.getLoc(rd->getSourceRange()); + + // Create the variable that will hold the construction vtable. + cir::GlobalOp vtable = cgm.createOrReplaceCXXRuntimeVariable( + loc, name, vtType, linkage, CharUnits::fromQuantity(align)); + + // V-tables are always unnamed_addr. + assert(!cir::MissingFeatures::opGlobalUnnamedAddr()); + + mlir::Attribute rtti = cgm.getAddrOfRTTIDescriptor( + loc, cgm.getASTContext().getCanonicalTagType(base.getBase())); + + // Create and set the initializer. + createVTableInitializer(vtable, *vtLayout, rtti, + cir::isLocalLinkage(vtable.getLinkage())); + + // Set properties only after the initializer has been set to ensure that the + // GV is treated as definition and not declaration. + assert(!vtable.isDeclaration() && "Shouldn't set properties on declaration"); + cgm.setGVProperties(vtable, rd); + + assert(!cir::MissingFeatures::vtableEmitMetadata()); + assert(!cir::MissingFeatures::vtableRelativeLayout()); + + return vtable; +} + /// Compute the required linkage of the vtable for the given class. /// /// Note that we only call this at the end of the translation unit. @@ -231,6 +289,155 @@ cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) { return cir::GlobalLinkageKind::ExternalLinkage; } +cir::GlobalOp CIRGenVTables::getAddrOfVTT(const CXXRecordDecl *rd) { + assert(rd->getNumVBases() && "Only classes with virtual bases need a VTT"); + + SmallString<256> outName; + llvm::raw_svector_ostream out(outName); + cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext()) + .mangleCXXVTT(rd, out); + StringRef name = outName.str(); + + // This will also defer the definition of the VTT. + (void)cgm.getCXXABI().getAddrOfVTable(rd, CharUnits()); + + VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false); + + auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(), + builder.getVTTComponents().size()); + llvm::Align align = + cgm.getDataLayout().getABITypeAlign(cgm.getBuilder().getUInt8PtrTy()); + cir::GlobalOp vtt = cgm.createOrReplaceCXXRuntimeVariable( + cgm.getLoc(rd->getSourceRange()), name, arrayType, + cir::GlobalLinkageKind::ExternalLinkage, CharUnits::fromQuantity(align)); + cgm.setGVProperties(vtt, rd); + return vtt; +} + +static cir::GlobalOp +getAddrOfVTTVTable(CIRGenVTables &cgvt, CIRGenModule &cgm, + const CXXRecordDecl *mostDerivedClass, + const VTTVTable &vtable, cir::GlobalLinkageKind linkage, + VTableLayout::AddressPointsMapTy &addressPoints) { + if (vtable.getBase() == mostDerivedClass) { + assert(vtable.getBaseOffset().isZero() && + "Most derived class vtable must have a zero offset!"); + // This is a regular vtable. + return cgm.getCXXABI().getAddrOfVTable(mostDerivedClass, CharUnits()); + } + return cgvt.generateConstructionVTable( + mostDerivedClass, vtable.getBaseSubobject(), vtable.isVirtual(), linkage, + addressPoints); +} + +/// Emit the definition of the given vtable. +void CIRGenVTables::emitVTTDefinition(cir::GlobalOp vttOp, + cir::GlobalLinkageKind linkage, + const CXXRecordDecl *rd) { + VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/true); + + mlir::MLIRContext *mlirContext = &cgm.getMLIRContext(); + + auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(), + builder.getVTTComponents().size()); + + SmallVector<cir::GlobalOp> vtables; + SmallVector<VTableAddressPointsMapTy> vtableAddressPoints; + for (const VTTVTable &vtt : builder.getVTTVTables()) { + vtableAddressPoints.push_back(VTableAddressPointsMapTy()); + vtables.push_back(getAddrOfVTTVTable(*this, cgm, rd, vtt, linkage, + vtableAddressPoints.back())); + } + + SmallVector<mlir::Attribute> vttComponents; + for (const VTTComponent &vttComponent : builder.getVTTComponents()) { + const VTTVTable &vttVT = builder.getVTTVTables()[vttComponent.VTableIndex]; + cir::GlobalOp vtable = vtables[vttComponent.VTableIndex]; + VTableLayout::AddressPointLocation addressPoint; + if (vttVT.getBase() == rd) { + // Just get the address point for the regular vtable. + addressPoint = + getItaniumVTableContext().getVTableLayout(rd).getAddressPoint( + vttComponent.VTableBase); + } else { + addressPoint = vtableAddressPoints[vttComponent.VTableIndex].lookup( + vttComponent.VTableBase); + assert(addressPoint.AddressPointIndex != 0 && + "Did not find ctor vtable address point!"); + } + + mlir::Attribute indices[2] = { + cgm.getBuilder().getI32IntegerAttr(addressPoint.VTableIndex), + cgm.getBuilder().getI32IntegerAttr(addressPoint.AddressPointIndex), + }; + + auto indicesAttr = mlir::ArrayAttr::get(mlirContext, indices); + cir::GlobalViewAttr init = cgm.getBuilder().getGlobalViewAttr( + cgm.getBuilder().getUInt8PtrTy(), vtable, indicesAttr); + + vttComponents.push_back(init); + } + + auto init = cir::ConstArrayAttr::get( + arrayType, mlir::ArrayAttr::get(mlirContext, vttComponents)); + + vttOp.setInitialValueAttr(init); + + // Set the correct linkage. + vttOp.setLinkage(linkage); + mlir::SymbolTable::setSymbolVisibility( + vttOp, CIRGenModule::getMLIRVisibility(vttOp)); + + if (cgm.supportsCOMDAT() && vttOp.isWeakForLinker()) + vttOp.setComdat(true); +} + +uint64_t CIRGenVTables::getSubVTTIndex(const CXXRecordDecl *rd, + BaseSubobject base) { + BaseSubobjectPairTy classSubobjectPair(rd, base); + + SubVTTIndiciesMapTy::iterator it = subVTTIndicies.find(classSubobjectPair); + if (it != subVTTIndicies.end()) + return it->second; + + VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false); + + for (const auto &entry : builder.getSubVTTIndices()) { + // Insert all indices. + BaseSubobjectPairTy subclassSubobjectPair(rd, entry.first); + + subVTTIndicies.insert(std::make_pair(subclassSubobjectPair, entry.second)); + } + + it = subVTTIndicies.find(classSubobjectPair); + assert(it != subVTTIndicies.end() && "Did not find index!"); + + return it->second; +} + +uint64_t CIRGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *rd, + BaseSubobject base) { + auto it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base)); + + if (it != secondaryVirtualPointerIndices.end()) + return it->second; + + VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false); + + // Insert all secondary vpointer indices. + for (const auto &entry : builder.getSecondaryVirtualPointerIndices()) { + std::pair<const CXXRecordDecl *, BaseSubobject> pair = + std::make_pair(rd, entry.first); + + secondaryVirtualPointerIndices.insert(std::make_pair(pair, entry.second)); + } + + it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base)); + assert(it != secondaryVirtualPointerIndices.end() && "Did not find index!"); + + return it->second; +} + void CIRGenVTables::emitThunks(GlobalDecl gd) { const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl(); |
