summaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenVTables.cpp')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenVTables.cpp267
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();