Skip to content

Commit 99bfe6e

Browse files
authored
[CIR] Add VTTAddrPointOp (llvm#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.
1 parent 9143746 commit 99bfe6e

File tree

7 files changed

+319
-3
lines changed

7 files changed

+319
-3
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,70 @@ def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [
19061906
}];
19071907
}
19081908

1909+
//===----------------------------------------------------------------------===//
1910+
// VTTAddrPointOp
1911+
//===----------------------------------------------------------------------===//
1912+
1913+
def CIR_VTTAddrPointOp : CIR_Op<"vtt.address_point", [
1914+
Pure, DeclareOpInterfaceMethods<SymbolUserOpInterface>
1915+
]> {
1916+
let summary = "Get the VTT address point";
1917+
let description = [{
1918+
The `vtt.address_point` operation retrieves an element from the virtual
1919+
table table (VTT), which is the address point of a C++ vtable. In virtual
1920+
inheritance, a set of internal `__vptr` members for an object are
1921+
initialized by this operation, which assigns an element from the VTT. The
1922+
initialization order is as follows:
1923+
1924+
The complete object constructors and destructors find the VTT,
1925+
via the mangled name of the VTT global variable. They pass the address of
1926+
the subobject's sub-VTT entry in the VTT as a second parameter
1927+
when calling the base object constructors and destructors.
1928+
The base object constructors and destructors use the address passed to
1929+
initialize the primary virtual pointer and virtual pointers that point to
1930+
the classes which either have virtual bases or override virtual functions
1931+
with a virtual step.
1932+
1933+
The first parameter is either the mangled name of VTT global variable
1934+
or the address of the subobject's sub-VTT entry in the VTT.
1935+
The second parameter `offset` provides a virtual step to adjust to
1936+
the actual address point of the vtable.
1937+
1938+
The return type is always a `!cir.ptr<!cir.ptr<void>>`.
1939+
1940+
Example:
1941+
```mlir
1942+
cir.global linkonce_odr @_ZTV1B = ...
1943+
...
1944+
%3 = cir.base_class_addr(%1 : !cir.ptr<!rec_D> nonnull) [0]
1945+
-> !cir.ptr<!rec_B>
1946+
%4 = cir.vtt.address_point @_ZTT1D, offset = 1
1947+
-> !cir.ptr<!cir.ptr<!void>>
1948+
cir.call @_ZN1BC2Ev(%3, %4)
1949+
```
1950+
Or:
1951+
```mlir
1952+
%7 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 1
1953+
-> !cir.ptr<!cir.ptr<!void>>
1954+
```
1955+
}];
1956+
1957+
let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$name,
1958+
Optional<CIR_AnyType>:$sym_addr,
1959+
I32Attr:$offset);
1960+
let results = (outs CIR_PointerType:$addr);
1961+
1962+
let assemblyFormat = [{
1963+
($name^)?
1964+
($sym_addr^ `:` type($sym_addr))?
1965+
`,`
1966+
`offset` `=` $offset
1967+
`->` qualified(type($addr)) attr-dict
1968+
}];
1969+
1970+
let hasVerifier = 1;
1971+
}
1972+
19091973
//===----------------------------------------------------------------------===//
19101974
// SetBitfieldOp
19111975
//===----------------------------------------------------------------------===//

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,53 @@ cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
14741474
return success();
14751475
}
14761476

1477+
//===----------------------------------------------------------------------===//
1478+
// VTTAddrPointOp
1479+
//===----------------------------------------------------------------------===//
1480+
1481+
LogicalResult
1482+
cir::VTTAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1483+
// VTT ptr is not coming from a symbol.
1484+
if (!getName())
1485+
return success();
1486+
StringRef name = *getName();
1487+
1488+
// Verify that the result type underlying pointer type matches the type of
1489+
// the referenced cir.global op.
1490+
auto op =
1491+
symbolTable.lookupNearestSymbolFrom<cir::GlobalOp>(*this, getNameAttr());
1492+
if (!op)
1493+
return emitOpError("'")
1494+
<< name << "' does not reference a valid cir.global";
1495+
std::optional<mlir::Attribute> init = op.getInitialValue();
1496+
if (!init)
1497+
return success();
1498+
if (!isa<cir::ConstArrayAttr>(*init))
1499+
return emitOpError(
1500+
"Expected constant array in initializer for global VTT '")
1501+
<< name << "'";
1502+
return success();
1503+
}
1504+
1505+
LogicalResult cir::VTTAddrPointOp::verify() {
1506+
// The operation uses either a symbol or a value to operate, but not both
1507+
if (getName() && getSymAddr())
1508+
return emitOpError("should use either a symbol or value, but not both");
1509+
1510+
// If not a symbol, stick with the concrete type used for getSymAddr.
1511+
if (getSymAddr())
1512+
return success();
1513+
1514+
mlir::Type resultType = getAddr().getType();
1515+
mlir::Type resTy = cir::PointerType::get(
1516+
cir::PointerType::get(cir::VoidType::get(getContext())));
1517+
1518+
if (resultType != resTy)
1519+
return emitOpError("result type must be ")
1520+
<< resTy << ", but provided result type is " << resultType;
1521+
return success();
1522+
}
1523+
14771524
//===----------------------------------------------------------------------===//
14781525
// FuncOp
14791526
//===----------------------------------------------------------------------===//

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2451,7 +2451,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
24512451
CIRToLLVMVecTernaryOpLowering,
24522452
CIRToLLVMVTableAddrPointOpLowering,
24532453
CIRToLLVMVTableGetVPtrOpLowering,
2454-
CIRToLLVMVTableGetVirtualFnAddrOpLowering
2454+
CIRToLLVMVTableGetVirtualFnAddrOpLowering,
2455+
CIRToLLVMVTTAddrPointOpLowering
24552456
// clang-format on
24562457
>(converter, patterns.getContext());
24572458

@@ -2600,6 +2601,36 @@ mlir::LogicalResult CIRToLLVMVTableGetVirtualFnAddrOpLowering::matchAndRewrite(
26002601
return mlir::success();
26012602
}
26022603

2604+
mlir::LogicalResult CIRToLLVMVTTAddrPointOpLowering::matchAndRewrite(
2605+
cir::VTTAddrPointOp op, OpAdaptor adaptor,
2606+
mlir::ConversionPatternRewriter &rewriter) const {
2607+
const mlir::Type resultType = getTypeConverter()->convertType(op.getType());
2608+
llvm::SmallVector<mlir::LLVM::GEPArg> offsets;
2609+
mlir::Type eltType;
2610+
mlir::Value llvmAddr = adaptor.getSymAddr();
2611+
2612+
if (op.getSymAddr()) {
2613+
if (op.getOffset() == 0) {
2614+
rewriter.replaceOp(op, {llvmAddr});
2615+
return mlir::success();
2616+
}
2617+
2618+
offsets.push_back(adaptor.getOffset());
2619+
eltType = mlir::IntegerType::get(resultType.getContext(), 8,
2620+
mlir::IntegerType::Signless);
2621+
} else {
2622+
llvmAddr = getValueForVTableSymbol(op, rewriter, getTypeConverter(),
2623+
op.getNameAttr(), eltType);
2624+
assert(eltType && "Shouldn't ever be missing an eltType here");
2625+
offsets.push_back(0);
2626+
offsets.push_back(adaptor.getOffset());
2627+
}
2628+
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
2629+
op, resultType, eltType, llvmAddr, offsets,
2630+
mlir::LLVM::GEPNoWrapFlags::inbounds);
2631+
return mlir::success();
2632+
}
2633+
26032634
mlir::LogicalResult CIRToLLVMStackSaveOpLowering::matchAndRewrite(
26042635
cir::StackSaveOp op, OpAdaptor adaptor,
26052636
mlir::ConversionPatternRewriter &rewriter) const {

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,16 @@ class CIRToLLVMVTableGetVirtualFnAddrOpLowering
508508
mlir::ConversionPatternRewriter &) const override;
509509
};
510510

511+
class CIRToLLVMVTTAddrPointOpLowering
512+
: public mlir::OpConversionPattern<cir::VTTAddrPointOp> {
513+
public:
514+
using mlir::OpConversionPattern<cir::VTTAddrPointOp>::OpConversionPattern;
515+
516+
mlir::LogicalResult
517+
matchAndRewrite(cir::VTTAddrPointOp op, OpAdaptor,
518+
mlir::ConversionPatternRewriter &) const override;
519+
};
520+
511521
class CIRToLLVMStackSaveOpLowering
512522
: public mlir::OpConversionPattern<cir::StackSaveOp> {
513523
public:

clang/test/CIR/IR/invalid-vtable.cir

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// RUN: cir-opt %s -verify-diagnostics -split-input-file
22

3-
!s8i = !cir.int<s, 8>
43
!u32i = !cir.int<u, 32>
54
cir.func @reference_unknown_vtable() {
65
// 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() {
1312
!u8i = !cir.int<u, 8>
1413
!u32i = !cir.int<u, 32>
1514
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>
16-
cir.func @reference_unknown_vtable() {
15+
cir.func @reference_non_vtable() {
1716
// expected-error @below {{Expected #cir.vtable in initializer for global '_ZTT1D'}}
1817
%0 = cir.vtable.address_point(@_ZTT1D, address_point = <index = 0, offset = 2>) : !cir.vptr
1918
cir.return
@@ -82,3 +81,54 @@ module {
8281
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
8382
cir.func private dso_local @_ZN2S23keyEv(%arg0: !cir.ptr<!rec_S2>)
8483
}
84+
85+
// -----
86+
87+
!u32i = !cir.int<u, 32>
88+
!void = !cir.void
89+
cir.func @reference_unknown_vtt() {
90+
// expected-error @below {{'cir.vtt.address_point' op 'some_vtt' does not reference a valid cir.global}}
91+
%0 = cir.vtt.address_point @some_vtt, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
92+
cir.return
93+
}
94+
95+
// -----
96+
97+
!u8i = !cir.int<u, 8>
98+
!u32i = !cir.int<u, 32>
99+
!void = !cir.void
100+
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
101+
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}
102+
cir.func @reference_non_vtt() {
103+
// expected-error @below {{'cir.vtt.address_point' op Expected constant array in initializer for global VTT '_ZTV1S'}}
104+
%0 = cir.vtt.address_point @_ZTV1S, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
105+
cir.return
106+
}
107+
108+
// -----
109+
110+
!u8i = !cir.int<u, 8>
111+
!u32i = !cir.int<u, 32>
112+
!void = !cir.void
113+
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
114+
!rec_C = !cir.record<class "C" {!cir.vptr}>
115+
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}
116+
cir.func @reference_name_and_value(%arg0: !cir.ptr<!rec_C>, %arg1: !cir.ptr<!cir.ptr<!void>>) {
117+
// expected-error @below {{'cir.vtt.address_point' op should use either a symbol or value, but not both}}
118+
%0 = cir.vtt.address_point @_ZTT1C %arg1 : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
119+
cir.return
120+
}
121+
122+
// -----
123+
124+
!u8i = !cir.int<u, 8>
125+
!u32i = !cir.int<u, 32>
126+
!void = !cir.void
127+
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
128+
!rec_C = !cir.record<class "C" {!cir.vptr}>
129+
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}
130+
cir.func @bad_return_type_for_vtt_addrpoint() {
131+
// expected-error @below {{result type must be '!cir.ptr<!cir.ptr<!cir.void>>', but provided result type is '!cir.ptr<!cir.int<u, 8>>'}}
132+
%0 = cir.vtt.address_point @_ZTT1C, offset = 1 -> !cir.ptr<!u8i>
133+
cir.return
134+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: cir-opt %s | FileCheck %s
2+
3+
// Test the parsing and printing of the two forms of vtt.address_point op, as
4+
// they will appear in constructors.
5+
6+
!u8i = !cir.int<u, 8>
7+
!void = !cir.void
8+
!rec_A = !cir.record<struct "A" {!u8i}>
9+
!rec_B = !cir.record<struct "B" {!cir.vptr}>
10+
!rec_C = !cir.record<struct "C" {!rec_B}>
11+
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 3>}>
12+
module {
13+
cir.func private @_ZN1AC2Ev(!cir.ptr<!rec_A>)
14+
cir.func private @_ZN1BC2Ev(!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>)
15+
cir.func dso_local @_ZN1CC2Ev(%arg0: !cir.ptr<!rec_C>, %arg1: !cir.ptr<!cir.ptr<!void>>) {
16+
%0 = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", init] {alignment = 8 : i64}
17+
%1 = cir.alloca !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!cir.ptr<!cir.ptr<!void>>>, ["vtt", init] {alignment = 8 : i64}
18+
cir.store %arg0, %0 : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
19+
cir.store %arg1, %1 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!cir.ptr<!cir.ptr<!void>>>
20+
%2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
21+
%3 = cir.load align(8) %1 : !cir.ptr<!cir.ptr<!cir.ptr<!void>>>, !cir.ptr<!cir.ptr<!void>>
22+
%4 = cir.base_class_addr %2 : !cir.ptr<!rec_C> nonnull [0] -> !cir.ptr<!rec_B>
23+
24+
%5 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
25+
// CHECK: cir.vtt.address_point %{{.*}} : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
26+
27+
cir.call @_ZN1BC2Ev(%4, %5) : (!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>) -> ()
28+
%6 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> !cir.ptr<!cir.ptr<!void>>
29+
%7 = cir.cast(bitcast, %6 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
30+
%8 = cir.load align(8) %7 : !cir.ptr<!cir.vptr>, !cir.vptr
31+
%9 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
32+
cir.store align(8) %8, %9 : !cir.vptr, !cir.ptr<!cir.vptr>
33+
cir.return
34+
}
35+
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}
36+
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}
37+
cir.func dso_local @_ZN1CC1Ev(%arg0: !cir.ptr<!rec_C>) {
38+
%0 = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", init] {alignment = 8 : i64}
39+
cir.store %arg0, %0 : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
40+
%1 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
41+
%2 = cir.base_class_addr %1 : !cir.ptr<!rec_C> nonnull [0] -> !cir.ptr<!rec_A>
42+
cir.call @_ZN1AC2Ev(%2) : (!cir.ptr<!rec_A>) -> ()
43+
%3 = cir.base_class_addr %1 : !cir.ptr<!rec_C> nonnull [0] -> !cir.ptr<!rec_B>
44+
45+
%4 = cir.vtt.address_point @_ZTT1C, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
46+
// CHECK: cir.vtt.address_point @_ZTT1C, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
47+
48+
cir.call @_ZN1BC2Ev(%3, %4) : (!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>) -> ()
49+
%5 = cir.vtable.address_point(@_ZTV1C, address_point = <index = 0, offset = 3>) : !cir.vptr
50+
%6 = cir.vtable.get_vptr %1 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
51+
cir.store align(8) %5, %6 : !cir.vptr, !cir.ptr<!cir.vptr>
52+
cir.return
53+
}
54+
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}
55+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: cir-translate %s -cir-to-llvmir --target x86_64-unknown-linux-gnu -o %t.ll
2+
// RUN: FileCheck %s --input-file=%t.ll
3+
4+
// Test the lowering of the two forms of vtt.address_point op, as they will
5+
// appear in constructors.
6+
7+
!u8i = !cir.int<u, 8>
8+
!void = !cir.void
9+
!rec_A = !cir.record<struct "A" {!u8i}>
10+
!rec_B = !cir.record<struct "B" {!cir.vptr}>
11+
!rec_C = !cir.record<struct "C" {!rec_B}>
12+
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 3>}>
13+
module {
14+
cir.func private @_ZN1AC2Ev(!cir.ptr<!rec_A>)
15+
cir.func private @_ZN1BC2Ev(!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>)
16+
cir.func dso_local @_ZN1CC2Ev(%arg0: !cir.ptr<!rec_C>, %arg1: !cir.ptr<!cir.ptr<!void>>) {
17+
%0 = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", init] {alignment = 8 : i64}
18+
%1 = cir.alloca !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!cir.ptr<!cir.ptr<!void>>>, ["vtt", init] {alignment = 8 : i64}
19+
cir.store %arg0, %0 : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
20+
cir.store %arg1, %1 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!cir.ptr<!cir.ptr<!void>>>
21+
%2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
22+
%3 = cir.load align(8) %1 : !cir.ptr<!cir.ptr<!cir.ptr<!void>>>, !cir.ptr<!cir.ptr<!void>>
23+
%4 = cir.base_class_addr %2 : !cir.ptr<!rec_C> nonnull [0] -> !cir.ptr<!rec_B>
24+
%5 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
25+
cir.call @_ZN1BC2Ev(%4, %5) : (!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>) -> ()
26+
%6 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> !cir.ptr<!cir.ptr<!void>>
27+
%7 = cir.cast(bitcast, %6 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
28+
%8 = cir.load align(8) %7 : !cir.ptr<!cir.vptr>, !cir.vptr
29+
%9 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
30+
cir.store align(8) %8, %9 : !cir.vptr, !cir.ptr<!cir.vptr>
31+
cir.return
32+
}
33+
34+
// CHECK: define{{.*}} void @_ZN1CC2Ev
35+
// CHECK: %[[VTT:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 1
36+
// CHECK: call void @_ZN1BC2Ev(ptr %{{.*}}, ptr %[[VTT]])
37+
38+
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}
39+
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}
40+
cir.func dso_local @_ZN1CC1Ev(%arg0: !cir.ptr<!rec_C>) {
41+
%0 = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", init] {alignment = 8 : i64}
42+
cir.store %arg0, %0 : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
43+
%1 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
44+
%2 = cir.base_class_addr %1 : !cir.ptr<!rec_C> nonnull [0] -> !cir.ptr<!rec_A>
45+
cir.call @_ZN1AC2Ev(%2) : (!cir.ptr<!rec_A>) -> ()
46+
%3 = cir.base_class_addr %1 : !cir.ptr<!rec_C> nonnull [0] -> !cir.ptr<!rec_B>
47+
%4 = cir.vtt.address_point @_ZTT1C, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
48+
cir.call @_ZN1BC2Ev(%3, %4) : (!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>) -> ()
49+
%5 = cir.vtable.address_point(@_ZTV1C, address_point = <index = 0, offset = 3>) : !cir.vptr
50+
%6 = cir.vtable.get_vptr %1 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
51+
cir.store align(8) %5, %6 : !cir.vptr, !cir.ptr<!cir.vptr>
52+
cir.return
53+
}
54+
55+
// CHECK: define{{.*}} void @_ZN1CC1Ev
56+
// CHECK: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1C, i64 24), ptr %{{.*}}
57+
58+
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}
59+
}

0 commit comments

Comments
 (0)