[clang] [CIR] Upstream TypeInfo attribute (PR #159426)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 19 09:56:42 PDT 2025
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/159426
>From e91f5372f652c2ce4d4c17e2d46044bae17a3044 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
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<i32>
+
+ !rec_anon_struct = !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>
+
+ cir.global constant external @type_info = #cir.typeinfo<{
+ #cir.global_view<@_ZTVN10__cxxabiv120__si_class_type_infoE, [2 : i32]>
+ : !cir.ptr<!u8i>, #cir.global_view<@_ZTS1B> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1A>
+ : !cir.ptr<!u8i>}> : !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<RecordMembers>($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<cir::ConstArrayAttr, cir::ConstVectorAttr,
cir::ConstComplexAttr, cir::ConstRecordAttr,
- cir::GlobalViewAttr, cir::PoisonAttr, cir::VTableAttr>(
- attrType))
+ cir::GlobalViewAttr, cir::PoisonAttr, cir::TypeInfoAttr,
+ cir::VTableAttr>(attrType))
return success();
assert(isa<TypedAttr>(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<GlobalViewAttr, IntAttr>(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<mlir::LLVM::UndefOp>(loc, llvmTy);
+
+ for (auto [idx, elt] : llvm::enumerate(typeinfoArr.getData())) {
+ mlir::Value init = visit(elt);
+ result = rewriter.create<mlir::LLVM::InsertValueOp>(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<u, 8>
+
+!rec_anon_struct = !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>
+
+// 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<!u8i>, #cir.global_view<@_ZTS1B> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1A> : !cir.ptr<!u8i>}> : !u8i
+
+// -----
+
+!u8i = !cir.int<u, 8>
+
+!rec_anon_struct = !cir.record<struct {!u8i, !u8i, !u8i}>
+
+// 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 <amr96 at programmer.net>
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<CIR_AnyIntAttr,
"integer array attribute">;
+def CIR_IntOrGlobalViewArrayAttr : TypedArrayAttrBase<CIR_AnyIntOrGlobalViewAttr,
+ "integer or global view array attribute">{
+ 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<i32>
+ cir.global "private" external @_ZTVN10__cxxabiv120__si_class_type_infoE
+ : !cir.ptr<i32>
- !rec_anon_struct = !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>
+ !rec_anon_struct = !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>,
+ !cir.ptr<!u8i>}>
cir.global constant external @type_info = #cir.typeinfo<{
#cir.global_view<@_ZTVN10__cxxabiv120__si_class_type_infoE, [2 : i32]>
- : !cir.ptr<!u8i>, #cir.global_view<@_ZTS1B> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1A>
- : !cir.ptr<!u8i>}> : !rec_anon_struct
+ : !cir.ptr<!u8i>, #cir.global_view<@_ZTS1B> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZTI1A> : !cir.ptr<!u8i>}> : !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 <numeric>
-
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<GlobalViewAttr, IntAttr>(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<mlir::LLVM::UndefOp>(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<mlir::LLVM::InsertValueOp>(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<!u8i>, #cir.global_view<@_ZTS1B> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1A> : !cir.ptr<!u8i>}> : !u8i
-// -----
-
-!u8i = !cir.int<u, 8>
-
-!rec_anon_struct = !cir.record<struct {!u8i, !u8i, !u8i}>
-
-// 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 <amr96 at programmer.net>
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<!u8i>, #cir.global_view<@_ZTS1B> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1A> : !cir.ptr<!u8i>}> : !u8i
+// -----
+
+!u8i = !cir.int<u, 8>
+
+!rec_anon_struct = !cir.record<struct {!u8i, !u8i, !u8i}>
+
+// 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 <amr96 at programmer.net>
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);
More information about the cfe-commits
mailing list