[clang] [CIR] Add vptr type and generate vptr field when needed (PR #151377)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 1 09:28:41 PDT 2025
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/151377
>From e6a0352f42818a13ece66f505d6cb107cb3dea0e Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 30 Jul 2025 11:43:02 -0700
Subject: [PATCH 1/2] [CIR] Add vptr type and generate vptr field when needed
This adds a new CIR type, cir.vptr, and generates a field of
that type when a record is declared that requires a vptr member.
---
.../include/clang/CIR/Dialect/IR/CIRTypes.td | 31 ++++++++++++++++++-
.../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 13 ++++++--
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 18 +++++++++++
.../CIR/CodeGen/virtual-function-calls.cpp | 13 ++++++++
4 files changed, 71 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/virtual-function-calls.cpp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index edd21b55640b9..4e8a8db091c7f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -281,6 +281,35 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
}];
}
+//===----------------------------------------------------------------------===//
+// CIR_VPtrType
+//===----------------------------------------------------------------------===//
+
+def CIR_VPtrType : CIR_Type<"VPtr", "vptr",
+ [DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {
+
+ let summary = "CIR type that is used for the vptr member of C++ objects";
+ let description = [{
+ `cir.vptr` is a special type used as the type for the vptr member of a C++
+ object. This avoids using arbitrary pointer types to declare vptr values
+ and allows stronger type-based checking for operations that use or provide
+ access to the vptr.
+
+ This type will be the element type of the 'vptr' member of structures that
+ require a vtable pointer. A pointer to this type is returned by the
+ `cir.vtable.address_point` and `cir.vtable.get_vptr` operations, and this
+ pointer may be passed to the `cir.vtable.get_virtual_fn_addr` operation to
+ get the address of a virtual function pointer.
+
+ The pointer may also be cast to other pointer types in order to perform
+ pointer arithmetic based on information encoded in the AST layout to get
+ the offset from a pointer to a dynamic object to the base object pointer,
+ the base object offset value from the vtable, or the type information
+ entry for an object.
+ TODO: We should have special operations to do that too.
+ }];
+}
+
//===----------------------------------------------------------------------===//
// BoolType
//===----------------------------------------------------------------------===//
@@ -635,7 +664,7 @@ def CIRRecordType : Type<
def CIR_AnyType : AnyTypeOf<[
CIR_VoidType, CIR_BoolType, CIR_ArrayType, CIR_VectorType, CIR_IntType,
CIR_AnyFloatType, CIR_PointerType, CIR_FuncType, CIR_RecordType,
- CIR_ComplexType
+ CIR_ComplexType, CIR_VPtrType
]>;
#endif // CLANG_CIR_DIALECT_IR_CIRTYPES_TD
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index e4ec380043689..170cd7583855f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -41,7 +41,7 @@ struct CIRRecordLowering final {
// member type that ensures correct rounding.
struct MemberInfo final {
CharUnits offset;
- enum class InfoKind { Field, Base } kind;
+ enum class InfoKind { VFPtr, Field, Base } kind;
mlir::Type data;
union {
const FieldDecl *fieldDecl;
@@ -87,6 +87,8 @@ struct CIRRecordLowering final {
accumulateBitFields(RecordDecl::field_iterator field,
RecordDecl::field_iterator fieldEnd);
+ mlir::Type getVFPtrType();
+
bool isAAPCS() const {
return astContext.getTargetInfo().getABI().starts_with("aapcs");
}
@@ -802,9 +804,14 @@ void CIRRecordLowering::accumulateBases(const CXXRecordDecl *cxxRecordDecl) {
void CIRRecordLowering::accumulateVPtrs() {
if (astRecordLayout.hasOwnVFPtr())
- cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
- "accumulateVPtrs: hasOwnVFPtr");
+ members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::InfoKind::VFPtr,
+ getVFPtrType()));
+
if (astRecordLayout.hasOwnVBPtr())
cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
"accumulateVPtrs: hasOwnVBPtr");
}
+
+mlir::Type CIRRecordLowering::getVFPtrType() {
+ return cir::VPtrType::get(builder.getContext());
+}
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 40da5e60a93f9..04c4660f03096 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -697,6 +697,24 @@ BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
return 1;
}
+//===----------------------------------------------------------------------===//
+// VPtrType Definitions
+//===----------------------------------------------------------------------===//
+
+llvm::TypeSize
+VPtrType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
+ ::mlir::DataLayoutEntryListRef params) const {
+ // FIXME: consider size differences under different ABIs
+ return llvm::TypeSize::getFixed(64);
+}
+
+uint64_t
+VPtrType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
+ ::mlir::DataLayoutEntryListRef params) const {
+ // FIXME: consider alignment differences under different ABIs
+ return 8;
+}
+
//===----------------------------------------------------------------------===//
// ArrayType Definitions
//===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/CodeGen/virtual-function-calls.cpp b/clang/test/CIR/CodeGen/virtual-function-calls.cpp
new file mode 100644
index 0000000000000..3e03b32ce1fd2
--- /dev/null
+++ b/clang/test/CIR/CodeGen/virtual-function-calls.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+
+struct A {
+ virtual void f(char);
+};
+
+// This is just here to force the class definition to be emitted without
+// requiring any other support. It will be removed when more complete
+// vtable support is implemented.
+A *a;
+
+// CIR: !rec_A = !cir.record<struct "A" {!cir.vptr}>
>From 790c766ce5973c4eebe3aa86fc0a19a040cf5532 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Fri, 1 Aug 2025 09:28:14 -0700
Subject: [PATCH 2/2] Address review feedback
---
clang/include/clang/CIR/Dialect/IR/CIRTypes.td | 6 +++---
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 8 ++++----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 4e8a8db091c7f..a258df79a6184 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -285,9 +285,9 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
// CIR_VPtrType
//===----------------------------------------------------------------------===//
-def CIR_VPtrType : CIR_Type<"VPtr", "vptr",
- [DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {
-
+def CIR_VPtrType : CIR_Type<"VPtr", "vptr", [
+ DeclareTypeInterfaceMethods<DataLayoutTypeInterface>
+]> {
let summary = "CIR type that is used for the vptr member of C++ objects";
let description = [{
`cir.vptr` is a special type used as the type for the vptr member of a C++
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 04c4660f03096..db527f232021e 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -702,15 +702,15 @@ BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
//===----------------------------------------------------------------------===//
llvm::TypeSize
-VPtrType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
- ::mlir::DataLayoutEntryListRef params) const {
+VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
+ mlir::DataLayoutEntryListRef params) const {
// FIXME: consider size differences under different ABIs
return llvm::TypeSize::getFixed(64);
}
uint64_t
-VPtrType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
- ::mlir::DataLayoutEntryListRef params) const {
+VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout,
+ mlir::DataLayoutEntryListRef params) const {
// FIXME: consider alignment differences under different ABIs
return 8;
}
More information about the cfe-commits
mailing list