https://github.com/andykaylor created 
https://github.com/llvm/llvm-project/pull/155048

This adds the definition, verification, and lowering for CIR's VTTAddrPointOp. 
This is a bit ahead of the current codegen implementation, which doesn't yet 
have support for emitting VTT definitions, but since this doesn't depend on any 
of the other work in progress, it is being upstreamed in advance.

>From 5442c29e2d0960843da83e944b61e8155ce0ff1f Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akay...@nvidia.com>
Date: Fri, 22 Aug 2025 13:26:30 -0700
Subject: [PATCH] [CIR] Add VTTAddrPointOp

This adds the definition, verification, and lowering for CIR's
VTTAddrPointOp. This is a bit ahead of the current codegen implementation,
which doesn't yet have support for emitting VTT definitions, but since
this doesn't depend on any of the other work in progress, it is being
upstreamed in advance.
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 64 +++++++++++++++++++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 47 ++++++++++++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 33 +++++++++-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h   | 10 +++
 clang/test/CIR/IR/invalid-vtable.cir          | 54 +++++++++++++++-
 clang/test/CIR/IR/vtt-addrpoint.cir           | 55 ++++++++++++++++
 clang/test/CIR/Lowering/vtt-addrpoint.cir     | 59 +++++++++++++++++
 7 files changed, 319 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CIR/IR/vtt-addrpoint.cir
 create mode 100644 clang/test/CIR/Lowering/vtt-addrpoint.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index f237642700924..145a410026565 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1906,6 +1906,70 @@ def CIR_VTableGetVirtualFnAddrOp : 
CIR_Op<"vtable.get_virtual_fn_addr", [
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// VTTAddrPointOp
+//===----------------------------------------------------------------------===//
+
+def CIR_VTTAddrPointOp : CIR_Op<"vtt.address_point", [
+  Pure, DeclareOpInterfaceMethods<SymbolUserOpInterface>
+]> {
+  let summary = "Get the VTT address point";
+  let description = [{
+    The `vtt.address_point` operation retrieves an element from the VTT,
+    which is the address point of a C++ vtable. In virtual inheritance,
+    a set of internal `__vptr` members for an object are initialized by this
+    operation, which assigns an element from the VTT. The initialization order
+    is as follows:
+
+    The complete object constructors and destructors find the VTT,
+    via the mangled name of the VTT global variable. They pass the address of
+    the subobject's sub-VTT entry in the VTT as a second parameter
+    when calling the base object constructors and destructors.
+    The base object constructors and destructors use the address passed to
+    initialize the primary virtual pointer and virtual pointers that point to
+    the classes which either have virtual bases or override virtual functions
+    with a virtual step.
+
+    The first parameter is either the mangled name of VTT global variable
+    or the address of the subobject's sub-VTT entry in the VTT.
+    The second parameter `offset` provides a virtual step to adjust to
+    the actual address point of the vtable.
+
+    The return type is always a `!cir.ptr<!cir.ptr<void>>`.
+
+    Example:
+    ```mlir
+    cir.global linkonce_odr @_ZTV1B = ...
+    ...
+    %3 = cir.base_class_addr(%1 : !cir.ptr<!rec_D> nonnull) [0]
+             -> !cir.ptr<!rec_B>
+    %4 = cir.vtt.address_point @_ZTT1D, offset = 1
+             -> !cir.ptr<!cir.ptr<!void>>
+    cir.call @_ZN1BC2Ev(%3, %4)
+    ```
+    Or:
+    ```mlir
+    %7 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 1
+             -> !cir.ptr<!cir.ptr<!void>>
+    ```
+  }];
+
+  let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$name,
+                       Optional<CIR_AnyType>:$sym_addr,
+                       I32Attr:$offset);
+  let results = (outs CIR_PointerType:$addr);
+
+  let assemblyFormat = [{
+      ($name^)?
+      ($sym_addr^ `:` type($sym_addr))?
+      `,`
+      `offset` `=` $offset
+    `->` qualified(type($addr)) attr-dict
+  }];
+
+  let hasVerifier = 1;
+}
+
 
//===----------------------------------------------------------------------===//
 // SetBitfieldOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 8c53939e89d01..83fff09d4fab3 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1474,6 +1474,53 @@ 
cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// VTTAddrPointOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+cir::VTTAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
+  // VTT ptr is not coming from a symbol.
+  if (!getName())
+    return success();
+  StringRef name = *getName();
+
+  // Verify that the result type underlying pointer type matches the type of
+  // the referenced cir.global op.
+  auto op =
+      symbolTable.lookupNearestSymbolFrom<cir::GlobalOp>(*this, getNameAttr());
+  if (!op)
+    return emitOpError("'")
+           << name << "' does not reference a valid cir.global";
+  std::optional<mlir::Attribute> init = op.getInitialValue();
+  if (!init)
+    return success();
+  if (!isa<cir::ConstArrayAttr>(*init))
+    return emitOpError(
+               "Expected constant array in initializer for global VTT '")
+           << name << "'";
+  return success();
+}
+
+LogicalResult cir::VTTAddrPointOp::verify() {
+  // The operation uses either a symbol or a value to operate, but not both
+  if (getName() && getSymAddr())
+    return emitOpError("should use either a symbol or value, but not both");
+
+  // If not a symbol, stick with the concrete type used for getSymAddr.
+  if (getSymAddr())
+    return success();
+
+  mlir::Type resultType = getAddr().getType();
+  mlir::Type resTy = cir::PointerType::get(
+      cir::PointerType::get(cir::VoidType::get(getContext())));
+
+  if (resultType != resTy)
+    return emitOpError("result type must be ")
+           << resTy << ", but provided result type is " << resultType;
+  return success();
+}
+
 
//===----------------------------------------------------------------------===//
 // FuncOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 9f0e4e6ecb8ce..03955dc737828 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2451,7 +2451,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
                CIRToLLVMVecTernaryOpLowering,
                CIRToLLVMVTableAddrPointOpLowering,
                CIRToLLVMVTableGetVPtrOpLowering,
-               CIRToLLVMVTableGetVirtualFnAddrOpLowering
+               CIRToLLVMVTableGetVirtualFnAddrOpLowering,
+               CIRToLLVMVTTAddrPointOpLowering
       // clang-format on
       >(converter, patterns.getContext());
 
@@ -2600,6 +2601,36 @@ mlir::LogicalResult 
CIRToLLVMVTableGetVirtualFnAddrOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMVTTAddrPointOpLowering::matchAndRewrite(
+    cir::VTTAddrPointOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  const mlir::Type resultType = getTypeConverter()->convertType(op.getType());
+  llvm::SmallVector<mlir::LLVM::GEPArg> offsets;
+  mlir::Type eltType;
+  mlir::Value llvmAddr = adaptor.getSymAddr();
+
+  if (op.getSymAddr()) {
+    if (op.getOffset() == 0) {
+      rewriter.replaceOp(op, {llvmAddr});
+      return mlir::success();
+    }
+
+    offsets.push_back(adaptor.getOffset());
+    eltType = mlir::IntegerType::get(resultType.getContext(), 8,
+                                     mlir::IntegerType::Signless);
+  } else {
+    llvmAddr = getValueForVTableSymbol(op, rewriter, getTypeConverter(),
+                                       op.getNameAttr(), eltType);
+    assert(eltType && "Shouldn't ever be missing an eltType here");
+    offsets.push_back(0);
+    offsets.push_back(adaptor.getOffset());
+  }
+  rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
+      op, resultType, eltType, llvmAddr, offsets,
+      mlir::LLVM::GEPNoWrapFlags::inbounds);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMStackSaveOpLowering::matchAndRewrite(
     cir::StackSaveOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 7b109c5cef9d3..513ad37839f1b 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -508,6 +508,16 @@ class CIRToLLVMVTableGetVirtualFnAddrOpLowering
                   mlir::ConversionPatternRewriter &) const override;
 };
 
+class CIRToLLVMVTTAddrPointOpLowering
+    : public mlir::OpConversionPattern<cir::VTTAddrPointOp> {
+public:
+  using mlir::OpConversionPattern<cir::VTTAddrPointOp>::OpConversionPattern;
+
+  mlir::LogicalResult
+  matchAndRewrite(cir::VTTAddrPointOp op, OpAdaptor,
+                  mlir::ConversionPatternRewriter &) const override;
+};
+
 class CIRToLLVMStackSaveOpLowering
     : public mlir::OpConversionPattern<cir::StackSaveOp> {
 public:
diff --git a/clang/test/CIR/IR/invalid-vtable.cir 
b/clang/test/CIR/IR/invalid-vtable.cir
index 41ddd4c2419be..2e880169abbfa 100644
--- a/clang/test/CIR/IR/invalid-vtable.cir
+++ b/clang/test/CIR/IR/invalid-vtable.cir
@@ -1,6 +1,5 @@
 // RUN: cir-opt %s -verify-diagnostics -split-input-file
 
-!s8i = !cir.int<s, 8>
 !u32i = !cir.int<u, 32>
 cir.func @reference_unknown_vtable() {
   // expected-error @below {{'cir.vtable.address_point' op 'some_vtable' does 
not reference a valid cir.global}}
@@ -13,7 +12,7 @@ cir.func @reference_unknown_vtable() {
 !u8i = !cir.int<u, 8>
 !u32i = !cir.int<u, 32>
 cir.global linkonce_odr @_ZTT1D = #cir.const_array<[#cir.global_view<@_ZTV1D, 
[0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1D0_1B, [0 : i32, 3 
: i32]> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 2>
-cir.func @reference_unknown_vtable() {
+cir.func @reference_non_vtable() {
   // expected-error @below {{Expected #cir.vtable in initializer for global 
'_ZTT1D'}}
   %0 = cir.vtable.address_point(@_ZTT1D, address_point = <index = 0, offset = 
2>) : !cir.vptr
   cir.return
@@ -82,3 +81,54 @@ module {
   cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
   cir.func private dso_local @_ZN2S23keyEv(%arg0: !cir.ptr<!rec_S2>)
 }
+
+// -----
+
+!u32i = !cir.int<u, 32>
+!void = !cir.void
+cir.func @reference_unknown_vtt() {
+  // expected-error @below {{'cir.vtt.address_point' op 'some_vtt' does not 
reference a valid cir.global}}
+  %0 = cir.vtt.address_point @some_vtt, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+  cir.return
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!u32i = !cir.int<u, 32>
+!void = !cir.void
+!rec_anon_struct = !cir.record<struct  {!cir.array<!cir.ptr<!u8i> x 4>}>
+cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : 
!cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> 
: !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : 
!cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
+cir.func @reference_non_vtt() {
+  // expected-error @below {{'cir.vtt.address_point' op Expected constant 
array in initializer for global VTT '_ZTV1S'}}
+  %0 = cir.vtt.address_point @_ZTV1S, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+  cir.return
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!u32i = !cir.int<u, 32>
+!void = !cir.void
+!rec_anon_struct = !cir.record<struct  {!cir.array<!cir.ptr<!u8i> x 4>}>
+!rec_C = !cir.record<class "C" {!cir.vptr}>
+cir.global linkonce_odr @_ZTT1C = #cir.const_array<[#cir.global_view<@_ZTV1C, 
[0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1C0_1B, [0 : i32, 3 
: i32]> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 2> {alignment = 8 : 
i64}
+cir.func @reference_name_and_value(%arg0: !cir.ptr<!rec_C>, %arg1: 
!cir.ptr<!cir.ptr<!void>>) {
+  // expected-error @below {{'cir.vtt.address_point' op should use either a 
symbol or value, but not both}}
+  %0 = cir.vtt.address_point @_ZTT1C %arg1 : !cir.ptr<!cir.ptr<!void>>, offset 
= 1 -> !cir.ptr<!cir.ptr<!void>>
+  cir.return
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!u32i = !cir.int<u, 32>
+!void = !cir.void
+!rec_anon_struct = !cir.record<struct  {!cir.array<!cir.ptr<!u8i> x 4>}>
+!rec_C = !cir.record<class "C" {!cir.vptr}>
+cir.global linkonce_odr @_ZTT1C = #cir.const_array<[#cir.global_view<@_ZTV1C, 
[0 : i32, 3 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTC1C0_1B, [0 : i32, 3 
: i32]> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 2> {alignment = 8 : 
i64}
+cir.func @bad_return_type_for_vtt_addrpoint() {
+  // expected-error @below {{result type must be 
'!cir.ptr<!cir.ptr<!cir.void>>', but provided result type is 
'!cir.ptr<!cir.int<u, 8>>'}}
+  %0 = cir.vtt.address_point @_ZTT1C, offset = 1 -> !cir.ptr<!u8i>
+  cir.return
+}
diff --git a/clang/test/CIR/IR/vtt-addrpoint.cir 
b/clang/test/CIR/IR/vtt-addrpoint.cir
new file mode 100644
index 0000000000000..f05bb782c6911
--- /dev/null
+++ b/clang/test/CIR/IR/vtt-addrpoint.cir
@@ -0,0 +1,55 @@
+// RUN: cir-opt %s | FileCheck %s
+
+// Test the parsing and printing of the two forms of vtt.address_point op, as
+// they will appear in constructors.
+
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+!rec_A = !cir.record<struct "A" {!u8i}>
+!rec_B = !cir.record<struct "B" {!cir.vptr}>
+!rec_C = !cir.record<struct "C" {!rec_B}>
+!rec_anon_struct = !cir.record<struct  {!cir.array<!cir.ptr<!u8i> x 3>}>
+module {
+  cir.func private @_ZN1AC2Ev(!cir.ptr<!rec_A>)
+  cir.func private @_ZN1BC2Ev(!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>)
+  cir.func dso_local @_ZN1CC2Ev(%arg0: !cir.ptr<!rec_C>, %arg1: 
!cir.ptr<!cir.ptr<!void>>) {
+    %0 = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", 
init] {alignment = 8 : i64}
+    %1 = cir.alloca !cir.ptr<!cir.ptr<!void>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!void>>>, ["vtt", init] {alignment = 8 : i64}
+    cir.store %arg0, %0 : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
+    cir.store %arg1, %1 : !cir.ptr<!cir.ptr<!void>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!void>>>
+    %2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
+    %3 = cir.load align(8) %1 : !cir.ptr<!cir.ptr<!cir.ptr<!void>>>, 
!cir.ptr<!cir.ptr<!void>>
+    %4 = cir.base_class_addr %2 : !cir.ptr<!rec_C> nonnull [0] -> 
!cir.ptr<!rec_B>
+
+    %5 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> 
!cir.ptr<!cir.ptr<!void>>
+    // CHECK: cir.vtt.address_point %{{.*}} : !cir.ptr<!cir.ptr<!void>>, 
offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+
+    cir.call @_ZN1BC2Ev(%4, %5) : (!cir.ptr<!rec_B>, 
!cir.ptr<!cir.ptr<!void>>) -> ()
+    %6 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> 
!cir.ptr<!cir.ptr<!void>>
+    %7 = cir.cast(bitcast, %6 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+    %8 = cir.load align(8) %7 : !cir.ptr<!cir.vptr>, !cir.vptr
+    %9 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
+    cir.store align(8) %8, %9 : !cir.vptr, !cir.ptr<!cir.vptr>
+    cir.return
+  }
+  cir.global linkonce_odr dso_local @_ZTV1C = 
#cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> 
: !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> 
x 3>}> : !rec_anon_struct {alignment = 8 : i64}
+  cir.global linkonce_odr @_ZTT1C = 
#cir.const_array<[#cir.global_view<@_ZTV1C, [0 : i32, 3 : i32]> : 
!cir.ptr<!u8i>, #cir.global_view<@_ZTC1C0_1B, [0 : i32, 3 : i32]> : 
!cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 2> {alignment = 8 : i64}
+  cir.func dso_local @_ZN1CC1Ev(%arg0: !cir.ptr<!rec_C>) {
+    %0 = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", 
init] {alignment = 8 : i64}
+    cir.store %arg0, %0 : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
+    %1 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
+    %2 = cir.base_class_addr %1 : !cir.ptr<!rec_C> nonnull [0] -> 
!cir.ptr<!rec_A>
+    cir.call @_ZN1AC2Ev(%2) : (!cir.ptr<!rec_A>) -> ()
+    %3 = cir.base_class_addr %1 : !cir.ptr<!rec_C> nonnull [0] -> 
!cir.ptr<!rec_B>
+
+    %4 = cir.vtt.address_point @_ZTT1C, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+    // CHECK: cir.vtt.address_point @_ZTT1C, offset = 1 -> 
!cir.ptr<!cir.ptr<!void>>
+
+    cir.call @_ZN1BC2Ev(%3, %4) : (!cir.ptr<!rec_B>, 
!cir.ptr<!cir.ptr<!void>>) -> ()
+    %5 = cir.vtable.address_point(@_ZTV1C, address_point = <index = 0, offset 
= 3>) : !cir.vptr
+    %6 = cir.vtable.get_vptr %1 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
+    cir.store align(8) %5, %6 : !cir.vptr, !cir.ptr<!cir.vptr>
+    cir.return
+  }
+  cir.global linkonce_odr dso_local @_ZTC1C0_1B = 
#cir.const_record<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, 
#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>]> : 
!cir.array<!cir.ptr<!u8i> x 3>}> : !rec_anon_struct {alignment = 8 : i64}
+}
diff --git a/clang/test/CIR/Lowering/vtt-addrpoint.cir 
b/clang/test/CIR/Lowering/vtt-addrpoint.cir
new file mode 100644
index 0000000000000..a3e7271f7446e
--- /dev/null
+++ b/clang/test/CIR/Lowering/vtt-addrpoint.cir
@@ -0,0 +1,59 @@
+// RUN: cir-translate %s -cir-to-llvmir --target x86_64-unknown-linux-gnu -o 
%t.ll
+// RUN: FileCheck %s --input-file=%t.ll
+
+// Test the lowering of the two forms of vtt.address_point op, as they will
+// appear in constructors.
+
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+!rec_A = !cir.record<struct "A" {!u8i}>
+!rec_B = !cir.record<struct "B" {!cir.vptr}>
+!rec_C = !cir.record<struct "C" {!rec_B}>
+!rec_anon_struct = !cir.record<struct  {!cir.array<!cir.ptr<!u8i> x 3>}>
+module {
+  cir.func private @_ZN1AC2Ev(!cir.ptr<!rec_A>)
+  cir.func private @_ZN1BC2Ev(!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>)
+  cir.func dso_local @_ZN1CC2Ev(%arg0: !cir.ptr<!rec_C>, %arg1: 
!cir.ptr<!cir.ptr<!void>>) {
+    %0 = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", 
init] {alignment = 8 : i64}
+    %1 = cir.alloca !cir.ptr<!cir.ptr<!void>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!void>>>, ["vtt", init] {alignment = 8 : i64}
+    cir.store %arg0, %0 : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
+    cir.store %arg1, %1 : !cir.ptr<!cir.ptr<!void>>, 
!cir.ptr<!cir.ptr<!cir.ptr<!void>>>
+    %2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
+    %3 = cir.load align(8) %1 : !cir.ptr<!cir.ptr<!cir.ptr<!void>>>, 
!cir.ptr<!cir.ptr<!void>>
+    %4 = cir.base_class_addr %2 : !cir.ptr<!rec_C> nonnull [0] -> 
!cir.ptr<!rec_B>
+    %5 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> 
!cir.ptr<!cir.ptr<!void>>
+    cir.call @_ZN1BC2Ev(%4, %5) : (!cir.ptr<!rec_B>, 
!cir.ptr<!cir.ptr<!void>>) -> ()
+    %6 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> 
!cir.ptr<!cir.ptr<!void>>
+    %7 = cir.cast(bitcast, %6 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+    %8 = cir.load align(8) %7 : !cir.ptr<!cir.vptr>, !cir.vptr
+    %9 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
+    cir.store align(8) %8, %9 : !cir.vptr, !cir.ptr<!cir.vptr>
+    cir.return
+  }
+
+// CHECK: define{{.*}} void @_ZN1CC2Ev
+// CHECK:   %[[VTT:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 1
+// CHECK:   call void @_ZN1BC2Ev(ptr %{{.*}}, ptr %[[VTT]])
+
+  cir.global linkonce_odr dso_local @_ZTV1C = 
#cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> 
: !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> 
x 3>}> : !rec_anon_struct {alignment = 8 : i64}
+  cir.global linkonce_odr @_ZTT1C = 
#cir.const_array<[#cir.global_view<@_ZTV1C, [0 : i32, 3 : i32]> : 
!cir.ptr<!u8i>, #cir.global_view<@_ZTC1C0_1B, [0 : i32, 3 : i32]> : 
!cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 2> {alignment = 8 : i64}
+  cir.func dso_local @_ZN1CC1Ev(%arg0: !cir.ptr<!rec_C>) {
+    %0 = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", 
init] {alignment = 8 : i64}
+    cir.store %arg0, %0 : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
+    %1 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
+    %2 = cir.base_class_addr %1 : !cir.ptr<!rec_C> nonnull [0] -> 
!cir.ptr<!rec_A>
+    cir.call @_ZN1AC2Ev(%2) : (!cir.ptr<!rec_A>) -> ()
+    %3 = cir.base_class_addr %1 : !cir.ptr<!rec_C> nonnull [0] -> 
!cir.ptr<!rec_B>
+    %4 = cir.vtt.address_point @_ZTT1C, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+    cir.call @_ZN1BC2Ev(%3, %4) : (!cir.ptr<!rec_B>, 
!cir.ptr<!cir.ptr<!void>>) -> ()
+    %5 = cir.vtable.address_point(@_ZTV1C, address_point = <index = 0, offset 
= 3>) : !cir.vptr
+    %6 = cir.vtable.get_vptr %1 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
+    cir.store align(8) %5, %6 : !cir.vptr, !cir.ptr<!cir.vptr>
+    cir.return
+  }
+
+// CHECK: define{{.*}} void @_ZN1CC1Ev
+// CHECK:   store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1C, i64 24), 
ptr %{{.*}}
+
+  cir.global linkonce_odr dso_local @_ZTC1C0_1B = 
#cir.const_record<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, 
#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>]> : 
!cir.array<!cir.ptr<!u8i> x 3>}> : !rec_anon_struct {alignment = 8 : i64}
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to