[Mlir-commits] [mlir] [MLIR][LLVM] Add range metadata to llvm.load (PR #228571)

Arseniy Obolenskiy llvmlistbot at llvm.org
Mon Oct 12 21:16:31 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/228571

>From aa78033858d8686b7a290c5cd77e54bce2efb04b Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 2 Oct 2026 22:18:58 +0200
Subject: [PATCH 1/2] [MLIR][LLVM] Add range metadata to llvm.load

---
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td   | 12 ++++++++++-
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    | 10 ++++++++-
 .../LLVMIR/LLVMIRToLLVMTranslation.cpp        | 21 +++++++++++++++++++
 mlir/test/Dialect/LLVMIR/invalid.mlir         | 21 +++++++++++++++++++
 mlir/test/Dialect/LLVMIR/roundtrip.mlir       |  9 ++++++++
 .../Target/LLVMIR/Import/import-failure.ll    | 10 +++++++++
 .../test/Target/LLVMIR/Import/instructions.ll | 13 ++++++++++++
 mlir/test/Target/LLVMIR/llvmir.mlir           | 11 ++++++++++
 8 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 2df02fae26d20..3fabd7b4dc1cf 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -393,7 +393,8 @@ def LLVM_LoadOp : LLVM_MemAccessOpBase<"load",
               DefaultValuedAttr<
                 AtomicOrdering, "AtomicOrdering::not_atomic">:$ordering,
               OptionalAttr<StrAttr>:$syncscope,
-              OptionalAttr<LLVM_DereferenceableAttr>:$dereferenceable);
+              OptionalAttr<LLVM_DereferenceableAttr>:$dereferenceable,
+              OptionalAttr<LLVM_ConstantRangeAttr>:$range);
   // Append the aliasing related attributes defined in LLVM_MemAccessOpBase.
   let arguments = !con(args, aliasAttrs);
   let results = (outs LLVM_LoadableType:$res);
@@ -414,6 +415,9 @@ def LLVM_LoadOp : LLVM_MemAccessOpBase<"load",
     // A nontemporal load of a float variable.
     %0 = llvm.load %ptr <nontemporal> : !llvm.ptr -> f32
 
+    // A load of an integer known to lie in [0, 10).
+    %0 = llvm.load %ptr range <i32, 0, 10> : !llvm.ptr -> i32
+
     // An atomic load of an integer variable.
     %0 = llvm.load %ptr atomic monotonic <alignment = 8>
         : !llvm.ptr -> i64
@@ -428,6 +432,7 @@ def LLVM_LoadOp : LLVM_MemAccessOpBase<"load",
     (`invariant` $invariant^)?
     (`invariant_group` $invariantGroup^)?
     (`dereferenceable` `` $dereferenceable^)?
+    (`range` $range^)?
     prop-dict
     attr-dict `:` qualified(type($addr)) `->` type($res)
   }];
@@ -440,6 +445,11 @@ def LLVM_LoadOp : LLVM_MemAccessOpBase<"load",
     }
     if ($dereferenceable)
       moduleTranslation.setDereferenceableMetadata(op, inst);
+    if ($range) {
+      llvm::MDNode *metadata = llvm::MDBuilder(inst->getContext())
+          .createRange($range->getLower(), $range->getUpper());
+      inst->setMetadata(llvm::LLVMContext::MD_range, metadata);
+    }
   }] # setOrderingCode
      # setSyncScopeCode
      # setAlignmentCode
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index ff75b5a7dfb2e..9d7bfa1074e8e 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -921,6 +921,14 @@ verifyAtomicMemOp(OpTy memOp, Type valueType,
 
 LogicalResult LoadOp::verify() {
   Type valueType = getResult().getType();
+  if (ConstantRangeAttr range = getRangeAttr()) {
+    auto intType = dyn_cast<IntegerType>(getElementTypeOrSelf(valueType));
+    if (!intType || intType.getWidth() != range.getLower().getBitWidth())
+      return emitOpError("expected range bitwidth to match the integer "
+                         "(element) result type");
+    if (range.getLower() == range.getUpper())
+      return emitOpError("expected range to be neither empty nor full");
+  }
   return verifyAtomicMemOp(*this, valueType,
                            {AtomicOrdering::release, AtomicOrdering::acq_rel});
 }
@@ -933,7 +941,7 @@ void LoadOp::build(OpBuilder &builder, OperationState &state, Type type,
         alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
         isNonTemporal, isInvariant, isInvariantGroup, ordering,
         syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
-        /*dereferenceable=*/nullptr,
+        /*dereferenceable=*/nullptr, /*range=*/nullptr,
         /*access_groups=*/nullptr,
         /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr,
         /*tbaa=*/nullptr);
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
index 6733d6ee3ceb0..eb851ef40deb4 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
@@ -92,6 +92,7 @@ getSupportedMetadataImpl(llvm::LLVMContext &llvmContext) {
       llvm::LLVMContext::MD_alias_scope,
       llvm::LLVMContext::MD_dereferenceable,
       llvm::LLVMContext::MD_dereferenceable_or_null,
+      llvm::LLVMContext::MD_range,
       llvm::LLVMContext::MD_mmra,
       llvmContext.getMDKindID(vecTypeHintMDName),
       llvmContext.getMDKindID(workGroupSizeHintMDName),
@@ -256,6 +257,24 @@ static LogicalResult setDereferenceableAttr(const llvm::MDNode *node,
   return success();
 }
 
+/// Fails on multi-range metadata since ConstantRangeAttr holds one range.
+static LogicalResult setRangeAttr(const llvm::MDNode *node, Operation *op) {
+  auto loadOp = dyn_cast<LoadOp>(op);
+  if (!loadOp || node->getNumOperands() != 2)
+    return failure();
+
+  auto *lower =
+      llvm::mdconst::dyn_extract<llvm::ConstantInt>(node->getOperand(0));
+  auto *upper =
+      llvm::mdconst::dyn_extract<llvm::ConstantInt>(node->getOperand(1));
+  if (!lower || !upper)
+    return failure();
+
+  loadOp.setRangeAttr(ConstantRangeAttr::get(
+      op->getContext(), lower->getValue(), upper->getValue()));
+  return success();
+}
+
 /// Convert the given MMRA metadata (either an MMRA tag or an array of them)
 /// into corresponding MLIR attributes and set them on the given operation as a
 /// discardable `llvm.mmra` attribute.
@@ -509,6 +528,8 @@ class LLVMDialectLLVMIRImportInterface : public LLVMImportDialectInterface {
       return setDereferenceableAttr(
           node, llvm::LLVMContext::MD_dereferenceable_or_null, op,
           moduleImport);
+    if (kind == llvm::LLVMContext::MD_range)
+      return setRangeAttr(node, op);
     if (kind == llvm::LLVMContext::MD_mmra)
       return setMmraAttr(node, op, moduleImport);
     llvm::LLVMContext &context = node->getContext();
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index 8b652b04d88b2..e405e5c6f95cd 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -183,6 +183,27 @@ func.func @load_unaligned_atomic(%ptr : !llvm.ptr) {
 
 // -----
 
+func.func @load_range_non_integer(%ptr : !llvm.ptr) {
+  // expected-error at below {{expected range bitwidth to match the integer (element) result type}}
+  %1 = llvm.load %ptr range <i32, 0, 10> : !llvm.ptr -> f32
+}
+
+// -----
+
+func.func @load_range_bitwidth_mismatch(%ptr : !llvm.ptr) {
+  // expected-error at below {{expected range bitwidth to match the integer (element) result type}}
+  %1 = llvm.load %ptr range <i64, 0, 10> : !llvm.ptr -> i32
+}
+
+// -----
+
+func.func @load_range_empty_or_full(%ptr : !llvm.ptr) {
+  // expected-error at below {{expected range to be neither empty nor full}}
+  %1 = llvm.load %ptr range <i32, 5, 5> : !llvm.ptr -> i32
+}
+
+// -----
+
 func.func @store_syncscope(%val : f32, %ptr : !llvm.ptr) {
   // expected-error at below {{expected syncscope to be null for non-atomic access}}
   "llvm.store"(%val, %ptr) <{syncscope = "singlethread"}> : (f32, !llvm.ptr) -> ()
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 6ef571efe5c51..5bff896e02bf4 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -598,6 +598,15 @@ func.func @invariant_load(%ptr : !llvm.ptr) -> i32 {
   func.return %0 : i32
 }
 
+// CHECK-LABEL: @range_load
+func.func @range_load(%ptr : !llvm.ptr) {
+  // CHECK: llvm.load %{{.+}} range <i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
+  %0 = llvm.load %ptr range <i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
+  // CHECK: llvm.load %{{.+}} range <i8, 0, 2> : !llvm.ptr -> vector<2xi8>
+  %1 = llvm.load %ptr range <i8, 0, 2> : !llvm.ptr -> vector<2xi8>
+  func.return
+}
+
 // CHECK-LABEL: @invariant_group_load
 func.func @invariant_group_load(%ptr : !llvm.ptr) -> i32 {
   // CHECK: llvm.load %{{.+}} invariant_group <alignment = 4> : !llvm.ptr -> i32
diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index 7dca9a3ed2be6..56bb6038e2f27 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -302,6 +302,16 @@ define void @deref(i64 %0) {
 
 ; // -----
 
+; CHECK: warning: unhandled metadata: ![[RANGE:[0-9]+]] = !{i32 0, i32 2, i32 4, i32 6} on %{{.*}} = load i32, ptr %{{.*}}, align 4, !range ![[RANGE]]
+define i32 @multi_range(ptr %ptr) {
+  %1 = load i32, ptr %ptr, !range !0
+  ret i32 %1
+}
+
+!0 = !{i32 0, i32 2, i32 4, i32 6}
+
+; // -----
+
 ; CHECK:      import-failure.ll
 ; CHECK-SAME: warning: unhandled data layout token: ni:42
 target datalayout = "e-ni:42-i64:64"
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index 28ab4bc44a40a..ac5eb38c161a0 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -375,6 +375,19 @@ define void @load_store(ptr %ptr) {
 
 ; // -----
 
+; CHECK-LABEL: @range_load
+; CHECK-SAME:  %[[PTR:[a-zA-Z0-9]+]]
+define i32 @range_load(ptr %ptr) {
+  ; CHECK:  %[[V:[0-9]+]] = llvm.load %[[PTR]] range <i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
+  %1 = load i32, ptr %ptr, align 4, !range !0
+  ; CHECK:  llvm.return %[[V]]
+  ret i32 %1
+}
+
+!0 = !{i32 0, i32 10}
+
+; // -----
+
 ; CHECK-LABEL: @invariant_load
 ; CHECK-SAME:  %[[PTR:[a-zA-Z0-9]+]]
 define float @invariant_load(ptr %ptr) {
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index f29184beb6b4d..49a258b3ad2fc 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2135,6 +2135,17 @@ llvm.func @nontemporal_store_and_load(%ptr : !llvm.ptr) -> i32 {
 
 // -----
 
+// CHECK-LABEL: @range_load
+llvm.func @range_load(%ptr : !llvm.ptr) -> i32 {
+  // CHECK: load i32, ptr %{{.*}}, align 4, !range ![[RANGE:[0-9]+]]
+  %0 = llvm.load %ptr range <i32, 0, 10> : !llvm.ptr -> i32
+  llvm.return %0 : i32
+}
+
+// CHECK: ![[RANGE]] = !{i32 0, i32 10}
+
+// -----
+
 // Check that invariant group attribute is exported as metadata node.
 llvm.func @nontemporal_store_and_load(%ptr : !llvm.ptr) -> i32 {
   %val = llvm.mlir.constant(42 : i32) : i32

>From 3b14b6190c94837033e3eb75a1afb0e6405655be Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 5 Oct 2026 06:28:24 +0200
Subject: [PATCH 2/2] Address comments

---
 .../mlir/Dialect/LLVMIR/LLVMInterfaces.h      |  3 ++
 .../mlir/Dialect/LLVMIR/LLVMInterfaces.td     | 35 +++++++++++++++++++
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td   |  7 ++--
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    |  8 -----
 mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp | 23 ++++++++++++
 .../LLVMIR/LLVMIRToLLVMTranslation.cpp        | 19 ++++------
 mlir/test/Dialect/LLVMIR/invalid.mlir         |  6 ++--
 mlir/test/Dialect/LLVMIR/roundtrip.mlir       |  8 ++---
 .../Target/LLVMIR/Import/import-failure.ll    | 10 ------
 .../test/Target/LLVMIR/Import/instructions.ll |  5 ++-
 mlir/test/Target/LLVMIR/llvmir.mlir           |  2 +-
 11 files changed, 84 insertions(+), 42 deletions(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.h
index e0e98e167f501..0b8c254eb5e3a 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.h
@@ -37,6 +37,9 @@ LogicalResult verifyAliasAnalysisOpInterface(Operation *op);
 /// exactly one result of LLVM pointer type.
 LogicalResult verifyDereferenceableOpInterface(Operation *op);
 
+/// Verifies that the range of an operation implementing the range interface
+/// matches the bitwidth of its single integer (element) result.
+LogicalResult verifyRangeOpInterface(Operation *op);
 } // namespace detail
 } // namespace LLVM
 } // namespace mlir
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
index 66a1fe0ce251a..1e671ce42fbd2 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
@@ -343,6 +343,41 @@ def DereferenceableOpInterface : OpInterface<"DereferenceableOpInterface"> {
   ];
 }
 
+def RangeOpInterface : OpInterface<"RangeOpInterface"> {
+  let description = [{
+    An interface for operations that can carry range metadata. The default
+    implementations expect a ConstantRangeAttr named `range`.
+  }];
+
+  let cppNamespace = "::mlir::LLVM";
+  let verify = [{ return detail::verifyRangeOpInterface($_op); }];
+
+  let methods = [
+    InterfaceMethod<
+      /*desc=*/        "Returns the range attribute or nullptr",
+      /*returnType=*/  "::mlir::LLVM::ConstantRangeAttr",
+      /*methodName=*/  "getRangeOrNull",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        return op.getRangeAttr();
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Sets the range attribute",
+      /*returnType=*/  "void",
+      /*methodName=*/  "setRange",
+      /*args=*/        (ins "::mlir::LLVM::ConstantRangeAttr":$attr),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        op.setRangeAttr(attr);
+      }]
+      >
+  ];
+}
+
 def FPExceptionBehaviorOpInterface : OpInterface<"FPExceptionBehaviorOpInterface"> {
   let description = [{
     An interface for operations receiving an exception behavior attribute
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 3fabd7b4dc1cf..98381b0f78951 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -383,7 +383,8 @@ def LLVM_LoadOp : LLVM_MemAccessOpBase<"load",
      DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
      DeclareOpInterfaceMethods<PromotableMemOpInterface>,
      DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>,
-     DeclareOpInterfaceMethods<DereferenceableOpInterface>]> {
+     DeclareOpInterfaceMethods<DereferenceableOpInterface>,
+     DeclareOpInterfaceMethods<RangeOpInterface>]> {
   dag args = (ins LLVM_AnyPointer:$addr,
               OptionalAttr<I64Attr>:$alignment,
               UnitAttr:$volatile_,
@@ -416,7 +417,7 @@ def LLVM_LoadOp : LLVM_MemAccessOpBase<"load",
     %0 = llvm.load %ptr <nontemporal> : !llvm.ptr -> f32
 
     // A load of an integer known to lie in [0, 10).
-    %0 = llvm.load %ptr range <i32, 0, 10> : !llvm.ptr -> i32
+    %0 = llvm.load %ptr range<i32, 0, 10> : !llvm.ptr -> i32
 
     // An atomic load of an integer variable.
     %0 = llvm.load %ptr atomic monotonic <alignment = 8>
@@ -432,7 +433,7 @@ def LLVM_LoadOp : LLVM_MemAccessOpBase<"load",
     (`invariant` $invariant^)?
     (`invariant_group` $invariantGroup^)?
     (`dereferenceable` `` $dereferenceable^)?
-    (`range` $range^)?
+    (`range` `` $range^)?
     prop-dict
     attr-dict `:` qualified(type($addr)) `->` type($res)
   }];
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 9d7bfa1074e8e..600de9b0727a1 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -921,14 +921,6 @@ verifyAtomicMemOp(OpTy memOp, Type valueType,
 
 LogicalResult LoadOp::verify() {
   Type valueType = getResult().getType();
-  if (ConstantRangeAttr range = getRangeAttr()) {
-    auto intType = dyn_cast<IntegerType>(getElementTypeOrSelf(valueType));
-    if (!intType || intType.getWidth() != range.getLower().getBitWidth())
-      return emitOpError("expected range bitwidth to match the integer "
-                         "(element) result type");
-    if (range.getLower() == range.getUpper())
-      return emitOpError("expected range to be neither empty nor full");
-  }
   return verifyAtomicMemOp(*this, valueType,
                            {AtomicOrdering::release, AtomicOrdering::acq_rel});
 }
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp
index 44a9284f5a5ab..7d5a86d6740af 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp
@@ -13,6 +13,7 @@
 #include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
 
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/TypeUtilities.h"
 
 using namespace mlir;
 using namespace mlir::LLVM;
@@ -80,6 +81,28 @@ mlir::LLVM::detail::verifyDereferenceableOpInterface(Operation *op) {
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// RangeOpInterface
+//===----------------------------------------------------------------------===//
+
+LogicalResult mlir::LLVM::detail::verifyRangeOpInterface(Operation *op) {
+  auto iface = cast<RangeOpInterface>(op);
+
+  ConstantRangeAttr range = iface.getRangeOrNull();
+  if (!range)
+    return success();
+  if (op->getNumResults() != 1)
+    return op->emitOpError("expected op to have a single result");
+  auto intType =
+      dyn_cast<IntegerType>(getElementTypeOrSelf(op->getResult(0).getType()));
+  if (!intType || intType.getWidth() != range.getLower().getBitWidth())
+    return op->emitOpError(
+        "expected range bitwidth to match the integer (element) result type");
+  if (range.getLower() == range.getUpper())
+    return op->emitOpError("expected range to be neither empty nor full");
+  return success();
+}
+
 SmallVector<Value> mlir::LLVM::AtomicCmpXchgOp::getAccessedOperands() {
   return {getPtr()};
 }
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
index eb851ef40deb4..de038c68596cb 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
@@ -18,6 +18,7 @@
 #include "mlir/Target/LLVMIR/ModuleImport.h"
 
 #include "llvm/ADT/TypeSwitch.h"
+#include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Instructions.h"
@@ -257,21 +258,15 @@ static LogicalResult setDereferenceableAttr(const llvm::MDNode *node,
   return success();
 }
 
-/// Fails on multi-range metadata since ConstantRangeAttr holds one range.
+/// Multi-range metadata is imported as the union of its ranges.
 static LogicalResult setRangeAttr(const llvm::MDNode *node, Operation *op) {
-  auto loadOp = dyn_cast<LoadOp>(op);
-  if (!loadOp || node->getNumOperands() != 2)
-    return failure();
-
-  auto *lower =
-      llvm::mdconst::dyn_extract<llvm::ConstantInt>(node->getOperand(0));
-  auto *upper =
-      llvm::mdconst::dyn_extract<llvm::ConstantInt>(node->getOperand(1));
-  if (!lower || !upper)
+  auto iface = dyn_cast<RangeOpInterface>(op);
+  if (!iface)
     return failure();
 
-  loadOp.setRangeAttr(ConstantRangeAttr::get(
-      op->getContext(), lower->getValue(), upper->getValue()));
+  llvm::ConstantRange range = llvm::getConstantRangeFromMetadata(*node);
+  iface.setRange(ConstantRangeAttr::get(op->getContext(), range.getLower(),
+                                        range.getUpper()));
   return success();
 }
 
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index e405e5c6f95cd..b67c1b8895113 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -185,21 +185,21 @@ func.func @load_unaligned_atomic(%ptr : !llvm.ptr) {
 
 func.func @load_range_non_integer(%ptr : !llvm.ptr) {
   // expected-error at below {{expected range bitwidth to match the integer (element) result type}}
-  %1 = llvm.load %ptr range <i32, 0, 10> : !llvm.ptr -> f32
+  %1 = llvm.load %ptr range<i32, 0, 10> : !llvm.ptr -> f32
 }
 
 // -----
 
 func.func @load_range_bitwidth_mismatch(%ptr : !llvm.ptr) {
   // expected-error at below {{expected range bitwidth to match the integer (element) result type}}
-  %1 = llvm.load %ptr range <i64, 0, 10> : !llvm.ptr -> i32
+  %1 = llvm.load %ptr range<i64, 0, 10> : !llvm.ptr -> i32
 }
 
 // -----
 
 func.func @load_range_empty_or_full(%ptr : !llvm.ptr) {
   // expected-error at below {{expected range to be neither empty nor full}}
-  %1 = llvm.load %ptr range <i32, 5, 5> : !llvm.ptr -> i32
+  %1 = llvm.load %ptr range<i32, 5, 5> : !llvm.ptr -> i32
 }
 
 // -----
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 5bff896e02bf4..cd2c4a11fa8a0 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -600,10 +600,10 @@ func.func @invariant_load(%ptr : !llvm.ptr) -> i32 {
 
 // CHECK-LABEL: @range_load
 func.func @range_load(%ptr : !llvm.ptr) {
-  // CHECK: llvm.load %{{.+}} range <i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
-  %0 = llvm.load %ptr range <i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
-  // CHECK: llvm.load %{{.+}} range <i8, 0, 2> : !llvm.ptr -> vector<2xi8>
-  %1 = llvm.load %ptr range <i8, 0, 2> : !llvm.ptr -> vector<2xi8>
+  // CHECK: llvm.load %{{.+}} range<i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
+  %0 = llvm.load %ptr range<i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
+  // CHECK: llvm.load %{{.+}} range<i8, 0, 2> : !llvm.ptr -> vector<2xi8>
+  %1 = llvm.load %ptr range<i8, 0, 2> : !llvm.ptr -> vector<2xi8>
   func.return
 }
 
diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index 56bb6038e2f27..7dca9a3ed2be6 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -302,16 +302,6 @@ define void @deref(i64 %0) {
 
 ; // -----
 
-; CHECK: warning: unhandled metadata: ![[RANGE:[0-9]+]] = !{i32 0, i32 2, i32 4, i32 6} on %{{.*}} = load i32, ptr %{{.*}}, align 4, !range ![[RANGE]]
-define i32 @multi_range(ptr %ptr) {
-  %1 = load i32, ptr %ptr, !range !0
-  ret i32 %1
-}
-
-!0 = !{i32 0, i32 2, i32 4, i32 6}
-
-; // -----
-
 ; CHECK:      import-failure.ll
 ; CHECK-SAME: warning: unhandled data layout token: ni:42
 target datalayout = "e-ni:42-i64:64"
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index ac5eb38c161a0..33904f55c77d5 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -378,13 +378,16 @@ define void @load_store(ptr %ptr) {
 ; CHECK-LABEL: @range_load
 ; CHECK-SAME:  %[[PTR:[a-zA-Z0-9]+]]
 define i32 @range_load(ptr %ptr) {
-  ; CHECK:  %[[V:[0-9]+]] = llvm.load %[[PTR]] range <i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
+  ; CHECK:  %[[V:[0-9]+]] = llvm.load %[[PTR]] range<i32, 0, 10> <alignment = 4> : !llvm.ptr -> i32
   %1 = load i32, ptr %ptr, align 4, !range !0
+  ; CHECK:  llvm.load %[[PTR]] range<i32, 0, 6> <alignment = 4> : !llvm.ptr -> i32
+  %2 = load i32, ptr %ptr, align 4, !range !1
   ; CHECK:  llvm.return %[[V]]
   ret i32 %1
 }
 
 !0 = !{i32 0, i32 10}
+!1 = !{i32 0, i32 2, i32 4, i32 6}
 
 ; // -----
 
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 49a258b3ad2fc..b0346d1c2893d 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2138,7 +2138,7 @@ llvm.func @nontemporal_store_and_load(%ptr : !llvm.ptr) -> i32 {
 // CHECK-LABEL: @range_load
 llvm.func @range_load(%ptr : !llvm.ptr) -> i32 {
   // CHECK: load i32, ptr %{{.*}}, align 4, !range ![[RANGE:[0-9]+]]
-  %0 = llvm.load %ptr range <i32, 0, 10> : !llvm.ptr -> i32
+  %0 = llvm.load %ptr range<i32, 0, 10> : !llvm.ptr -> i32
   llvm.return %0 : i32
 }
 



More information about the Mlir-commits mailing list