From e91f5372f652c2ce4d4c17e2d46044bae17a3044 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Wed, 17 Sep 2025 21:02:56 +0200 Subject: [PATCH 1/4] [CIR] Upstream TypeInfo attribute --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 48 +++++++++++++++++++ clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 23 ++++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 15 ++++++ clang/test/CIR/IR/invalid-type-info.cir | 17 +++++++ 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 clang/test/CIR/IR/invalid-type-info.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 16b818f851e1c..10afd7133eed3 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -779,4 +779,52 @@ def CIR_AddressPointAttr : CIR_Attr<"AddressPoint", "address_point"> { }]; } +//===----------------------------------------------------------------------===// +// TypeInfoAttr +//===----------------------------------------------------------------------===// + +def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> { + let summary = "Represents a typeinfo used for RTTI"; + let description = [{ + The typeinfo data for a given class is stored into an ArrayAttr. The + layout is determined by the C++ ABI used (clang only implements + itanium on CIRGen). + + The verifier enforces that the output type is always a `!cir.record`, + and that the ArrayAttr element types match the equivalent member type + for the resulting record, i.e, a GlobalViewAttr for symbol reference or + an IntAttr for flags. + + Example: + + ``` + cir.global "private" external @_ZTVN10__cxxabiv120__si_class_type_infoE : !cir.ptr + + !rec_anon_struct = !cir.record, !cir.ptr, !cir.ptr}> + + cir.global constant external @type_info = #cir.typeinfo<{ + #cir.global_view<@_ZTVN10__cxxabiv120__si_class_type_infoE, [2 : i32]> + : !cir.ptr, #cir.global_view<@_ZTS1B> : !cir.ptr, #cir.global_view<@_ZTI1A> + : !cir.ptr}> : !rec_anon_struct + ``` + }]; + + let parameters = (ins AttributeSelfTypeParameter<"">:$type, + "mlir::ArrayAttr":$data); + + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + "mlir::ArrayAttr":$data), [{ + return $_get(type.getContext(), type, data); + }]> + ]; + + // Checks record element types should match the array for every equivalent + // element type. + let genVerifyDecl = 1; + let assemblyFormat = [{ + `<` custom($data) `>` + }]; +} + #endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 8918eb4cbb1ad..3fcc0aad9b11b 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -342,8 +342,8 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType, if (mlir::isa( - attrType)) + cir::GlobalViewAttr, cir::PoisonAttr, cir::TypeInfoAttr, + cir::VTableAttr>(attrType)) return success(); assert(isa(attrType) && "What else could we be looking at here?"); @@ -2741,6 +2741,25 @@ LogicalResult cir::AtomicCmpXchg::verify() { return success(); } +//===----------------------------------------------------------------------===// +// TypeInfoAttr +//===----------------------------------------------------------------------===// + +LogicalResult cir::TypeInfoAttr::verify( + ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, + ::mlir::Type type, ::mlir::ArrayAttr typeinfoData) { + + if (cir::ConstRecordAttr::verify(emitError, type, typeinfoData).failed()) + return failure(); + + for (auto &member : typeinfoData) { + if (llvm::isa(member)) + continue; + return emitError() << "expected GlobalViewAttr or IntAttr attribute"; + } + return success(); +} + //===----------------------------------------------------------------------===// // TableGen'd op method definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index e18149a61abd0..6d3034ce3b77d 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -235,6 +235,7 @@ class CIRAttrToValue { mlir::Value visitCirAttr(cir::ConstRecordAttr attr); mlir::Value visitCirAttr(cir::ConstVectorAttr attr); mlir::Value visitCirAttr(cir::GlobalViewAttr attr); + mlir::Value visitCirAttr(cir::TypeInfoAttr attr); mlir::Value visitCirAttr(cir::VTableAttr attr); mlir::Value visitCirAttr(cir::ZeroAttr attr); @@ -521,6 +522,20 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) { llvm_unreachable("Expecting pointer or integer type for GlobalViewAttr"); } +// TypeInfoAttr visitor. +mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeinfoArr) { + mlir::Type llvmTy = converter->convertType(typeinfoArr.getType()); + mlir::Location loc = parentOp->getLoc(); + mlir::Value result = rewriter.create(loc, llvmTy); + + for (auto [idx, elt] : llvm::enumerate(typeinfoArr.getData())) { + mlir::Value init = visit(elt); + result = rewriter.create(loc, result, init, idx); + } + + return result; +} + // VTableAttr visitor. mlir::Value CIRAttrToValue::visitCirAttr(cir::VTableAttr vtableArr) { mlir::Type llvmTy = converter->convertType(vtableArr.getType()); diff --git a/clang/test/CIR/IR/invalid-type-info.cir b/clang/test/CIR/IR/invalid-type-info.cir new file mode 100644 index 0000000000000..9a6c0d7234021 --- /dev/null +++ b/clang/test/CIR/IR/invalid-type-info.cir @@ -0,0 +1,17 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +!u8i = !cir.int + +!rec_anon_struct = !cir.record, !cir.ptr, !cir.ptr}> + +// expected-error @below {{expected !cir.record type}} +cir.global constant external @type_info = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv120__si_class_type_infoE, [2 : i32]> : !cir.ptr, #cir.global_view<@_ZTS1B> : !cir.ptr, #cir.global_view<@_ZTI1A> : !cir.ptr}> : !u8i + +// ----- + +!u8i = !cir.int + +!rec_anon_struct = !cir.record + +// expected-error @below {{expected GlobalViewAttr or IntAttr attribute}} +cir.global constant external @type_info = #cir.typeinfo<{ #cir.undef : !u8i, #cir.int<1> : !u8i, #cir.int<1> : !u8i}> : !rec_anon_struct From 43c54a81d19f892a8283be1784aa1bbd828d6dc2 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Thu, 18 Sep 2025 19:15:51 +0200 Subject: [PATCH 2/4] Address code review comments --- .../clang/CIR/Dialect/IR/CIRAttrConstraints.td | 16 ++++++++++++++++ clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 12 +++++++----- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 7 ------- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 11 ++++++----- clang/test/CIR/IR/invalid-type-info.cir | 8 -------- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td index a8c81dbd71a09..8f72ff4d754ad 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td @@ -38,6 +38,17 @@ def CIR_AnyIntOrFloatAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyFPAttr], string cppType = "::mlir::TypedAttr"; } +//===----------------------------------------------------------------------===// +// GlobalViewAttr constraints +//===----------------------------------------------------------------------===// + +def CIR_AnyGlobalViewAttr : CIR_AttrConstraint<"::cir::GlobalViewAttr", "GlobalView attribute">; + +def CIR_AnyIntOrGlobalViewAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyGlobalViewAttr], + "integer or global view attribute"> { + string cppType = "::mlir::TypedAttr"; +} + //===----------------------------------------------------------------------===// // ArrayAttr constraints //===----------------------------------------------------------------------===// @@ -45,4 +56,9 @@ def CIR_AnyIntOrFloatAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyFPAttr], def CIR_IntArrayAttr : TypedArrayAttrBase; +def CIR_IntOrGlobalViewArrayAttr : TypedArrayAttrBase{ + string cppType = "::mlir::ArrayAttr"; +} + #endif // CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD \ No newline at end of file diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 10afd7133eed3..e7a29e8b3dba1 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -798,19 +798,21 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> { Example: ``` - cir.global "private" external @_ZTVN10__cxxabiv120__si_class_type_infoE : !cir.ptr + cir.global "private" external @_ZTVN10__cxxabiv120__si_class_type_infoE + : !cir.ptr - !rec_anon_struct = !cir.record, !cir.ptr, !cir.ptr}> + !rec_anon_struct = !cir.record, !cir.ptr, + !cir.ptr}> cir.global constant external @type_info = #cir.typeinfo<{ #cir.global_view<@_ZTVN10__cxxabiv120__si_class_type_infoE, [2 : i32]> - : !cir.ptr, #cir.global_view<@_ZTS1B> : !cir.ptr, #cir.global_view<@_ZTI1A> - : !cir.ptr}> : !rec_anon_struct + : !cir.ptr, #cir.global_view<@_ZTS1B> : !cir.ptr, + #cir.global_view<@_ZTI1A> : !cir.ptr}> : !rec_anon_struct ``` }]; let parameters = (ins AttributeSelfTypeParameter<"">:$type, - "mlir::ArrayAttr":$data); + CIR_IntOrGlobalViewArrayAttr:$data); let builders = [ AttrBuilderWithInferredContext<(ins "mlir::Type":$type, diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 3fcc0aad9b11b..97c5c8440ff57 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -26,8 +26,6 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/Support/LogicalResult.h" -#include - using namespace mlir; using namespace cir; @@ -2752,11 +2750,6 @@ LogicalResult cir::TypeInfoAttr::verify( if (cir::ConstRecordAttr::verify(emitError, type, typeinfoData).failed()) return failure(); - for (auto &member : typeinfoData) { - if (llvm::isa(member)) - continue; - return emitError() << "expected GlobalViewAttr or IntAttr attribute"; - } return success(); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 6d3034ce3b77d..4bd1d89db78bb 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -523,14 +523,15 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) { } // TypeInfoAttr visitor. -mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeinfoArr) { - mlir::Type llvmTy = converter->convertType(typeinfoArr.getType()); +mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeinfoAttr) { + mlir::Type llvmTy = converter->convertType(typeinfoAttr.getType()); mlir::Location loc = parentOp->getLoc(); - mlir::Value result = rewriter.create(loc, llvmTy); + mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy); - for (auto [idx, elt] : llvm::enumerate(typeinfoArr.getData())) { + for (auto [idx, elt] : llvm::enumerate(typeinfoAttr.getData())) { mlir::Value init = visit(elt); - result = rewriter.create(loc, result, init, idx); + result = + mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx); } return result; diff --git a/clang/test/CIR/IR/invalid-type-info.cir b/clang/test/CIR/IR/invalid-type-info.cir index 9a6c0d7234021..b07a27cd69e19 100644 --- a/clang/test/CIR/IR/invalid-type-info.cir +++ b/clang/test/CIR/IR/invalid-type-info.cir @@ -7,11 +7,3 @@ // expected-error @below {{expected !cir.record type}} cir.global constant external @type_info = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv120__si_class_type_infoE, [2 : i32]> : !cir.ptr, #cir.global_view<@_ZTS1B> : !cir.ptr, #cir.global_view<@_ZTI1A> : !cir.ptr}> : !u8i -// ----- - -!u8i = !cir.int - -!rec_anon_struct = !cir.record - -// expected-error @below {{expected GlobalViewAttr or IntAttr attribute}} -cir.global constant external @type_info = #cir.typeinfo<{ #cir.undef : !u8i, #cir.int<1> : !u8i, #cir.int<1> : !u8i}> : !rec_anon_struct From 16c5a4f666aaed95768210ee1bf4b5768924fa54 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Thu, 18 Sep 2025 19:36:39 +0200 Subject: [PATCH 3/4] Update error message for invalid type info test --- clang/test/CIR/IR/invalid-type-info.cir | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clang/test/CIR/IR/invalid-type-info.cir b/clang/test/CIR/IR/invalid-type-info.cir index b07a27cd69e19..4d4726bdac002 100644 --- a/clang/test/CIR/IR/invalid-type-info.cir +++ b/clang/test/CIR/IR/invalid-type-info.cir @@ -7,3 +7,11 @@ // expected-error @below {{expected !cir.record type}} cir.global constant external @type_info = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv120__si_class_type_infoE, [2 : i32]> : !cir.ptr, #cir.global_view<@_ZTS1B> : !cir.ptr, #cir.global_view<@_ZTI1A> : !cir.ptr}> : !u8i +// ----- + +!u8i = !cir.int + +!rec_anon_struct = !cir.record + +// expected-error @below {{integer or global view array attribute}} +cir.global constant external @type_info = #cir.typeinfo<{ #cir.undef : !u8i, #cir.int<1> : !u8i, #cir.int<1> : !u8i}> : !rec_anon_struct From 25e2f3ac584658e77d494d322b0fabe3cd0551fe Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Fri, 19 Sep 2025 18:55:26 +0200 Subject: [PATCH 4/4] Address code review comments --- clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 6 ++++-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 4 ++-- clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index e7a29e8b3dba1..f8358de9a1eb9 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -811,8 +811,10 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> { ``` }]; - let parameters = (ins AttributeSelfTypeParameter<"">:$type, - CIR_IntOrGlobalViewArrayAttr:$data); + let parameters = (ins + AttributeSelfTypeParameter<"">:$type, + CIR_IntOrGlobalViewArrayAttr:$data + ); let builders = [ AttrBuilderWithInferredContext<(ins "mlir::Type":$type, diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 97c5c8440ff57..53126348c3bdc 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2745,9 +2745,9 @@ LogicalResult cir::AtomicCmpXchg::verify() { LogicalResult cir::TypeInfoAttr::verify( ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, - ::mlir::Type type, ::mlir::ArrayAttr typeinfoData) { + ::mlir::Type type, ::mlir::ArrayAttr typeInfoData) { - if (cir::ConstRecordAttr::verify(emitError, type, typeinfoData).failed()) + if (cir::ConstRecordAttr::verify(emitError, type, typeInfoData).failed()) return failure(); return success(); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 4bd1d89db78bb..8e0991e8c0708 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -523,12 +523,12 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) { } // TypeInfoAttr visitor. -mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeinfoAttr) { - mlir::Type llvmTy = converter->convertType(typeinfoAttr.getType()); +mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeInfoAttr) { + mlir::Type llvmTy = converter->convertType(typeInfoAttr.getType()); mlir::Location loc = parentOp->getLoc(); mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy); - for (auto [idx, elt] : llvm::enumerate(typeinfoAttr.getData())) { + for (auto [idx, elt] : llvm::enumerate(typeInfoAttr.getData())) { mlir::Value init = visit(elt); result = mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx);