[Mlir-commits] [mlir] 42b4645 - [mlir][arith] Add ValueBoundsOpInterface external models for the arith operations DivUI and DivSI (#206514)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Tue Jun 30 04:43:16 PDT 2026


Author: Hagai Lev Hacohen
Date: 2026-06-30T11:43:10Z
New Revision: 42b46452f0c539f9dd3638d25e792eb7368cff72

URL: https://github.com/llvm/llvm-project/commit/42b46452f0c539f9dd3638d25e792eb7368cff72
DIFF: https://github.com/llvm/llvm-project/commit/42b46452f0c539f9dd3638d25e792eb7368cff72.diff

LOG: [mlir][arith] Add ValueBoundsOpInterface external models for the arith operations DivUI and DivSI (#206514)

Add ValueBoundsOpInterface external models for the arith operations
DivUI and DivSI.

Added: 
    

Modified: 
    mlir/lib/Dialect/Arith/IR/ArithDialect.cpp
    mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
    mlir/test/Dialect/Arith/value-bounds-op-interface-impl.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Dialect/Arith/IR/ArithDialect.cpp b/mlir/lib/Dialect/Arith/IR/ArithDialect.cpp
index 2a342eaba4e61..5584314140de1 100644
--- a/mlir/lib/Dialect/Arith/IR/ArithDialect.cpp
+++ b/mlir/lib/Dialect/Arith/IR/ArithDialect.cpp
@@ -56,9 +56,9 @@ void arith::ArithDialect::initialize() {
   declarePromisedInterfaces<bufferization::BufferizableOpInterface, ConstantOp,
                             IndexCastOp, SelectOp>();
   declarePromisedInterfaces<ValueBoundsOpInterface, ConstantOp, ExtSIOp, AddIOp,
-                            ConstantOp, SubIOp, MulIOp, SelectOp, FloorDivSIOp,
-                            CeilDivSIOp, MinSIOp, MaxSIOp, MinUIOp, MaxUIOp,
-                            RemSIOp, RemUIOp>();
+                            SubIOp, MulIOp, SelectOp, FloorDivSIOp, CeilDivSIOp,
+                            MinSIOp, MaxSIOp, MinUIOp, MaxUIOp, RemSIOp,
+                            RemUIOp, DivUIOp, DivSIOp>();
 }
 
 /// Materialize an integer or floating point constant.

diff  --git a/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp b/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
index c9fd446a26a83..bc15d3b22f1b3 100644
--- a/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
@@ -62,6 +62,71 @@ struct AddIOpInterface
   }
 };
 
+struct DivUIOpInterface
+    : public ValueBoundsOpInterface::ExternalModel<DivUIOpInterface,
+                                                   arith::DivUIOp> {
+  void populateBoundsForIndexValue(Operation *op, Value value,
+                                   ValueBoundsConstraintSet &cstr) const {
+    auto divOp = cast<arith::DivUIOp>(op);
+    assert(value == divOp.getResult() && "invalid value");
+
+    bool lhsNonNegative =
+        ValueBoundsConstraintSet::isProvablyNonNegative(divOp.getLhs(), cstr);
+    bool rhsPositive =
+        ValueBoundsConstraintSet::isProvablyPositive(divOp.getRhs(), cstr);
+    if (!lhsNonNegative || !rhsPositive)
+      return;
+
+    AffineExpr lhs = cstr.getExpr(divOp.getLhs());
+    AffineExpr rhs = cstr.getExpr(divOp.getRhs());
+    cstr.bound(value) >= 0;
+    cstr.bound(value) == lhs.floorDiv(rhs);
+  }
+};
+
+struct DivSIOpInterface
+    : public ValueBoundsOpInterface::ExternalModel<DivSIOpInterface,
+                                                   arith::DivSIOp> {
+  void populateBoundsForIndexValue(Operation *op, Value value,
+                                   ValueBoundsConstraintSet &cstr) const {
+    auto divOp = cast<arith::DivSIOp>(op);
+    assert(value == divOp.getResult() && "invalid value");
+
+    Value lhsValue = divOp.getLhs();
+    Value rhsValue = divOp.getRhs();
+
+    bool lhsNonNegative =
+        ValueBoundsConstraintSet::isProvablyNonNegative(lhsValue, cstr);
+    bool lhsNonPositive =
+        ValueBoundsConstraintSet::isProvablyNonPositive(lhsValue, cstr);
+    bool rhsPositive =
+        ValueBoundsConstraintSet::isProvablyPositive(rhsValue, cstr);
+    bool rhsNegative =
+        ValueBoundsConstraintSet::isProvablyNegative(rhsValue, cstr);
+
+    AffineExpr lhs = cstr.getExpr(lhsValue);
+    AffineExpr rhs = cstr.getExpr(rhsValue);
+
+    // divsi rounds toward zero, unlike floorDiv/ceilDiv which round toward
+    // negative/positive infinity respectively. When the result is non-negative,
+    // divsi equals floorDiv(lhs, rhs); when negative, it equals ceilDiv(lhs,
+    // rhs). Without knowing the sign, bound the result between those two
+    // expressions, which is always correct.
+    cstr.bound(value) >= lhs.floorDiv(rhs);
+    cstr.bound(value) <= lhs.ceilDiv(rhs);
+
+    // If the sign of the result is known, we can use the exact expression.
+    if ((lhsNonNegative && rhsPositive) || (lhsNonPositive && rhsNegative)) {
+      cstr.bound(value) == lhs.floorDiv(rhs);
+      cstr.bound(value) >= 0;
+    } else if ((lhsNonPositive && rhsPositive) ||
+               (lhsNonNegative && rhsNegative)) {
+      cstr.bound(value) == lhs.ceilDiv(rhs);
+      cstr.bound(value) <= 0;
+    }
+  }
+};
+
 struct SubIOpInterface
     : public ValueBoundsOpInterface::ExternalModel<SubIOpInterface, SubIOp> {
   void populateBoundsForIndexValue(Operation *op, Value value,
@@ -338,6 +403,8 @@ void mlir::arith::registerValueBoundsOpInterfaceExternalModels(
     arith::ConstantOp::attachInterface<arith::ConstantOpInterface>(*ctx);
     arith::ExtSIOp::attachInterface<arith::ExtSIOpInterface>(*ctx);
     arith::AddIOp::attachInterface<arith::AddIOpInterface>(*ctx);
+    arith::DivUIOp::attachInterface<arith::DivUIOpInterface>(*ctx);
+    arith::DivSIOp::attachInterface<arith::DivSIOpInterface>(*ctx);
     arith::SubIOp::attachInterface<arith::SubIOpInterface>(*ctx);
     arith::MulIOp::attachInterface<arith::MulIOpInterface>(*ctx);
     arith::FloorDivSIOp::attachInterface<arith::FloorDivSIOpInterface>(*ctx);

diff  --git a/mlir/test/Dialect/Arith/value-bounds-op-interface-impl.mlir b/mlir/test/Dialect/Arith/value-bounds-op-interface-impl.mlir
index 5871a67d618c2..41f7f18baefec 100644
--- a/mlir/test/Dialect/Arith/value-bounds-op-interface-impl.mlir
+++ b/mlir/test/Dialect/Arith/value-bounds-op-interface-impl.mlir
@@ -136,6 +136,83 @@ func.func @arith_ceildivsi_non_pure(%a: index, %b: index) -> index {
 
 // -----
 
+// CHECK-LABEL: func @arith_divui_constant()
+//       CHECK:   %[[c1:.*]] = arith.constant 1 : index
+//       CHECK:   return %[[c1]]
+func.func @arith_divui_constant() -> index {
+  %c7 = arith.constant 7 : index
+  %c5 = arith.constant 5 : index
+  %0 = arith.divui %c7, %c5 : index
+  %1 = "test.reify_bound"(%0) : (index) -> (index)
+  return %1 : index
+}
+
+// -----
+
+
+// CHECK-LABEL: func @arith_divui_positive_lhs()
+//       CHECK:   %[[c1:.*]] = arith.constant 1 : index
+//       CHECK:   return %[[c1]]
+
+func.func @arith_divui_positive_lhs() -> index {
+  %c7 = arith.constant 7 : index
+  %c5 = arith.constant 5 : index
+  %c1 = arith.constant 1 : index
+  %lhs = arith.maxsi %c7, %c1 : index
+  %0 = arith.divui %lhs, %c5 : index
+  %1 = "test.reify_bound"(%0) {type = "LB", constant} : (index) -> (index)
+  return %1 : index
+}
+
+
+// -----
+
+// CHECK-LABEL: func @arith_divsi_negative_positive()
+//       CHECK:   %[[cm1:.*]] = arith.constant -1 : index
+//       CHECK:   return %[[cm1]]
+func.func @arith_divsi_negative_positive() -> index {
+  %cm7 = arith.constant -7 : index
+  %c5 = arith.constant 5 : index
+  %0 = arith.divsi %cm7, %c5 : index
+  %1 = "test.reify_bound"(%0) : (index) -> (index)
+  return %1 : index
+}
+
+// -----
+
+// CHECK-LABEL: func @arith_divsi_negative_lhs()
+//       CHECK:   %[[cm2:.*]] = arith.constant -2 : index
+//       CHECK:   return %[[cm2]]
+func.func @arith_divsi_negative_lhs() -> index {
+  %c2 = arith.constant 2 : index
+  %cm7 = arith.constant -7 : index
+  %cm5 = arith.constant -5 : index
+  %lhs = arith.minsi %cm5, %cm7 : index
+  %0 = arith.divsi %lhs, %c2 : index
+  %1 = "test.reify_bound"(%0) {type = "UB", constant}: (index) -> (index)
+  return %1 : index
+}
+
+// -----
+
+func.func @arith_divsi_unknown_lhs_constant_rhs(%a: index) {
+  %c5 = arith.constant 5 : index
+  %0 = arith.divsi %a, %c5 : index
+  // expected-remark @below{{true}}
+  "test.compare"(%0, %a) {
+      cmp = "GE",
+      rhs_map = affine_map<()[s0] -> (s0 floordiv 5)>
+  } : (index, index) -> ()
+  // expected-remark @below{{true}}
+  "test.compare"(%0, %a) {
+      cmp = "LE",
+      rhs_map = affine_map<()[s0] -> (s0 ceildiv 5)>
+  } : (index, index) -> ()
+  return
+}
+
+// -----
+
 // CHECK-LABEL: func @arith_remsi_positive_positive()
 //       CHECK:   %[[c0:.*]] = arith.constant 0 : index
 //       CHECK:   %[[c5:.*]] = arith.constant 5 : index


        


More information about the Mlir-commits mailing list