-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[CIR] Add support for emitting multi-vtables #155027
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
Conversation
This change adds support for emitting multiple tables in a global vtable object to handle the case of multiple-inheritence.
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesThis change adds support for emitting multiple tables in a global vtable object to handle the case of multiple-inheritence. Full diff: https://github.com/llvm/llvm-project/pull/155027.diff 2 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
index 438b483ccb9c2..28a630becc3dc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
@@ -144,33 +144,30 @@ void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp,
layout.getAddressPointIndices();
unsigned nextVTableThunkIndex = 0;
- if (layout.getNumVTables() > 1)
- cgm.errorNYI("emitVTableDefinitions: multiple vtables");
-
- // We'll need a loop here to handle multiple vtables, but for now we only
- // support one.
- unsigned vtableIndex = 0;
- size_t vtableStart = layout.getVTableOffset(vtableIndex);
- size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex);
-
- // Build a ConstArrayAttr of the vtable components.
- llvm::SmallVector<mlir::Attribute> components;
- for (size_t componentIndex = vtableStart; componentIndex < vtableEnd;
- ++componentIndex) {
- components.push_back(
- getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex,
- addressPoints[vtableIndex], vtableHasLocalLinkage));
- }
-
mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
- // Create a ConstArrayAttr to hold the components.
- auto arr = cir::ConstArrayAttr::get(
- cir::ArrayType::get(componentType, components.size()),
- mlir::ArrayAttr::get(mlirContext, components));
+ SmallVector<mlir::Attribute> vtables;
+ for (unsigned vtableIndex = 0, endIndex = layout.getNumVTables();
+ vtableIndex != endIndex; ++vtableIndex) {
+ // Build a ConstArrayAttr of the vtable components.
+ size_t vtableStart = layout.getVTableOffset(vtableIndex);
+ size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex);
+ llvm::SmallVector<mlir::Attribute> components;
+ for (size_t componentIndex = vtableStart; componentIndex < vtableEnd;
+ ++componentIndex) {
+ components.push_back(getVTableComponent(
+ layout, componentIndex, rtti, nextVTableThunkIndex,
+ addressPoints[vtableIndex], vtableHasLocalLinkage));
+ }
+ // Create a ConstArrayAttr to hold the components.
+ auto arr = cir::ConstArrayAttr::get(
+ cir::ArrayType::get(componentType, components.size()),
+ mlir::ArrayAttr::get(mlirContext, components));
+ vtables.push_back(arr);
+ }
// Create a ConstRecordAttr to hold the component array.
- const auto members = mlir::ArrayAttr::get(mlirContext, {arr});
+ const auto members = mlir::ArrayAttr::get(mlirContext, vtables);
cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members);
// Create a VTableAttr
diff --git a/clang/test/CIR/CodeGen/multi-vtable.cpp b/clang/test/CIR/CodeGen/multi-vtable.cpp
new file mode 100644
index 0000000000000..c127285800844
--- /dev/null
+++ b/clang/test/CIR/CodeGen/multi-vtable.cpp
@@ -0,0 +1,136 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -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 -mconstructor-aliases -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 -mconstructor-aliases -fno-rtti -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+// Note: This test is using -fno-rtti so that we can delay implemntation of that handling.
+// When rtti handling for vtables is implemented, that option should be removed.
+
+class Mother {
+public:
+ virtual void MotherKey();
+ void simple() { }
+ virtual void MotherNonKey() {}
+};
+
+class Father {
+public:
+ virtual void FatherKey();
+};
+
+class Child : public Mother, public Father {
+public:
+ void MotherKey() override;
+};
+
+void Mother::MotherKey() {}
+void Father::FatherKey() {}
+void Child::MotherKey() {}
+
+// CIR-DAG: [[MOTHER_VTABLE_TYPE:.*]] = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
+// CIR-DAG: [[FATHER_VTABLE_TYPE:.*]] = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 3>}>
+// CIR-DAG: [[CHILD_VTABLE_TYPE:.*]] = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 3>}>
+// CIR-DAG: !rec_Father = !cir.record<class "Father" {!cir.vptr}
+// CIR-DAG: !rec_Mother = !cir.record<class "Mother" {!cir.vptr}
+// CIR-DAG: !rec_Child = !cir.record<class "Child" {!rec_Mother, !rec_Father}
+
+// Mother vtable
+
+// CIR: cir.global "private" external @_ZTV6Mother = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Mother9MotherKeyEv> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Mother12MotherNonKeyEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>
+// CIR-SAME: }> : [[MOTHER_VTABLE_TYPE]]
+
+// LLVM: @_ZTV6Mother = global { [4 x ptr] } {
+// LLVM-SAME: [4 x ptr] [
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr @_ZN6Mother9MotherKeyEv,
+// LLVM-SAME: ptr @_ZN6Mother12MotherNonKeyEv
+// LLVM-SAME: ]
+// LLVM-SAME: }
+
+// OGCG: @_ZTV6Mother = unnamed_addr constant { [4 x ptr] } {
+// OGCG-SAME: [4 x ptr] [
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr @_ZN6Mother9MotherKeyEv,
+// OGCG-SAME: ptr @_ZN6Mother12MotherNonKeyEv
+// OGCG-SAME: ]
+// OGCG-SAME: }
+
+// Father vtable
+
+// CIR: cir.global "private" external @_ZTV6Father = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Father9FatherKeyEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 3>
+// CIR-SAME: }> : [[FATHER_VTABLE_TYPE]]
+
+// LLVM: @_ZTV6Father = global { [3 x ptr] } {
+// LLVM-SAME: [3 x ptr] [
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr @_ZN6Father9FatherKeyEv
+// LLVM-SAME: ]
+// LLVM-SAME: }
+
+// OGCG: @_ZTV6Father = unnamed_addr constant { [3 x ptr] } {
+// OGCG-SAME: [3 x ptr] [
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr @_ZN6Father9FatherKeyEv
+// OGCG-SAME: ]
+// OGCG-SAME: }
+
+// Child vtable
+
+// CIR: cir.global "private" external @_ZTV5Child = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN5Child9MotherKeyEv> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Mother12MotherNonKeyEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>,
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<-8 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Father9FatherKeyEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 3>
+// CIR-SAME: }> : [[CHILD_VTABLE_TYPE]]
+
+// LLVM: @_ZTV5Child = global { [4 x ptr], [3 x ptr] } {
+// LLVM-SAME: [4 x ptr] [
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr @_ZN5Child9MotherKeyEv,
+// LLVM-SAME: ptr @_ZN6Mother12MotherNonKeyEv
+// LLVM-SAME: ],
+// LLVM-SAME: [3 x ptr] [
+// LLVM-SAME: ptr inttoptr (i64 -8 to ptr),
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr @_ZN6Father9FatherKeyEv
+// LLVM-SAME: ]
+// LLVM-SAME: }
+
+// OGCG: @_ZTV5Child = unnamed_addr constant { [4 x ptr], [3 x ptr] } {
+// OGCG-SAME: [4 x ptr] [
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr @_ZN5Child9MotherKeyEv,
+// OGCG-SAME: ptr @_ZN6Mother12MotherNonKeyEv
+// OGCG-SAME: ],
+// OGCG-SAME: [3 x ptr] [
+// OGCG-SAME: ptr inttoptr (i64 -8 to ptr),
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr @_ZN6Father9FatherKeyEv
+// OGCG-SAME: ]
+// OGCG-SAME: }
|
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.
LGTM w/ minor suggestion
cir::ArrayType::get(componentType, components.size()), | ||
mlir::ArrayAttr::get(mlirContext, components)); | ||
SmallVector<mlir::Attribute> vtables; | ||
for (unsigned vtableIndex = 0, endIndex = layout.getNumVTables(); |
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.
Shall we llvm::enumerate
here?
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.
Nice! I hadn't noticed that was a possibility here.
// Build a ConstArrayAttr of the vtable components. | ||
size_t vtableStart = layout.getVTableOffset(vtableIndex); | ||
size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex); | ||
llvm::SmallVector<mlir::Attribute> components; |
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.
Maybe we could reserve capacity here, or use llvm::SmallVector<mlir::Attribute, num_components>
since the size is known from vtableStart
and vtableEnd
?
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.
llvm::SmallVector<mlir::Attribute, num_components>
THAT wouldn't work, since vtableStart/vtableEnd aren't constant expressions. But a .reserve
isn't a terrible idea. That said, our growth rate and slab allocator makes reserve not particularly valuable for SmallVector.
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.
It doesn't seem like there's much downside to a reserve, maybe a few extra instructions in cases where we wouldn't need to grow the vector, and it might save us a memcpy in cases where the vector does need to grow.
size_t vtableStart = layout.getVTableOffset(vtableIndex); | ||
size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex); | ||
llvm::SmallVector<mlir::Attribute> components; | ||
for (size_t componentIndex = vtableStart; componentIndex < vtableEnd; |
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.
for (size_t componentIndex = vtableStart; componentIndex < vtableEnd; | |
for (size_t componentIndex : llvm::seq(vtableStart, vtableEnd)) |
I think llvm::seq
makes this loop shorter.
This change adds support for emitting multiple tables in a global vtable object to handle the case of multiple-inheritence.