29#define GEN_PASS_DEF_SCFFORLOOPPEELING
30#define GEN_PASS_DEF_SCFFORLOOPSPECIALIZATION
31#define GEN_PASS_DEF_SCFPARALLELLOOPSPECIALIZATION
32#include "mlir/Dialect/SCF/Transforms/Passes.h.inc"
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(), op.getResultTypes(), cond,
77 scf::YieldOp::create(thenBuilder, op.getLoc(), thenOp->
getResults());
81 scf::YieldOp::create(elseBuilder, op.getLoc(), elseOp->
getResults());
83 op.replaceAllUsesWith(ifOp.getResults());
92 auto bound = op.getUpperBound();
93 auto minOp = bound.getDefiningOp<AffineMinOp>();
96 AffineMap canonicalizedMap = minOp.getMap();
99 int64_t minConstant = std::numeric_limits<int64_t>::max();
101 if (
auto constantIndex = dyn_cast<AffineConstantExpr>(expr))
102 minConstant = std::min(minConstant, constantIndex.getValue());
104 if (minConstant == std::numeric_limits<int64_t>::max())
109 Value constant = arith::ConstantOp::create(
111 IntegerAttr::get(op.getUpperBound().getType(), minConstant));
112 Value cond = arith::CmpIOp::create(
b, op.getLoc(), arith::CmpIPredicate::eq,
114 map.
map(bound, constant);
115 auto ifOp = scf::IfOp::create(
b, op.getLoc(), op->getResultTypes(), cond,
118 OpBuilder thenB = ifOp.getThenBodyBuilder();
120 OpBuilder elseB = ifOp.getElseBodyBuilder();
123 if (op->getNumResults() > 0) {
124 scf::YieldOp::create(thenB, op.getLoc(), thenLoop->
getResults());
125 scf::YieldOp::create(elseB, op.getLoc(), elseLoop->
getResults());
126 op->replaceAllUsesWith(ifOp.getResults());
147 ForOp &partialIteration,
Value &splitBound) {
149 Value lbVal = forOp.getLowerBound();
150 Value ubVal = forOp.getUpperBound();
151 Value stepVal = forOp.getStep();
152 b.setInsertionPoint(forOp);
153 auto loc = forOp.getLoc();
155 bool isUnsigned = forOp.getUnsignedCmp();
156 IntegerAttr lbAttr, ubAttr, stepAttr;
158 APInt step = stepAttr.getValue();
159 if (isUnsigned ? step.ule(1) : step.sle(1))
165 APInt lb = lbAttr.getValue();
166 APInt
ub = ubAttr.getValue();
168 if (isUnsigned ?
ub.ule(lb) :
ub.sle(lb))
173 if (stepAttr && (
ub - lb).urem(stepAttr.getValue()).isZero())
179 if (!isUnsigned && forOp.getInductionVar().getType().isIndex()) {
186 if (
auto constExpr = dyn_cast<AffineConstantExpr>(map.
getResult(0)))
187 if (constExpr.getValue() == 0)
196 Value lbEff = isUnsigned ?
b.createOrFold<arith::MinUIOp>(loc, lbVal, ubVal)
197 :
b.createOrFold<arith::MinSIOp>(loc, lbVal, ubVal);
198 Value diff =
b.createOrFold<arith::SubIOp>(loc, ubVal, lbEff);
199 Value rem =
b.createOrFold<arith::RemUIOp>(loc, diff, stepVal);
200 splitBound =
b.createOrFold<arith::SubIOp>(loc, ubVal,
rem);
203 b.setInsertionPointAfter(forOp);
204 partialIteration = cast<ForOp>(
b.clone(*forOp.getOperation()));
205 partialIteration.getLowerBoundMutable().assign(splitBound);
206 b.replaceAllUsesWith(forOp.getResults(), partialIteration->getResults());
207 partialIteration.getInitArgsMutable().assign(forOp->getResults());
210 b.modifyOpInPlace(forOp,
211 [&]() { forOp.getUpperBoundMutable().assign(splitBound); });
217 ForOp partialIteration,
219 Value mainIv = forOp.getInductionVar();
220 Value partialIv = partialIteration.getInductionVar();
221 assert(forOp.getStep() == partialIteration.getStep() &&
222 "expected same step in main and partial loop");
223 Value step = forOp.getStep();
226 if (!isa<AffineMinOp, AffineMaxOp>(affineOp))
233 partialIteration.walk([&](
Operation *affineOp) {
234 if (!isa<AffineMinOp, AffineMaxOp>(affineOp))
244 ForOp &partialIteration) {
245 Value previousUb = forOp.getUpperBound();
252 if (forOp.getUnsignedCmp())
267 ForOp &firstIteration) {
269 Value lbVal = forOp.getLowerBound();
270 Value ubVal = forOp.getUpperBound();
271 Value stepVal = forOp.getStep();
272 auto loc = forOp.
getLoc();
275 b.setInsertionPoint(forOp);
276 bool isUnsigned = forOp.getUnsignedCmp();
277 IntegerAttr lbAttr, ubAttr, stepAttr;
281 APInt step = stepAttr.getValue();
282 if (isUnsigned ? step.ult(1) : step.slt(1))
288 APInt lb = lbAttr.getValue();
289 APInt
ub = ubAttr.getValue();
290 APInt step = stepAttr.getValue();
292 if (isUnsigned ?
ub.ule(lb) :
ub.sle(lb))
301 if ((
ub - lb).
ule(step))
308 Value sum =
b.createOrFold<arith::AddIOp>(loc, lbVal, stepVal);
309 Value capped = isUnsigned ?
b.createOrFold<arith::MinUIOp>(loc, sum, ubVal)
310 :
b.createOrFold<
arith::MinSIOp>(loc, sum, ubVal);
311 splitBound = isUnsigned ?
b.createOrFold<arith::MaxUIOp>(loc, lbVal, capped)
312 :
b.createOrFold<arith::MaxSIOp>(loc, lbVal, capped);
315 firstIteration = cast<ForOp>(
b.clone(*forOp.getOperation()));
316 b.modifyOpInPlace(firstIteration, [&]() {
317 firstIteration.getUpperBoundMutable().assign(splitBound);
320 b.modifyOpInPlace(forOp, [&]() {
321 forOp.getInitArgsMutable().assign(firstIteration->getResults());
322 forOp.getLowerBoundMutable().assign(splitBound);
329 ForOp partialIteration) {
332 Location loc = partialIteration.getLoc();
335 auto pred = partialIteration.getUnsignedCmp() ? arith::CmpIPredicate::ult
336 : arith::CmpIPredicate::slt;
337 Value cond = arith::CmpIOp::create(rewriter, loc, pred,
338 partialIteration.getLowerBound(),
339 partialIteration.getUpperBound());
340 bool hasResults = partialIteration.getNumResults() > 0;
341 auto ifOp = IfOp::create(rewriter, loc, partialIteration.getResultTypes(),
347 llvm::append_range(replacements, partialIteration.getInitArgs());
349 ifOp.thenBlock()->end(), replacements);
354 YieldOp::create(rewriter, loc, partialIteration.getInitArgs());
357 rewriter.
replaceOp(partialIteration, ifOp.getResults());
366 ForLoopPeelingPattern(
MLIRContext *ctx,
bool peelFront,
bool skipPartial,
369 skipPartial(skipPartial), partialAsIf(partialAsIf) {}
371 LogicalResult matchAndRewrite(ForOp forOp,
378 scf::ForOp partialIteration;
382 peelForLoopFirstIteration(rewriter, forOp, partialIteration))) {
398 peelForLoopAndSimplifyBounds(rewriter, forOp, partialIteration)))
404 partialOp = convertPartialIterationToIf(rewriter, partialIteration);
436struct ParallelLoopSpecialization
437 :
public impl::SCFParallelLoopSpecializationBase<
438 ParallelLoopSpecialization> {
439 void runOnOperation()
override {
440 getOperation()->walk(
445struct ForLoopSpecialization
446 :
public impl::SCFForLoopSpecializationBase<ForLoopSpecialization> {
447 void runOnOperation()
override {
452struct ForLoopPeeling :
public impl::SCFForLoopPeelingBase<ForLoopPeeling> {
453 using impl::SCFForLoopPeelingBase<ForLoopPeeling>::SCFForLoopPeelingBase;
455 void runOnOperation()
override {
456 auto *parentOp = getOperation();
457 MLIRContext *ctx = parentOp->getContext();
458 RewritePatternSet patterns(ctx);
459 patterns.add<ForLoopPeelingPattern>(ctx, peelFront, skipPartial,
464 parentOp->walk([](Operation *op) {
473 return std::make_unique<ParallelLoopSpecialization>();
477 return std::make_unique<ForLoopSpecialization>();
static void specializeForLoopForUnrolling(ForOp op)
Rewrite a for loop with bounds defined by an affine.min with a constant into 2 loops after checking i...
static void specializeParallelLoopForUnrolling(ParallelOp op)
Rewrite a parallel loop with bounds defined by an affine.min with a constant into 2 loops after check...
static constexpr char kPeeledLoopLabel[]
static void rewriteAffineOpAfterPeeling(RewriterBase &rewriter, ForOp forOp, ForOp partialIteration, Value previousUb)
static LogicalResult peelForLoop(RewriterBase &b, ForOp forOp, ForOp &partialIteration, Value &splitBound)
Rewrite a for loop with bounds/step that potentially do not divide evenly into a for loop where the s...
static constexpr char kPartialIterationLabel[]
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
ArrayRef< AffineExpr > getResults() const
AffineExpr getResult(unsigned idx) const
This is a utility class for mapping one set of IR entities to another.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
static OpBuilder atBlockEnd(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to after the last operation in the block but still insid...
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Operation is the basic unit of execution within MLIR.
void setDiscardableAttr(StringAttr name, Attribute value)
Set a discardable attribute by name.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
bool hasDiscardableAttr(StringRef name)
Return true if this operation has a discardable attribute with the provided name.
Attribute removeDiscardableAttr(StringAttr name)
Remove the discardable attribute with the specified name if it exists.
result_range getResults()
void erase()
Remove this operation from its parent block and delete it.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={})
Inline the operations of block 'source' into block 'dest' before the given position.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Location getLoc() const
Return the location of this value.
static WalkResult advance()
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
void canonicalizeMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands)
Modifies both map and operands in-place so as to:
void fullyComposeAffineMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands, bool composeAffineMin=false)
Given an affine map map and its input operands, this method composes into map, maps of AffineApplyOps...
IfOp convertPartialIterationToIf(RewriterBase &rewriter, ForOp partialIteration)
Rewrite partialIteration, the partial iteration created by peelForLoopAndSimplifyBounds or peelForLoo...
LogicalResult peelForLoopAndSimplifyBounds(RewriterBase &rewriter, ForOp forOp, scf::ForOp &partialIteration)
Rewrite a for loop with bounds/step that potentially do not divide evenly into a for loop where the s...
LogicalResult peelForLoopFirstIteration(RewriterBase &rewriter, ForOp forOp, scf::ForOp &partialIteration)
Peel the first iteration out of the scf.for loop.
LogicalResult rewritePeeledMinMaxOp(RewriterBase &rewriter, Operation *op, Value iv, Value ub, Value step, bool insideLoop)
Try to simplify the given affine.min/max operation op after loop peeling.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
std::unique_ptr< Pass > createParallelLoopSpecializationPass()
Creates a pass that specializes parallel loop for unrolling and vectorization.
std::unique_ptr< Pass > createForLoopSpecializationPass()
Creates a pass that specializes for loop for unrolling and vectorization.
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
void bindSymbols(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to SymbolExpr at positions: [0 .
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...