[Mlir-commits] [mlir] [MLIR][Index] Restrict subtraction comparison canonicalization (PR #216831)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Aug 17 13:50:53 PDT 2026


https://github.com/at0m741 created https://github.com/llvm/llvm-project/pull/216831

Fix the unsafe canonicalization of ordered comparisons involving `index.sub`.

Ordered comparisons may change semantics when the subtraction wraps, so the
rewrite is now restricted to `eq` and `ne`.

Regression tests cover ordered comparisons while preserving the valid `eq` and
`ne` canonicalizations.

Fixes #216042 

>From 420f71a7ecb866f0f1cd643c41768bd164feca80 Mon Sep 17 00:00:00 2001
From: at0m741 <louistouz at icloud.com>
Date: Mon, 17 Aug 2026 22:33:51 +0200
Subject: [PATCH] [MLIR][Index] Restrict subtraction cmp canonicalization

---
 mlir/lib/Dialect/Index/IR/IndexOps.cpp        | 16 ++++++--
 .../Dialect/Index/index-canonicalize.mlir     | 38 +++++++++++++++++--
 2 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/mlir/lib/Dialect/Index/IR/IndexOps.cpp b/mlir/lib/Dialect/Index/IR/IndexOps.cpp
index 2b1baa8b44643..b6863befb3fbd 100644
--- a/mlir/lib/Dialect/Index/IR/IndexOps.cpp
+++ b/mlir/lib/Dialect/Index/IR/IndexOps.cpp
@@ -693,9 +693,11 @@ OpFoldResult CmpOp::fold(FoldAdaptor adaptor) {
   return {};
 }
 
-/// Canonicalize
-/// `x - y cmp 0` to `x cmp y`. or `x - y cmp 0` to `x cmp y`.
-/// `0 cmp x - y` to `y cmp x`. or `0 cmp x - y` to `y cmp x`.
+/// Canonicalize `(x - y) == 0` to `x == y` and `(x - y) != 0` to `x != y`.
+/// Likewise, canonicalize `0 == (x - y)` and `0 != (x - y)`.
+///
+/// Ordered comparisons cannot be canonicalized this way because subtraction
+/// may wrap at the target index bitwidth.
 LogicalResult CmpOp::canonicalize(CmpOp op, PatternRewriter &rewriter) {
   IntegerAttr cmpRhs;
   IntegerAttr cmpLhs;
@@ -707,12 +709,19 @@ LogicalResult CmpOp::canonicalize(CmpOp op, PatternRewriter &rewriter) {
   if (!rhsIsZero && !lhsIsZero)
     return rewriter.notifyMatchFailure(op.getLoc(),
                                        "cmp is not comparing something with 0");
+
   SubOp subOp = rhsIsZero ? op.getLhs().getDefiningOp<index::SubOp>()
                           : op.getRhs().getDefiningOp<index::SubOp>();
   if (!subOp)
     return rewriter.notifyMatchFailure(
         op.getLoc(), "non-zero operand is not a result of subtraction");
 
+  if (op.getPred() != IndexCmpPredicate::EQ &&
+      op.getPred() != IndexCmpPredicate::NE)
+    return rewriter.notifyMatchFailure(
+        op.getLoc(),
+        "only eq and ne comparisons can be canonicalized through subtraction");
+
   index::CmpOp newCmp;
   if (rhsIsZero)
     newCmp = index::CmpOp::create(rewriter, op.getLoc(), op.getPred(),
@@ -720,6 +729,7 @@ LogicalResult CmpOp::canonicalize(CmpOp op, PatternRewriter &rewriter) {
   else
     newCmp = index::CmpOp::create(rewriter, op.getLoc(), op.getPred(),
                                   subOp.getRhs(), subOp.getLhs());
+
   rewriter.replaceOp(op, newCmp);
   return success();
 }
diff --git a/mlir/test/Dialect/Index/index-canonicalize.mlir b/mlir/test/Dialect/Index/index-canonicalize.mlir
index 45da6ea57d796..06fc9abba8bcc 100644
--- a/mlir/test/Dialect/Index/index-canonicalize.mlir
+++ b/mlir/test/Dialect/Index/index-canonicalize.mlir
@@ -609,13 +609,43 @@ func.func @cmp(%arg0: index) -> (i1, i1, i1, i1, i1, i1) {
 
   // CHECK-DAG: %[[TRUE:.*]] = index.bool.constant true
   // CHECK-DAG: %[[FALSE:.*]] = index.bool.constant false
-  // CHECK-DAG: [[IDX0:%.*]] = index.constant 0
-  // CHECK-DAG: [[V4:%.*]] = index.cmp sgt([[IDX0]], %arg0)
-  // CHECK-DAG: [[V5:%.*]] = index.cmp sgt(%arg0, [[IDX0]])
-  // CHECK: return %[[FALSE]], %[[TRUE]], %[[TRUE]], %[[FALSE]]
+  // CHECK-DAG: %[[IDX0:.*]] = index.constant 0
+  // CHECK: %[[SUB0:.*]] = index.sub %[[IDX0]], %arg0
+  // CHECK-NEXT: %[[V4:.*]] = index.cmp sgt(%[[SUB0]], %[[IDX0]])
+  // CHECK-NEXT: %[[SUB1:.*]] = index.sub %[[IDX0]], %arg0
+  // CHECK-NEXT: %[[V5:.*]] = index.cmp sgt(%[[IDX0]], %[[SUB1]])
+  // CHECK-NEXT: return %[[FALSE]], %[[TRUE]], %[[TRUE]], %[[FALSE]], %[[V4]], %[[V5]]
   return %0, %1, %2, %3, %5, %7 : i1, i1, i1, i1, i1, i1
 }
 
+// CHECK-LABEL: @cmp_sub_ordered
+func.func @cmp_sub_ordered(%arg0: index) -> i1 {
+  %zero = index.constant 0
+  %two = index.constant 2
+  %sub = index.sub %arg0, %two
+  %cmp = index.cmp ule(%sub, %zero)
+
+  // CHECK-DAG: %[[ZERO:.*]] = index.constant 0
+  // CHECK-DAG: %[[TWO:.*]] = index.constant 2
+  // CHECK: %[[SUB:.*]] = index.sub %arg0, %[[TWO]]
+  // CHECK-NEXT: %[[CMP:.*]] = index.cmp ule(%[[SUB]], %[[ZERO]])
+  // CHECK-NEXT: return %[[CMP]]
+  return %cmp : i1
+}
+
+// CHECK-LABEL: @cmp_sub_eq_ne
+func.func @cmp_sub_eq_ne(%arg0: index, %arg1: index) -> (i1, i1) {
+  %zero = index.constant 0
+  %sub = index.sub %arg0, %arg1
+  %eq = index.cmp eq(%sub, %zero)
+  %ne = index.cmp ne(%zero, %sub)
+
+  // CHECK-DAG: %[[EQ:.*]] = index.cmp eq(%arg0, %arg1)
+  // CHECK-DAG: %[[NE:.*]] = index.cmp ne(%arg1, %arg0)
+  // CHECK: return %[[EQ]], %[[NE]]
+  return %eq, %ne : i1, i1
+}
+
 // CHECK-LABEL: @cmp_same_args
 func.func @cmp_same_args(%a: index) -> (i1, i1, i1, i1, i1, i1, i1, i1, i1, i1) {
   %0 = index.cmp eq(%a, %a)



More information about the Mlir-commits mailing list