Skip to content

Commit 7d51b13

Browse files
bcardosolopeslanza
authored andcommitted
[CIR][CIRGen] Support for visual bases in getAddressOfBaseClass
This is going to be raised in follow up work, which is hard to do in one go because createBaseClassAddr goes of the OG skeleton and ideally we want ApplyNonVirtualAndVirtualOffset to work naturally. This also doesn't handle null checks, coming next.
1 parent ec6c39a commit 7d51b13

File tree

2 files changed

+75
-26
lines changed

2 files changed

+75
-26
lines changed

clang/lib/CIR/CodeGen/CIRGenClass.cpp

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,9 @@ CIRGenFunction::getAddressOfBaseClass(Address Value,
15451545
// *start* with a step down to the correct virtual base subobject,
15461546
// and hence will not require any further steps.
15471547
if ((*Start)->isVirtual()) {
1548-
llvm_unreachable("NYI: Cast to virtual base class");
1548+
VBase = cast<CXXRecordDecl>(
1549+
(*Start)->getType()->castAs<RecordType>()->getDecl());
1550+
++Start;
15491551
}
15501552

15511553
// Compute the static offset of the ultimate destination within its
@@ -1574,39 +1576,33 @@ CIRGenFunction::getAddressOfBaseClass(Address Value,
15741576
if (sanitizePerformTypeCheck()) {
15751577
llvm_unreachable("NYI: sanitizePerformTypeCheck");
15761578
}
1577-
return builder.createBaseClassAddr(getLoc(Loc), Value, BaseValueTy,
1578-
NonVirtualOffset.getQuantity(),
1579-
/*assumeNotNull=*/not NullCheckValue);
15801579
}
15811580

15821581
if (sanitizePerformTypeCheck()) {
15831582
assert(!cir::MissingFeatures::sanitizeOther());
15841583
}
15851584

1586-
// Conversion to a virtual base. cir.base_class_addr can't handle this.
1587-
// Generate the code to look up the address in the virtual table.
1588-
1589-
llvm_unreachable("NYI: Cast to virtual base class");
1590-
1591-
// This is just an outline of what the code might look like, since I can't
1592-
// actually test it.
1593-
#if 0
1594-
mlir::Value VirtualOffset = ...; // This is a dynamic expression. Creating
1595-
// it requires calling an ABI-specific
1596-
// function.
1597-
Value = ApplyNonVirtualAndVirtualOffset(getLoc(Loc), *this, Value,
1598-
NonVirtualOffset, VirtualOffset,
1599-
Derived, VBase);
1600-
Value = builder.createElementBitCast(Value.getPointer().getLoc(), Value,
1601-
BaseValueTy);
1602-
if (sanitizePerformTypeCheck()) {
1603-
// Do something here
1604-
}
1605-
if (NullCheckValue) {
1606-
// Convert to 'derivedPtr == nullptr ? nullptr : basePtr'
1585+
// Compute the virtual offset.
1586+
mlir::Value VirtualOffset = nullptr;
1587+
if (VBase) {
1588+
VirtualOffset = CGM.getCXXABI().getVirtualBaseClassOffset(
1589+
getLoc(Loc), *this, Value, Derived, VBase);
1590+
} else {
1591+
Value = builder.createBaseClassAddr(getLoc(Loc), Value, BaseValueTy,
1592+
NonVirtualOffset.getQuantity(),
1593+
/*assumeNotNull=*/not NullCheckValue);
16071594
}
1608-
#endif
16091595

1596+
// Apply both offsets.
1597+
// FIXME: remove condition.
1598+
if (VBase)
1599+
Value = ApplyNonVirtualAndVirtualOffset(getLoc(Loc), *this, Value,
1600+
NonVirtualOffset, VirtualOffset,
1601+
Derived, VBase);
1602+
1603+
// Cast to the destination type.
1604+
if (VBase)
1605+
Value = Value.withElementType(BaseValueTy);
16101606
return Value;
16111607
}
16121608

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -std=c++20 -mconstructor-aliases -O0 -fclangir -emit-cir %s -o %t.cir
3+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
4+
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -std=c++20 -mconstructor-aliases -O0 -fclangir -emit-llvm -fno-clangir-call-conv-lowering %s -o %t.ll
5+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
6+
7+
struct A { int a; virtual int aa(); };
8+
struct B { int b; virtual int bb(); };
9+
struct C : virtual A, virtual B { int c; virtual int aa(); virtual int bb(); };
10+
struct AA { int a; virtual int aa(); };
11+
struct BB { int b; virtual int bb(); };
12+
struct CC : AA, BB { virtual int aa(); virtual int bb(); virtual int cc(); };
13+
struct D : virtual C, virtual CC { int e; };
14+
15+
D* x;
16+
17+
A* a() { return x; }
18+
// CIR-LABEL: @_Z1av()
19+
// CIR: %[[OFFSET_OFFSET:.*]] = cir.const #cir.int<-32> : !s64i
20+
// CIR: %[[OFFSET_PTR:.*]] = cir.ptr_stride(%4 : !cir.ptr<!u8i>, %[[OFFSET_OFFSET]] : !s64i), !cir.ptr<!u8i>
21+
// CIR: %[[OFFSET_PTR_CAST:.*]] = cir.cast(bitcast, %[[OFFSET_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!s64i>
22+
// CIR: %[[OFFSET:.*]] = cir.load %[[OFFSET_PTR_CAST]] : !cir.ptr<!s64i>, !s64i
23+
// CIR: %[[VBASE_ADDR:.*]] = cir.ptr_stride({{.*}} : !cir.ptr<!u8i>, %[[OFFSET]] : !s64i), !cir.ptr<!u8i>
24+
// CIR: cir.cast(bitcast, %[[VBASE_ADDR]] : !cir.ptr<!u8i>), !cir.ptr<!ty_D>
25+
26+
// FIXME: this version should include null check.
27+
// LLVM-LABEL: @_Z1av()
28+
// LLVM: %[[OFFSET_OFFSET:.*]] = getelementptr i8, ptr {{.*}}, i64 -32
29+
// LLVM: %[[OFFSET_PTR:.*]] = load i64, ptr %[[OFFSET_OFFSET]], align 8
30+
// LLVM: %[[VBASE_ADDR:.*]] = getelementptr i8, ptr {{.*}}, i64 %[[OFFSET_PTR]]
31+
// LLVM: store ptr %[[VBASE_ADDR]], ptr {{.*}}, align 8
32+
33+
B* b() { return x; }
34+
BB* c() { return x; }
35+
36+
// Put the vbptr at a non-zero offset inside a non-virtual base.
37+
struct E { int e; };
38+
struct F : E, D { int f; };
39+
40+
F* y;
41+
42+
BB* d() { return y; }
43+
// CIR-LABEL: @_Z1dv
44+
// CIR: %[[OFFSET:.*]] = cir.load {{.*}} : !cir.ptr<!s64i>, !s64i
45+
// CIR: %[[ADJUST:.*]] = cir.const #cir.int<16> : !s64i
46+
// CIR: cir.binop(add, %[[OFFSET]], %[[ADJUST]]) : !s64i
47+
48+
// LLVM-LABEL: @_Z1dv
49+
// LLVM: %[[OFFSET_OFFSET:.*]] = getelementptr i8, ptr {{.*}}, i64 -48
50+
// LLVM: %[[OFFSET_PTR:.*]] = load i64, ptr %[[OFFSET_OFFSET]], align 8
51+
// LLVM: %[[ADJUST:.*]] = add i64 %[[OFFSET_PTR]], 16
52+
// LLVM: %[[VBASE_ADDR:.*]] = getelementptr i8, ptr {{.*}}, i64 %[[ADJUST]]
53+
// LLVM: store ptr %[[VBASE_ADDR]],

0 commit comments

Comments
 (0)