[Mlir-commits] [llvm] [mlir] [mlir][Arith] Move ceil/floor div expansion to ArithUtils. NFC (PR #231064)
Fangrui Song
llvmlistbot at llvm.org
Sun Oct 11 21:35:44 PDT 2026
https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/231064
MLIRArithToLLVM depends on MLIRArithTransforms only for
populateCeilFloorDivExpandOpsPatterns (#118839). MLIRArithTransforms
pulls in Bufferization, SCF, Shard, SparseTensor, Tensor, and Vector, so
every user of the LLVM lowering builds them. ClangIR reaches
MLIRArithToLLVM through MLIROpenMPToLLVM.
Move the three patterns and their populate function to MLIRArithUtils,
which MLIRArithTransforms now links. The declaration moves from
Arith/Transforms/Passes.h to Arith/Utils/Utils.h.
LLM aided. With -DCLANG_ENABLE_CIR=ON, clang links 16 fewer MLIR
libraries (90 -> 74), whose 64 object files take 147 s summed to
compile.
>From c3b2b06ef5e9cc3f05303282583757f9eb71c6ca Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 11 Oct 2026 15:34:14 -0700
Subject: [PATCH] [mlir][Arith] Move ceil/floor div expansion to ArithUtils.
NFC
MLIRArithToLLVM depends on MLIRArithTransforms only for
populateCeilFloorDivExpandOpsPatterns (#118839). MLIRArithTransforms
pulls in Bufferization, SCF, Shard, SparseTensor, Tensor, and Vector, so
every user of the LLVM lowering builds them. ClangIR reaches
MLIRArithToLLVM through MLIROpenMPToLLVM.
Move the three patterns and their populate function to MLIRArithUtils,
which MLIRArithTransforms now links. The declaration moves from
Arith/Transforms/Passes.h to Arith/Utils/Utils.h.
LLM aided. With -DCLANG_ENABLE_CIR=ON, clang links 16 fewer MLIR
libraries (90 -> 74), whose 64 object files take 147 s summed to
compile.
---
.../mlir/Dialect/Arith/Transforms/Passes.h | 3 -
mlir/include/mlir/Dialect/Arith/Utils/Utils.h | 2 +
.../Conversion/ArithToLLVM/ArithToLLVM.cpp | 3 +-
.../lib/Conversion/ArithToLLVM/CMakeLists.txt | 2 +-
.../Dialect/Arith/Transforms/CMakeLists.txt | 1 +
.../Dialect/Arith/Transforms/ExpandOps.cpp | 113 +---------------
mlir/lib/Dialect/Arith/Utils/Utils.cpp | 126 ++++++++++++++++++
mlir/test/lib/Pass/TestConvertToSPIRVPass.cpp | 1 +
.../llvm-project-overlay/mlir/BUILD.bazel | 2 +-
.../mlir/test/BUILD.bazel | 1 +
10 files changed, 136 insertions(+), 118 deletions(-)
diff --git a/mlir/include/mlir/Dialect/Arith/Transforms/Passes.h b/mlir/include/mlir/Dialect/Arith/Transforms/Passes.h
index 26832ba652680..7d7909c5f8231 100644
--- a/mlir/include/mlir/Dialect/Arith/Transforms/Passes.h
+++ b/mlir/include/mlir/Dialect/Arith/Transforms/Passes.h
@@ -53,9 +53,6 @@ void populateEmulateUnsupportedFloatsPatterns(RewritePatternSet &patterns,
/// float types.
void populateEmulateUnsupportedFloatsLegality(ConversionTarget &target,
const TypeConverter &converter);
-/// Add patterns to expand Arith ceil/floor division ops.
-void populateCeilFloorDivExpandOpsPatterns(RewritePatternSet &patterns);
-
/// Add patterns to expand Arith bf16 patterns to lower level bitcasts/shifts.
void populateExpandBFloat16Patterns(RewritePatternSet &patterns);
diff --git a/mlir/include/mlir/Dialect/Arith/Utils/Utils.h b/mlir/include/mlir/Dialect/Arith/Utils/Utils.h
index 4ebb7e16239f7..3594453a492a5 100644
--- a/mlir/include/mlir/Dialect/Arith/Utils/Utils.h
+++ b/mlir/include/mlir/Dialect/Arith/Utils/Utils.h
@@ -129,6 +129,8 @@ struct ArithIndexingBuilder : public ArithBuilder {
};
namespace arith {
+/// Add patterns to expand Arith ceil/floor division ops.
+void populateCeilFloorDivExpandOpsPatterns(RewritePatternSet &patterns);
// Build the product of a sequence.
// If values = (v0, v1, ..., vn) than the returned
diff --git a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
index bac19144d6ea7..82ff88f55228e 100644
--- a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
+++ b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
@@ -14,12 +14,13 @@
#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
#include "mlir/Conversion/LLVMCommon/VectorPattern.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
-#include "mlir/Dialect/Arith/Transforms/Passes.h"
+#include "mlir/Dialect/Arith/Utils/Utils.h"
#include "mlir/Dialect/LLVMIR/FunctionCallUtils.h"
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/DialectResourceBlobManager.h"
#include "mlir/IR/TypeUtilities.h"
+#include "mlir/Pass/Pass.h"
#include <type_traits>
namespace mlir {
diff --git a/mlir/lib/Conversion/ArithToLLVM/CMakeLists.txt b/mlir/lib/Conversion/ArithToLLVM/CMakeLists.txt
index 8fdfa991a35d3..d445cbe2f1260 100644
--- a/mlir/lib/Conversion/ArithToLLVM/CMakeLists.txt
+++ b/mlir/lib/Conversion/ArithToLLVM/CMakeLists.txt
@@ -13,7 +13,7 @@ add_mlir_conversion_library(MLIRArithToLLVM
LINK_LIBS PUBLIC
MLIRArithAttrToLLVMConversion
MLIRArithDialect
- MLIRArithTransforms
+ MLIRArithUtils
MLIRAnalysis
MLIRDataLayoutInterfaces
MLIRLLVMCommonConversion
diff --git a/mlir/lib/Dialect/Arith/Transforms/CMakeLists.txt b/mlir/lib/Dialect/Arith/Transforms/CMakeLists.txt
index 637e16a3963d6..3f850589d4166 100644
--- a/mlir/lib/Dialect/Arith/Transforms/CMakeLists.txt
+++ b/mlir/lib/Dialect/Arith/Transforms/CMakeLists.txt
@@ -20,6 +20,7 @@ add_mlir_dialect_library(MLIRArithTransforms
LINK_LIBS PUBLIC
MLIRAnalysis
MLIRArithDialect
+ MLIRArithUtils
MLIRBufferizationDialect
MLIRBufferizationTransforms
MLIRFuncDialect
diff --git a/mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp b/mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp
index 2e02d44bdbe2c..829f568e33e6b 100644
--- a/mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp
+++ b/mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp
@@ -8,6 +8,7 @@
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Arith/Transforms/Passes.h"
+#include "mlir/Dialect/Arith/Utils/Utils.h"
#include "mlir/Dialect/Vector/IR/VectorDialect.h"
#include "mlir/IR/BuiltinTypeInterfaces.h"
#include "mlir/IR/Location.h"
@@ -67,111 +68,6 @@ static Type cloneToShapedType(Type cloneFrom, Type cloneTo) {
namespace {
-/// Expands CeilDivUIOp (n, m) into
-/// n == 0 ? 0 : ((n-1) / m) + 1
-struct CeilDivUIOpConverter : public OpRewritePattern<arith::CeilDivUIOp> {
- using Base::Base;
- LogicalResult matchAndRewrite(arith::CeilDivUIOp op,
- PatternRewriter &rewriter) const final {
- Location loc = op.getLoc();
- Value a = op.getLhs();
- Value b = op.getRhs();
- Value zero = createConst(loc, a.getType(), 0, rewriter);
- Value compare =
- arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::eq, a, zero);
- Value one = createConst(loc, a.getType(), 1, rewriter);
- Value minusOne = arith::SubIOp::create(rewriter, loc, a, one);
- Value quotient = arith::DivUIOp::create(rewriter, loc, minusOne, b);
- Value plusOne = arith::AddIOp::create(rewriter, loc, quotient, one);
- rewriter.replaceOpWithNewOp<arith::SelectOp>(op, compare, zero, plusOne);
- return success();
- }
-};
-
-/// Expands CeilDivSIOp (a, b) into
-/// z = a / b
-/// if (z * b != a && (a < 0) == (b < 0)) {
-/// return z + 1;
-/// } else {
-/// return z;
-/// }
-struct CeilDivSIOpConverter : public OpRewritePattern<arith::CeilDivSIOp> {
- using Base::Base;
- LogicalResult matchAndRewrite(arith::CeilDivSIOp op,
- PatternRewriter &rewriter) const final {
- Location loc = op.getLoc();
- Type type = op.getType();
- Value a = op.getLhs();
- Value b = op.getRhs();
-
- Value zero = createConst(loc, type, 0, rewriter);
- Value one = createConst(loc, type, 1, rewriter);
-
- Value quotient = arith::DivSIOp::create(rewriter, loc, a, b);
- Value product = arith::MulIOp::create(rewriter, loc, quotient, b);
- Value notEqualDivisor = arith::CmpIOp::create(
- rewriter, loc, arith::CmpIPredicate::ne, a, product);
-
- Value aNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
- a, zero);
- Value bNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
- b, zero);
-
- Value signEqual = arith::CmpIOp::create(
- rewriter, loc, arith::CmpIPredicate::eq, aNeg, bNeg);
- Value cond =
- arith::AndIOp::create(rewriter, loc, notEqualDivisor, signEqual);
-
- Value quotientPlusOne = arith::AddIOp::create(rewriter, loc, quotient, one);
-
- rewriter.replaceOpWithNewOp<arith::SelectOp>(op, cond, quotientPlusOne,
- quotient);
- return success();
- }
-};
-
-/// Expands FloorDivSIOp (x, y) into
-/// z = x / y
-/// if (z * y != x && (x < 0) != (y < 0)) {
-/// return z - 1;
-/// } else {
-/// return z;
-/// }
-struct FloorDivSIOpConverter : public OpRewritePattern<arith::FloorDivSIOp> {
- using Base::Base;
- LogicalResult matchAndRewrite(arith::FloorDivSIOp op,
- PatternRewriter &rewriter) const final {
- Location loc = op.getLoc();
- Type type = op.getType();
- Value a = op.getLhs();
- Value b = op.getRhs();
-
- Value quotient = arith::DivSIOp::create(rewriter, loc, a, b);
- Value product = arith::MulIOp::create(rewriter, loc, quotient, b);
- Value notEqualDivisor = arith::CmpIOp::create(
- rewriter, loc, arith::CmpIPredicate::ne, a, product);
- Value zero = createConst(loc, type, 0, rewriter);
-
- Value aNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
- a, zero);
- Value bNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
- b, zero);
-
- Value signOpposite = arith::CmpIOp::create(
- rewriter, loc, arith::CmpIPredicate::ne, aNeg, bNeg);
- Value cond =
- arith::AndIOp::create(rewriter, loc, notEqualDivisor, signOpposite);
-
- Value minusOne = createConst(loc, type, -1, rewriter);
- Value quotientMinusOne =
- arith::AddIOp::create(rewriter, loc, quotient, minusOne);
-
- rewriter.replaceOpWithNewOp<arith::SelectOp>(op, cond, quotientMinusOne,
- quotient);
- return success();
- }
-};
-
template <typename OpTy, arith::CmpIPredicate pred>
struct MaxMinIOpConverter : public OpRewritePattern<OpTy> {
public:
@@ -1197,13 +1093,6 @@ struct ArithExpandOpsPass
} // namespace
-void mlir::arith::populateCeilFloorDivExpandOpsPatterns(
- RewritePatternSet &patterns) {
- patterns
- .add<CeilDivSIOpConverter, CeilDivUIOpConverter, FloorDivSIOpConverter>(
- patterns.getContext());
-}
-
void mlir::arith::populateExpandBFloat16Patterns(RewritePatternSet &patterns) {
patterns.add<BFloat16ExtFOpConverter, BFloat16TruncFOpConverter>(
patterns.getContext());
diff --git a/mlir/lib/Dialect/Arith/Utils/Utils.cpp b/mlir/lib/Dialect/Arith/Utils/Utils.cpp
index 8cbddd920c91f..8b90be0f87346 100644
--- a/mlir/lib/Dialect/Arith/Utils/Utils.cpp
+++ b/mlir/lib/Dialect/Arith/Utils/Utils.cpp
@@ -16,6 +16,7 @@
#include "mlir/Dialect/Complex/IR/Complex.h"
#include "mlir/Dialect/Utils/StaticValueUtils.h"
#include "mlir/IR/Diagnostics.h"
+#include "mlir/IR/TypeUtilities.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVectorExtras.h"
#include <numeric>
@@ -375,3 +376,128 @@ FloatType parseFloatType(MLIRContext *ctx, StringRef name) {
}
} // namespace mlir::arith
+
+/// Create an integer or index constant.
+static Value createConst(Location loc, Type type, int value,
+ PatternRewriter &rewriter) {
+ auto attr = rewriter.getIntegerAttr(getElementTypeOrSelf(type), value);
+ if (auto shapedTy = dyn_cast<ShapedType>(type)) {
+ return arith::ConstantOp::create(rewriter, loc,
+ DenseElementsAttr::get(shapedTy, attr));
+ }
+ return arith::ConstantOp::create(rewriter, loc, attr);
+}
+
+namespace {
+/// Expands CeilDivUIOp (n, m) into
+/// n == 0 ? 0 : ((n-1) / m) + 1
+struct CeilDivUIOpConverter : public OpRewritePattern<arith::CeilDivUIOp> {
+ using Base::Base;
+ LogicalResult matchAndRewrite(arith::CeilDivUIOp op,
+ PatternRewriter &rewriter) const final {
+ Location loc = op.getLoc();
+ Value a = op.getLhs();
+ Value b = op.getRhs();
+ Value zero = createConst(loc, a.getType(), 0, rewriter);
+ Value compare =
+ arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::eq, a, zero);
+ Value one = createConst(loc, a.getType(), 1, rewriter);
+ Value minusOne = arith::SubIOp::create(rewriter, loc, a, one);
+ Value quotient = arith::DivUIOp::create(rewriter, loc, minusOne, b);
+ Value plusOne = arith::AddIOp::create(rewriter, loc, quotient, one);
+ rewriter.replaceOpWithNewOp<arith::SelectOp>(op, compare, zero, plusOne);
+ return success();
+ }
+};
+
+/// Expands CeilDivSIOp (a, b) into
+/// z = a / b
+/// if (z * b != a && (a < 0) == (b < 0)) {
+/// return z + 1;
+/// } else {
+/// return z;
+/// }
+struct CeilDivSIOpConverter : public OpRewritePattern<arith::CeilDivSIOp> {
+ using Base::Base;
+ LogicalResult matchAndRewrite(arith::CeilDivSIOp op,
+ PatternRewriter &rewriter) const final {
+ Location loc = op.getLoc();
+ Type type = op.getType();
+ Value a = op.getLhs();
+ Value b = op.getRhs();
+
+ Value zero = createConst(loc, type, 0, rewriter);
+ Value one = createConst(loc, type, 1, rewriter);
+
+ Value quotient = arith::DivSIOp::create(rewriter, loc, a, b);
+ Value product = arith::MulIOp::create(rewriter, loc, quotient, b);
+ Value notEqualDivisor = arith::CmpIOp::create(
+ rewriter, loc, arith::CmpIPredicate::ne, a, product);
+
+ Value aNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
+ a, zero);
+ Value bNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
+ b, zero);
+
+ Value signEqual = arith::CmpIOp::create(
+ rewriter, loc, arith::CmpIPredicate::eq, aNeg, bNeg);
+ Value cond =
+ arith::AndIOp::create(rewriter, loc, notEqualDivisor, signEqual);
+
+ Value quotientPlusOne = arith::AddIOp::create(rewriter, loc, quotient, one);
+
+ rewriter.replaceOpWithNewOp<arith::SelectOp>(op, cond, quotientPlusOne,
+ quotient);
+ return success();
+ }
+};
+
+/// Expands FloorDivSIOp (x, y) into
+/// z = x / y
+/// if (z * y != x && (x < 0) != (y < 0)) {
+/// return z - 1;
+/// } else {
+/// return z;
+/// }
+struct FloorDivSIOpConverter : public OpRewritePattern<arith::FloorDivSIOp> {
+ using Base::Base;
+ LogicalResult matchAndRewrite(arith::FloorDivSIOp op,
+ PatternRewriter &rewriter) const final {
+ Location loc = op.getLoc();
+ Type type = op.getType();
+ Value a = op.getLhs();
+ Value b = op.getRhs();
+
+ Value quotient = arith::DivSIOp::create(rewriter, loc, a, b);
+ Value product = arith::MulIOp::create(rewriter, loc, quotient, b);
+ Value notEqualDivisor = arith::CmpIOp::create(
+ rewriter, loc, arith::CmpIPredicate::ne, a, product);
+ Value zero = createConst(loc, type, 0, rewriter);
+
+ Value aNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
+ a, zero);
+ Value bNeg = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
+ b, zero);
+
+ Value signOpposite = arith::CmpIOp::create(
+ rewriter, loc, arith::CmpIPredicate::ne, aNeg, bNeg);
+ Value cond =
+ arith::AndIOp::create(rewriter, loc, notEqualDivisor, signOpposite);
+
+ Value minusOne = createConst(loc, type, -1, rewriter);
+ Value quotientMinusOne =
+ arith::AddIOp::create(rewriter, loc, quotient, minusOne);
+
+ rewriter.replaceOpWithNewOp<arith::SelectOp>(op, cond, quotientMinusOne,
+ quotient);
+ return success();
+ }
+};
+} // namespace
+
+void mlir::arith::populateCeilFloorDivExpandOpsPatterns(
+ RewritePatternSet &patterns) {
+ patterns
+ .add<CeilDivSIOpConverter, CeilDivUIOpConverter, FloorDivSIOpConverter>(
+ patterns.getContext());
+}
diff --git a/mlir/test/lib/Pass/TestConvertToSPIRVPass.cpp b/mlir/test/lib/Pass/TestConvertToSPIRVPass.cpp
index fa07a94aba474..253f7343231cc 100644
--- a/mlir/test/lib/Pass/TestConvertToSPIRVPass.cpp
+++ b/mlir/test/lib/Pass/TestConvertToSPIRVPass.cpp
@@ -17,6 +17,7 @@
#include "mlir/Conversion/UBToSPIRV/UBToSPIRV.h"
#include "mlir/Conversion/VectorToSPIRV/VectorToSPIRV.h"
#include "mlir/Dialect/Arith/Transforms/Passes.h"
+#include "mlir/Dialect/Arith/Utils/Utils.h"
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
#include "mlir/Dialect/SPIRV/Transforms/SPIRVConversion.h"
diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
index be52547a9da73..27251d9fa6526 100644
--- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
@@ -8971,7 +8971,7 @@ cc_library(
":Analysis",
":ArithAttrToLLVMConversion",
":ArithDialect",
- ":ArithTransforms",
+ ":ArithUtils",
":ConversionPassIncGen",
":ConvertToLLVMInterface",
":IR",
diff --git a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
index ee7215395cedf..f46074f0d1d1b 100644
--- a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
@@ -554,6 +554,7 @@ cc_library(
"//llvm:Support",
"//mlir:ArithToSPIRV",
"//mlir:ArithTransforms",
+ "//mlir:ArithUtils",
"//mlir:ControlFlowToSPIRV",
"//mlir:FuncDialect",
"//mlir:FuncToSPIRV",
More information about the Mlir-commits
mailing list