Skip to content

Conversation

andykaylor
Copy link
Contributor

This adds support for emitting virtual table tables (VTTs) and construction vtables.

This adds support for emitting virtual table tables (VTTs) and
construction vtables.
@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Aug 27, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 27, 2025

@llvm/pr-subscribers-clangir

@llvm/pr-subscribers-clang

Author: Andy Kaylor (andykaylor)

Changes

This 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:

  • (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.h (+4)
  • (modified) clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp (+8)
  • (modified) clang/lib/CIR/CodeGen/CIRGenVTables.cpp (+173-7)
  • (modified) clang/lib/CIR/CodeGen/CIRGenVTables.h (+16)
  • (modified) clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp (-9)
  • (modified) clang/test/CIR/CodeGen/vtt.cpp (+132-9)
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]

Copy link
Collaborator

@erichkeane erichkeane left a 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants