Skip to content

[CIR] Add vptr type and generate vptr field when needed #151377

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

Merged
merged 3 commits into from
Aug 1, 2025

Conversation

andykaylor
Copy link
Contributor

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.

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.
@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Jul 30, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 30, 2025

@llvm/pr-subscribers-clangir

@llvm/pr-subscribers-clang

Author: Andy Kaylor (andykaylor)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/151377.diff

4 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.td (+30-1)
  • (modified) clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp (+10-3)
  • (modified) clang/lib/CIR/Dialect/IR/CIRTypes.cpp (+18)
  • (added) clang/test/CIR/CodeGen/virtual-function-calls.cpp (+13)
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}>

@andykaylor
Copy link
Contributor Author

Corresponding changes at llvm/clangir#1745 show how I intend to use this type.

Copy link
Contributor

@xlauko xlauko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Comment on lines 288 to 290
def CIR_VPtrType : CIR_Type<"VPtr", "vptr",
[DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {

Copy link
Contributor

@xlauko xlauko Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, to align with style of the rest:

Suggested change
def CIR_VPtrType : CIR_Type<"VPtr", "vptr",
[DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {
def CIR_VPtrType : CIR_Type<"VPtr", "vptr", [
DeclareTypeInterfaceMethods<DataLayoutTypeInterface>
]> {

Comment on lines 705 to 716
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;
}
Copy link
Contributor

@xlauko xlauko Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason these have ::mlir not just mlir?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. I copied this code from another type, and I guess it had the scoping that way. I'll fix it.

Copy link

github-actions bot commented Aug 1, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@andykaylor andykaylor merged commit c188e1d into llvm:main Aug 1, 2025
9 checks passed
@andykaylor andykaylor deleted the cir-vptr-type branch August 1, 2025 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants