46 constantIndices.reserve(op.getUpperBound().size());
47 for (
auto bound : op.getUpperBound()) {
48 auto minOp = bound.getDefiningOp<AffineMinOp>();
51 int64_t minConstant = std::numeric_limits<int64_t>::max();
52 for (
AffineExpr expr : minOp.getMap().getResults()) {
53 if (
auto constantIndex = dyn_cast<AffineConstantExpr>(expr))
54 minConstant = std::min(minConstant, constantIndex.getValue());
56 if (minConstant == std::numeric_limits<int64_t>::max())
58 constantIndices.push_back(minConstant);
64 for (
auto bound : llvm::zip(op.getUpperBound(), constantIndices)) {
67 Value cmp = arith::CmpIOp::create(
b, op.getLoc(), arith::CmpIPredicate::eq,
68 std::get<0>(bound), constant);
69 cond = cond ? arith::AndIOp::create(
b, op.getLoc(), cond, cmp) : cmp;
70 map.
map(std::get<0>(bound), constant);
72 auto ifOp = scf::IfOp::create(
b, op.getLoc(), cond,
true);
73 ifOp.getThenBodyBuilder().clone(*op.getOperation(), map);
74 ifOp.getElseBodyBuilder().clone(*op.getOperation());
83 auto bound = op.getUpperBound();
84 auto minOp = bound.getDefiningOp<AffineMinOp>();
87 AffineMap canonicalizedMap = minOp.getMap();
90 int64_t minConstant = std::numeric_limits<int64_t>::max();
92 if (
auto constantIndex = dyn_cast<AffineConstantExpr>(expr))
93 minConstant = std::min(minConstant, constantIndex.getValue());
95 if (minConstant == std::numeric_limits<int64_t>::max())
100 Value constant = arith::ConstantOp::create(
102 IntegerAttr::get(op.getUpperBound().getType(), minConstant));
103 Value cond = arith::CmpIOp::create(
b, op.getLoc(), arith::CmpIPredicate::eq,
105 map.
map(bound, constant);
106 auto ifOp = scf::IfOp::create(
b, op.getLoc(), cond,
true);
107 ifOp.getThenBodyBuilder().clone(*op.getOperation(), map);
108 ifOp.getElseBodyBuilder().clone(*op.getOperation());
127 ForOp &partialIteration,
Value &splitBound) {
129 Value lbVal = forOp.getLowerBound();
130 Value ubVal = forOp.getUpperBound();
131 Value stepVal = forOp.getStep();
132 b.setInsertionPoint(forOp);
133 auto loc = forOp.getLoc();
136 if (forOp.getUnsignedCmp()) {
137 IntegerAttr lbAttr, ubAttr, stepAttr;
143 APInt lb = lbAttr.getValue();
144 APInt
ub = ubAttr.getValue();
145 APInt step = stepAttr.getValue();
147 if (step.ule(1) ||
ub.ule(lb) || (
ub - lb).urem(step).isZero())
155 Value lbEff =
b.createOrFold<arith::MinUIOp>(loc, lbVal, ubVal);
156 Value diff =
b.createOrFold<arith::SubIOp>(loc, ubVal, lbEff);
157 Value rem =
b.createOrFold<arith::RemUIOp>(loc, diff, stepVal);
158 splitBound =
b.createOrFold<arith::SubIOp>(loc, ubVal,
rem);
167 if (stepInt && *stepInt <= 1)
172 if (lbInt && ubInt && stepInt) {
175 if (llvm::SubOverflow(*ubInt, *lbInt, diff) || diff % *stepInt == 0)
181 if ((!lbInt || !ubInt || !stepInt) &&
182 !forOp.getInductionVar().getType().isIndex())
192 if (
auto constExpr = dyn_cast<AffineConstantExpr>(map.
getResult(0)))
193 if (constExpr.getValue() == 0)
199 auto modMap =
AffineMap::get(0, 3, {sym1 - ((sym1 - sym0) % sym2), sym0},
201 splitBound =
b.createOrFold<AffineMaxOp>(loc, modMap,
203 forOp.getUpperBound(),
205 if (splitBound.
getType() != forOp.getLowerBound().getType())
206 splitBound =
b.createOrFold<arith::IndexCastOp>(
207 loc, forOp.getLowerBound().
getType(), splitBound);
210 b.setInsertionPointAfter(forOp);
211 partialIteration = cast<ForOp>(
b.clone(*forOp.getOperation()));
212 partialIteration.getLowerBoundMutable().assign(splitBound);
213 b.replaceAllUsesWith(forOp.getResults(), partialIteration->getResults());
214 partialIteration.getInitArgsMutable().assign(forOp->getResults());
217 b.modifyOpInPlace(forOp,
218 [&]() { forOp.getUpperBoundMutable().assign(splitBound); });
224 ForOp partialIteration,
226 Value mainIv = forOp.getInductionVar();
227 Value partialIv = partialIteration.getInductionVar();
228 assert(forOp.getStep() == partialIteration.getStep() &&
229 "expected same step in main and partial loop");
230 Value step = forOp.getStep();
233 if (!isa<AffineMinOp, AffineMaxOp>(affineOp))
240 partialIteration.walk([&](
Operation *affineOp) {
241 if (!isa<AffineMinOp, AffineMaxOp>(affineOp))
251 ForOp &partialIteration) {
252 Value previousUb = forOp.getUpperBound();
259 if (forOp.getUnsignedCmp())
274 ForOp &firstIteration) {
276 Value lbVal = forOp.getLowerBound();
277 Value ubVal = forOp.getUpperBound();
279 auto loc = forOp.
getLoc();
282 b.setInsertionPoint(forOp);
285 if (forOp.getUnsignedCmp()) {
286 IntegerAttr lbAttr, ubAttr, stepAttr;
292 APInt lb = lbAttr.getValue();
293 APInt
ub = ubAttr.getValue();
294 APInt step = stepAttr.getValue();
297 if (
ub.ule(lb) || (
ub - lb).ule(step))
305 Value sum =
b.createOrFold<arith::AddIOp>(loc, lbVal, stepVal);
306 Value capped =
b.createOrFold<arith::MinUIOp>(loc, sum, ubVal);
307 splitBound =
b.createOrFold<arith::MaxUIOp>(loc, lbVal, capped);
318 if (lbInt && ubInt && stepInt) {
320 if (llvm::SubOverflow(*ubInt, *lbInt, diff) || diff <= *stepInt)
327 Value sum =
b.createOrFold<arith::AddIOp>(loc, lbVal, stepVal);
328 Value capped =
b.createOrFold<arith::MinSIOp>(loc, sum, ubVal);
329 splitBound =
b.createOrFold<arith::MaxSIOp>(loc, lbVal, capped);
332 firstIteration = cast<ForOp>(
b.clone(*forOp.getOperation()));
333 b.modifyOpInPlace(firstIteration, [&]() {
334 firstIteration.getUpperBoundMutable().assign(splitBound);
337 b.modifyOpInPlace(forOp, [&]() {
338 forOp.getInitArgsMutable().assign(firstIteration->getResults());
339 forOp.getLowerBoundMutable().assign(splitBound);
350 ForLoopPeelingPattern(
MLIRContext *ctx,
bool peelFront,
bool skipPartial)
352 skipPartial(skipPartial) {}
354 LogicalResult matchAndRewrite(ForOp forOp,
361 scf::ForOp partialIteration;
365 peelForLoopFirstIteration(rewriter, forOp, partialIteration))) {
380 peelForLoopAndSimplifyBounds(rewriter, forOp, partialIteration)))
411struct ParallelLoopSpecialization
413 ParallelLoopSpecialization> {
414 void runOnOperation()
override {
415 getOperation()->walk(
420struct ForLoopSpecialization
422 void runOnOperation()
override {
428 using impl::SCFForLoopPeelingBase<ForLoopPeeling>::SCFForLoopPeelingBase;
430 void runOnOperation()
override {
431 auto *parentOp = getOperation();
432 MLIRContext *ctx = parentOp->getContext();
433 RewritePatternSet patterns(ctx);
434 patterns.add<ForLoopPeelingPattern>(ctx, peelFront, skipPartial);
438 parentOp->walk([](Operation *op) {
447 return std::make_unique<ParallelLoopSpecialization>();
451 return std::make_unique<ForLoopSpecialization>();
MLIRContext is the top-level object for a collection of MLIR operations.