-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[CIR] Add support for emitting vtables #154808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This adds a simplified version of the code to emit vtables. It does not yet handle RTTI or cases that require multiple vtables.
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) ChangesThis adds a simplified version of the code to emit vtables. It does not yet handle RTTI or cases that require multiple vtables. Patch is 27.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/154808.diff 12 Files Affected:
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 49c66a40e47b6..e2326b1031765 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -279,6 +279,7 @@ struct MissingFeatures {
static bool appleKext() { return false; }
static bool dtorCleanups() { return false; }
static bool vtableInitialization() { return false; }
+ static bool vtableEmitMetadata() { return false; }
static bool vtableRelativeLayout() { return false; }
static bool msvcBuiltins() { return false; }
static bool vaArgABILowering() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 3f1cb8363a556..b5f2e1a067274 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -95,6 +95,10 @@ class CIRGenCXXABI {
isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,
CIRGenFunction::VPtr vptr) = 0;
+ /// Emits the VTable definitions required for the given record type.
+ virtual void emitVTableDefinitions(CIRGenVTables &cgvt,
+ 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.
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 6d749940fa128..8a15e5f96aea2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -42,6 +42,11 @@ CIRGenFunctionInfo::create(CanQualType resultType,
return fi;
}
+cir::FuncType CIRGenTypes::getFunctionType(GlobalDecl gd) {
+ const CIRGenFunctionInfo &fi = arrangeGlobalDeclaration(gd);
+ return getFunctionType(fi);
+}
+
cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &info) {
mlir::Type resultType = convertType(info.getReturnType());
SmallVector<mlir::Type, 8> argTypes;
@@ -55,6 +60,16 @@ cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &info) {
info.isVariadic());
}
+cir::FuncType CIRGenTypes::getFunctionTypeForVTable(GlobalDecl gd) {
+ const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
+ const FunctionProtoType *fpt = md->getType()->getAs<FunctionProtoType>();
+
+ if (!isFuncTypeConvertible(fpt))
+ cgm.errorNYI("getFunctionTypeForVTable: non-convertible function type");
+
+ return getFunctionType(gd);
+}
+
CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
if (isVirtual()) {
const CallExpr *ce = getVirtualCallExpr();
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 347656b5f6488..aaf7dc767d888 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -81,6 +81,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
clang::BaseSubobject base,
const clang::CXXRecordDecl *nearestVBase) override;
+ void emitVTableDefinitions(CIRGenVTables &cgvt,
+ const CXXRecordDecl *rd) override;
bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
return true;
@@ -270,6 +272,67 @@ bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {
return false;
}
+void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt,
+ const CXXRecordDecl *rd) {
+ cir::GlobalOp vtable = getAddrOfVTable(rd, CharUnits());
+ if (vtable.hasInitializer())
+ return;
+
+ ItaniumVTableContext &vtContext = cgm.getItaniumVTableContext();
+ const VTableLayout &vtLayout = vtContext.getVTableLayout(rd);
+ cir::GlobalLinkageKind linkage = cgm.getVTableLinkage(rd);
+ mlir::Attribute rtti =
+ cgm.getAddrOfRTTIDescriptor(cgm.getLoc(rd->getBeginLoc()),
+ cgm.getASTContext().getCanonicalTagType(rd));
+
+ // Classic codegen uses ConstantInitBuilder here, which is a very general
+ // and feature-rich class to generate initializers for global values.
+ // For now, this is using a simpler approach to create the initializer in CIR.
+ cgvt.createVTableInitializer(vtable, vtLayout, rtti,
+ cir::isLocalLinkage(linkage));
+
+ // Set the correct linkage.
+ vtable.setLinkage(linkage);
+
+ if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))
+ vtable.setComdat(true);
+
+ // Set the right visibility.
+ cgm.setGVProperties(vtable, rd);
+
+ // If this is the magic class __cxxabiv1::__fundamental_type_info,
+ // we will emit the typeinfo for the fundamental types. This is the
+ // same behaviour as GCC.
+ const DeclContext *DC = rd->getDeclContext();
+ if (rd->getIdentifier() &&
+ rd->getIdentifier()->isStr("__fundamental_type_info") &&
+ isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&
+ cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
+ DC->getParent()->isTranslationUnit()) {
+ cgm.errorNYI(rd->getSourceRange(),
+ "emitVTableDefinitions: __fundamental_type_info");
+ }
+
+ auto vtableAsGlobalValue = dyn_cast<cir::CIRGlobalValueInterface>(*vtable);
+ assert(vtableAsGlobalValue && "VTable must support CIRGlobalValueInterface");
+ // Always emit type metadata on non-available_externally definitions, and on
+ // available_externally definitions if we are performing whole program
+ // devirtualization. For WPD we need the type metadata on all vtable
+ // definitions to ensure we associate derived classes with base classes
+ // defined in headers but with a strong definition only in a shared
+ // library.
+ assert(!cir::MissingFeatures::vtableEmitMetadata());
+ if (cgm.getCodeGenOpts().WholeProgramVTables) {
+ cgm.errorNYI(rd->getSourceRange(),
+ "emitVTableDefinitions: WholeProgramVTables");
+ }
+
+ assert(!cir::MissingFeatures::vtableRelativeLayout());
+ if (vtContext.isRelativeLayout()) {
+ cgm.errorNYI(rd->getSourceRange(), "vtableRelativeLayout");
+ }
+}
+
void CIRGenItaniumCXXABI::emitDestructorCall(
CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index a557d2aae9dd9..46bca51767c02 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -845,7 +845,7 @@ void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
emitGlobalFunctionDefinition(gd, op);
if (method->isVirtual())
- errorNYI(method->getSourceRange(), "virtual member function");
+ getVTables().emitThunks(gd);
return;
}
@@ -2151,6 +2151,18 @@ bool CIRGenModule::verifyModule() const {
return mlir::verify(theModule).succeeded();
}
+mlir::Attribute CIRGenModule::getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty, bool forEh) {
+ // Return a bogus pointer if RTTI is disabled, unless it's for EH.
+ // FIXME: should we even be calling this method if RTTI is disabled
+ // and it's not for EH?
+ if (!shouldEmitRTTI(forEh))
+ return builder.getConstNullPtrAttr(builder.getUInt8PtrTy());
+
+ errorNYI(loc, "getAddrOfRTTIDescriptor");
+ return mlir::Attribute();
+}
+
// TODO(cir): this can be shared with LLVM codegen.
CharUnits CIRGenModule::computeNonVirtualBaseClassOffset(
const CXXRecordDecl *derivedClass,
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 128e2af5e1126..d90baa55d0b5c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -190,6 +190,16 @@ class CIRGenModule : public CIRGenTypeCache {
mlir::Location loc, llvm::StringRef name, mlir::Type ty,
cir::GlobalLinkageKind linkage, clang::CharUnits alignment);
+ void emitVTable(const CXXRecordDecl *rd);
+
+ /// Return the appropriate linkage for the vtable, VTT, and type information
+ /// of the given class.
+ cir::GlobalLinkageKind getVTableLinkage(const CXXRecordDecl *rd);
+
+ /// Get the address of the RTTI descriptor for the given type.
+ mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc, QualType ty,
+ bool forEH = false);
+
/// Return a constant array for the given string.
mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);
@@ -290,6 +300,13 @@ class CIRGenModule : public CIRGenTypeCache {
getAddrOfGlobal(clang::GlobalDecl gd,
ForDefinition_t isForDefinition = NotForDefinition);
+ // Return whether RTTI information should be emitted for this target.
+ bool shouldEmitRTTI(bool forEH = false) {
+ return (forEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&
+ !(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice &&
+ getTriple().isNVPTX());
+ }
+
/// Emit type info if type of an expression is a variably modified
/// type. Also emit proper debug info for cast types.
void emitExplicitCastExprType(const ExplicitCastExpr *e,
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index c2813d79bf63b..7af0d956e7d56 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -130,6 +130,13 @@ class CIRGenTypes {
/// Get the CIR function type for \arg Info.
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info);
+ cir::FuncType getFunctionType(clang::GlobalDecl gd);
+
+ /// Get the CIR function type for use in a vtable, given a CXXMethodDecl. If
+ /// the method has an incomplete return type, and/or incomplete argument
+ /// types, this will return the opaque type.
+ cir::FuncType getFunctionTypeForVTable(clang::GlobalDecl gd);
+
// The arrangement methods are split into three families:
// - those meant to drive the signature and prologue/epilogue
// of a function declaration or definition,
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
index fdd1a6e3f57ef..dec73ba793b1d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
@@ -11,6 +11,8 @@
//===----------------------------------------------------------------------===//
#include "CIRGenVTables.h"
+
+#include "CIRGenCXXABI.h"
#include "CIRGenModule.h"
#include "mlir/IR/Types.h"
#include "clang/AST/VTableBuilder.h"
@@ -33,9 +35,9 @@ mlir::Type CIRGenVTables::getVTableComponentType() {
return cgm.getVTableComponentType();
}
-mlir::Type CIRGenVTables::getVTableType(const VTableLayout &layout) {
+cir::RecordType CIRGenVTables::getVTableType(const VTableLayout &layout) {
SmallVector<mlir::Type, 4> tys;
- auto componentType = getVTableComponentType();
+ mlir::Type componentType = getVTableComponentType();
for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i)
tys.push_back(cir::ArrayType::get(componentType, layout.getVTableSize(i)));
@@ -43,3 +45,205 @@ mlir::Type CIRGenVTables::getVTableType(const VTableLayout &layout) {
// AST nodes?
return cgm.getBuilder().getAnonRecordTy(tys, /*incomplete=*/false);
}
+
+/// This is a callback from Sema to tell us that a particular vtable is
+/// required to be emitted in this translation unit.
+///
+/// This is only called for vtables that _must_ be emitted (mainly due to key
+/// functions). For weak vtables, CodeGen tracks when they are needed and
+/// emits them as-needed.
+void CIRGenModule::emitVTable(const CXXRecordDecl *rd) {
+ vtables.generateClassData(rd);
+}
+
+void CIRGenVTables::generateClassData(const CXXRecordDecl *rd) {
+ assert(!cir::MissingFeatures::generateDebugInfo());
+
+ if (rd->getNumVBases())
+ cgm.errorNYI(rd->getSourceRange(), "emitVirtualInheritanceTables");
+
+ cgm.getCXXABI().emitVTableDefinitions(*this, rd);
+}
+
+mlir::Attribute CIRGenVTables::getVTableComponent(
+ const VTableLayout &layout, unsigned componentIndex, mlir::Attribute rtti,
+ unsigned &nextVTableThunkIndex, unsigned vtableAddressPoint,
+ bool vtableHasLocalLinkage) {
+ auto &component = layout.vtable_components()[componentIndex];
+
+ CIRGenBuilderTy builder = cgm.getBuilder();
+
+ 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();
+ case VTableComponent::CK_DeletingDtorPointer:
+ cgm.errorNYI("getVTableComponent: DeletingDtorPointer");
+ return mlir::Attribute();
+ case VTableComponent::CK_UnusedFunctionPointer:
+ cgm.errorNYI("getVTableComponent: UnusedFunctionPointer");
+ return mlir::Attribute();
+
+ case VTableComponent::CK_OffsetToTop:
+ return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
+ component.getOffsetToTop().getQuantity());
+
+ case VTableComponent::CK_RTTI:
+ assert((mlir::isa<cir::GlobalViewAttr>(rtti) ||
+ mlir::isa<cir::ConstPtrAttr>(rtti)) &&
+ "expected GlobalViewAttr or ConstPtrAttr");
+ return rtti;
+
+ case VTableComponent::CK_FunctionPointer: {
+ GlobalDecl gd = component.getGlobalDecl();
+
+ assert(!cir::MissingFeatures::cudaSupport());
+
+ cir::FuncOp fnPtr;
+ if (cast<CXXMethodDecl>(gd.getDecl())->isPureVirtual()) {
+ cgm.errorNYI("getVTableComponent: CK_FunctionPointer: pure virtual");
+ return mlir::Attribute();
+ } else if (cast<CXXMethodDecl>(gd.getDecl())->isDeleted()) {
+ cgm.errorNYI("getVTableComponent: CK_FunctionPointer: deleted virtual");
+ return mlir::Attribute();
+ } else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&
+ layout.vtable_thunks()[nextVTableThunkIndex].first ==
+ componentIndex) {
+ cgm.errorNYI("getVTableComponent: CK_FunctionPointer: thunk");
+ return mlir::Attribute();
+ } else {
+ // Otherwise we can use the method definition directly.
+ cir::FuncType fnTy = cgm.getTypes().getFunctionTypeForVTable(gd);
+ fnPtr = cgm.getAddrOfFunction(gd, fnTy, /*ForVTable=*/true);
+ }
+
+ return cir::GlobalViewAttr::get(
+ builder.getUInt8PtrTy(),
+ mlir::FlatSymbolRefAttr::get(fnPtr.getSymNameAttr()));
+ }
+ }
+
+ llvm_unreachable("Unexpected vtable component kind");
+}
+
+void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp,
+ const clang::VTableLayout &layout,
+ mlir::Attribute rtti,
+ bool vtableHasLocalLinkage) {
+ mlir::Type componentType = getVTableComponentType();
+
+ const llvm::SmallVector<unsigned, 4> &addressPoints =
+ 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, 4> 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));
+
+ // Create a ConstRecordAttr to hold the component array.
+ const auto members = mlir::ArrayAttr::get(mlirContext, {arr});
+ cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members);
+
+ // Create a VTableAttr
+ auto vtableAttr = cir::VTableAttr::get(record.getType(), record.getMembers());
+
+ // Add the vtable initializer to the vtable global op.
+ cgm.setInitializer(vtableOp, vtableAttr);
+}
+
+/// Compute the required linkage of the vtable for the given class.
+///
+/// Note that we only call this at the end of the translation unit.
+cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
+ if (!rd->isExternallyVisible())
+ return cir::GlobalLinkageKind::InternalLinkage;
+
+ // We're at the end of the translation unit, so the current key
+ // function is fully correct.
+ const CXXMethodDecl *keyFunction = astContext.getCurrentKeyFunction(rd);
+ if (keyFunction && !rd->hasAttr<DLLImportAttr>()) {
+ // If this class has a key function, use that to determine the
+ // linkage of the vtable.
+ const FunctionDecl *def = nullptr;
+ if (keyFunction->hasBody(def))
+ keyFunction = cast<CXXMethodDecl>(def);
+
+ // All of the cases below do something different with AppleKext enabled.
+ assert(!cir::MissingFeatures::appleKext());
+ switch (keyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ assert(
+ (def || codeGenOpts.OptimizationLevel > 0 ||
+ codeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo) &&
+ "Shouldn't query vtable linkage without key function, "
+ "optimizations, or debug info");
+ if (!def && codeGenOpts.OptimizationLevel > 0)
+ return cir::GlobalLinkageKind::AvailableExternallyLinkage;
+
+ if (keyFunction->isInlined())
+ return !astContext.getLangOpts().AppleKext
+ ? cir::GlobalLinkageKind::LinkOnceODRLinkage
+ : cir::GlobalLinkageKind::InternalLinkage;
+ return cir::GlobalLinkageKind::ExternalLinkage;
+
+ case TSK_ImplicitInstantiation:
+ return cir::GlobalLinkageKind::LinkOnceODRLinkage;
+
+ case TSK_ExplicitInstantiationDefinition:
+ return cir::GlobalLinkageKind::WeakODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ llvm_unreachable("Should not have been asked to emit this");
+ }
+ }
+
+ errorNYI(rd->getSourceRange(), "getVTableLinkage: no key function");
+ return cir::GlobalLinkageKind::ExternalLinkage;
+}
+
+void CIRGenVTables::emitThunks(GlobalDecl gd) {
+ const CXXMethodDecl *md =
+ cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl();
+
+ // We don't need to generate thunks for the base destructor.
+ if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)
+ return;
+
+ const VTableContextBase::ThunkInfoVectorTy *thunkInfoVector =
+ vtContext->getThunkInfo(gd);
+
+ if (!thunkInfoVector)
+ return;
+
+ cgm.errorNYI(md->getSourceRange(), "emitThunks");
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.h b/clang/lib/CIR/CodeGen/CIRGenVTables.h
index 66318c5f2393a..518d7d78f1737 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.h
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.h
@@ -16,6 +16,7 @@
#include "mlir/IR/Types.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/VTableBuilder.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
namespace clang {
class CXXRecordDecl;
@@ -29,11 +30,23 @@ class CIRGenVTables {
clang::VTableContextBase *vtContext;
+ mlir::Attribute
+ getVTableComponent(const VTableLayout &layout, unsigned componentIndex,
+ mlir::Attribute rtti, unsigned &nextVTableThunkIndex,
+ unsigned vtableAddressPoint, bool vtableHasLocalLinkage);
+
mlir::Type getVTableComponentType();
public:
CIRGenVTables(CIRGenModule &cgm);
+ /// Add vtable components for the giv...
[truncated]
|
const VTableLayout &layout, unsigned componentIndex, mlir::Attribute rtti, | ||
unsigned &nextVTableThunkIndex, unsigned vtableAddressPoint, | ||
bool vtableHasLocalLinkage) { | ||
auto &component = layout.vtable_components()[componentIndex]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto &component = layout.vtable_components()[componentIndex]; | |
VTableComponent &component = layout.vtable_components()[componentIndex]; |
I didn’t know what VTableComponent
was, so the explicit type makes it clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, 'auto' here isn't allowed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few nits, else LGTM.
const VTableLayout &layout, unsigned componentIndex, mlir::Attribute rtti, | ||
unsigned &nextVTableThunkIndex, unsigned vtableAddressPoint, | ||
bool vtableHasLocalLinkage) { | ||
auto &component = layout.vtable_components()[componentIndex]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, 'auto' here isn't allowed.
bool vtableHasLocalLinkage) { | ||
mlir::Type componentType = getVTableComponentType(); | ||
|
||
const llvm::SmallVector<unsigned, 4> &addressPoints = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const llvm::SmallVector<unsigned, 4> &addressPoints = | |
const llvm::SmallVector<unsigned> &addressPoints = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out the clang::VTableLayout::getAddressPointIndices() returns SmallVector<unsigned, 4>
(using a type alias, AddressPointsIndexMapTy
), so my options here are:
const llvm::SmallVector<unsigned, 4> &addressPoints =
const llvm::SmallVectorImpl<unsigned> &addressPoints =
or
const AddressPointsIndexMapTy &addressPoints =
Classic codegen uses
const auto &addressPoints =
I'm going with SmallVectorImpl
because I feel like the type alias is disinformation. There's another type alias in the same class (AddressPointsMapTy
) that is a DenseMap
but this one is neither a map nor a map key, so I don't know what they were thinking with the name.
size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex); | ||
|
||
// Build a ConstArrayAttr of the vtable components. | ||
llvm::SmallVector<mlir::Attribute, 4> components; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
llvm::SmallVector<mlir::Attribute, 4> components; | |
llvm::SmallVector<mlir::Attribute> components; |
This adds a simplified version of the code to emit vtables. It does not yet handle RTTI or cases that require multiple vtables.