24#include "llvm/ADT/SmallVector.h"
27#define GEN_PASS_DEF_RAISESCFTOAFFINEPASS
28#include "mlir/Conversion/Passes.h.inc"
41 void runOnOperation()
override;
51 using OpRewritePattern<scf::ForOp>::OpRewritePattern;
53 LogicalResult matchAndRewrite(scf::ForOp op,
54 PatternRewriter &rewriter)
const override;
62 bool canRaiseToAffine(scf::ForOp op)
const;
69 void castBoundsToIndex(scf::ForOp op, PatternRewriter &rewriter)
const;
93 std::pair<affine::AffineForOp, Value>
94 createAffineFor(scf::ForOp op, PatternRewriter &rewriter)
const;
96 std::pair<affine::AffineForOp, Value>
97 createAffineForWithConstantStep(scf::ForOp op, int64_t step,
98 PatternRewriter &rewriter)
const;
100 std::pair<affine::AffineForOp, Value>
101 createAffineForWithDynamicStep(scf::ForOp op,
102 PatternRewriter &rewriter)
const;
105bool indexBoundsRaisable(scf::ForOp op) {
106 Value lb = op.getLowerBound();
108 IntegerAttr constAttr;
117 isa_and_present<affine::AffineMinOp>(
ub.getDefiningOp());
120 return lbOK && ubOK && stepOK;
127bool intBoundsRaisable(scf::ForOp op, IntegerType intType) {
129 .getTypeSizeInBits(IndexType::get(op.getContext()))
133 uint64_t requiredWidth = intType.getWidth() + (op.getUnsignedCmp() ? 1 : 0);
134 if (requiredWidth > indexWidth)
147bool ForOpRewrite::canRaiseToAffine(scf::ForOp op)
const {
148 Type type = op.getInductionVar().getType();
149 if (isa<IndexType>(type))
150 return indexBoundsRaisable(op);
151 if (
auto intType = dyn_cast<IntegerType>(type))
152 return intBoundsRaisable(op, intType);
156LogicalResult ForOpRewrite::matchAndRewrite(scf::ForOp op,
157 PatternRewriter &rewriter)
const {
158 if (!canRaiseToAffine(op)) {
162 if (!isa<IndexType>(op.getInductionVar().getType()))
163 castBoundsToIndex(op, rewriter);
165 auto [affineFor, oldIV] = createAffineFor(op, rewriter);
166 Block *affineBody = affineFor.getBody();
171 assert(isa<affine::AffineYieldOp>(terminator) &&
172 "expected affine.yield if there *might* be terminator");
176 SmallVector<Value> argValues;
177 argValues.push_back(oldIV);
178 llvm::append_range(argValues, affineFor.getRegionIterArgs());
182 auto scfYieldOp = cast<scf::YieldOp>(affineBody->
getTerminator());
185 scfYieldOp->getOperands());
191std::pair<affine::AffineForOp, Value>
192ForOpRewrite::createAffineFor(scf::ForOp op, PatternRewriter &rewriter)
const {
193 IntegerAttr constAttr;
195 int64_t step = constAttr.getInt();
196 assert(step > 0 &&
"scf.for has positive step");
197 return createAffineForWithConstantStep(op, step, rewriter);
199 return createAffineForWithDynamicStep(op, rewriter);
202std::pair<affine::AffineForOp, Value>
203ForOpRewrite::createAffineForWithConstantStep(scf::ForOp op, int64_t step,
204 PatternRewriter &rewriter)
const {
205 Value lb = op.getLowerBound();
206 Value ub = op.getUpperBound();
214 if (
auto ubMinOp = ub.
getDefiningOp<affine::AffineMinOp>()) {
215 ubOperands = ubMinOp->getOperands();
216 ubMap = ubMinOp.getAffineMap();
219 if (
auto lbMaxOp = lb.
getDefiningOp<affine::AffineMaxOp>()) {
220 lbOperands = lbMaxOp->getOperands();
221 lbMap = lbMaxOp.getAffineMap();
225 affine::AffineForOp::create(rewriter, op.getLoc(), lbOperands, lbMap,
226 ubOperands, ubMap, step, op.getInits());
228 return std::make_pair(affineFor, affineFor.getInductionVar());
231std::pair<affine::AffineForOp, Value>
232ForOpRewrite::createAffineForWithDynamicStep(scf::ForOp op,
233 PatternRewriter &rewriter)
const {
234 Value lb = op.getLowerBound();
235 Value ub = op.getUpperBound();
236 Value step = op.getStep();
239 "dynamic-step lower bound must be a valid affine dim");
246 llvm::SmallVector<Value, 3> ubOperands = {lb, ub, step};
251 AffineMap ubMap =
AffineMap::get(2, 1, (d1 - d0 + s0 - 1).floorDiv(s0));
253 if (
auto ubMinOp = ub.
getDefiningOp<affine::AffineMinOp>()) {
254 AffineMap origUbMap = ubMinOp.getAffineMap();
261 SmallVector<AffineExpr> ubExprs;
263 for (AffineExpr ubI : origUbMap.
getResults()) {
264 ubExprs.push_back((ubI - lbDim + stepSym - 1).floorDiv(stepSym));
274 SmallVector<Value> combined;
275 combined.append(ubOps.begin(), ubOps.begin() + ubDims);
276 combined.push_back(lb);
277 combined.append(ubOps.begin() + ubDims, ubOps.end());
278 combined.push_back(op.getStep());
279 ubOperands = std::move(combined);
282 auto affineFor = affine::AffineForOp::create(
283 rewriter, op.getLoc(), {}, zeroMap, ubOperands, ubMap, 1, op.getInits());
288 llvm::SmallVector<Value, 3> ivOperands = {lb, affineFor.getInductionVar(),
293 affine::AffineApplyOp::create(rewriter, op.getLoc(), ivMap, ivOperands);
295 return std::make_pair(affineFor, oldIV);
298void ForOpRewrite::castBoundsToIndex(scf::ForOp loop,
299 PatternRewriter &rewriter)
const {
300 OpBuilder::InsertionGuard guard(rewriter);
302 Value lb = loop.getLowerBound();
303 Value ub = loop.getUpperBound();
304 Value step = loop.getStep();
305 Type originalType = step.
getType();
307 assert(lb.
getType() == originalType && ub.
getType() == originalType &&
308 "expected lb, ub, and step to have the same type");
310 auto createIndexCast = [&](Type out, Value in) -> Value {
311 Location loc = loop.getLoc();
312 if (loop.getUnsignedCmp())
313 return arith::IndexCastUIOp::create(rewriter, loc, out, in);
314 return arith::IndexCastOp::create(rewriter, loc, out, in);
321 Operation *anchor = loop;
326 Value newLb = createIndexCast(rewriter.
getIndexType(), lb);
327 Value newUb = createIndexCast(rewriter.
getIndexType(), ub);
328 Value newStep = createIndexCast(rewriter.
getIndexType(), step);
331 loop.setLowerBound(newLb);
332 loop.setUpperBound(newUb);
333 loop.setStep(newStep);
335 Value originalIV = loop.getInductionVar();
336 Value iv = loop.getBody()->insertArgument(
340 Value castIV = createIndexCast(originalType, iv);
344 loop.getBody()->eraseArgument(1);
352void SCFToAffinePass::runOnOperation() {
354 RewritePatternSet patterns(&ctx);
static AffineMap getMultiDimIdentityMap(unsigned numDims, MLIRContext *context)
Returns an AffineMap with 'numDims' identity result dim exprs.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
unsigned getNumSymbols() const
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
unsigned getNumResults() const
Operation * getTerminator()
Get the terminator operation of this block.
bool mightHaveTerminator()
Return "true" if this block might have a terminator.
AffineExpr getAffineSymbolExpr(unsigned position)
AffineExpr getAffineDimExpr(unsigned position)
AffineMap getConstantAffineMap(int64_t val)
Returns a single constant result affine map with 0 dimensions and 0 symbols.
MLIRContext * getContext() const
static DataLayout closest(Operation *op)
Returns the layout of the closest parent operation carrying layout info.
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.
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Region * getParentRegion()
Returns the region to which the instruction belongs.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
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.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
bool isValidDim(Value value)
Returns true if the given Value can be used as a dimension id in the region of the closest surroundin...
bool isTopLevelValue(Value value)
A utility function to check if a value is defined at the top level of an op with trait AffineScope or...
bool isValidSymbol(Value value)
Returns true if the given value can be used as a symbol in the region of the closest surrounding op t...
Region * getAffineScope(Operation *op)
Returns the closest region enclosing op that is held by an operation with trait AffineScope; nullptr ...
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
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 populateSCFToAffineConversionPatterns(RewritePatternSet &patterns)
Collect a set of patterns to convert SCF operations to Affine operations.
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...