[clang] [CIR] Add support for emitting vtables (PR #154808)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 22 10:33:04 PDT 2025
================
@@ -33,13 +35,215 @@ 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)));
// FIXME(cir): should VTableLayout be encoded like we do for some
// 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;
----------------
erichkeane wrote:
```suggestion
llvm::SmallVector<mlir::Attribute> components;
```
https://github.com/llvm/llvm-project/pull/154808
More information about the cfe-commits
mailing list