[clang] [CIR] Add metadata type, attributes and metadata_as_value op. (PR #204190)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 22 21:58:18 PDT 2026
https://github.com/skc7 updated https://github.com/llvm/llvm-project/pull/204190
>From 6604679ad19e92cf843046e209367d07b365e9e2 Mon Sep 17 00:00:00 2001
From: skc7 <Krishna.Sankisa at amd.com>
Date: Tue, 16 Jun 2026 21:42:07 +0530
Subject: [PATCH 1/2] [CIR] Add metadata type, attributes, and
metadata_as_value op.
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 41 +++++++++++++++++++
clang/include/clang/CIR/Dialect/IR/CIROps.td | 30 ++++++++++++++
.../include/clang/CIR/Dialect/IR/CIRTypes.td | 15 ++++++-
clang/lib/CIR/CodeGen/CIRGenBuilder.h | 15 +++++++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 13 ++++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 40 ++++++++++++++++++
clang/test/CIR/Lowering/metadata-as-value.cir | 37 +++++++++++++++++
7 files changed, 190 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CIR/Lowering/metadata-as-value.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index e3c992ed327ac..bdd1e2394939e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1692,6 +1692,47 @@ def CIR_AnnotationArrayAttr
: CIR_TypedArrayAttrBase<CIR_AnnotationAttr,
"array of cir.annotation attributes">;
+//===----------------------------------------------------------------------===//
+// Metadata attributes
+//===----------------------------------------------------------------------===//
+
+def CIR_MDStringAttr : CIR_Attr<"MDString", "md_string"> {
+ let summary = "CIR metadata string";
+ let description = [{
+ Wraps a string as a metadata node, mirroring the LLVM dialect's
+ `#llvm.md_string`.
+
+ Example:
+ ```mlir
+ #cir.md_string<"agent-one-as">
+ ```
+ }];
+ let parameters = (ins "::mlir::StringAttr":$value);
+ let assemblyFormat = "`<` $value `>`";
+ let canHaveIllegalCXXABIType = 0;
+}
+
+def CIR_MDNodeAttr : CIR_Attr<"MDNode", "md_node"> {
+ let summary = "CIR metadata node";
+ let description = [{
+ Represents a metadata node, mirroring the LLVM dialect's `#llvm.md_node`.
+ Its operands can be any combination of metadata attributes, including
+ nested `#cir.md_node`.
+
+ Example:
+ ```mlir
+ #cir.md_node<#cir.md_string<"agent-one-as">>
+ #cir.md_node<>
+ ```
+ }];
+ let parameters = (ins OptionalArrayRefParameter<"mlir::Attribute">:$operands);
+ let assemblyFormat = "`<` (`>`) : ($operands^ `>`)?";
+ let canHaveIllegalCXXABIType = 0;
+}
+
+def CIR_AnyMDAttr : AnyAttrOf<[CIR_MDStringAttr, CIR_MDNodeAttr],
+ "CIR metadata attribute (md_string or md_node)">;
+
include "clang/CIR/Dialect/IR/CIROpenCLAttrs.td"
include "clang/CIR/Dialect/IR/CIRCUDAAttrs.td"
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 9dae3534991e5..f429e3efeb1e7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4092,6 +4092,36 @@ def CIR_LocalInitOp : CIR_Op<"local_init", [
let hasLLVMLowering = false;
}
+//===----------------------------------------------------------------------===//
+// MetadataAsValueOp
+//===----------------------------------------------------------------------===//
+
+def CIR_MetadataAsValueOp
+ : CIR_Op<"metadata_as_value", [Pure, ConstantLike]> {
+ let summary = "Wrap a metadata node so it can be used as an SSA value";
+ let description = [{
+ Materializes a `!cir.metadata` SSA value from a metadata attribute,
+ mirroring the LLVM dialect's `llvm.mlir.metadata_as_value`. This lifts a
+ metadata node into the value domain so it can be passed as an operand to
+ intrinsic calls that take `metadata` arguments.
+
+ The wrapped metadata is described by the `metadata` attribute, which must
+ be one of the CIR metadata attributes.
+
+ ```mlir
+ %0 = cir.metadata_as_value #cir.md_string<"agent-one-as">
+ %1 = cir.metadata_as_value #cir.md_node<#cir.md_string<"sp">>
+ ```
+ }];
+
+ let arguments = (ins CIR_AnyMDAttr:$metadata);
+ let results = (outs CIR_MetadataType:$result);
+
+ let assemblyFormat = "$metadata attr-dict";
+
+ let hasFolder = 1;
+}
+
//===----------------------------------------------------------------------===//
// LLVMIntrinsicCallOp
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 95be236854338..c44487b570415 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -619,6 +619,19 @@ def CIR_VoidType : CIR_Type<"Void", "void"> {
}];
}
+//===----------------------------------------------------------------------===//
+// MetadataType
+//===----------------------------------------------------------------------===//
+
+def CIR_MetadataType : CIR_Type<"Metadata", "metadata"> {
+ let summary = "CIR metadata type";
+ let description = [{
+ The `!cir.metadata` type mirrors the LLVM dialect's `!llvm.metadata`. It
+ wraps a metadata node so it can be used as an operand of intrinsic calls
+ that take `metadata` arguments.
+ }];
+}
+
//===----------------------------------------------------------------------===//
// StructType
//
@@ -957,7 +970,7 @@ def CIR_AnyType : AnyTypeOf<[
CIR_AnyFloatType, CIR_PointerType, CIR_FuncType, CIR_StructType,
CIR_UnionType,
CIR_ComplexType, CIR_VPtrType, CIR_DataMemberType, CIR_MethodType,
- CIR_EhTokenType, CIR_CleanupTokenType, CIR_CatchTokenType
+ CIR_EhTokenType, CIR_CleanupTokenType, CIR_CatchTokenType, CIR_MetadataType
]>;
#endif // CLANG_CIR_DIALECT_IR_CIRTYPES_TD
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 3188b096579be..a4345598aa45e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -464,6 +464,21 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return cir::ConstantOp::create(*this, loc, cir::ZeroAttr::get(ty));
}
+ //===--------------------------------------------------------------------===//
+ // Metadata creation helpers
+ //===--------------------------------------------------------------------===//
+ cir::MDStringAttr getMDStringAttr(llvm::StringRef str) {
+ return cir::MDStringAttr::get(getContext(), getStringAttr(str));
+ }
+
+ cir::MDNodeAttr getMDNodeAttr(llvm::ArrayRef<mlir::Attribute> operands) {
+ return cir::MDNodeAttr::get(getContext(), operands);
+ }
+
+ mlir::Value createMetadataAsValue(mlir::Location loc, mlir::Attribute md) {
+ return cir::MetadataAsValueOp::create(*this, loc, md);
+ }
+
//===--------------------------------------------------------------------===//
// UnaryOp creation helpers
//===--------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index f374e9beb2068..9135bdc69052a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -105,6 +105,11 @@ Operation *cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder,
mlir::Attribute value,
mlir::Type type,
mlir::Location loc) {
+ // Metadata folds to its wrapped attribute, so rematerialize the wrapper
+ // rather than a cir.const (the attribute is not a TypedAttr).
+ if (mlir::isa<cir::MDStringAttr, cir::MDNodeAttr>(value) &&
+ mlir::isa<cir::MetadataType>(type))
+ return cir::MetadataAsValueOp::create(builder, loc, type, value);
return cir::ConstantOp::create(builder, loc, type,
mlir::cast<mlir::TypedAttr>(value));
}
@@ -604,6 +609,14 @@ OpFoldResult cir::ConstantOp::fold(FoldAdaptor /*adaptor*/) {
return getValue();
}
+//===----------------------------------------------------------------------===//
+// MetadataAsValueOp
+//===----------------------------------------------------------------------===//
+
+OpFoldResult cir::MetadataAsValueOp::fold(FoldAdaptor /*adaptor*/) {
+ return getMetadataAttr();
+}
+
//===----------------------------------------------------------------------===//
// CastOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index c844375a000e0..5d6cc8c4e6d4e 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -404,6 +404,43 @@ mlir::LogicalResult CIRToLLVMLLVMIntrinsicCallOpLowering::matchAndRewrite(
return mlir::success();
}
+/// Translate a CIR metadata attribute into the matching LLVM dialect metadata
+/// attribute, recursing through md_node operands. Returns null on an
+/// unsupported attribute.
+static mlir::Attribute convertCirMetadataAttr(mlir::Attribute attr) {
+ mlir::MLIRContext *ctx = attr.getContext();
+ if (auto str = mlir::dyn_cast<cir::MDStringAttr>(attr))
+ return mlir::LLVM::MDStringAttr::get(ctx, str.getValue());
+ if (auto node = mlir::dyn_cast<cir::MDNodeAttr>(attr)) {
+ llvm::SmallVector<mlir::Attribute> operands;
+ operands.reserve(node.getOperands().size());
+ for (mlir::Attribute operand : node.getOperands()) {
+ mlir::Attribute converted = convertCirMetadataAttr(operand);
+ if (!converted)
+ return {};
+ operands.push_back(converted);
+ }
+ return mlir::LLVM::MDNodeAttr::get(ctx, operands);
+ }
+ return {};
+}
+
+mlir::LogicalResult CIRToLLVMMetadataAsValueOpLowering::matchAndRewrite(
+ cir::MetadataAsValueOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Attribute llvmMetadata = convertCirMetadataAttr(op.getMetadata());
+ if (!llvmMetadata)
+ return op.emitError("unsupported CIR metadata attribute");
+
+ mlir::Type resTy = typeConverter->convertType(op.getType());
+ if (!resTy)
+ return op.emitError("expected LLVM metadata result type");
+
+ rewriter.replaceOpWithNewOp<mlir::LLVM::MetadataAsValueOp>(op, resTy,
+ llvmMetadata);
+ return mlir::success();
+}
+
/// BoolAttr visitor.
mlir::Value CIRAttrToValue::visitCirAttr(cir::BoolAttr boolAttr) {
mlir::Location loc = parentOp->getLoc();
@@ -3292,6 +3329,9 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
converter.addConversion([&](cir::VoidType type) -> mlir::Type {
return mlir::LLVM::LLVMVoidType::get(type.getContext());
});
+ converter.addConversion([&](cir::MetadataType type) -> mlir::Type {
+ return mlir::LLVM::LLVMMetadataType::get(type.getContext());
+ });
}
static void buildCtorDtorList(
diff --git a/clang/test/CIR/Lowering/metadata-as-value.cir b/clang/test/CIR/Lowering/metadata-as-value.cir
new file mode 100644
index 0000000000000..d994b6f5bb2e6
--- /dev/null
+++ b/clang/test/CIR/Lowering/metadata-as-value.cir
@@ -0,0 +1,37 @@
+// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s
+
+// Lowering test for CIRToLLVMMetadataAsValueOpLowering and the
+// !cir.metadata -> !llvm.metadata type conversion.
+
+module {
+ // md_string operand.
+ // CHECK-LABEL: llvm.func @md_string
+ // CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"foo">
+ // CHECK: llvm.call_intrinsic "llvm.test.md.string"(%[[MD]]) : (!llvm.metadata) -> ()
+ // CHECK: llvm.return
+ cir.func @md_string() {
+ %0 = cir.metadata_as_value #cir.md_string<"foo">
+ cir.call_llvm_intrinsic "test.md.string" %0 : (!cir.metadata) -> ()
+ cir.return
+ }
+
+ // Nested md_node<md_string>.
+ // CHECK-LABEL: llvm.func @md_node_nested
+ // CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"bar">>
+ // CHECK: llvm.call_intrinsic "llvm.test.md.node"(%[[MD]]) : (!llvm.metadata) -> ()
+ cir.func @md_node_nested() {
+ %0 = cir.metadata_as_value #cir.md_node<#cir.md_string<"bar">>
+ cir.call_llvm_intrinsic "test.md.node" %0 : (!cir.metadata) -> ()
+ cir.return
+ }
+
+ // Empty md_node.
+ // CHECK-LABEL: llvm.func @md_node_empty
+ // CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_node<>
+ // CHECK: llvm.call_intrinsic "llvm.test.md.empty"(%[[MD]]) : (!llvm.metadata) -> ()
+ cir.func @md_node_empty() {
+ %0 = cir.metadata_as_value #cir.md_node<>
+ cir.call_llvm_intrinsic "test.md.empty" %0 : (!cir.metadata) -> ()
+ cir.return
+ }
+}
>From ad725233be20b8d53c31b8ffd8033c754647d73e Mon Sep 17 00:00:00 2001
From: skc7 <Krishna.Sankisa at amd.com>
Date: Tue, 23 Jun 2026 10:27:02 +0530
Subject: [PATCH 2/2] add metadata verify-roundtrip test
---
clang/test/CIR/IR/metadata.cir | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 clang/test/CIR/IR/metadata.cir
diff --git a/clang/test/CIR/IR/metadata.cir b/clang/test/CIR/IR/metadata.cir
new file mode 100644
index 0000000000000..c988d810d3230
--- /dev/null
+++ b/clang/test/CIR/IR/metadata.cir
@@ -0,0 +1,43 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+// Round-trip test for the !cir.metadata type, the #cir.md_string / #cir.md_node
+// attributes, and the cir.metadata_as_value op.
+
+module {
+ // CHECK-LABEL: cir.func @md_string
+ cir.func @md_string() {
+ // CHECK: %{{.*}} = cir.metadata_as_value #cir.md_string<"agent-one-as">
+ %0 = cir.metadata_as_value #cir.md_string<"agent-one-as">
+ cir.return
+ }
+
+ // CHECK-LABEL: cir.func @md_node_nested
+ cir.func @md_node_nested() {
+ // CHECK: %{{.*}} = cir.metadata_as_value #cir.md_node<#cir.md_string<"sp">>
+ %0 = cir.metadata_as_value #cir.md_node<#cir.md_string<"sp">>
+ cir.return
+ }
+
+ // CHECK-LABEL: cir.func @md_node_multi
+ cir.func @md_node_multi() {
+ // CHECK: %{{.*}} = cir.metadata_as_value #cir.md_node<#cir.md_string<"a">, #cir.md_string<"b">>
+ %0 = cir.metadata_as_value #cir.md_node<#cir.md_string<"a">, #cir.md_string<"b">>
+ cir.return
+ }
+
+ // CHECK-LABEL: cir.func @md_node_empty
+ cir.func @md_node_empty() {
+ // CHECK: %{{.*}} = cir.metadata_as_value #cir.md_node<>
+ %0 = cir.metadata_as_value #cir.md_node<>
+ cir.return
+ }
+
+ // CHECK-LABEL: cir.func @md_as_intrinsic_arg
+ cir.func @md_as_intrinsic_arg() {
+ // CHECK: %[[MD:.*]] = cir.metadata_as_value #cir.md_string<"foo">
+ // CHECK: cir.call_llvm_intrinsic "test.md.string" %[[MD]] : (!cir.metadata) -> ()
+ %0 = cir.metadata_as_value #cir.md_string<"foo">
+ cir.call_llvm_intrinsic "test.md.string" %0 : (!cir.metadata) -> ()
+ cir.return
+ }
+}
More information about the cfe-commits
mailing list