[Mlir-commits] [mlir] [MLIR][LLVMIR] Add support for intrinsics with metadata arguments (PR #200308)
Andy Kaylor
llvmlistbot at llvm.org
Thu Jun 4 09:43:58 PDT 2026
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/200308
>From 0ba7a6a52bc37bd8bc5ea1a43947d503eb8a8b3f Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 27 May 2026 16:38:40 -0700
Subject: [PATCH 1/5] [MLIR][LLVMIR] Add support for intrinsics with metadata
arguments
This updates the LLVM dialect to properly handle intrinsics with
metadata arguments.
Assisted-by: Cursor / claude-opus-4.7
---
.../mlir/Dialect/LLVMIR/LLVMAttrDefs.td | 4 +
.../include/mlir/Dialect/LLVMIR/LLVMOpBase.td | 6 +
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 62 +++
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 59 +-
mlir/lib/Target/LLVMIR/TypeToLLVM.cpp | 5 +-
mlir/test/Dialect/LLVMIR/call-intrin.mlir | 24 +
mlir/test/Dialect/LLVMIR/roundtrip.mlir | 26 +
.../LLVMIR/Import/intrinsic-constrained-fp.ll | 512 ++++++++++++++++++
.../LLVMIR/Import/intrinsic-unregistered.ll | 35 ++
9 files changed, 728 insertions(+), 5 deletions(-)
create mode 100644 mlir/test/Target/LLVMIR/Import/intrinsic-constrained-fp.ll
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 4304371cc0a54..56f3afba6a030 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -1784,4 +1784,8 @@ def LLVM_MDNodeAttr : LLVM_Attr<"MDNode", "md_node"> {
let assemblyFormat = "`<` (`>`) : ($operands^ `>`)?";
}
+def LLVM_AnyMDAttr : AnyAttrOf<[
+ LLVM_MDStringAttr, LLVM_MDConstantAttr, LLVM_MDFuncAttr, LLVM_MDNodeAttr],
+ "LLVM metadata attribute (md_string, md_const, md_func, or md_node)">;
+
#endif // LLVMIR_ATTRDEFS
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
index bd59319c79ad3..49b2bbde478e9 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
@@ -35,6 +35,12 @@ def LLVM_TokenType : Type<
"LLVM token type">,
BuildableType<"::mlir::LLVM::LLVMTokenType::get($_builder.getContext())">;
+// Type constraint accepting LLVM metadata type.
+def LLVM_MetadataType : Type<
+ CPred<"::llvm::isa<::mlir::LLVM::LLVMMetadataType>($_self)">,
+ "LLVM metadata type">,
+ BuildableType<"::mlir::LLVM::LLVMMetadataType::get($_builder.getContext())">;
+
// Type constraint accepting LLVM primitive types, i.e. all types except void
// and function.
def LLVM_PrimitiveType : Type<
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index d7c8cf236f0da..667352b295ee9 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -2502,6 +2502,68 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEf
let hasVerifier = 1;
}
+//===--------------------------------------------------------------------===//
+// MetadataAsValueOp
+//===--------------------------------------------------------------------===//
+
+def LLVM_MetadataAsValueOp : LLVM_Op<"mlir.metadata_as_value", [Pure]> {
+ let summary =
+ "Wraps an LLVM `metadata` constant so it can be used as an SSA value.";
+ let description = [{
+ Materializes an `!llvm.metadata` SSA value that mirrors LLVM IR's
+ `llvm::MetadataAsValue`: a wrapper that lifts an arbitrary
+ `llvm::Metadata` node into the value domain so it can be used as an
+ operand to instructions that take `metadata` arguments (for example the
+ constrained floating-point intrinsics or `llvm.read_register`).
+
+ The wrapped metadata is described by the `metadata` attribute, which
+ must be one of the LLVM dialect's metadata-attribute classes:
+
+ * `#llvm.md_string<"...">` — `llvm::MDString`.
+ * `#llvm.md_const<...>` — `llvm::ConstantAsMetadata`.
+ * `#llvm.md_func<@symbol>` — `llvm::ValueAsMetadata` of a function.
+ * `#llvm.md_node<...>` — `llvm::MDNode` over any of the above.
+
+ These can be nested arbitrarily to form metadata trees. Lowering to LLVM
+ IR materialises the corresponding `llvm::Metadata` via the dialect's
+ metadata-attribute converter and wraps the result with
+ `llvm::MetadataAsValue::get(ctx, md)`.
+
+ Example:
+
+ ```mlir
+ // Rounding-mode operand of a constrained-FP intrinsic:
+ %rm = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+ : !llvm.metadata
+ // Named-register metadata for llvm.read_register:
+ %nr = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+ : !llvm.metadata
+ ```
+ }];
+
+ let arguments = (ins LLVM_AnyMDAttr:$metadata);
+ let results = (outs LLVM_MetadataType:$res);
+
+ let assemblyFormat = "$metadata attr-dict";
+
+ let builders = [
+ OpBuilder<(ins "::mlir::Attribute":$metadata), [{
+ build($_builder, $_state,
+ ::mlir::LLVM::LLVMMetadataType::get($_builder.getContext()),
+ metadata);
+ }]>,
+ ];
+
+ let llvmBuilder = [{
+ ::llvm::Metadata *md = convertMetadataAttr(
+ op.getMetadataAttr(), builder, moduleTranslation);
+ if (!md)
+ return ::mlir::emitError(op.getLoc(),
+ "llvm.mlir.metadata_as_value: cannot lower metadata attribute");
+ $res = ::llvm::MetadataAsValue::get(builder.getContext(), md);
+ }];
+}
+
//===--------------------------------------------------------------------===//
// CallIntrinsicOp
//===--------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index eab4379a28610..3b26c1e904884 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -149,6 +149,42 @@ static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
return failure();
}
+/// Recursively converts an `llvm::Metadata` node to the matching LLVM dialect
+/// metadata attribute. Returns a null attribute for shapes that the dialect's
+/// metadata-attribute hierarchy does not currently model.
+static Attribute convertMetadataToAttr(MLIRContext *ctx,
+ const llvm::Metadata *md) {
+ if (!md)
+ return {};
+ if (auto *mdStr = dyn_cast<llvm::MDString>(md))
+ return MDStringAttr::get(ctx, StringAttr::get(ctx, mdStr->getString()));
+ if (auto *cam = dyn_cast<llvm::ConstantAsMetadata>(md)) {
+ auto *ci = dyn_cast<llvm::ConstantInt>(cam->getValue());
+ if (!ci)
+ return {};
+ auto intType = IntegerType::get(ctx, ci->getBitWidth());
+ return MDConstantAttr::get(ctx, IntegerAttr::get(intType, ci->getValue()));
+ }
+ if (auto *vam = dyn_cast<llvm::ValueAsMetadata>(md)) {
+ auto *fn = dyn_cast<llvm::Function>(vam->getValue());
+ if (!fn)
+ return {};
+ return MDFuncAttr::get(ctx, FlatSymbolRefAttr::get(ctx, fn->getName()));
+ }
+ if (auto *node = dyn_cast<llvm::MDNode>(md)) {
+ SmallVector<Attribute> operands;
+ operands.reserve(node->getNumOperands());
+ for (const llvm::MDOperand &op : node->operands()) {
+ Attribute opAttr = convertMetadataToAttr(ctx, op.get());
+ if (!opAttr)
+ return {};
+ operands.push_back(opAttr);
+ }
+ return MDNodeAttr::get(ctx, operands);
+ }
+ return {};
+}
+
/// Get a topologically sorted list of blocks for the given basic blocks.
static SetVector<llvm::BasicBlock *>
getTopologicallySortedBlocks(ArrayRef<llvm::BasicBlock *> basicBlocks) {
@@ -1980,10 +2016,29 @@ LogicalResult ModuleImport::convertIntrinsicArguments(
value = nullptr;
}
+ // Convert a single intrinsic operand into an MLIR value.
+ // `llvm::MetadataAsValue` operands (e.g. the rounding-mode / FP-exception
+ // MDString arguments used by the constrained floating-point intrinsics, or
+ // the named-register MDNode used by `llvm.read_register`) are lifted into a
+ // `llvm.mlir.metadata_as_value` SSA op carrying the corresponding metadata
+ // attribute. All other operands go through the standard `convertValue` path,
+ // which rejects metadata values.
+ auto convertOperand = [&](llvm::Value *value) -> FailureOr<Value> {
+ if (auto *mdAsVal = dyn_cast<llvm::MetadataAsValue>(value)) {
+ Attribute mdAttr = convertMetadataToAttr(context, mdAsVal->getMetadata());
+ if (!mdAttr)
+ return failure();
+ return MetadataAsValueOp::create(builder, UnknownLoc::get(context),
+ mdAttr)
+ .getRes();
+ }
+ return convertValue(value);
+ };
+
for (llvm::Value *value : operands) {
if (!value)
continue;
- auto mlirValue = convertValue(value);
+ auto mlirValue = convertOperand(value);
if (failed(mlirValue))
return failure();
valuesOut.push_back(*mlirValue);
@@ -2000,7 +2055,7 @@ LogicalResult ModuleImport::convertIntrinsicArguments(
opBundleTagAttrs.push_back(StringAttr::get(context, bundle.getTagName()));
for (const llvm::Use &opBundleOperand : bundle.Inputs) {
- auto operandMlirValue = convertValue(opBundleOperand.get());
+ auto operandMlirValue = convertOperand(opBundleOperand.get());
if (failed(operandMlirValue))
return failure();
valuesOut.push_back(*operandMlirValue);
diff --git a/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp b/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
index 807a94c61f0c8..34f3d9b671f40 100644
--- a/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
+++ b/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
@@ -64,9 +64,8 @@ class TypeToLLVMIRTranslatorImpl {
.Case([this](LLVM::LLVMLabelType) {
return llvm::Type::getLabelTy(context);
})
- .Case([this](LLVM::LLVMMetadataType) {
- return llvm::Type::getMetadataTy(context);
- })
+ .Case<LLVM::LLVMMetadataType>(
+ [this](Type) { return llvm::Type::getMetadataTy(context); })
.Case([this](LLVM::LLVMX86AMXType) {
return llvm::Type::getX86_AMXTy(context);
})
diff --git a/mlir/test/Dialect/LLVMIR/call-intrin.mlir b/mlir/test/Dialect/LLVMIR/call-intrin.mlir
index 81590d8c5f69d..c58a74c0327f1 100644
--- a/mlir/test/Dialect/LLVMIR/call-intrin.mlir
+++ b/mlir/test/Dialect/LLVMIR/call-intrin.mlir
@@ -122,3 +122,27 @@ llvm.func @intrinsic_element_type(%arg0: !llvm.ptr) {
%0 = llvm.call_intrinsic "llvm.aarch64.ldxr.p0"(%arg0) : (!llvm.ptr {llvm.elementtype = i8}) -> i64
llvm.return
}
+
+// -----
+
+// CHECK-LABEL: define float @constrained_sqrt(float %0)
+// CHECK: call float @llvm.experimental.constrained.sqrt.f32(float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+llvm.func @constrained_sqrt(%a: f32) -> f32 {
+ %rm = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+ %eb = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+ %r = llvm.call_intrinsic "llvm.experimental.constrained.sqrt.f32"(%a, %rm, %eb)
+ : (f32, !llvm.metadata, !llvm.metadata) -> f32
+ llvm.return %r : f32
+}
+
+// -----
+
+// CHECK-LABEL: define i32 @read_named_register()
+// CHECK: call i32 @llvm.read_register.i32(metadata !{{[0-9]+}})
+// CHECK: !{{[0-9]+}} = !{!"sp"}
+llvm.func @read_named_register() -> i32 {
+ %md = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+ %r = llvm.call_intrinsic "llvm.read_register.i32"(%md)
+ : (!llvm.metadata) -> i32
+ llvm.return %r : i32
+}
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 83d1f1b8e2884..d0acdfec6c8de 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -1128,6 +1128,32 @@ llvm.func @intrinsic_call_arg_attrs_bundles(%arg0: i32) -> i32 {
llvm.return %0 : i32
}
+// CHECK-LABEL: constrained_fp_metadata
+llvm.func @constrained_fp_metadata(%a: f32, %b: f32) -> f32 {
+ // CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+ // CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+ // CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fadd.f32"(%{{.*}}, %{{.*}}, %[[RM]], %[[EB]]) : (f32, f32, !llvm.metadata, !llvm.metadata) -> f32
+ %rm = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+ %eb = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+ %r = llvm.call_intrinsic "llvm.experimental.constrained.fadd.f32"(%a, %b, %rm, %eb)
+ : (f32, f32, !llvm.metadata, !llvm.metadata) -> f32
+ llvm.return %r : f32
+}
+
+// CHECK-LABEL: metadata_as_value_shapes
+llvm.func @metadata_as_value_shapes() {
+ // Exercise each of the LLVM metadata-attribute kinds the op accepts.
+ // CHECK: %{{.*}} = llvm.mlir.metadata_as_value #llvm.md_string<"sp">
+ %0 = llvm.mlir.metadata_as_value #llvm.md_string<"sp">
+ // CHECK: %{{.*}} = llvm.mlir.metadata_as_value #llvm.md_const<42 : i32>
+ %1 = llvm.mlir.metadata_as_value #llvm.md_const<42 : i32>
+ // CHECK: %{{.*}} = llvm.mlir.metadata_as_value #llvm.md_func<@md_kernel>
+ %2 = llvm.mlir.metadata_as_value #llvm.md_func<@md_kernel>
+ // CHECK: %{{.*}} = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+ %3 = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+ llvm.return
+}
+
llvm.mlir.global private @blockaddr_global() {addr_space = 0 : i32, dso_local} : !llvm.ptr {
%0 = llvm.blockaddress <function = @blockaddr_fn, tag = <id = 0>> : !llvm.ptr
llvm.return %0 : !llvm.ptr
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-constrained-fp.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-constrained-fp.ll
new file mode 100644
index 0000000000000..e41a09bcf61e8
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic-constrained-fp.ll
@@ -0,0 +1,512 @@
+; RUN: mlir-translate -import-llvm %s -split-input-file | FileCheck %s
+
+; -----------------------------------------------------------------------------
+; FP -> int conversions: one fp arg, single exception-behavior metadata.
+; -----------------------------------------------------------------------------
+
+declare i32 @llvm.experimental.constrained.fptosi.i32.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_fptosi
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fptosi.i32.f32"(%{{.*}}, %[[EB]]) : (f32, !llvm.metadata) -> i32
+define i32 @constrained_fptosi(float %a) {
+ %r = call i32 @llvm.experimental.constrained.fptosi.i32.f32(float %a, metadata !"fpexcept.strict")
+ ret i32 %r
+}
+
+; // -----
+
+declare i32 @llvm.experimental.constrained.fptoui.i32.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_fptoui
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fptoui.i32.f32"(%{{.*}}, %[[EB]]) : (f32, !llvm.metadata) -> i32
+define i32 @constrained_fptoui(float %a) {
+ %r = call i32 @llvm.experimental.constrained.fptoui.i32.f32(float %a, metadata !"fpexcept.ignore")
+ ret i32 %r
+}
+
+; -----------------------------------------------------------------------------
+; Unary math intrinsics: one fp arg, rounding-mode + exception-behavior.
+; -----------------------------------------------------------------------------
+
+; // -----
+
+declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_sqrt
+; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.sqrt.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> f32
+define float @constrained_sqrt(float %a) {
+ %r = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.asin.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_asin
+; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.asin.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> f32
+define float @constrained_asin(float %a) {
+ %r = call float @llvm.experimental.constrained.asin.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.acos.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_acos
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.towardzero">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.maytrap">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.acos.f32"
+define float @constrained_acos(float %a) {
+ %r = call float @llvm.experimental.constrained.acos.f32(float %a, metadata !"round.towardzero", metadata !"fpexcept.maytrap")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.atan.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_atan
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.upward">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.atan.f32"
+define float @constrained_atan(float %a) {
+ %r = call float @llvm.experimental.constrained.atan.f32(float %a, metadata !"round.upward", metadata !"fpexcept.ignore")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.sin.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_sin
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.downward">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.sin.f32"
+define float @constrained_sin(float %a) {
+ %r = call float @llvm.experimental.constrained.sin.f32(float %a, metadata !"round.downward", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.cos.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_cos
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearestaway">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.cos.f32"
+define float @constrained_cos(float %a) {
+ %r = call float @llvm.experimental.constrained.cos.f32(float %a, metadata !"round.tonearestaway", metadata !"fpexcept.ignore")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.tan.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_tan
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.dynamic">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.tan.f32"
+define float @constrained_tan(float %a) {
+ %r = call float @llvm.experimental.constrained.tan.f32(float %a, metadata !"round.dynamic", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.sinh.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_sinh
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.sinh.f32"
+define float @constrained_sinh(float %a) {
+ %r = call float @llvm.experimental.constrained.sinh.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.cosh.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_cosh
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.cosh.f32"
+define float @constrained_cosh(float %a) {
+ %r = call float @llvm.experimental.constrained.cosh.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.tanh.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_tanh
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.tanh.f32"
+define float @constrained_tanh(float %a) {
+ %r = call float @llvm.experimental.constrained.tanh.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.log.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_log
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.log.f32"
+define float @constrained_log(float %a) {
+ %r = call float @llvm.experimental.constrained.log.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.log10.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_log10
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.log10.f32"
+define float @constrained_log10(float %a) {
+ %r = call float @llvm.experimental.constrained.log10.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.log2.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_log2
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.log2.f32"
+define float @constrained_log2(float %a) {
+ %r = call float @llvm.experimental.constrained.log2.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.exp.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_exp
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.exp.f32"
+define float @constrained_exp(float %a) {
+ %r = call float @llvm.experimental.constrained.exp.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.exp2.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_exp2
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.exp2.f32"
+define float @constrained_exp2(float %a) {
+ %r = call float @llvm.experimental.constrained.exp2.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.rint.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_rint
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.upward">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.rint.f32"
+define float @constrained_rint(float %a) {
+ %r = call float @llvm.experimental.constrained.rint.f32(float %a, metadata !"round.upward", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.nearbyint.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_nearbyint
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.downward">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.nearbyint.f32"
+define float @constrained_nearbyint(float %a) {
+ %r = call float @llvm.experimental.constrained.nearbyint.f32(float %a, metadata !"round.downward", metadata !"fpexcept.ignore")
+ ret float %r
+}
+
+; -----------------------------------------------------------------------------
+; Binary math intrinsics: two fp args, rounding + exception metadata.
+; -----------------------------------------------------------------------------
+
+; // -----
+
+declare float @llvm.experimental.constrained.atan2.f32(float, float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_atan2
+; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.atan2.f32"(%{{.*}}, %{{.*}}, %[[RM]], %[[EB]]) : (f32, f32, !llvm.metadata, !llvm.metadata) -> f32
+define float @constrained_atan2(float %a, float %b) {
+ %r = call float @llvm.experimental.constrained.atan2.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.pow.f32(float, float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_pow
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.pow.f32"
+define float @constrained_pow(float %a, float %b) {
+ %r = call float @llvm.experimental.constrained.pow.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; -----------------------------------------------------------------------------
+; Mixed-type binary intrinsics.
+; -----------------------------------------------------------------------------
+
+; // -----
+
+declare float @llvm.experimental.constrained.powi.f32(float, i32, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_powi
+; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.powi.f32"(%{{.*}}, %{{.*}}, %[[RM]], %[[EB]]) : (f32, i32, !llvm.metadata, !llvm.metadata) -> f32
+define float @constrained_powi(float %a, i32 %b) {
+ %r = call float @llvm.experimental.constrained.powi.f32(float %a, i32 %b, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.ldexp.f32.i32(float, i32, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_ldexp
+; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.ldexp.f32.i32"(%{{.*}}, %{{.*}}, %[[RM]], %[[EB]]) : (f32, i32, !llvm.metadata, !llvm.metadata) -> f32
+define float @constrained_ldexp(float %a, i32 %b) {
+ %r = call float @llvm.experimental.constrained.ldexp.f32.i32(float %a, i32 %b, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; -----------------------------------------------------------------------------
+; FP -> int rounding (lrint / llrint): rounding + exception metadata.
+; -----------------------------------------------------------------------------
+
+; // -----
+
+declare i32 @llvm.experimental.constrained.lrint.i32.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_lrint
+; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.lrint.i32.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> i32
+define i32 @constrained_lrint(float %a) {
+ %r = call i32 @llvm.experimental.constrained.lrint.i32.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret i32 %r
+}
+
+; // -----
+
+declare i64 @llvm.experimental.constrained.llrint.i64.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_llrint
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.llrint.i64.f32"
+define i64 @constrained_llrint(float %a) {
+ %r = call i64 @llvm.experimental.constrained.llrint.i64.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret i64 %r
+}
+
+; -----------------------------------------------------------------------------
+; Binary intrinsics with exception-behavior metadata only (no rounding mode).
+; -----------------------------------------------------------------------------
+
+; // -----
+
+declare float @llvm.experimental.constrained.maxnum.f32(float, float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_maxnum
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.maxnum.f32"(%{{.*}}, %{{.*}}, %[[EB]]) : (f32, f32, !llvm.metadata) -> f32
+define float @constrained_maxnum(float %a, float %b) {
+ %r = call float @llvm.experimental.constrained.maxnum.f32(float %a, float %b, metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.minnum.f32(float, float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_minnum
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.minnum.f32"
+define float @constrained_minnum(float %a, float %b) {
+ %r = call float @llvm.experimental.constrained.minnum.f32(float %a, float %b, metadata !"fpexcept.ignore")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.maximum.f32(float, float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_maximum
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.maytrap">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.maximum.f32"
+define float @constrained_maximum(float %a, float %b) {
+ %r = call float @llvm.experimental.constrained.maximum.f32(float %a, float %b, metadata !"fpexcept.maytrap")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.minimum.f32(float, float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_minimum
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.minimum.f32"
+define float @constrained_minimum(float %a, float %b) {
+ %r = call float @llvm.experimental.constrained.minimum.f32(float %a, float %b, metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; -----------------------------------------------------------------------------
+; Unary intrinsics with exception-behavior metadata only (no rounding mode).
+; -----------------------------------------------------------------------------
+
+; // -----
+
+declare float @llvm.experimental.constrained.ceil.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_ceil
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.ceil.f32"(%{{.*}}, %[[EB]]) : (f32, !llvm.metadata) -> f32
+define float @constrained_ceil(float %a) {
+ %r = call float @llvm.experimental.constrained.ceil.f32(float %a, metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.floor.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_floor
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.floor.f32"
+define float @constrained_floor(float %a) {
+ %r = call float @llvm.experimental.constrained.floor.f32(float %a, metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.round.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_round
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.round.f32"
+define float @constrained_round(float %a) {
+ %r = call float @llvm.experimental.constrained.round.f32(float %a, metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.roundeven.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_roundeven
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.roundeven.f32"
+define float @constrained_roundeven(float %a) {
+ %r = call float @llvm.experimental.constrained.roundeven.f32(float %a, metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare float @llvm.experimental.constrained.trunc.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_trunc
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.trunc.f32"
+define float @constrained_trunc(float %a) {
+ %r = call float @llvm.experimental.constrained.trunc.f32(float %a, metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+declare i32 @llvm.experimental.constrained.lround.i32.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_lround
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.lround.i32.f32"(%{{.*}}, %[[EB]]) : (f32, !llvm.metadata) -> i32
+define i32 @constrained_lround(float %a) {
+ %r = call i32 @llvm.experimental.constrained.lround.i32.f32(float %a, metadata !"fpexcept.strict")
+ ret i32 %r
+}
+
+; // -----
+
+declare i64 @llvm.experimental.constrained.llround.i64.f32(float, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_llround
+; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.llround.i64.f32"
+define i64 @constrained_llround(float %a) {
+ %r = call i64 @llvm.experimental.constrained.llround.i64.f32(float %a, metadata !"fpexcept.strict")
+ ret i64 %r
+}
+
+; -----------------------------------------------------------------------------
+; Constrained comparisons (fcmp / fcmps): predicate string + exception metadata.
+; -----------------------------------------------------------------------------
+
+; // -----
+
+declare i1 @llvm.experimental.constrained.fcmp.f32(float, float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_fcmp
+; CHECK: %[[PRED:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"oeq">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fcmp.f32"(%{{.*}}, %{{.*}}, %[[PRED]], %[[EB]]) : (f32, f32, !llvm.metadata, !llvm.metadata) -> i1
+define i1 @constrained_fcmp(float %a, float %b) {
+ %r = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"oeq", metadata !"fpexcept.strict")
+ ret i1 %r
+}
+
+; // -----
+
+declare i1 @llvm.experimental.constrained.fcmps.f32(float, float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_fcmps
+; CHECK: %[[PRED:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"olt">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fcmps.f32"(%{{.*}}, %{{.*}}, %[[PRED]], %[[EB]]) : (f32, f32, !llvm.metadata, !llvm.metadata) -> i1
+define i1 @constrained_fcmps(float %a, float %b) {
+ %r = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"olt", metadata !"fpexcept.strict")
+ ret i1 %r
+}
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
index 46dd4b532cc82..01dd342b7a0ce 100644
--- a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
@@ -77,3 +77,38 @@ define signext i32 @test_intrin_arg_attr(i32 signext %a) nounwind {
%val = call i32 @llvm.riscv.sha256sig0(i32 signext %a)
ret i32 %val
}
+
+; // -----
+
+; Constrained FP intrinsics with no dedicated MLIR op should fall back to
+; `llvm.call_intrinsic`, and their `metadata !"..."` operands should be
+; imported as `llvm.mlir.metadata_as_value` ops wrapping the corresponding
+; `#llvm.md_string` attribute.
+
+declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata)
+
+; CHECK-LABEL: llvm.func @constrained_sqrt
+; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.sqrt.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> f32
+define float @constrained_sqrt(float %a) {
+ %r = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret float %r
+}
+
+; // -----
+
+; Importer should also handle MDNode metadata operands such as the
+; `!{!"register_name"}` form used by `llvm.read_register`.
+
+declare i32 @llvm.read_register.i32(metadata)
+
+; CHECK-LABEL: llvm.func @read_named_register
+; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
+define i32 @read_named_register() {
+ %r = call i32 @llvm.read_register.i32(metadata !0)
+ ret i32 %r
+}
+
+!0 = !{!"sp"}
>From c8a80340747b042748e0d59c61570bab5b277e24 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Thu, 28 May 2026 17:39:25 -0700
Subject: [PATCH 2/5] Undo an unnecessary change
---
mlir/lib/Target/LLVMIR/TypeToLLVM.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp b/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
index 34f3d9b671f40..807a94c61f0c8 100644
--- a/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
+++ b/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
@@ -64,8 +64,9 @@ class TypeToLLVMIRTranslatorImpl {
.Case([this](LLVM::LLVMLabelType) {
return llvm::Type::getLabelTy(context);
})
- .Case<LLVM::LLVMMetadataType>(
- [this](Type) { return llvm::Type::getMetadataTy(context); })
+ .Case([this](LLVM::LLVMMetadataType) {
+ return llvm::Type::getMetadataTy(context);
+ })
.Case([this](LLVM::LLVMX86AMXType) {
return llvm::Type::getX86_AMXTy(context);
})
>From 4692905dc90a088c81b5b348f558d400366a4bd7 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Tue, 2 Jun 2026 18:21:12 -0700
Subject: [PATCH 3/5] Address review feedback
---
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 13 +--
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 13 +++
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 86 ++++++++++++-------
mlir/test/Dialect/LLVMIR/canonicalize.mlir | 16 ++++
.../Target/LLVMIR/Import/import-failure.ll | 12 +++
5 files changed, 104 insertions(+), 36 deletions(-)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 667352b295ee9..fc7975bb99f13 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -2506,7 +2506,8 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEf
// MetadataAsValueOp
//===--------------------------------------------------------------------===//
-def LLVM_MetadataAsValueOp : LLVM_Op<"mlir.metadata_as_value", [Pure]> {
+def LLVM_MetadataAsValueOp
+ : LLVM_Op<"mlir.metadata_as_value", [Pure, ConstantLike]> {
let summary =
"Wraps an LLVM `metadata` constant so it can be used as an SSA value.";
let description = [{
@@ -2519,10 +2520,10 @@ def LLVM_MetadataAsValueOp : LLVM_Op<"mlir.metadata_as_value", [Pure]> {
The wrapped metadata is described by the `metadata` attribute, which
must be one of the LLVM dialect's metadata-attribute classes:
- * `#llvm.md_string<"...">` — `llvm::MDString`.
- * `#llvm.md_const<...>` — `llvm::ConstantAsMetadata`.
- * `#llvm.md_func<@symbol>` — `llvm::ValueAsMetadata` of a function.
- * `#llvm.md_node<...>` — `llvm::MDNode` over any of the above.
+ * `#llvm.md_string<"...">` -> `llvm::MDString`.
+ * `#llvm.md_const<...>` -> `llvm::ConstantAsMetadata`.
+ * `#llvm.md_func<@symbol>` -> `llvm::ValueAsMetadata` of a function.
+ * `#llvm.md_node<...>` -> `llvm::MDNode` over any of the above.
These can be nested arbitrarily to form metadata trees. Lowering to LLVM
IR materialises the corresponding `llvm::Metadata` via the dialect's
@@ -2562,6 +2563,8 @@ def LLVM_MetadataAsValueOp : LLVM_Op<"mlir.metadata_as_value", [Pure]> {
"llvm.mlir.metadata_as_value: cannot lower metadata attribute");
$res = ::llvm::MetadataAsValue::get(builder.getContext(), md);
}];
+
+ let hasFolder = 1;
}
//===--------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 63bd9f8a3d625..867f5185419f2 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3363,6 +3363,15 @@ OpFoldResult LLVM::PoisonOp::fold(FoldAdaptor) {
return LLVM::PoisonAttr::get(getContext());
}
+//===----------------------------------------------------------------------===//
+// MetadataAsValueOp.
+//===----------------------------------------------------------------------===//
+
+/// Fold a metadata-as-value operation to its wrapped metadata attribute.
+OpFoldResult LLVM::MetadataAsValueOp::fold(FoldAdaptor) {
+ return getMetadataAttr();
+}
+
//===----------------------------------------------------------------------===//
// ZeroOp.
//===----------------------------------------------------------------------===//
@@ -4698,6 +4707,10 @@ Operation *LLVMDialect::materializeConstant(OpBuilder &builder, Attribute value,
return LLVM::PoisonOp::create(builder, loc, type);
if (isa<LLVM::ZeroAttr>(value))
return LLVM::ZeroOp::create(builder, loc, type);
+ if (isa<LLVM::MDStringAttr, LLVM::MDConstantAttr, LLVM::MDFuncAttr,
+ LLVM::MDNodeAttr>(value))
+ if (isa<LLVM::LLVMMetadataType>(type))
+ return LLVM::MetadataAsValueOp::create(builder, loc, type, value);
// Otherwise try materializing it as a regular llvm.mlir.constant op.
return LLVM::ConstantOp::materialize(builder, value, type, loc);
}
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 3b26c1e904884..b04310b07432c 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -30,6 +30,7 @@
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/IR/Comdat.h"
@@ -149,11 +150,19 @@ static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
return failure();
}
-/// Recursively converts an `llvm::Metadata` node to the matching LLVM dialect
-/// metadata attribute. Returns a null attribute for shapes that the dialect's
-/// metadata-attribute hierarchy does not currently model.
-static Attribute convertMetadataToAttr(MLIRContext *ctx,
- const llvm::Metadata *md) {
+/// Depth-first conversion of the metadata node `md` to the matching LLVM
+/// dialect metadata attribute. Returns a null attribute for shapes that the
+/// dialect's metadata-attribute hierarchy does not currently model. `path`
+/// holds the metadata nodes on the current depth-first search path. Cyclic
+/// metadata graphs are valid in LLVM IR, but they cannot be expressed by the
+/// immutable, structurally-uniqued metadata attributes built here. The `path`
+/// set lets the traversal recognize such a back-edge and bail out. `attrMap`
+/// caches the attributes of fully converted nodes so that shared subgraphs
+/// are visited only once.
+static Attribute
+convertMetadataToAttrImpl(MLIRContext *ctx, const llvm::Metadata *md,
+ SmallPtrSetImpl<const llvm::Metadata *> &path,
+ DenseMap<const llvm::Metadata *, Attribute> &attrMap) {
if (!md)
return {};
if (auto *mdStr = dyn_cast<llvm::MDString>(md))
@@ -172,19 +181,41 @@ static Attribute convertMetadataToAttr(MLIRContext *ctx,
return MDFuncAttr::get(ctx, FlatSymbolRefAttr::get(ctx, fn->getName()));
}
if (auto *node = dyn_cast<llvm::MDNode>(md)) {
+ if (Attribute cached = attrMap.lookup(node))
+ return cached;
+ // If `node` is already on the current search path, this is a back-edge into
+ // a cyclic graph. While that's valid it isn't implemented yet, so bail out.
+ if (!path.insert(node).second)
+ return {};
SmallVector<Attribute> operands;
operands.reserve(node->getNumOperands());
for (const llvm::MDOperand &op : node->operands()) {
- Attribute opAttr = convertMetadataToAttr(ctx, op.get());
- if (!opAttr)
+ Attribute opAttr = convertMetadataToAttrImpl(ctx, op.get(), path, attrMap);
+ if (!opAttr) {
+ path.erase(node);
return {};
+ }
operands.push_back(opAttr);
}
- return MDNodeAttr::get(ctx, operands);
+ path.erase(node);
+ Attribute nodeAttr = MDNodeAttr::get(ctx, operands);
+ attrMap.try_emplace(node, nodeAttr);
+ return nodeAttr;
}
return {};
}
+/// Converts the metadata node `md` to the matching LLVM dialect metadata
+/// attribute. Returns a null attribute for shapes that the dialect's
+/// metadata-attribute hierarchy does not currently model, including cyclic
+/// metadata graphs that the immutable metadata attributes cannot express.
+static Attribute convertMetadataToAttr(MLIRContext *ctx,
+ const llvm::Metadata *md) {
+ SmallPtrSet<const llvm::Metadata *, 8> path;
+ DenseMap<const llvm::Metadata *, Attribute> attrMap;
+ return convertMetadataToAttrImpl(ctx, md, path, attrMap);
+}
+
/// Get a topologically sorted list of blocks for the given basic blocks.
static SetVector<llvm::BasicBlock *>
getTopologicallySortedBlocks(ArrayRef<llvm::BasicBlock *> basicBlocks) {
@@ -1940,8 +1971,20 @@ FailureOr<Value> ModuleImport::convertConstantExpr(llvm::Constant *constant) {
}
FailureOr<Value> ModuleImport::convertValue(llvm::Value *value) {
- assert(!isa<llvm::MetadataAsValue>(value) &&
- "expected value to not be metadata");
+ // `llvm::MetadataAsValue` operands (e.g. the rounding-mode / FP-exception
+ // MDString arguments used by the constrained floating-point intrinsics, or
+ // the named-register MDNode used by `llvm.read_register`) are lifted into a
+ // `llvm.mlir.metadata_as_value` SSA op carrying the corresponding metadata
+ // attribute.
+ if (auto *mdAsVal = dyn_cast<llvm::MetadataAsValue>(value)) {
+ llvm::Metadata *md = mdAsVal->getMetadata();
+ Attribute mdAttr = convertMetadataToAttr(context, md);
+ if (!mdAttr)
+ return emitError(mlirModule.getLoc())
+ << "unsupported metadata: " << diagMD(md, llvmModule.get());
+ return MetadataAsValueOp::create(builder, UnknownLoc::get(context), mdAttr)
+ .getRes();
+ }
// Return the mapped value if it has been converted before.
auto it = valueMapping.find(value);
@@ -2016,29 +2059,10 @@ LogicalResult ModuleImport::convertIntrinsicArguments(
value = nullptr;
}
- // Convert a single intrinsic operand into an MLIR value.
- // `llvm::MetadataAsValue` operands (e.g. the rounding-mode / FP-exception
- // MDString arguments used by the constrained floating-point intrinsics, or
- // the named-register MDNode used by `llvm.read_register`) are lifted into a
- // `llvm.mlir.metadata_as_value` SSA op carrying the corresponding metadata
- // attribute. All other operands go through the standard `convertValue` path,
- // which rejects metadata values.
- auto convertOperand = [&](llvm::Value *value) -> FailureOr<Value> {
- if (auto *mdAsVal = dyn_cast<llvm::MetadataAsValue>(value)) {
- Attribute mdAttr = convertMetadataToAttr(context, mdAsVal->getMetadata());
- if (!mdAttr)
- return failure();
- return MetadataAsValueOp::create(builder, UnknownLoc::get(context),
- mdAttr)
- .getRes();
- }
- return convertValue(value);
- };
-
for (llvm::Value *value : operands) {
if (!value)
continue;
- auto mlirValue = convertOperand(value);
+ auto mlirValue = convertValue(value);
if (failed(mlirValue))
return failure();
valuesOut.push_back(*mlirValue);
@@ -2055,7 +2079,7 @@ LogicalResult ModuleImport::convertIntrinsicArguments(
opBundleTagAttrs.push_back(StringAttr::get(context, bundle.getTagName()));
for (const llvm::Use &opBundleOperand : bundle.Inputs) {
- auto operandMlirValue = convertOperand(opBundleOperand.get());
+ auto operandMlirValue = convertValue(opBundleOperand.get());
if (failed(operandMlirValue))
return failure();
valuesOut.push_back(*operandMlirValue);
diff --git a/mlir/test/Dialect/LLVMIR/canonicalize.mlir b/mlir/test/Dialect/LLVMIR/canonicalize.mlir
index b1c2df87d4867..544666fb30099 100644
--- a/mlir/test/Dialect/LLVMIR/canonicalize.mlir
+++ b/mlir/test/Dialect/LLVMIR/canonicalize.mlir
@@ -427,3 +427,19 @@ llvm.func @inline_asm_side_effects(%x : i32) {
llvm.inline_asm has_side_effects "inline asm with side effects", "r" %x : (i32) -> ()
llvm.return
}
+
+// -----
+
+// CHECK-LABEL: func @metadata_as_value_dedup
+llvm.func @metadata_as_value_dedup() -> i32 {
+ // CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+ // CHECK-NOT: llvm.mlir.metadata_as_value
+ %0 = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+ %1 = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+ // CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]])
+ %2 = llvm.call_intrinsic "llvm.read_register.i32"(%0) : (!llvm.metadata) -> i32
+ // CHECK: llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]])
+ %3 = llvm.call_intrinsic "llvm.read_register.i32"(%1) : (!llvm.metadata) -> i32
+ %4 = llvm.add %2, %3 : i32
+ llvm.return %4 : i32
+}
diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index b468a3e95c907..57c8438bfd362 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -456,3 +456,15 @@ bb1:
!91885 = !{!91886, !91887}
!91886 = !{i32 10000, i64 86427, i32 1}
!91887 = !{i32 100000, i64 86427, i32 1}
+
+; // -----
+
+; CHECK: error: unsupported metadata: !{{[0-9]+}} = distinct !{!{{[0-9]+}}}
+declare i32 @llvm.read_register.i32(metadata)
+
+define i32 @cyclic_metadata_as_value() {
+ %r = call i32 @llvm.read_register.i32(metadata !0)
+ ret i32 %r
+}
+
+!0 = distinct !{!0}
>From 762b635502a2cfe045b1b09788ba25fa31c8e08d Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 3 Jun 2026 11:51:17 -0700
Subject: [PATCH 4/5] Address second round of review feedback
---
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 32 +-
.../LLVMIR/Import/intrinsic-constrained-fp.ll | 512 ------------------
.../LLVMIR/Import/intrinsic-unregistered.ll | 17 +-
3 files changed, 27 insertions(+), 534 deletions(-)
delete mode 100644 mlir/test/Target/LLVMIR/Import/intrinsic-constrained-fp.ll
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index b04310b07432c..c5f6a837bc3ad 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -159,10 +159,10 @@ static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
/// set lets the traversal recognize such a back-edge and bail out. `attrMap`
/// caches the attributes of fully converted nodes so that shared subgraphs
/// are visited only once.
-static Attribute
-convertMetadataToAttrImpl(MLIRContext *ctx, const llvm::Metadata *md,
- SmallPtrSetImpl<const llvm::Metadata *> &path,
- DenseMap<const llvm::Metadata *, Attribute> &attrMap) {
+static Attribute convertMetadataToAttrImpl(
+ MLIRContext *ctx, const llvm::Metadata *md,
+ SmallPtrSetImpl<const llvm::Metadata *> &path,
+ DenseMap<const llvm::Metadata *, Attribute> &attrMap) {
if (!md)
return {};
if (auto *mdStr = dyn_cast<llvm::MDString>(md))
@@ -190,11 +190,10 @@ convertMetadataToAttrImpl(MLIRContext *ctx, const llvm::Metadata *md,
SmallVector<Attribute> operands;
operands.reserve(node->getNumOperands());
for (const llvm::MDOperand &op : node->operands()) {
- Attribute opAttr = convertMetadataToAttrImpl(ctx, op.get(), path, attrMap);
- if (!opAttr) {
- path.erase(node);
+ Attribute opAttr =
+ convertMetadataToAttrImpl(ctx, op.get(), path, attrMap);
+ if (!opAttr)
return {};
- }
operands.push_back(opAttr);
}
path.erase(node);
@@ -1971,6 +1970,11 @@ FailureOr<Value> ModuleImport::convertConstantExpr(llvm::Constant *constant) {
}
FailureOr<Value> ModuleImport::convertValue(llvm::Value *value) {
+ // Return the mapped value if it has been converted before.
+ auto it = valueMapping.find(value);
+ if (it != valueMapping.end())
+ return it->getSecond();
+
// `llvm::MetadataAsValue` operands (e.g. the rounding-mode / FP-exception
// MDString arguments used by the constrained floating-point intrinsics, or
// the named-register MDNode used by `llvm.read_register`) are lifted into a
@@ -1982,15 +1986,13 @@ FailureOr<Value> ModuleImport::convertValue(llvm::Value *value) {
if (!mdAttr)
return emitError(mlirModule.getLoc())
<< "unsupported metadata: " << diagMD(md, llvmModule.get());
- return MetadataAsValueOp::create(builder, UnknownLoc::get(context), mdAttr)
- .getRes();
+ auto op =
+ MetadataAsValueOp::create(builder, UnknownLoc::get(context), mdAttr)
+ .getRes();
+ mapValue(value, op);
+ return op;
}
- // Return the mapped value if it has been converted before.
- auto it = valueMapping.find(value);
- if (it != valueMapping.end())
- return it->getSecond();
-
// Convert constants such as immediate values that have no mapping yet.
if (auto *constant = dyn_cast<llvm::Constant>(value))
return convertConstantExpr(constant);
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-constrained-fp.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-constrained-fp.ll
deleted file mode 100644
index e41a09bcf61e8..0000000000000
--- a/mlir/test/Target/LLVMIR/Import/intrinsic-constrained-fp.ll
+++ /dev/null
@@ -1,512 +0,0 @@
-; RUN: mlir-translate -import-llvm %s -split-input-file | FileCheck %s
-
-; -----------------------------------------------------------------------------
-; FP -> int conversions: one fp arg, single exception-behavior metadata.
-; -----------------------------------------------------------------------------
-
-declare i32 @llvm.experimental.constrained.fptosi.i32.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_fptosi
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fptosi.i32.f32"(%{{.*}}, %[[EB]]) : (f32, !llvm.metadata) -> i32
-define i32 @constrained_fptosi(float %a) {
- %r = call i32 @llvm.experimental.constrained.fptosi.i32.f32(float %a, metadata !"fpexcept.strict")
- ret i32 %r
-}
-
-; // -----
-
-declare i32 @llvm.experimental.constrained.fptoui.i32.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_fptoui
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fptoui.i32.f32"(%{{.*}}, %[[EB]]) : (f32, !llvm.metadata) -> i32
-define i32 @constrained_fptoui(float %a) {
- %r = call i32 @llvm.experimental.constrained.fptoui.i32.f32(float %a, metadata !"fpexcept.ignore")
- ret i32 %r
-}
-
-; -----------------------------------------------------------------------------
-; Unary math intrinsics: one fp arg, rounding-mode + exception-behavior.
-; -----------------------------------------------------------------------------
-
-; // -----
-
-declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_sqrt
-; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.sqrt.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> f32
-define float @constrained_sqrt(float %a) {
- %r = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.asin.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_asin
-; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.asin.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> f32
-define float @constrained_asin(float %a) {
- %r = call float @llvm.experimental.constrained.asin.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.acos.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_acos
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.towardzero">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.maytrap">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.acos.f32"
-define float @constrained_acos(float %a) {
- %r = call float @llvm.experimental.constrained.acos.f32(float %a, metadata !"round.towardzero", metadata !"fpexcept.maytrap")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.atan.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_atan
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.upward">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.atan.f32"
-define float @constrained_atan(float %a) {
- %r = call float @llvm.experimental.constrained.atan.f32(float %a, metadata !"round.upward", metadata !"fpexcept.ignore")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.sin.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_sin
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.downward">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.sin.f32"
-define float @constrained_sin(float %a) {
- %r = call float @llvm.experimental.constrained.sin.f32(float %a, metadata !"round.downward", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.cos.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_cos
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearestaway">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.cos.f32"
-define float @constrained_cos(float %a) {
- %r = call float @llvm.experimental.constrained.cos.f32(float %a, metadata !"round.tonearestaway", metadata !"fpexcept.ignore")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.tan.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_tan
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.dynamic">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.tan.f32"
-define float @constrained_tan(float %a) {
- %r = call float @llvm.experimental.constrained.tan.f32(float %a, metadata !"round.dynamic", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.sinh.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_sinh
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.sinh.f32"
-define float @constrained_sinh(float %a) {
- %r = call float @llvm.experimental.constrained.sinh.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.cosh.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_cosh
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.cosh.f32"
-define float @constrained_cosh(float %a) {
- %r = call float @llvm.experimental.constrained.cosh.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.tanh.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_tanh
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.tanh.f32"
-define float @constrained_tanh(float %a) {
- %r = call float @llvm.experimental.constrained.tanh.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.log.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_log
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.log.f32"
-define float @constrained_log(float %a) {
- %r = call float @llvm.experimental.constrained.log.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.log10.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_log10
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.log10.f32"
-define float @constrained_log10(float %a) {
- %r = call float @llvm.experimental.constrained.log10.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.log2.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_log2
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.log2.f32"
-define float @constrained_log2(float %a) {
- %r = call float @llvm.experimental.constrained.log2.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.exp.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_exp
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.exp.f32"
-define float @constrained_exp(float %a) {
- %r = call float @llvm.experimental.constrained.exp.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.exp2.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_exp2
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.exp2.f32"
-define float @constrained_exp2(float %a) {
- %r = call float @llvm.experimental.constrained.exp2.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.rint.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_rint
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.upward">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.rint.f32"
-define float @constrained_rint(float %a) {
- %r = call float @llvm.experimental.constrained.rint.f32(float %a, metadata !"round.upward", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.nearbyint.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_nearbyint
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.downward">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.nearbyint.f32"
-define float @constrained_nearbyint(float %a) {
- %r = call float @llvm.experimental.constrained.nearbyint.f32(float %a, metadata !"round.downward", metadata !"fpexcept.ignore")
- ret float %r
-}
-
-; -----------------------------------------------------------------------------
-; Binary math intrinsics: two fp args, rounding + exception metadata.
-; -----------------------------------------------------------------------------
-
-; // -----
-
-declare float @llvm.experimental.constrained.atan2.f32(float, float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_atan2
-; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.atan2.f32"(%{{.*}}, %{{.*}}, %[[RM]], %[[EB]]) : (f32, f32, !llvm.metadata, !llvm.metadata) -> f32
-define float @constrained_atan2(float %a, float %b) {
- %r = call float @llvm.experimental.constrained.atan2.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.pow.f32(float, float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_pow
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.pow.f32"
-define float @constrained_pow(float %a, float %b) {
- %r = call float @llvm.experimental.constrained.pow.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; -----------------------------------------------------------------------------
-; Mixed-type binary intrinsics.
-; -----------------------------------------------------------------------------
-
-; // -----
-
-declare float @llvm.experimental.constrained.powi.f32(float, i32, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_powi
-; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.powi.f32"(%{{.*}}, %{{.*}}, %[[RM]], %[[EB]]) : (f32, i32, !llvm.metadata, !llvm.metadata) -> f32
-define float @constrained_powi(float %a, i32 %b) {
- %r = call float @llvm.experimental.constrained.powi.f32(float %a, i32 %b, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.ldexp.f32.i32(float, i32, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_ldexp
-; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.ldexp.f32.i32"(%{{.*}}, %{{.*}}, %[[RM]], %[[EB]]) : (f32, i32, !llvm.metadata, !llvm.metadata) -> f32
-define float @constrained_ldexp(float %a, i32 %b) {
- %r = call float @llvm.experimental.constrained.ldexp.f32.i32(float %a, i32 %b, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret float %r
-}
-
-; -----------------------------------------------------------------------------
-; FP -> int rounding (lrint / llrint): rounding + exception metadata.
-; -----------------------------------------------------------------------------
-
-; // -----
-
-declare i32 @llvm.experimental.constrained.lrint.i32.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_lrint
-; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.lrint.i32.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> i32
-define i32 @constrained_lrint(float %a) {
- %r = call i32 @llvm.experimental.constrained.lrint.i32.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret i32 %r
-}
-
-; // -----
-
-declare i64 @llvm.experimental.constrained.llrint.i64.f32(float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_llrint
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.llrint.i64.f32"
-define i64 @constrained_llrint(float %a) {
- %r = call i64 @llvm.experimental.constrained.llrint.i64.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
- ret i64 %r
-}
-
-; -----------------------------------------------------------------------------
-; Binary intrinsics with exception-behavior metadata only (no rounding mode).
-; -----------------------------------------------------------------------------
-
-; // -----
-
-declare float @llvm.experimental.constrained.maxnum.f32(float, float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_maxnum
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.maxnum.f32"(%{{.*}}, %{{.*}}, %[[EB]]) : (f32, f32, !llvm.metadata) -> f32
-define float @constrained_maxnum(float %a, float %b) {
- %r = call float @llvm.experimental.constrained.maxnum.f32(float %a, float %b, metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.minnum.f32(float, float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_minnum
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.minnum.f32"
-define float @constrained_minnum(float %a, float %b) {
- %r = call float @llvm.experimental.constrained.minnum.f32(float %a, float %b, metadata !"fpexcept.ignore")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.maximum.f32(float, float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_maximum
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.maytrap">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.maximum.f32"
-define float @constrained_maximum(float %a, float %b) {
- %r = call float @llvm.experimental.constrained.maximum.f32(float %a, float %b, metadata !"fpexcept.maytrap")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.minimum.f32(float, float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_minimum
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.minimum.f32"
-define float @constrained_minimum(float %a, float %b) {
- %r = call float @llvm.experimental.constrained.minimum.f32(float %a, float %b, metadata !"fpexcept.strict")
- ret float %r
-}
-
-; -----------------------------------------------------------------------------
-; Unary intrinsics with exception-behavior metadata only (no rounding mode).
-; -----------------------------------------------------------------------------
-
-; // -----
-
-declare float @llvm.experimental.constrained.ceil.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_ceil
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.ceil.f32"(%{{.*}}, %[[EB]]) : (f32, !llvm.metadata) -> f32
-define float @constrained_ceil(float %a) {
- %r = call float @llvm.experimental.constrained.ceil.f32(float %a, metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.floor.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_floor
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.floor.f32"
-define float @constrained_floor(float %a) {
- %r = call float @llvm.experimental.constrained.floor.f32(float %a, metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.round.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_round
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.round.f32"
-define float @constrained_round(float %a) {
- %r = call float @llvm.experimental.constrained.round.f32(float %a, metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.roundeven.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_roundeven
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.roundeven.f32"
-define float @constrained_roundeven(float %a) {
- %r = call float @llvm.experimental.constrained.roundeven.f32(float %a, metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare float @llvm.experimental.constrained.trunc.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_trunc
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.trunc.f32"
-define float @constrained_trunc(float %a) {
- %r = call float @llvm.experimental.constrained.trunc.f32(float %a, metadata !"fpexcept.strict")
- ret float %r
-}
-
-; // -----
-
-declare i32 @llvm.experimental.constrained.lround.i32.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_lround
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.lround.i32.f32"(%{{.*}}, %[[EB]]) : (f32, !llvm.metadata) -> i32
-define i32 @constrained_lround(float %a) {
- %r = call i32 @llvm.experimental.constrained.lround.i32.f32(float %a, metadata !"fpexcept.strict")
- ret i32 %r
-}
-
-; // -----
-
-declare i64 @llvm.experimental.constrained.llround.i64.f32(float, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_llround
-; CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: llvm.call_intrinsic "llvm.experimental.constrained.llround.i64.f32"
-define i64 @constrained_llround(float %a) {
- %r = call i64 @llvm.experimental.constrained.llround.i64.f32(float %a, metadata !"fpexcept.strict")
- ret i64 %r
-}
-
-; -----------------------------------------------------------------------------
-; Constrained comparisons (fcmp / fcmps): predicate string + exception metadata.
-; -----------------------------------------------------------------------------
-
-; // -----
-
-declare i1 @llvm.experimental.constrained.fcmp.f32(float, float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_fcmp
-; CHECK: %[[PRED:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"oeq">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fcmp.f32"(%{{.*}}, %{{.*}}, %[[PRED]], %[[EB]]) : (f32, f32, !llvm.metadata, !llvm.metadata) -> i1
-define i1 @constrained_fcmp(float %a, float %b) {
- %r = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"oeq", metadata !"fpexcept.strict")
- ret i1 %r
-}
-
-; // -----
-
-declare i1 @llvm.experimental.constrained.fcmps.f32(float, float, metadata, metadata)
-
-; CHECK-LABEL: llvm.func @constrained_fcmps
-; CHECK: %[[PRED:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"olt">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.fcmps.f32"(%{{.*}}, %{{.*}}, %[[PRED]], %[[EB]]) : (f32, f32, !llvm.metadata, !llvm.metadata) -> i1
-define i1 @constrained_fcmps(float %a, float %b) {
- %r = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"olt", metadata !"fpexcept.strict")
- ret i1 %r
-}
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
index 01dd342b7a0ce..da58d48d995be 100644
--- a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
@@ -88,10 +88,10 @@ define signext i32 @test_intrin_arg_attr(i32 signext %a) nounwind {
declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata)
; CHECK-LABEL: llvm.func @constrained_sqrt
-; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
-; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.sqrt.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> f32
define float @constrained_sqrt(float %a) {
+ ; CHECK: %[[RM:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"round.tonearest">
+ ; CHECK: %[[EB:.*]] = llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.strict">
+ ; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.experimental.constrained.sqrt.f32"(%{{.*}}, %[[RM]], %[[EB]]) : (f32, !llvm.metadata, !llvm.metadata) -> f32
%r = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
ret float %r
}
@@ -104,11 +104,14 @@ define float @constrained_sqrt(float %a) {
declare i32 @llvm.read_register.i32(metadata)
; CHECK-LABEL: llvm.func @read_named_register
-; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
-; CHECK: %{{.*}} = llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
define i32 @read_named_register() {
- %r = call i32 @llvm.read_register.i32(metadata !0)
- ret i32 %r
+ ; CHECK: %[[MD:.*]] = llvm.mlir.metadata_as_value #llvm.md_node<#llvm.md_string<"sp">>
+ ; CHECK: %[[R0:.*]] = llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
+ %r0 = call i32 @llvm.read_register.i32(metadata !0)
+ ; CHECK-NOT: llvm.mlir.metadata_as_value
+ ; CHECK: %[[R1:.*]] = llvm.call_intrinsic "llvm.read_register.i32"(%[[MD]]) : (!llvm.metadata) -> i32
+ %r1 = call i32 @llvm.read_register.i32(metadata !0)
+ ret i32 %r1
}
!0 = !{!"sp"}
>From cd270e11f80f73703c9c6da05486d484c640a6bc Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Thu, 4 Jun 2026 09:43:32 -0700
Subject: [PATCH 5/5] Fix last nit
---
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index c5f6a837bc3ad..3038a6a2ed986 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1986,11 +1986,11 @@ FailureOr<Value> ModuleImport::convertValue(llvm::Value *value) {
if (!mdAttr)
return emitError(mlirModule.getLoc())
<< "unsupported metadata: " << diagMD(md, llvmModule.get());
- auto op =
+ Value result =
MetadataAsValueOp::create(builder, UnknownLoc::get(context), mdAttr)
.getRes();
- mapValue(value, op);
- return op;
+ mapValue(value, result);
+ return result;
}
// Convert constants such as immediate values that have no mapping yet.
More information about the Mlir-commits
mailing list