Skip to content

Commit

Permalink
[CIR][Codegen] VTT support for virtual class inheritance (llvm#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 committed Sep 13, 2023
1 parent 86d68fd commit 470aba9
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 34 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
24 changes: 14 additions & 10 deletions clang/lib/CIR/CodeGen/CIRGenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,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 @@ -235,7 +234,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 @@ -523,9 +522,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 @@ -604,7 +604,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 @@ -698,7 +702,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 Expand Up @@ -1286,4 +1290,4 @@ mlir::Value CIRGenFunction::getVTablePtr(SourceLocation Loc, Address This,
}

return VTable;
}
}
4 changes: 2 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,8 @@ void CIRGenFunction::buildCXXConstructExpr(const CXXConstructExpr *E,
llvm_unreachable("NYI");
break;
case CXXConstructExpr::CK_VirtualBase:
llvm_unreachable("NYI");
break;
ForVirtualBase = true;
[[fallthrough]];
case CXXConstructExpr::CK_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 @@ -1432,6 +1433,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 @@ -1554,8 +1559,7 @@ mlir::Attribute CIRGenItaniumRTTIBuilder::BuildTypeInfo(
if (CanUseSingleInheritance(RD)) {
BuildSIClassTypeInfo(loc, RD);
} else {
llvm_unreachable("NYI");
// BuildVMIClassTypeInfo(RD);
BuildVMIClassTypeInfo(RD);
}

break;
Expand Down Expand Up @@ -1724,6 +1728,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 @@ -1836,4 +1847,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
Loading

0 comments on commit 470aba9

Please sign in to comment.