-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[CIR] Add support for emitting VTTs and related ojects #155721
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
base: main
Are you sure you want to change the base?
Conversation
This adds support for emitting virtual table tables (VTTs) and construction vtables.
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesThis adds support for emitting virtual table tables (VTTs) and construction vtables. Patch is 22.96 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/155721.diff 6 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index df7ffbb4a2759..db50cb5148d1b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -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.
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 4fd5a278e1a99..80703b348aed7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -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;
@@ -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) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
index aca12aa62f55b..9fbc0f67b4b92 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
@@ -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"
@@ -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);
}
@@ -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();
@@ -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());
@@ -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.
@@ -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());
+
+ 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();
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.h b/clang/lib/CIR/CodeGen/CIRGenVTables.h
index 518d7d78f1737..8d352c9949109 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.h
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.h
@@ -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,
@@ -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);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp b/clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp
index 42d45819de0f3..4635ce943b17c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp
@@ -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());
diff --git a/clang/test/CIR/CodeGen/vtt.cpp b/clang/test/CIR/CodeGen/vtt.cpp
index 631aab428840a..fcbfc07324c6d 100644
--- a/clang/test/CIR/CodeGen/vtt.cpp
+++ b/clang/test/CIR/CodeGen/vtt.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
// Note: This test will be expanded to verify VTT emission and VTT implicit
@@ -11,7 +11,7 @@
class A {
public:
int a;
- virtual void v() {}
+ virtual void v();
};
class B : public virtual A {
@@ -23,23 +23,146 @@ class B : public virtual A {
class C : public virtual A {
public:
long c;
- virtual void x() {}
+ virtual void x();
};
class D : public B, public C {
public:
long d;
- virtual void y() {}
+ virtual void y();
};
// This is just here to force the record types to be emitted.
void f(D *d) {}
+// Trigger vtable and VTT emission for D.
+void D::y() {}
+
// CIR: !rec_A2Ebase = !cir.record<struct "A.base" packed {!cir.vptr, !s32i}>
// CIR: !rec_B2Ebase = !cir.record<struct "B.base" packed {!cir.vptr, !s32i}>
// CIR: !rec_C2Ebase = !cir.record<struct "C.base" {!cir.vptr, !s64i}>
+// CIR: !rec_A = !cir.record<class "A" packed padded {!cir.vptr, !s32i, !cir.array<!u8i x 4>}>
+// CIR: !rec_B = !cir.record<class "B" packed padded {!cir.vptr, !s32i, !cir.array<!u8i x 4>, !rec_A2Ebase, !cir.array<!u8i x 4>}>
+// CIR: !rec_C = !cir.record<class "C" {!cir.vptr, !s64i, !rec_A2Ebase}>
// CIR: !rec_D = !cir.record<class "D" {!rec_B2Ebase, !rec_C2Ebase, !s64i, !rec_A2Ebase}>
-// Nothing interesting to see here yet.
-// LLVM: define{{.*}} void @_Z1fP1D
-// OGCG: define{{.*}} void @_Z1fP1D
+// CIR: !rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 5>, !cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 4>}>
+// CIR: !rec_anon_struct1 = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 4>}>
+
+// Vtable for D
+// CIR: cir.global{{.*}} @_ZTV1D = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<40 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1B1wEv> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1D1yEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 5>,
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<24 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<-16 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1C1xEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>,
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<-40 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1A1vEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>
+// CIR-SAME: }> : !rec_anon_struct {alignment = 8 : i64}
+
+// LLVM: @_ZTV1D = global { [5 x ptr], [4 x ptr], [4 x ptr] } {
+// LLVM-SAME: [5 x ptr] [ptr inttoptr (i64 40 to ptr), ptr null, ptr null, ptr @_ZN1B1wEv, ptr @_ZN1D1yEv],
+// LLVM-SAME: [4 x ptr] [ptr inttoptr (i64 24 to ptr), ptr inttoptr (i64 -16 to ptr), ptr null, ptr @_ZN1C1xEv],
+// LLVM-SAME: [4 x ptr] [ptr null, ptr inttoptr (i64 -40 to ptr), ptr null, ptr @_ZN1A1vEv]
+// LLVM-SAME: }, align 8
+
+// OGCG: @_ZTV1D = unnamed_addr constant { [5 x ptr], [4 x ptr], [4 x ptr] } {
+// OGCG-SAME: [5 x ptr] [ptr inttoptr (i64 40 to ptr), ptr null, ptr null, ptr @_ZN1B1wEv, ptr @_ZN1D1yEv],
+// OGCG-SAME: [4 x ptr] [ptr inttoptr (i64 24 to ptr), ptr inttoptr (i64 -16 to ptr), ptr null, ptr @_ZN1C1xEv],
+// OGCG-SAME: [4 x ptr] [ptr null, ptr inttoptr (i64 -40 to ptr), ptr null, ptr @_ZN1A1vEv]
+// OGCG-SAME: }, align 8
+
+// VTT for D
+// CIR: cir.global{{.*}} @_ZTT1D = #cir.const_array<[
+// CIR-SAME: #cir.global_view<@_ZTV1D, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTC1D0_1B, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTC1D0_1B, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTC1D16_1C, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTC1D16_1C, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTV1D, [2 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTV1D, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 7> {alignment = 8 : i64}
+
+// LLVM: @_ZTT1D = global [7 x ptr] [
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 24),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTC1D0_1B, i64 24),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTC1D0_1B, i64 56),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTC1D16_1C, i64 24),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTC1D16_1C, i64 56),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 96),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 64)
+// LLVM-SAME: ], align 8
+
+// OGCG: @_ZTT1D = unnamed_addr constant [7 x ptr] [
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 16) ({ [5 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTC1D0_1B, i32 0, i32 0, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTC1D0_1B, i32 0, i32 1, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTC1D16_1C, i32 0, i32 0, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [4 x ptr] }...
[truncated]
|
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.
This all looks fine to me, but please let someone else take a look before merging.
This adds support for emitting virtual table tables (VTTs) and construction vtables.