[Mlir-commits] [mlir] [mlir] Add splitForOpAtBound utility and use it in loop unrolling (PR #215108)
Matthias Springer
llvmlistbot at llvm.org
Wed Aug 26 00:07:21 PDT 2026
================
@@ -363,6 +364,112 @@ void mlir::generateUnrolledLoop(
loopBodyBlock->getTerminator()->setOperands(lastYielded);
}
+/// Splits `forOp` into two consecutive loops at `splitPoint`.
+FailureOr<std::pair<scf::ForOp, scf::ForOp>>
+mlir::splitForOpAtPoint(scf::ForOp forOp, Value splitPoint) {
+ if (splitPoint.getType() != forOp.getLowerBound().getType())
+ return failure();
+
+ // When a bound is constant, require a valid lattice-aligned split point.
+ // When it is dynamic, emit the same checks as runtime asserts.
+ OpBuilder runtimeBuilder(forOp);
+ Location loc = forOp.getLoc();
+ bool isUnsigned = forOp.getUnsignedCmp();
+ Value lbVal = forOp.getLowerBound();
+ Value ubVal = forOp.getUpperBound();
+ Value stepVal = forOp.getStep();
+ // Fail at runtime if `cond` is false.
+ auto emitAssert = [&](Value cond, StringRef msg) {
+ forOp->getContext()->getOrLoadDialect<cf::ControlFlowDialect>();
+ cf::AssertOp::create(runtimeBuilder, loc, cond,
+ runtimeBuilder.getStringAttr(msg));
+ };
+ // Compare according to the loop's signedness.
+ auto emitICmp = [&](arith::CmpIPredicate signedPred,
+ arith::CmpIPredicate unsignedPred, Value lhs, Value rhs) {
+ return arith::CmpIOp::create(
+ runtimeBuilder, loc, isUnsigned ? unsignedPred : signedPred, lhs, rhs);
+ };
+ // Check the split point statically when constant, otherwise at runtime.
+ auto checkSplitPoint = [&](auto getBound) -> LogicalResult {
+ auto lb = getBound(lbVal);
+ auto ub = getBound(ubVal);
+ auto step = getBound(stepVal);
+ auto split = getBound(splitPoint);
+ // lowerBound <= splitPoint
+ if (lb && split) {
+ if (*lb > *split)
+ return failure();
+ } else {
+ emitAssert(emitICmp(arith::CmpIPredicate::sle, arith::CmpIPredicate::ule,
+ lbVal, splitPoint),
+ "splitForOpAtPoint: split point below lower bound");
+ }
+ // splitPoint < upperBound
+ if (split && ub) {
+ if (*split >= *ub)
+ return failure();
+ } else {
+ emitAssert(emitICmp(arith::CmpIPredicate::slt, arith::CmpIPredicate::ult,
+ splitPoint, ubVal),
+ "splitForOpAtPoint: split point not below upper bound");
+ }
+ // step > 0
+ if (step) {
+ if (*step <= 0)
+ return failure();
+ } else {
+ Value zero = arith::ConstantOp::create(
+ runtimeBuilder, loc,
+ runtimeBuilder.getIntegerAttr(stepVal.getType(), 0));
+ emitAssert(emitICmp(arith::CmpIPredicate::sgt, arith::CmpIPredicate::ugt,
+ stepVal, zero),
+ "splitForOpAtPoint: step must be positive");
+ }
+ // splitPoint == lowerBound + k * step
+ if (lb && step && split) {
+ if ((*split - *lb) % *step != 0)
+ return failure();
+ } else {
+ Value zero = arith::ConstantOp::create(
----------------
matthias-springer wrote:
nit: You can use `getValueOrCreateConstantIntOp(getIntegerAttr(...))`
https://github.com/llvm/llvm-project/pull/215108
More information about the Mlir-commits
mailing list