diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index edd21b55640b9..a258df79a6184 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 +]> { + 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..4fecb0108e001 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -697,6 +697,23 @@ 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