https://github.com/skc7 updated https://github.com/llvm/llvm-project/pull/204190
>From 6604679ad19e92cf843046e209367d07b365e9e2 Mon Sep 17 00:00:00 2001 From: skc7 <[email protected]> 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 <[email protected]> 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 + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
