MLIR 24.0.0git
Utils.h
Go to the documentation of this file.
1//===- Utils.h - SCF dialect utilities --------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This header file defines prototypes for various SCF utilities.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_DIALECT_SCF_UTILS_UTILS_H_
14#define MLIR_DIALECT_SCF_UTILS_UTILS_H_
15
18#include "mlir/Support/LLVM.h"
19#include "llvm/ADT/STLExtras.h"
20#include <optional>
21#include <tuple>
22#include <utility>
23
24namespace mlir {
25class Location;
26class Operation;
27class OpBuilder;
28class Region;
29class RewriterBase;
30class ValueRange;
31class Value;
32
33namespace func {
34class CallOp;
35class FuncOp;
36} // namespace func
37
38/// Update a perfectly nested loop nest to yield new values from the innermost
39/// loop and propagating it up through the loop nest. This function
40/// - Expects `loopNest` to be a perfectly nested loop with outer most loop
41/// first and innermost loop last.
42/// - `newIterOperands` are the initialization values to be used for the
43/// outermost loop
44/// - `newYielValueFn` is the callback that generates the new values to be
45/// yielded from within the innermost loop.
46/// - The original loops are not erased, but are left in a "no-op" state where
47/// the body of the loop just yields the basic block arguments that correspond
48/// to the initialization values of a loop. The original loops are dead after
49/// this method.
50/// - If `replaceIterOperandsUsesInLoop` is true, all uses of the
51/// `newIterOperands` within the generated new loop are replaced with the
52/// corresponding `BlockArgument` in the loop body.
54 RewriterBase &rewriter, MutableArrayRef<scf::ForOp> loopNest,
55 ValueRange newIterOperands, const NewYieldValuesFn &newYieldValuesFn,
56 bool replaceIterOperandsUsesInLoop = true);
57
58/// Outline a region with a single block into a new FuncOp.
59/// Assumes the FuncOp result types is the type of the yielded operands of the
60/// single block. This constraint makes it easy to determine the result.
61/// This method also clones the `arith::ConstantIndexOp` at the start of
62/// `outlinedFuncBody` to alloc simple canonicalizations.
63/// Creates a new FuncOp and thus cannot be used in a FuncOp pass.
64/// The client is responsible for providing a unique `funcName` that will not
65/// collide with another FuncOp name. If `callOp` is provided, it will be set
66/// to point to the operation that calls the outlined function.
67// TODO: support more than single-block regions.
68// TODO: more flexible constant handling.
69FailureOr<func::FuncOp>
71 StringRef funcName, func::CallOp *callOp = nullptr);
72
73/// Outline the then and/or else regions of `ifOp` as follows:
74/// - if `thenFn` is not null, `thenFnName` must be specified and the `then`
75/// region is inlined into a new FuncOp that is captured by the pointer.
76/// - if `elseFn` is not null, `elseFnName` must be specified and the `else`
77/// region is inlined into a new FuncOp that is captured by the pointer.
78/// Creates new FuncOps and thus cannot be used in a FuncOp pass.
79/// The client is responsible for providing a unique `thenFnName`/`elseFnName`
80/// that will not collide with another FuncOp name.
81LogicalResult outlineIfOp(RewriterBase &b, scf::IfOp ifOp, func::FuncOp *thenFn,
82 StringRef thenFnName, func::FuncOp *elseFn,
83 StringRef elseFnName);
84
85/// Get a list of innermost parallel loops contained in `rootOp`. Innermost
86/// parallel loops are those that do not contain further parallel loops
87/// themselves.
90
91/// Replace a perfect nest of "for" loops with a single linearized loop. Assumes
92/// `loops` contains a list of perfectly nested loops with bounds and steps
93/// independent of any loop induction variable involved in the nest.
95LogicalResult coalesceLoops(RewriterBase &rewriter,
97
98/// Walk an affine.for to find a band to coalesce.
99LogicalResult coalescePerfectlyNestedSCFForLoops(scf::ForOp op);
100
101/// Take the ParallelLoop and for each set of dimension indices, combine them
102/// into a single dimension. combinedDimensions must contain each index into
103/// loops exactly once.
104void collapseParallelLoops(RewriterBase &rewriter, scf::ParallelOp loops,
105 ArrayRef<std::vector<unsigned>> combinedDimensions);
106
108 std::optional<scf::ForOp> mainLoopOp = std::nullopt;
109 std::optional<scf::ForOp> epilogueLoopOp = std::nullopt;
110};
111
112/// Splits `forOp` into two consecutive loops at `splitPoint`:
113/// first: [lowerBound, splitPoint)
114/// second: [splitPoint, upperBound)
115///
116/// Uses `rewriter` to replace `forOp` and returns the two new loops. Iter-args
117/// are chained from the first loop to the second.
118///
119/// The caller must ensure that `splitPoint` has the same type as the loop
120/// bounds, that the step is positive, and that
121/// `lowerBound <= splitPoint < upperBound`. The split point must also lie on
122/// the loop's iteration lattice: `splitPoint == lowerBound + k * step` for
123/// some non-negative integer `k`. Statically known violations cause failure;
124/// dynamic values are assumed to satisfy these preconditions.
125FailureOr<std::pair<scf::ForOp, scf::ForOp>>
126splitForOpAtPoint(RewriterBase &rewriter, scf::ForOp forOp, Value splitPoint);
127
128/// Unrolls this for operation by the specified unroll factor. Returns the
129/// unrolled main loop and the epilogue loop, if the loop is unrolled. Otherwise
130/// returns failure if the loop cannot be unrolled either due to restrictions or
131/// due to invalid unroll factors. Requires positive loop bounds and step. If
132/// specified, annotates the Ops in each unrolled iteration by applying
133/// `annotateFn`.
134/// If `shouldPromoteIfSingleIteration` is true, the function will promote the
135/// loop body up if this has turned into a single iteration loop.
136FailureOr<UnrolledLoopInfo> loopUnrollByFactor(
137 scf::ForOp forOp, uint64_t unrollFactor,
138 function_ref<void(unsigned, Operation *, OpBuilder)> annotateFn = nullptr,
139 bool shouldPromoteIfSingleIteration = true);
140
141/// Unrolls this loop completely.
142LogicalResult loopUnrollFull(scf::ForOp forOp);
143
144/// Unrolls and jams this `scf.for` operation by the specified unroll factor.
145/// Returns failure if the loop cannot be unrolled either due to restrictions or
146/// due to invalid unroll factors. In case of unroll factor of 1, the function
147/// bails out without doing anything (returns success). Currently, only constant
148/// trip count that are divided by the unroll factor is supported. Currently,
149/// for operations with results are not supported.
150LogicalResult loopUnrollJamByFactor(scf::ForOp forOp, uint64_t unrollFactor);
151
152/// Materialize bounds and step of a zero-based and unit-step loop derived by
153/// normalizing the specified bounds and step.
156 OpFoldResult step);
157
158/// Get back the original induction variable values after loop normalization.
160 Value normalizedIv, OpFoldResult origLb,
161 OpFoldResult origStep);
162
163/// Tile a nest of standard for loops rooted at `rootForOp` by finding such
164/// parametric tile sizes that the outer loops have a fixed number of iterations
165/// as defined in `sizes`.
167using TileLoops = std::pair<Loops, Loops>;
168TileLoops extractFixedOuterLoops(scf::ForOp rootFOrOp, ArrayRef<int64_t> sizes);
169
170/// Performs tiling fo imperfectly nested loops (with interchange) by
171/// strip-mining the `forOps` by `sizes` and sinking them, in their order of
172/// occurrence in `forOps`, under each of the `targets`.
173/// Returns the new AffineForOps, one per each of (`forOps`, `targets`) pair,
174/// nested immediately under each of `targets`.
176 ArrayRef<scf::ForOp> targets);
177
178/// Performs tiling (with interchange) by strip-mining the `forOps` by `sizes`
179/// and sinking them, in their order of occurrence in `forOps`, under `target`.
180/// Returns the new AffineForOps, one per `forOps`, nested immediately under
181/// `target`.
183 scf::ForOp target);
184
185/// Tile a nest of scf::ForOp loops rooted at `rootForOp` with the given
186/// (parametric) sizes. Sizes are expected to be strictly positive values at
187/// runtime. If more sizes than loops are provided, discard the trailing values
188/// in sizes. Assumes the loop nest is permutable.
189/// Returns the newly created intra-tile loops.
190Loops tilePerfectlyNested(scf::ForOp rootForOp, ArrayRef<Value> sizes);
191
192/// Get perfectly nested sequence of loops starting at root of loop nest
193/// (the first op being another AffineFor, and the second op - a terminator).
194/// A loop is perfectly nested iff: the first op in the loop's body is another
195/// AffineForOp, and the second op is a terminator).
197 scf::ForOp root);
198
199/// Given two scf.forall loops, `target` and `source`, fuses `target` into
200/// `source`. Assumes that the given loops are siblings and are independent of
201/// each other.
202///
203/// This function does not perform any legality checks and simply fuses the
204/// loops. The caller is responsible for ensuring that the loops are legal to
205/// fuse.
206scf::ForallOp fuseIndependentSiblingForallLoops(scf::ForallOp target,
207 scf::ForallOp source,
208 RewriterBase &rewriter);
209
210/// Given two scf.for loops, `target` and `source`, fuses `target` into
211/// `source`. Assumes that the given loops are siblings and are independent of
212/// each other.
213///
214/// This function does not perform any legality checks and simply fuses the
215/// loops. The caller is responsible for ensuring that the loops are legal to
216/// fuse.
217scf::ForOp fuseIndependentSiblingForLoops(scf::ForOp target, scf::ForOp source,
218 RewriterBase &rewriter);
219
220/// Normalize an `scf.forall` operation. Returns `failure()`if normalization
221/// fails.
222// On `success()` returns the
223/// newly created operation with all uses of the original operation replaced
224/// with results of the new operation.
225FailureOr<scf::ForallOp> normalizeForallOp(RewriterBase &rewriter,
226 scf::ForallOp forallOp);
227
228/// Check if the provided loops are perfectly nested for-loops. Perfect nesting
229/// means:
230/// 1. All loops are scf.for operations
231/// 2. Each outer loop's region iter args match the inner loop's init args
232/// 3. Each outer loop's yields match the inner loop's results
233/// 4. Each region iter arg and result has exactly one use
235
236/// Generate unrolled copies of an scf loop's 'loopBodyBlock', with 'iterArgs'
237/// and 'yieldedValues' as the block arguments and yielded values of the loop.
238/// The content of the loop body is replicated 'unrollFactor' times, calling
239/// 'ivRemapFn' to remap 'iv' for each unrolled body. If specified, annotates
240/// the Ops in each unrolled iteration using annotateFn. If provided,
241/// 'clonedToSrcOpsMap' is populated with the mappings from the cloned ops to
242/// the original op.
244 Block *loopBodyBlock, Value iv, uint64_t unrollFactor,
245 function_ref<Value(unsigned, Value, OpBuilder)> ivRemapFn,
246 function_ref<void(unsigned, Operation *, OpBuilder)> annotateFn,
247 ValueRange iterArgs, ValueRange yieldedValues,
248 IRMapping *clonedToSrcOpsMap = nullptr);
249
250/// Unroll this scf::Parallel loop by the specified unroll factors. Returns the
251/// unrolled loop if the unroll succeded; otherwise returns failure if the loop
252/// cannot be unrolled either due to restrictions or to invalid unroll factors.
253/// Requires positive loop bounds and step. If specified, annotates the Ops in
254/// each unrolled iteration by applying `annotateFn`.
255/// If provided, 'clonedToSrcOpsMap' is populated with the mappings from the
256/// cloned ops to the original op.
257FailureOr<scf::ParallelOp> parallelLoopUnrollByFactors(
258 scf::ParallelOp op, ArrayRef<uint64_t> unrollFactors,
259 RewriterBase &rewriter,
260 function_ref<void(unsigned, Operation *, OpBuilder)> annotateFn = nullptr,
261 IRMapping *clonedToSrcOpsMap = nullptr);
262
263/// Get constant loop bounds and steps for each of the induction variables of
264/// the given loop operation, if all the loop's ranges are constant. Each entry
265/// in the returned vector is a tuple (lowerBound, upperBound, step).
267getConstLoopBounds(mlir::LoopLikeOpInterface loopOp);
268
269/// Get constant trip counts for each of the induction variables of the given
270/// loop operation. If any of the loop's trip counts is not constant, return an
271/// empty vector.
273getConstLoopTripCounts(mlir::LoopLikeOpInterface loopOp);
274
275} // namespace mlir
276
277#endif // MLIR_DIALECT_SCF_UTILS_UTILS_H_
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
Block represents an ordered list of Operations.
Definition Block.h:33
This is a utility class for mapping one set of IR entities to another.
Definition IRMapping.h:26
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class helps build Operations.
Definition Builders.h:210
This class represents a single result from folding an operation.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Include the generated interface declarations.
void getPerfectlyNestedLoops(SmallVectorImpl< scf::ForOp > &nestedLoops, scf::ForOp root)
Get perfectly nested sequence of loops starting at root of loop nest (the first op being another Affi...
Definition Utils.cpp:1413
bool isPerfectlyNestedForLoops(MutableArrayRef< LoopLikeOpInterface > loops)
Check if the provided loops are perfectly nested for-loops.
Definition Utils.cpp:1620
FailureOr< UnrolledLoopInfo > loopUnrollByFactor(scf::ForOp forOp, uint64_t unrollFactor, function_ref< void(unsigned, Operation *, OpBuilder)> annotateFn=nullptr, bool shouldPromoteIfSingleIteration=true)
Unrolls this for operation by the specified unroll factor.
Definition Utils.cpp:419
LogicalResult outlineIfOp(RewriterBase &b, scf::IfOp ifOp, func::FuncOp *thenFn, StringRef thenFnName, func::FuncOp *elseFn, StringRef elseFnName)
Outline the then and/or else regions of ifOp as follows:
Definition Utils.cpp:218
SmallVector< scf::ForOp > replaceLoopNestWithNewYields(RewriterBase &rewriter, MutableArrayRef< scf::ForOp > loopNest, ValueRange newIterOperands, const NewYieldValuesFn &newYieldValuesFn, bool replaceIterOperandsUsesInLoop=true)
Update a perfectly nested loop nest to yield new values from the innermost loop and propagating it up...
Definition Utils.cpp:36
std::function< SmallVector< Value >( OpBuilder &b, Location loc, ArrayRef< BlockArgument > newBbArgs)> NewYieldValuesFn
A function that returns the additional yielded values during replaceWithAdditionalYields.
LogicalResult coalescePerfectlyNestedSCFForLoops(scf::ForOp op)
Walk an affine.for to find a band to coalesce.
Definition Utils.cpp:1095
void generateUnrolledLoop(Block *loopBodyBlock, Value iv, uint64_t unrollFactor, function_ref< Value(unsigned, Value, OpBuilder)> ivRemapFn, function_ref< void(unsigned, Operation *, OpBuilder)> annotateFn, ValueRange iterArgs, ValueRange yieldedValues, IRMapping *clonedToSrcOpsMap=nullptr)
Generate unrolled copies of an scf loop's 'loopBodyBlock', with 'iterArgs' and 'yieldedValues' as the...
Definition Utils.cpp:295
LogicalResult loopUnrollFull(scf::ForOp forOp)
Unrolls this loop completely.
Definition Utils.cpp:576
llvm::SmallVector< llvm::APInt > getConstLoopTripCounts(mlir::LoopLikeOpInterface loopOp)
Get constant trip counts for each of the induction variables of the given loop operation.
Definition Utils.cpp:1678
std::pair< Loops, Loops > TileLoops
Definition Utils.h:167
llvm::SmallVector< std::tuple< int64_t, int64_t, int64_t > > getConstLoopBounds(mlir::LoopLikeOpInterface loopOp)
Get constant loop bounds and steps for each of the induction variables of the given loop operation,...
Definition Utils.cpp:1659
void collapseParallelLoops(RewriterBase &rewriter, scf::ParallelOp loops, ArrayRef< std::vector< unsigned > > combinedDimensions)
Take the ParallelLoop and for each set of dimension indices, combine them into a single dimension.
Definition Utils.cpp:1170
FailureOr< std::pair< scf::ForOp, scf::ForOp > > splitForOpAtPoint(RewriterBase &rewriter, scf::ForOp forOp, Value splitPoint)
Splits forOp into two consecutive loops at splitPoint: first: [lowerBound, splitPoint) second: [split...
Definition Utils.cpp:368
Loops tilePerfectlyNested(scf::ForOp rootForOp, ArrayRef< Value > sizes)
Tile a nest of scf::ForOp loops rooted at rootForOp with the given (parametric) sizes.
Definition Utils.cpp:1401
LogicalResult loopUnrollJamByFactor(scf::ForOp forOp, uint64_t unrollFactor)
Unrolls and jams this scf.for operation by the specified unroll factor.
Definition Utils.cpp:604
bool getInnermostParallelLoops(Operation *rootOp, SmallVectorImpl< scf::ParallelOp > &result)
Get a list of innermost parallel loops contained in rootOp.
Definition Utils.cpp:241
FailureOr< scf::ParallelOp > parallelLoopUnrollByFactors(scf::ParallelOp op, ArrayRef< uint64_t > unrollFactors, RewriterBase &rewriter, function_ref< void(unsigned, Operation *, OpBuilder)> annotateFn=nullptr, IRMapping *clonedToSrcOpsMap=nullptr)
Unroll this scf::Parallel loop by the specified unroll factors.
Definition Utils.cpp:1696
SmallVector< Loops, 8 > tile(ArrayRef< scf::ForOp > forOps, ArrayRef< Value > sizes, ArrayRef< scf::ForOp > targets)
Performs tiling fo imperfectly nested loops (with interchange) by strip-mining the forOps by sizes an...
Definition Utils.cpp:1380
FailureOr< func::FuncOp > outlineSingleBlockRegion(RewriterBase &rewriter, Location loc, Region &region, StringRef funcName, func::CallOp *callOp=nullptr)
Outline a region with a single block into a new FuncOp.
Definition Utils.cpp:115
void denormalizeInductionVariable(RewriterBase &rewriter, Location loc, Value normalizedIv, OpFoldResult origLb, OpFoldResult origStep)
Get back the original induction variable values after loop normalization.
Definition Utils.cpp:858
scf::ForallOp fuseIndependentSiblingForallLoops(scf::ForallOp target, scf::ForallOp source, RewriterBase &rewriter)
Given two scf.forall loops, target and source, fuses target into source.
Definition Utils.cpp:1469
LogicalResult coalesceLoops(MutableArrayRef< scf::ForOp > loops)
Replace a perfect nest of "for" loops with a single linearized loop.
Definition Utils.cpp:1087
scf::ForOp fuseIndependentSiblingForLoops(scf::ForOp target, scf::ForOp source, RewriterBase &rewriter)
Given two scf.for loops, target and source, fuses target into source.
Definition Utils.cpp:1522
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147
TileLoops extractFixedOuterLoops(scf::ForOp rootFOrOp, ArrayRef< int64_t > sizes)
Definition Utils.cpp:1418
Range emitNormalizedLoopBounds(RewriterBase &rewriter, Location loc, OpFoldResult lb, OpFoldResult ub, OpFoldResult step)
Materialize bounds and step of a zero-based and unit-step loop derived by normalizing the specified b...
Definition Utils.cpp:787
SmallVector< scf::ForOp, 8 > Loops
Tile a nest of standard for loops rooted at rootForOp by finding such parametric tile sizes that the ...
Definition Utils.h:166
FailureOr< scf::ForallOp > normalizeForallOp(RewriterBase &rewriter, scf::ForallOp forallOp)
Normalize an scf.forall operation.
Definition Utils.cpp:1575
Represents a range (offset, size, and stride) where each element of the triple may be dynamic or stat...
std::optional< scf::ForOp > epilogueLoopOp
Definition Utils.h:109
std::optional< scf::ForOp > mainLoopOp
Definition Utils.h:108