MLIR
20.0.0git
|
#include "mlir/Dialect/Affine/LoopUtils.h"
#include "mlir/Analysis/SliceAnalysis.h"
#include "mlir/Dialect/Affine/Analysis/LoopAnalysis.h"
#include "mlir/Dialect/Affine/Analysis/Utils.h"
#include "mlir/Dialect/Affine/IR/AffineValueMap.h"
#include "mlir/Dialect/Affine/Utils.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/IR/IRMapping.h"
#include "mlir/IR/IntegerSet.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
Go to the source code of this file.
Classes | |
struct | StrideInfo |
Macros | |
#define | DEBUG_TYPE "loop-utils" |
Functions | |
static void | getCleanupLoopLowerBound (AffineForOp forOp, unsigned unrollFactor, AffineMap &cleanupLbMap, SmallVectorImpl< Value > &cleanupLbOperands) |
Computes the cleanup loop lower bound of the loop being unrolled with the specified unroll factor; this bound will also be upper bound of the main part of the unrolled loop. More... | |
static void | replaceIterArgsAndYieldResults (AffineForOp forOp) |
Helper to replace uses of loop carried values (iter_args) and loop yield values while promoting single iteration affine.for ops. More... | |
static AffineForOp | generateShiftedLoop (AffineMap lbMap, AffineMap ubMap, const std::vector< std::pair< uint64_t, ArrayRef< Operation * >>> &opGroupQueue, unsigned offset, AffineForOp srcForOp, OpBuilder b) |
Generates an affine.for op with the specified lower and upper bounds while generating the right IV remappings to realize shifts for operations in its body. More... | |
static LogicalResult | checkIfHyperRectangular (MutableArrayRef< AffineForOp > input) |
Checks whether a loop nest is hyper-rectangular or not. More... | |
template<typename t > | |
static LogicalResult | performPreTilingChecks (MutableArrayRef< AffineForOp > input, ArrayRef< t > tileSizes) |
Check if the input nest is supported for tiling and whether tiling would be legal or not. More... | |
static void | moveLoopBodyImpl (AffineForOp src, AffineForOp dest, Block::iterator loc) |
Move the loop body of AffineForOp 'src' from 'src' into the specified location in destination's body, ignoring the terminator. More... | |
static void | moveLoopBody (AffineForOp src, AffineForOp dest) |
Move the loop body of AffineForOp 'src' from 'src' to the start of dest body. More... | |
static void | constructTiledLoopNest (MutableArrayRef< AffineForOp > origLoops, AffineForOp rootAffineForOp, unsigned width, MutableArrayRef< AffineForOp > tiledLoops) |
Constructs tiled loop nest, without setting the loop bounds and move the body of the original loop nest to the tiled loop nest. More... | |
static void | setIntraTileBoundsParametric (OpBuilder &b, AffineForOp origLoop, AffineForOp newInterTileLoop, AffineForOp newIntraTileLoop, Value tileSize) |
Set lower and upper bounds of intra-tile loops for parametric tiling. More... | |
static void | setInterTileBoundsParametric (OpBuilder &b, AffineForOp origLoop, AffineForOp newLoop, Value tileSize) |
Set lower and upper bounds of inter-tile loops for parametric tiling. More... | |
static void | constructParametricallyTiledIndexSetHyperRect (MutableArrayRef< AffineForOp > origLoops, MutableArrayRef< AffineForOp > newLoops, ArrayRef< Value > tileSizes) |
Constructs and sets new loop bounds after tiling for the case of hyper-rectangular index sets, where the bounds of one dimension do not depend on other dimensions and tiling parameters are captured from SSA values. More... | |
static void | constructTiledIndexSetHyperRect (MutableArrayRef< AffineForOp > origLoops, MutableArrayRef< AffineForOp > newLoops, ArrayRef< unsigned > tileSizes) |
Constructs and sets new loop bounds after tiling for the case of hyper-rectangular index sets, where the bounds of one dimension do not depend on other dimensions. More... | |
static void | generateUnrolledLoop (Block *loopBodyBlock, Value forOpIV, uint64_t unrollFactor, function_ref< Value(unsigned, Value, OpBuilder)> ivRemapFn, function_ref< void(unsigned, Operation *, OpBuilder)> annotateFn, ValueRange iterArgs, ValueRange yieldedValues) |
Generates unrolled copies of AffineForOp 'loopBodyBlock', with associated 'forOpIV' by 'unrollFactor', calling 'ivRemapFn' to remap 'forOpIV' for each unrolled body. More... | |
static LogicalResult | generateCleanupLoopForUnroll (AffineForOp forOp, uint64_t unrollFactor) |
Helper to generate cleanup loop for unroll or unroll-and-jam when the trip count is not a multiple of unrollFactor . More... | |
static bool | areInnerBoundsInvariant (AffineForOp forOp) |
Check if all control operands of all loops are defined outside of forOp and return false if not. More... | |
static bool | checkLoopInterchangeDependences (const std::vector< SmallVector< DependenceComponent, 2 >> &depCompsVec, ArrayRef< AffineForOp > loops, ArrayRef< unsigned > loopPermMap) |
static void | augmentMapAndBounds (OpBuilder &b, Value iv, AffineMap *map, SmallVector< Value, 4 > *operands, int64_t offset=0) |
static SmallVector< AffineForOp, 8 > | stripmineSink (AffineForOp forOp, uint64_t factor, ArrayRef< AffineForOp > targets) |
template<typename SizeType > | |
static AffineForOp | stripmineSink (AffineForOp forOp, SizeType factor, AffineForOp target) |
static void | findHighestBlockForPlacement (const MemRefRegion ®ion, Block &block, Block::iterator &begin, Block::iterator &end, Block **copyPlacementBlock, Block::iterator *copyInPlacementStart, Block::iterator *copyOutPlacementStart) |
Given a memref region, determine the lowest depth at which transfers can be placed for it, and return the corresponding block, start and end positions in the block for placing incoming (read) and outgoing (write) copies respectively. More... | |
static void | getMultiLevelStrides (const MemRefRegion ®ion, ArrayRef< int64_t > bufferShape, SmallVectorImpl< StrideInfo > *strideInfos) |
Returns striding information for a copy/transfer of this region with potentially multiple striding levels from outermost to innermost. More... | |
static AffineForOp | generatePointWiseCopy (Location loc, Value memref, Value fastMemRef, ArrayRef< AffineMap > lbMaps, ArrayRef< Value > lbOperands, ArrayRef< AffineMap > ubMaps, ArrayRef< Value > ubOperands, ArrayRef< AffineExpr > fastBufOffsets, bool isCopyOut, OpBuilder b) |
Generates a point-wise copy from/to ‘memref’ to/from ‘fastMemRef’ and returns the outermost AffineForOp of the copy loop nest. More... | |
static InFlightDiagnostic LLVM_ATTRIBUTE_UNUSED | emitRemarkForBlock (Block &block) |
static LogicalResult | generateCopy (const MemRefRegion ®ion, Block *block, Block::iterator begin, Block::iterator end, Block *copyPlacementBlock, Block::iterator copyInPlacementStart, Block::iterator copyOutPlacementStart, const AffineCopyOptions ©Options, DenseMap< Value, Value > &fastBufferMap, DenseSet< Operation * > ©Nests, uint64_t *sizeInBytes, Block::iterator *nBegin, Block::iterator *nEnd) |
Creates a buffer in the faster memory space for the specified memref region; generates a copy from the lower memory space to this one, and replaces all loads/stores in the block range [‘begin’, ‘end’) of ‘block’ to load/store from that buffer. More... | |
static bool | getFullMemRefAsRegion (Operation *op, unsigned numParamLoopIVs, MemRefRegion *region) |
Construct the memref region to just include the entire memref. More... | |
static void | gatherLoopsInBlock (Block *block, unsigned currLoopDepth, std::vector< SmallVector< AffineForOp, 2 >> &depthToLoops) |
Gathers all AffineForOps in 'block' at 'currLoopDepth' in 'depthToLoops'. More... | |
static AffineIfOp | createSeparationCondition (MutableArrayRef< AffineForOp > loops, OpBuilder b) |
Creates an AffineIfOp that encodes the conditional to choose between the constant trip count version and an unknown trip count version of this nest of loops. More... | |
static LogicalResult | createFullTiles (MutableArrayRef< AffineForOp > inputNest, SmallVectorImpl< AffineForOp > &fullTileLoops, OpBuilder b) |
Create the full tile loop nest (along with its body). More... | |
#define DEBUG_TYPE "loop-utils" |
Definition at line 31 of file LoopUtils.cpp.
|
static |
Check if all control operands of all loops are defined outside of forOp
and return false if not.
Definition at line 1086 of file LoopUtils.cpp.
References mlir::WalkResult::advance().
Referenced by mlir::affine::loopUnrollJamByFactor().
|
static |
Definition at line 1513 of file LoopUtils.cpp.
References mlir::affine::canonicalizeMapAndOperands(), mlir::AffineMap::get(), mlir::Builder::getAffineDimExpr(), mlir::Builder::getContext(), mlir::AffineMap::getNumDims(), mlir::AffineMap::getNumSymbols(), and mlir::AffineMap::getResults().
Referenced by stripmineSink().
|
static |
Checks whether a loop nest is hyper-rectangular or not.
Definition at line 361 of file LoopUtils.cpp.
References mlir::affine::getIndexSet(), and mlir::presburger::IntegerRelation::isHyperRectangular().
Referenced by performPreTilingChecks().
|
static |
Definition at line 1317 of file LoopUtils.cpp.
Referenced by mlir::affine::isValidLoopInterchangePermutation(), and mlir::affine::sinkSequentialLoops().
|
static |
Constructs and sets new loop bounds after tiling for the case of hyper-rectangular index sets, where the bounds of one dimension do not depend on other dimensions and tiling parameters are captured from SSA values.
Bounds of each dimension can thus be treated independently, and deriving the new bounds is much simpler and faster than for the case of tiling arbitrary polyhedral shapes.
Definition at line 660 of file LoopUtils.cpp.
References setInterTileBoundsParametric(), and setIntraTileBoundsParametric().
Referenced by mlir::affine::tilePerfectlyNestedParametric().
|
static |
Constructs and sets new loop bounds after tiling for the case of hyper-rectangular index sets, where the bounds of one dimension do not depend on other dimensions.
Bounds of each dimension can thus be treated independently, and deriving the new bounds is much simpler and faster than for the case of tiling arbitrary polyhedral shapes.
Definition at line 688 of file LoopUtils.cpp.
References mlir::AffineMap::get(), mlir::Builder::getAffineDimExpr(), mlir::affine::getConstantTripCount(), mlir::Builder::getContext(), mlir::Builder::getDimIdentityMap(), mlir::affine::getLargestDivisorOfTripCount(), mlir::affine::AffineBound::getMap(), mlir::AffineMap::getNumDims(), mlir::affine::AffineBound::getNumOperands(), mlir::AffineMap::getNumResults(), mlir::AffineMap::getNumSymbols(), mlir::affine::AffineBound::getOperand(), mlir::AffineMap::getResults(), and mlir::Builder::getSingleDimShiftAffineMap().
Referenced by mlir::affine::tilePerfectlyNested().
|
static |
Constructs tiled loop nest, without setting the loop bounds and move the body of the original loop nest to the tiled loop nest.
Definition at line 423 of file LoopUtils.cpp.
References mlir::OpBuilder::create(), mlir::Operation::getBlock(), mlir::Block::getOperations(), and moveLoopBody().
Referenced by mlir::affine::tilePerfectlyNested(), and mlir::affine::tilePerfectlyNestedParametric().
|
static |
Create the full tile loop nest (along with its body).
Definition at line 2630 of file LoopUtils.cpp.
References mlir::OpBuilder::atBlockTerminator(), mlir::OpBuilder::clone(), mlir::affine::createCanonicalizedAffineForOp(), mlir::detail::enumerate(), mlir::affine::AffineValueMap::getAffineMap(), mlir::presburger::IntegerRelation::getConstantBoundOnDimSize(), mlir::Builder::getContext(), mlir::affine::getIndexSet(), mlir::affine::FlatAffineValueConstraints::getIneqAsAffineValueMap(), mlir::presburger::IntegerRelation::getNumDimAndSymbolVars(), mlir::affine::AffineValueMap::getOperands(), mlir::IRMapping::map(), and mlir::presburger::IntegerRelation::setDimSymbolSeparation().
Referenced by mlir::affine::separateFullTiles().
|
static |
Creates an AffineIfOp that encodes the conditional to choose between the constant trip count version and an unknown trip count version of this nest of loops.
This is used to separate partial and full tiles if loops
has the intra-tile loops. The affine.if op is inserted at the builder insertion point of b
.
Definition at line 2550 of file LoopUtils.cpp.
References mlir::presburger::IntegerRelation::atIneq(), mlir::affine::canonicalizeSetAndOperands(), mlir::OpBuilder::create(), mlir::FlatLinearConstraints::getAsIntegerSet(), mlir::presburger::IntegerRelation::getConstantBoundOnDimSize(), mlir::affine::getIndexSet(), mlir::presburger::IntegerRelation::getInequality(), mlir::presburger::IntegerRelation::getLowerAndUpperBoundIndices(), mlir::presburger::IntegerRelation::getNumCols(), mlir::presburger::IntegerRelation::getNumDimAndSymbolVars(), mlir::FlatLinearValueConstraints::getValues(), mlir::presburger::IntegerRelation::removeIndependentConstraints(), mlir::presburger::IntegerRelation::removeTrivialRedundancy(), mlir::presburger::IntegerRelation::removeVar(), and mlir::presburger::IntegerRelation::setDimSymbolSeparation().
Referenced by mlir::affine::separateFullTiles().
|
static |
Definition at line 1917 of file LoopUtils.cpp.
References mlir::Operation::emitRemark(), and mlir::Block::getParentOp().
Referenced by generateCopy().
|
static |
Given a memref region, determine the lowest depth at which transfers can be placed for it, and return the corresponding block, start and end positions in the block for placing incoming (read) and outgoing (write) copies respectively.
The lowest depth depends on whether the region being accessed is hoistable with respect to one or more immediately surrounding loops.
Definition at line 1765 of file LoopUtils.cpp.
References mlir::Block::begin(), mlir::affine::getAffineForIVs(), and mlir::affine::MemRefRegion::getConstraints().
Referenced by mlir::affine::affineDataCopyGenerate().
|
static |
Gathers all AffineForOps in 'block' at 'currLoopDepth' in 'depthToLoops'.
Definition at line 2500 of file LoopUtils.cpp.
Referenced by mlir::affine::gatherLoops().
|
static |
Helper to generate cleanup loop for unroll or unroll-and-jam when the trip count is not a multiple of unrollFactor
.
Definition at line 973 of file LoopUtils.cpp.
References mlir::OpBuilder::clone(), getCleanupLoopLowerBound(), and mlir::affine::promoteIfSingleIteration().
Referenced by mlir::affine::loopUnrollByFactor(), and mlir::affine::loopUnrollJamByFactor().
|
static |
Creates a buffer in the faster memory space for the specified memref region; generates a copy from the lower memory space to this one, and replaces all loads/stores in the block range [‘begin’, ‘end’) of ‘block’ to load/store from that buffer.
Returns failure if copies could not be generated due to yet unimplemented cases. copyInPlacementStart
and copyOutPlacementStart
in copyPlacementBlock specify the insertion points where the incoming copies and outgoing copies, respectively, should be inserted (the insertion happens right before the insertion point). Since begin
can itself be invalidated due to the memref rewriting done from this method, the output argument nBegin
is set to its replacement (set to begin
if no invalidation happens). Since outgoing copies could have been inserted at end
, the output argument nEnd
is set to the new end. sizeInBytes
is set to the size of the fast buffer allocated.
Definition at line 1934 of file LoopUtils.cpp.
References mlir::Block::begin(), mlir::OpBuilder::create(), mlir::detail::divideCeil(), emitRemarkForBlock(), mlir::affine::AffineCopyOptions::fastMemorySpace, mlir::affine::fullyComposeAffineMapAndOperands(), mlir::affine::AffineCopyOptions::generateDma, generatePointWiseCopy(), mlir::AffineMap::get(), mlir::get(), mlir::Builder::getAffineDimExpr(), mlir::affine::MemRefRegion::getConstantBoundingSizeAndShape(), mlir::affine::MemRefRegion::getConstraints(), mlir::Builder::getContext(), mlir::affine::getIntOrFloatMemRefSizeInBytes(), mlir::affine::MemRefRegion::getLowerAndUpperBound(), mlir::Builder::getMultiDimIdentityMap(), getMultiLevelStrides(), mlir::presburger::IntegerRelation::getNumCols(), mlir::presburger::IntegerRelation::getNumDimVars(), mlir::presburger::IntegerRelation::getNumSymbolVars(), mlir::presburger::IntegerRelation::getNumVars(), mlir::Op< ConcreteType, Traits >::getOperation(), mlir::Block::getParent(), mlir::Region::getParentOfType(), mlir::FlatLinearValueConstraints::getValues(), mlir::affine::MemRefRegion::isWrite(), mlir::affine::MemRefRegion::loc, mlir::affine::MemRefRegion::memref, mlir::affine::replaceAllMemRefUsesWith(), and mlir::affine::AffineCopyOptions::tagMemorySpace.
Referenced by mlir::affine::affineDataCopyGenerate(), and mlir::affine::generateCopyForMemRegion().
|
static |
Generates a point-wise copy from/to ‘memref’ to/from ‘fastMemRef’ and returns the outermost AffineForOp of the copy loop nest.
lbMaps
and ubMaps
along with lbOperands
and ubOperands
hold the lower and upper bound information for the copy loop nest. fastBufOffsets
contain the expressions to be subtracted out from the respective copy loop iterators in order to index the fast buffer. If ‘copyOut’ is true, generates a copy-out; otherwise a copy-in. Builder b
should be set to the point the copy nest is inserted. The copy-in nest is generated as follows as an example for a 2-d region: for x = ... for y = ... fast_buf[x - offset_x][y - offset_y] = memref[x][y]
Definition at line 1845 of file LoopUtils.cpp.
References mlir::OpBuilder::atBlockTerminator(), mlir::affine::canonicalizeMapAndOperands(), mlir::OpBuilder::create(), mlir::affine::createCanonicalizedAffineForOp(), mlir::affine::fullyComposeAffineMapAndOperands(), mlir::AffineMap::get(), mlir::Builder::getAffineDimExpr(), mlir::Builder::getContext(), mlir::AffineMap::getNumInputs(), mlir::Value::getType(), and mlir::simplifyAffineMap().
Referenced by generateCopy().
|
static |
Generates an affine.for op with the specified lower and upper bounds while generating the right IV remappings to realize shifts for operations in its body.
The operations that go into the loop body are specified in opGroupQueue starting from the specified offset, and in that order. The first element of the pair specifies the shift applied to that group of operations; the shift is multiplied by the loop step before being applied. Returns nullptr if the generated loop simplifies to a single iteration one.
Definition at line 174 of file LoopUtils.cpp.
References mlir::OpBuilder::atBlockTerminator(), mlir::OpBuilder::create(), mlir::AffineMap::getNumInputs(), mlir::IRMapping::map(), and mlir::affine::promoteIfSingleIteration().
Referenced by mlir::affine::affineForOpBodySkew().
|
static |
Generates unrolled copies of AffineForOp 'loopBodyBlock', with associated 'forOpIV' by 'unrollFactor', calling 'ivRemapFn' to remap 'forOpIV' for each unrolled body.
If specified, annotates the Ops in each unrolled iteration using annotateFn.
Definition at line 913 of file LoopUtils.cpp.
References mlir::OpBuilder::atBlockTerminator(), mlir::Block::begin(), mlir::Operation::clone(), mlir::Block::end(), mlir::Operation::getBlock(), mlir::Block::getTerminator(), mlir::IRMapping::lookup(), mlir::IRMapping::map(), mlir::Operation::setOperands(), and mlir::Value::use_empty().
Referenced by mlir::affine::loopUnrollByFactor().
|
static |
Computes the cleanup loop lower bound of the loop being unrolled with the specified unroll factor; this bound will also be upper bound of the main part of the unrolled loop.
Computes the bound as an AffineMap with its operands or a null map when the trip count can't be expressed as an affine expression.
Definition at line 44 of file LoopUtils.cpp.
References mlir::affine::canonicalizeMapAndOperands(), mlir::OpBuilder::create(), mlir::affine::fullyComposeAffineMapAndOperands(), mlir::AffineMap::get(), mlir::Builder::getAffineDimExpr(), mlir::Builder::getContext(), mlir::AffineMap::getNumDims(), mlir::AffineMap::getNumResults(), mlir::AffineMap::getNumSymbols(), mlir::AffineMap::getResult(), mlir::affine::getTripCountMapAndOperands(), and mlir::simplifyAffineMap().
Referenced by generateCleanupLoopForUnroll().
|
static |
Construct the memref region to just include the entire memref.
Returns false dynamic shaped memref's for now. numParamLoopIVs
is the number of enclosing loop IVs of op
(starting from the outermost) that the region is parametric on.
Definition at line 2228 of file LoopUtils.cpp.
References mlir::affine::extractForInductionVars(), mlir::affine::getAffineForIVs(), mlir::affine::MemRefRegion::getConstraints(), mlir::Value::getType(), mlir::affine::MemRefRegion::memref, and mlir::affine::MemRefRegion::setWrite().
Referenced by mlir::affine::affineDataCopyGenerate().
|
static |
Returns striding information for a copy/transfer of this region with potentially multiple striding levels from outermost to innermost.
For an n-dimensional region, there can be at most n-1 levels of striding successively nested.
Definition at line 1809 of file LoopUtils.cpp.
References mlir::Value::getType(), and mlir::affine::MemRefRegion::memref.
Referenced by generateCopy().
|
static |
Move the loop body of AffineForOp 'src' from 'src' to the start of dest body.
Definition at line 417 of file LoopUtils.cpp.
References moveLoopBodyImpl().
Referenced by constructTiledLoopNest().
|
static |
Move the loop body of AffineForOp 'src' from 'src' into the specified location in destination's body, ignoring the terminator.
Definition at line 408 of file LoopUtils.cpp.
Referenced by moveLoopBody().
|
static |
Check if the input nest is supported for tiling and whether tiling would be legal or not.
Definition at line 382 of file LoopUtils.cpp.
References checkIfHyperRectangular(), and mlir::affine::isPerfectlyNested().
Referenced by mlir::affine::tilePerfectlyNested(), and mlir::affine::tilePerfectlyNestedParametric().
|
static |
Helper to replace uses of loop carried values (iter_args) and loop yield values while promoting single iteration affine.for ops.
Definition at line 102 of file LoopUtils.cpp.
Referenced by mlir::affine::promoteIfSingleIteration().
|
static |
Set lower and upper bounds of inter-tile loops for parametric tiling.
Definition at line 559 of file LoopUtils.cpp.
References mlir::AffineMap::get(), mlir::Builder::getAffineConstantExpr(), mlir::Builder::getAffineSymbolExpr(), mlir::Builder::getContext(), mlir::affine::AffineBound::getMap(), mlir::AffineMap::getNumDims(), mlir::affine::AffineBound::getNumOperands(), mlir::AffineMap::getNumResults(), mlir::AffineMap::getNumSymbols(), mlir::affine::AffineBound::getOperand(), and mlir::AffineMap::getResults().
Referenced by constructParametricallyTiledIndexSetHyperRect().
|
static |
Set lower and upper bounds of intra-tile loops for parametric tiling.
Definition at line 464 of file LoopUtils.cpp.
References mlir::AffineMap::get(), mlir::Builder::getAffineConstantExpr(), mlir::Builder::getAffineDimExpr(), mlir::Builder::getAffineSymbolExpr(), mlir::Builder::getContext(), mlir::affine::AffineBound::getMap(), mlir::AffineMap::getNumDims(), mlir::affine::AffineBound::getNumOperands(), mlir::AffineMap::getNumResults(), mlir::AffineMap::getNumSymbols(), mlir::affine::AffineBound::getOperand(), and mlir::AffineMap::getResults().
Referenced by constructParametricallyTiledIndexSetHyperRect().
|
static |
Definition at line 1576 of file LoopUtils.cpp.
References stripmineSink().
|
static |
Definition at line 1533 of file LoopUtils.cpp.
References mlir::OpBuilder::atBlockTerminator(), augmentMapAndBounds(), mlir::OpBuilder::create(), and mlir::replaceAllUsesInRegionWith().
Referenced by stripmineSink(), and mlir::affine::tile().