[Mlir-commits] [mlir] [mlir][arith] Fold min/max with absorption and redundancy (PR #160224)

Ziliang Zhang llvmlistbot at llvm.org
Sun Sep 28 19:33:14 PDT 2025


================
@@ -1116,6 +1116,18 @@ OpFoldResult arith::MaximumFOp::fold(FoldAdaptor adaptor) {
   if (matchPattern(adaptor.getRhs(), m_NegInfFloat()))
     return getLhs();
 
+  // max(max(a, b), b) -> max(a, b)
+  // max(max(a, b), a) -> max(a, b)
+  if (auto max = getLhs().getDefiningOp<MaximumFOp>())
+    if (getRhs() == max.getRhs() || getRhs() == max.getLhs())
+      return getLhs();
+
+  // max(a, max(a, b)) -> max(a, b)
+  // max(b, max(a, b)) -> max(a, b)
----------------
ziliangzl wrote:

Good point. Currently, the Commutative trait only provides a generic fold that moves constant operands to the end:
https://github.com/llvm/llvm-project/blob/cac0635ee9e947b5f90130df2f471aa4b722e04b/mlir/lib/IR/Operation.cpp#L856-L873

so it helps in canonicalize patterns like `max(max(x, c0), c1) -> max(x, max(c0, c1))`, where there are constants.

But for cases like fold patterns in this pr `max(max(a, b), a) -> max(a, b)` , no constants are involved, so the commutative fold doesn’t normalize operands. That’s why I explicitly check both lhs and rhs here.

An alternative would be to normalize operands inside the canonicalization itself (e.g., always move the nested max to the RHS), but for now I kept both conditions for clarity.
cc @joker-eph 

https://github.com/llvm/llvm-project/pull/160224


More information about the Mlir-commits mailing list