Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ class CIRGenCXXABI {
virtual void emitVTableDefinitions(CIRGenVTables &cgvt,
const CXXRecordDecl *rd) = 0;

/// Emit any tables needed to implement virtual inheritance. For Itanium,
/// this emits virtual table tables.
virtual void emitVirtualInheritanceTables(const CXXRecordDecl *rd) = 0;

/// Returns true if the given destructor type should be emitted as a linkonce
/// delegating thunk, regardless of whether the dtor is defined in this TU or
/// not.
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
const clang::CXXRecordDecl *nearestVBase) override;
void emitVTableDefinitions(CIRGenVTables &cgvt,
const CXXRecordDecl *rd) override;
void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;

bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
return true;
Expand Down Expand Up @@ -333,6 +334,13 @@ void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt,
}
}

void CIRGenItaniumCXXABI::emitVirtualInheritanceTables(
const CXXRecordDecl *rd) {
CIRGenVTables &vtables = cgm.getVTables();
cir::GlobalOp vtt = vtables.getAddrOfVTT(rd);
vtables.emitVTTDefinition(vtt, cgm.getVTableLinkage(rd), rd);
}

void CIRGenItaniumCXXABI::emitDestructorCall(
CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
Expand Down
180 changes: 173 additions & 7 deletions clang/lib/CIR/CodeGen/CIRGenVTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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);
}
Expand All @@ -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();
Expand All @@ -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());
Expand Down Expand Up @@ -175,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.
Expand Down Expand Up @@ -226,6 +289,109 @@ 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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of using [[maybe_unused]] here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that can be used here. It can only be applied to declarations.


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);
}

void CIRGenVTables::emitThunks(GlobalDecl gd) {
const CXXMethodDecl *md =
cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl();
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenVTables.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class CIRGenVTables {

clang::VTableContextBase *vtContext;

/// Address points for a single vtable.
using VTableAddressPointsMapTy = clang::VTableLayout::AddressPointsMapTy;

mlir::Attribute
getVTableComponent(const VTableLayout &layout, unsigned componentIndex,
mlir::Attribute rtti, unsigned &nextVTableThunkIndex,
Expand All @@ -55,6 +58,19 @@ class CIRGenVTables {
return *llvm::cast<clang::ItaniumVTableContext>(vtContext);
}

/// Generate a construction vtable for the given base subobject.
cir::GlobalOp
generateConstructionVTable(const CXXRecordDecl *rd, const BaseSubobject &base,
bool baseIsVirtual, cir::GlobalLinkageKind linkage,
VTableAddressPointsMapTy &addressPoints);

/// Get the address of the VTT for the given record decl.
cir::GlobalOp getAddrOfVTT(const CXXRecordDecl *rd);

/// Emit the definition of the given vtable.
void emitVTTDefinition(cir::GlobalOp vttOp, cir::GlobalLinkageKind linkage,
const CXXRecordDecl *rd);

/// Emit the associated thunks for the given global decl.
void emitThunks(GlobalDecl gd);

Expand Down
9 changes: 0 additions & 9 deletions clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@ void CIRDataLayout::reset(mlir::DataLayoutSpecInterface spec) {
}

llvm::Align CIRDataLayout::getAlignment(mlir::Type ty, bool useABIAlign) const {
if (auto recTy = llvm::dyn_cast<cir::RecordType>(ty)) {
// Packed record types always have an ABI alignment of one.
if (recTy && recTy.getPacked() && useABIAlign)
return llvm::Align(1);

// Get the layout annotation... which is lazily created on demand.
llvm_unreachable("getAlignment()) for record type is not implemented");
}

// FIXME(cir): This does not account for differnt address spaces, and relies
// on CIR's data layout to give the proper alignment.
assert(!cir::MissingFeatures::addressSpace());
Expand Down
Loading