Skip to content

Commit

Permalink
[CIR][Codegen] VTT support for virtual class inheritance (#252)
Browse files Browse the repository at this point in the history
This patch brings up the basic support for C++ virtual inheritance. VTT
(virtual table table) now can be laid out as expected for simple program
with single virtual inheritance. RTTI support is on the way.

This patch does not include LLVM lowering support.
  • Loading branch information
htyu authored and lanza committed Sep 13, 2023
1 parent 952e4cb commit 4074112
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 32 deletions.
11 changes: 11 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ class CIRGenCXXABI {
/// Emits the VTable definitions required for the given record type.
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;

virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
QualType Ty) = 0;
virtual CatchTypeInfo
Expand Down Expand Up @@ -280,6 +285,12 @@ class CIRGenCXXABI {
// directly or require access through a thread wrapper function.
virtual bool usesThreadWrapperFunction(const VarDecl *VD) const = 0;

/// Emit the code to initialize hidden members required to handle virtual
/// inheritance, if needed by the ABI.
virtual void
initializeHiddenVirtualInheritanceMembers(CIRGenFunction &CGF,
const CXXRecordDecl *RD) {}

/// Emit a single constructor/destructor with the gien type from a C++
/// constructor Decl.
virtual void buildCXXStructor(clang::GlobalDecl GD) = 0;
Expand Down
22 changes: 13 additions & 9 deletions clang/lib/CIR/CodeGen/CIRGenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ bool CIRGenFunction::IsConstructorDelegationValid(
// };
// ...although even this example could in principle be emitted as a delegation
// since the address of the parameter doesn't escape.
if (Ctor->getParent()->getNumVBases()) {
llvm_unreachable("NYI");
}
if (Ctor->getParent()->getNumVBases())
return false;

// We also disable the optimization for variadic functions because it's
// impossible to "re-pass" varargs.
Expand Down Expand Up @@ -236,7 +235,7 @@ static void buildMemberInitializer(CIRGenFunction &CGF,
if (CGF.CurGD.getCtorType() == Ctor_Base)
LHS = CGF.MakeNaturalAlignPointeeAddrLValue(ThisPtr, RecordTy);
else
llvm_unreachable("NYI");
LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);

buildLValueForAnyFieldInitialization(CGF, MemberInit, LHS);

Expand Down Expand Up @@ -524,9 +523,10 @@ Address CIRGenFunction::getAddressOfDirectBaseInCompleteClass(
// TODO: for complete types, this should be possible with a GEP.
Address V = This;
if (!Offset.isZero()) {
// TODO(cir): probably create a new operation to account for
// down casting when the offset isn't zero.
llvm_unreachable("NYI");
mlir::Value OffsetVal = builder.getSInt32(Offset.getQuantity(), loc);
mlir::Value VBaseThisPtr = builder.create<mlir::cir::PtrStrideOp>(
loc, This.getPointer().getType(), This.getPointer(), OffsetVal);
V = Address(VBaseThisPtr, CXXABIThisAlignment);
}
V = builder.createElementBitCast(loc, V, ConvertType(Base));
return V;
Expand Down Expand Up @@ -605,7 +605,11 @@ void CIRGenFunction::buildCtorPrologue(const CXXConstructorDecl *CD,
for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) {
if (!ConstructVBases)
continue;
llvm_unreachable("NYI");
if (CGM.getCodeGenOpts().StrictVTablePointers &&
CGM.getCodeGenOpts().OptimizationLevel > 0 &&
isInitializerOfDynamicClass(*B))
llvm_unreachable("NYI");
buildBaseInitializer(getLoc(CD->getBeginLoc()), *this, ClassDecl, *B);
}

if (BaseCtorContinueBB) {
Expand Down Expand Up @@ -699,7 +703,7 @@ void CIRGenFunction::initializeVTablePointers(mlir::Location loc,
initializeVTablePointer(loc, Vptr);

if (RD->getNumVBases())
llvm_unreachable("NYI");
CGM.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, RD);
}

CIRGenFunction::VPtrsVector
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,10 @@ void CIRGenFunction::buildCXXConstructExpr(const CXXConstructExpr *E,
break;
case CXXConstructionKind::Delegating:
llvm_unreachable("NYI");
break;
case CXXConstructionKind::VirtualBase:
llvm_unreachable("NYI");
ForVirtualBase = true;
[[fallthrough]];
case CXXConstructionKind::NonVirtualBase:
Type = Ctor_Base;
break;
Expand Down
25 changes: 18 additions & 7 deletions clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class CIRGenItaniumCXXABI : public cir::CIRGenCXXABI {
const CXXRecordDecl *NearestVBase) override;
void emitVTableDefinitions(CIRGenVTables &CGVT,
const CXXRecordDecl *RD) override;
void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
QualType Ty) override;
bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
Expand Down Expand Up @@ -821,10 +822,10 @@ class CIRGenItaniumRTTIBuilder {
/// to the Itanium C++ ABI, 2.9.5p6b.
void BuildSIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *RD);

// /// Build an abi::__vmi_class_type_info, used for
// /// classes with bases that do not satisfy the abi::__si_class_type_info
// /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
// void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);
/// Build an abi::__vmi_class_type_info, used for
/// classes with bases that do not satisfy the abi::__si_class_type_info
/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);

// /// Build an abi::__pointer_type_info struct, used
// /// for pointer types.
Expand Down Expand Up @@ -1436,6 +1437,10 @@ void CIRGenItaniumRTTIBuilder::BuildSIClassTypeInfo(mlir::Location loc,
Fields.push_back(BaseTypeInfo);
}

void CIRGenItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
// TODO: Implement this function.
}

mlir::Attribute
CIRGenItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(mlir::Location loc,
QualType Ty) {
Expand Down Expand Up @@ -1560,8 +1565,7 @@ mlir::Attribute CIRGenItaniumRTTIBuilder::BuildTypeInfo(
if (CanUseSingleInheritance(RD)) {
BuildSIClassTypeInfo(loc, RD);
} else {
llvm_unreachable("NYI");
// BuildVMIClassTypeInfo(RD);
BuildVMIClassTypeInfo(RD);
}

break;
Expand Down Expand Up @@ -1730,6 +1734,13 @@ void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &CGVT,
llvm_unreachable("NYI");
}

void CIRGenItaniumCXXABI::emitVirtualInheritanceTables(
const CXXRecordDecl *RD) {
CIRGenVTables &VTables = CGM.getVTables();
auto VTT = VTables.getAddrOfVTT(RD);
VTables.buildVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD);
}

/// What sort of uniqueness rules should we use for the RTTI for the
/// given type?
CIRGenItaniumCXXABI::RTTIUniquenessKind
Expand Down Expand Up @@ -1842,4 +1853,4 @@ void CIRGenItaniumCXXABI::buildThrow(CIRGenFunction &CGF,
// Now throw the exception.
builder.create<mlir::cir::ThrowOp>(CGF.getLoc(E->getSourceRange()),
exceptionPtr, typeInfo.getSymbol(), dtor);
}
}
123 changes: 119 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenVTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@
#include "CIRGenCXXABI.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "mlir/IR/Attributes.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/VTTBuilder.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <algorithm>
Expand Down Expand Up @@ -151,17 +154,17 @@ void CIRGenVTables::GenerateClassData(const CXXRecordDecl *RD) {
assert(!UnimplementedFeature::generateDebugInfo());

if (RD->getNumVBases())
llvm_unreachable("NYI");
CGM.getCXXABI().emitVirtualInheritanceTables(RD);

CGM.getCXXABI().emitVTableDefinitions(*this, RD);
}

static void AddPointerLayoutOffset(CIRGenModule &CGM,
ConstantArrayBuilder &builder,
CharUnits offset) {
assert(offset.getQuantity() == 0 && "NYI");
builder.add(mlir::cir::ConstPtrAttr::get(
CGM.getBuilder().getContext(), CGM.getBuilder().getUInt8PtrTy(), 0));
builder.add(mlir::cir::ConstPtrAttr::get(CGM.getBuilder().getContext(),
CGM.getBuilder().getUInt8PtrTy(),
offset.getQuantity()));
}

static void AddRelativeLayoutOffset(CIRGenModule &CGM,
Expand Down Expand Up @@ -415,6 +418,118 @@ CIRGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
llvm_unreachable("Invalid TemplateSpecializationKind!");
}

mlir::cir::GlobalOp
getAddrOfVTTVTable(CIRGenVTables &CGVT, CIRGenModule &CGM,
const CXXRecordDecl *MostDerivedClass,
const VTTVTable &vtable,
mlir::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());
}

llvm_unreachable("generateConstructionVTable NYI");
}

mlir::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 = mlir::cir::ArrayType::get(CGM.getBuilder().getContext(),
CGM.getBuilder().getUInt8PtrTy(),
Builder.getVTTComponents().size());
auto Align =
CGM.getDataLayout().getABITypeAlign(CGM.getBuilder().getUInt8PtrTy());
auto VTT = CGM.createOrReplaceCXXRuntimeVariable(
CGM.getLoc(RD->getSourceRange()), Name, ArrayType,
mlir::cir::GlobalLinkageKind::ExternalLinkage,
CharUnits::fromQuantity(Align));
CGM.setGVProperties(VTT, RD);
return VTT;
}

/// Emit the definition of the given vtable.
void CIRGenVTables::buildVTTDefinition(mlir::cir::GlobalOp VTT,
mlir::cir::GlobalLinkageKind Linkage,
const CXXRecordDecl *RD) {
VTTBuilder Builder(CGM.getASTContext(), RD, /*GenerateDefinition=*/true);

auto ArrayType = mlir::cir::ArrayType::get(CGM.getBuilder().getContext(),
CGM.getBuilder().getUInt8PtrTy(),
Builder.getVTTComponents().size());

SmallVector<mlir::cir::GlobalOp, 8> VTables;
SmallVector<VTableAddressPointsMapTy, 8> VTableAddressPoints;
for (const VTTVTable *i = Builder.getVTTVTables().begin(),
*e = Builder.getVTTVTables().end();
i != e; ++i) {
VTableAddressPoints.push_back(VTableAddressPointsMapTy());
VTables.push_back(getAddrOfVTTVTable(*this, CGM, RD, *i, Linkage,
VTableAddressPoints.back()));
}

SmallVector<mlir::Attribute, 8> VTTComponents;
for (const VTTComponent *i = Builder.getVTTComponents().begin(),
*e = Builder.getVTTComponents().end();
i != e; ++i) {
const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex];
mlir::cir::GlobalOp VTable = VTables[i->VTableIndex];
VTableLayout::AddressPointLocation AddressPoint;
if (VTTVT.getBase() == RD) {
// Just get the address point for the regular vtable.
AddressPoint =
getItaniumVTableContext().getVTableLayout(RD).getAddressPoint(
i->VTableBase);
} else {
AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase);
assert(AddressPoint.AddressPointIndex != 0 &&
"Did not find ctor vtable address point!");
}

mlir::Attribute Idxs[3] = {
CGM.getBuilder().getI32IntegerAttr(0),
CGM.getBuilder().getI32IntegerAttr(AddressPoint.VTableIndex),
CGM.getBuilder().getI32IntegerAttr(AddressPoint.AddressPointIndex),
};

auto Init = mlir::cir::GlobalViewAttr::get(
CGM.getBuilder().getUInt8PtrTy(),
mlir::FlatSymbolRefAttr::get(VTable.getSymNameAttr()),
mlir::ArrayAttr::get(CGM.getBuilder().getContext(), Idxs));

VTTComponents.push_back(Init);
}

auto Init = CGM.getBuilder().getConstArray(
mlir::ArrayAttr::get(CGM.getBuilder().getContext(), VTTComponents),
ArrayType);

VTT.setInitialValueAttr(Init);

// Set the correct linkage.
VTT.setLinkage(Linkage);
mlir::SymbolTable::setSymbolVisibility(VTT,
CIRGenModule::getMLIRVisibility(VTT));

if (CGM.supportsCOMDAT() && VTT.isWeakForLinker()) {
assert(!UnimplementedFeature::setComdat());
}
}

void CIRGenVTables::buildThunks(GlobalDecl GD) {
const CXXMethodDecl *MD =
cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl();
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/CIR/CodeGen/CIRGenVTables.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,13 @@ class CIRGenVTables {
// llvm::GlobalVariable::LinkageTypes Linkage,
// VTableAddressPointsMapTy &AddressPoints);

// /// GetAddrOfVTT - Get the address of the VTT for the given record decl.
// llvm::GlobalVariable *GetAddrOfVTT(const CXXRecordDecl *RD);
/// Get the address of the VTT for the given record decl.
mlir::cir::GlobalOp getAddrOfVTT(const CXXRecordDecl *RD);

// /// EmitVTTDefinition - Emit the definition of the given vtable.
// void EmitVTTDefinition(llvm::GlobalVariable *VTT,
// llvm::GlobalVariable::LinkageTypes Linkage,
// const CXXRecordDecl *RD);
/// Emit the definition of the given vtable.
void buildVTTDefinition(mlir::cir::GlobalOp VTT,
mlir::cir::GlobalLinkageKind Linkage,
const CXXRecordDecl *RD);

/// Emit the associated thunks for the given global decl.
void buildThunks(GlobalDecl GD);
Expand Down
31 changes: 26 additions & 5 deletions clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,15 +410,37 @@ void CIRRecordLowering::accumulateVBases() {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
if (BaseDecl->isEmpty())
continue;
llvm_unreachable("NYI");
// If the vbase is a primary virtual base of some base, then it doesn't
// get its own storage location but instead lives inside of that base.
if (astContext.isNearlyEmpty(BaseDecl) &&
!hasOwnStorage(cxxRecordDecl, BaseDecl))
continue;
ScissorOffset = std::min(ScissorOffset,
astRecordLayout.getVBaseClassOffset(BaseDecl));
}
members.push_back(MemberInfo(ScissorOffset, MemberInfo::InfoKind::Scissor,
mlir::Type{}, cxxRecordDecl));
for (const auto &Base : cxxRecordDecl->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
if (BaseDecl->isEmpty())
continue;
llvm_unreachable("NYI");
CharUnits Offset = astRecordLayout.getVBaseClassOffset(BaseDecl);
// If the vbase is a primary virtual base of some base, then it doesn't
// get its own storage location but instead lives inside of that base.
if (isOverlappingVBaseABI() && astContext.isNearlyEmpty(BaseDecl) &&
!hasOwnStorage(cxxRecordDecl, BaseDecl)) {
members.push_back(
MemberInfo(Offset, MemberInfo::InfoKind::VBase, nullptr, BaseDecl));
continue;
}
// If we've got a vtordisp, add it as a storage type.
if (astRecordLayout.getVBaseOffsetsMap()
.find(BaseDecl)
->second.hasVtorDisp())
members.push_back(
StorageInfo(Offset - CharUnits::fromQuantity(4), getUIntNType(32)));
members.push_back(MemberInfo(Offset, MemberInfo::InfoKind::VBase,
getStorageType(BaseDecl), BaseDecl));
}
}

Expand Down Expand Up @@ -449,8 +471,7 @@ void CIRRecordLowering::fillOutputFields() {
} else if (member.kind == MemberInfo::InfoKind::Base) {
nonVirtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1;
} else if (member.kind == MemberInfo::InfoKind::VBase) {
llvm_unreachable("NYI");
// virtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1;
virtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1;
}
}
}
Expand Down Expand Up @@ -657,4 +678,4 @@ CIRDataLayout::CIRDataLayout(mlir::ModuleOp modOp) : layout{modOp} {
llvm_unreachable("unknown endianess");
}
}
}
}
Loading

0 comments on commit 4074112

Please sign in to comment.