MLIR  22.0.0git
Utils.h
Go to the documentation of this file.
1 //===- Utils.h - Utilities to support the Linalg dialect --------*- 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 #ifndef MLIR_DIALECT_LINALG_UTILS_UTILS_H
10 #define MLIR_DIALECT_LINALG_UTILS_UTILS_H
11 
15 #include "llvm/ADT/StringSet.h"
16 #include <optional>
17 
18 namespace mlir {
19 class AffineExpr;
20 class AffineMap;
21 class PatternRewriter;
22 
23 namespace affine {
24 class AffineForOp;
25 } // namespace affine
26 
27 namespace tensor {
28 class ExtractSliceOp;
29 } // namespace tensor
30 
31 namespace linalg {
32 
33 //===----------------------------------------------------------------------===//
34 // Utilities for inferring various semantics properties of Linalg ops.
35 //===----------------------------------------------------------------------===//
36 /// Shell function to compute the Destination Permutation of PackOp
37 /// This function uses the helper function `computePackUnPackPerm` to get
38 /// the permutation vector. Only major difference between UnPack and Pack is
39 /// that packOp uses destination rank whereas unpack Uses source rank.
41 
42 /// Shell function to compute the Source Permutation of unPackOp.
43 /// This function, like the getPackInverseDestPerm uses the helper function
44 /// computePackUnPackPerm` to get the permutation vector.
45 /// Only major difference between UnPack and Pack is that packOp uses
46 /// destination rank whereas unpack Uses source rank.
47 SmallVector<int64_t> getUnPackInverseSrcPerm(linalg::UnPackOp unpackOp);
48 
49 /// Shell function to compute the Source rank permutation for unpackOp
50 /// Unpack requires some packing metadata data information, so created
51 /// another function where this value is passed by reference.
53  PackingMetadata &metadata);
54 
55 //===----------------------------------------------------------------------===//
56 // General utilities
57 //===----------------------------------------------------------------------===//
58 
59 /// Check if all indexing maps are projected permutations.
60 bool allIndexingsAreProjectedPermutation(LinalgOp op);
61 
62 /// Detect whether `r` has only ConstantOp, ElementwiseMappable and YieldOp.
64 
65 /// Check if a LinalgOp is an element-wise operation.
66 bool isElementwise(LinalgOp op);
67 
68 /// Check if iterator type has "parallel" semantics.
69 bool isParallelIterator(utils::IteratorType iteratorType);
70 
71 /// Check if iterator type has "reduction" semantics.
72 bool isReductionIterator(utils::IteratorType iteratorType);
73 
74 /// Create a tensor::PadOp that pads `source` to the shape of `type` whose sizes
75 /// are assumed to be greater than the dynamic `source` size. If `typeDynDims`
76 /// is specified, then it must contain the sizes of all the dynamic dimensions
77 /// in order of appearance in `type`, otherwise the function will pad those
78 /// values to `0`. The padding introduces trailing `pad` values until the target
79 /// size is met. If `source` is defined by one or more LinalgOps that have been
80 /// padded with the same value and sizes, return their padded result instead of
81 /// creating a tensor::PadOp.
82 ///
83 /// Example:
84 /// ```
85 /// %0 = tensor.extract_slice %arg0 [%iv0, %iv1] [%sz0, %sz1]
86 /// %1 = tensor.pad %0 low[0, 0] high[...] { tensor.yield %cst }
87 /// %2 = linalg.matmul ins(...) outs(%1)
88 /// %3 = tensor.extract_slice %2 [0, 0] [%sz0, %sz1]
89 /// ```
90 /// makeComposedPadHighOp(source=%3, pad=%cst) returns %2
91 /// makeComposedPadHighOp(source=%3, pad=%other_cst) returns %4
92 /// ```
93 /// %4 = tensor.pad %3 low[0, 0] high[...] { tensor.yield %other_cst }
94 /// ```
95 Value makeComposedPadHighOp(OpBuilder &b, Location loc, RankedTensorType type,
96  Value source, Value padding, bool nofold,
97  ValueRange typeDynDims = {});
98 
99 /// Returns GenericOp that copies an n-D memref. Unlike the current
100 /// implementation of memref::CopyOp, this op can further tile, lower to loops
101 /// or vectorize.
102 GenericOp makeMemRefCopyOp(OpBuilder &b, Location loc, Value from, Value to);
103 
104 /// Get the reassociation maps to fold the result of a extract_slice (or
105 /// source of a insert_slice) operation with given offsets, and sizes to its
106 /// rank-reduced version. This is only done for the cases where the size is 1
107 /// and offset is 0. Strictly speaking the offset 0 is not required in
108 /// general, but non-zero offsets are not handled by SPIR-V backend at this
109 /// point (and potentially cannot be handled).
110 std::optional<SmallVector<ReassociationIndices>>
112 
113 //===----------------------------------------------------------------------===//
114 // Fusion / Tiling utilities
115 //===----------------------------------------------------------------------===//
116 
117 /// The type of loops to be generated during tiling.
119  Loops = 0,
120  AffineLoops = 1,
121  ParallelLoops = 2
122 };
123 
124 /// Computes tile offsets, given a list of loop `ivs` and `tileSizes`. In case
125 /// a tile size is zero (i.e., no tiling), the corresponding offset is also
126 /// zero.
129  ArrayRef<OpFoldResult> tileSizes);
130 
131 /// Computes tile sizes, given a list of `tileSizes` and dimension
132 /// sizes (`sizeBounds`). In case a tile size is zero (i.e., no tiling), the
133 /// corresponding result size is the corresponding value from `sizeBounds`.
134 /// Note: The returned tile sizes are closed intervals.
136  ArrayRef<OpFoldResult> tileSizes,
137  ArrayRef<OpFoldResult> sizeBounds);
138 
139 /// Returns the list of tensor output types produced when the given structured
140 /// operation `op` is applied to the given `operands`. Note that `operands`
141 /// are not necessarily the actual operands of `op`.
142 SmallVector<Type> getTensorOutputTypes(LinalgOp op, ValueRange operands);
143 
144 /// Creates `insert_slice` ops that insert `results` back into larger tensors
145 /// they were originally extracted from with `extract_slice` before being
146 /// passed as `operands` to the given structured operation `op` or its clone.
147 /// Note that `operands` are not necessarily the actual operands of `op`, the
148 /// operation serves only as metadata container for operand types and
149 /// positions.
151  LinalgOp op, ValueRange operands,
152  ValueRange results);
153 
154 /// A struct containg offsets-sizes-strides arguments of the tiled shape.
159 };
160 
161 /// Computes SliceParameters for a single `valueToTile` assuming that its user
162 /// is being tiled with the given loop bounds `lbs` and `ubs` and the tile
163 /// sizes `tileSizes`.
164 ///
165 /// `omitPartialTileCheck` controls whether to omit the partial/boundary tile
166 /// condition check in cases where we statically know that it is unnecessary.
168 computeSliceParameters(OpBuilder &builder, Location loc, Value valueToTile,
169  ArrayRef<OpFoldResult> tileSizes, AffineMap map,
171  ArrayRef<OpFoldResult> subShapeSizes,
172  bool omitPartialTileCheck);
173 
174 /// Computes SliceParamaters for all `valuesToTile` of the given `linalgOp`,
175 /// assuming `linalgOp` is being fused into a loop nest. Calls
176 /// `computeSliceParameters` for every individual value.
177 ///
178 /// Note that a constant zero in `tileSizes` means no tiling at that implicit
179 /// loop. The number of non-zero values in `tileSizes` should be equal to the
180 /// number of values in `ivs`.
181 ///
182 /// Some of the `valuesToTile` won't be affected by tiling. For these values,
183 /// std::nullopt will be returned.
185 computeAllSliceParameters(OpBuilder &builder, Location loc, LinalgOp linalgOp,
186  ValueRange valuesToTile, ArrayRef<OpFoldResult> ivs,
187  ArrayRef<OpFoldResult> tileSizes,
188  ArrayRef<OpFoldResult> sizeBounds,
189  bool omitPartialTileCheck);
190 
191 /// Creates an extract_slice/subview op for a single `valueToTile` with
192 /// `builder`. This new operation extracts a tile of `valueToTile`, starting
193 /// at offsets `lbs` and with sizes `subShapeSizes`. `omitPartialTileCheck`
194 /// controls whether to omit the partial/boundary tile condition check in
195 /// cases where we statically know that it is unnecessary.
196 Operation *makeTiledShape(OpBuilder &builder, Location loc, Value valueToTile,
197  ArrayRef<OpFoldResult> tileSizes, AffineMap map,
200  ArrayRef<OpFoldResult> subShapeSizes,
201  bool omitPartialTileCheck);
202 
203 /// Creates extract_slice/subview ops for all `valuesToTile` of the given
204 /// `linalgOp` with `builder`, assuming `linalgOp` is being fused into a loop
205 /// nest for tiling with the given induction variables `ivs` and tile sizes
206 /// `tileSizes`. `sizeBounds` are the iteration space bounds for *all* the
207 /// implicit loops in `linalgOp`. `omitPartialTileCheck` controls whether to
208 /// omit the partial/boundary tile condition check in cases where we
209 /// statically know that it is unnecessary.
210 ///
211 /// Note that a constant zero in `tileSizes` means no tiling at that implicit
212 /// loop. The number of non-zero values in `tileSizes` should be equal to the
213 /// number of values in `ivs`.
215  LinalgOp linalgOp, ValueRange valuesToTile,
217  ArrayRef<OpFoldResult> tileSizes,
218  ArrayRef<OpFoldResult> sizeBounds,
219  bool omitPartialTileCheck);
220 
221 /// Add the specified offsets to any `linalg.index` ops contained in the given
222 /// `linalgOp`. The offsets are provided in the same order as iteration space
223 /// dimensions. Null offests are assumed to be zero.
224 void offsetIndices(OpBuilder &b, LinalgOp linalgOp,
225  ArrayRef<OpFoldResult> offests);
226 void offsetIndices(RewriterBase &b, LinalgOp linalgOp,
227  ArrayRef<OpFoldResult> offests);
228 
229 /// A struct containing the Linalg producer before and after fusion.
230 /// When operating on tensors, `fusedProducer` may feed into a `tensor.cast`
231 /// op before the consumer Linalg op, until enough canonicalizations have
232 /// applied.
233 struct FusionInfo {
235  LinalgOp fusedProducer;
236 };
237 
238 /// This implements the fusion part of the "tileAndFuse on tensors"
239 /// transformation and thus requires the `consumerOpOperand` to be a
240 /// `extract_slice` op (generally obtained by applying the tiling
241 /// transformation).
242 FailureOr<FusionInfo> fuseProducerOfTensor(OpBuilder &b,
243  OpOperand &consumerOpOperand);
244 
245 /// This implements the fusion part of the "tileAndFuse on tensors"
246 /// transformation and thus requires the `consumerOpOperand` to be a
247 /// `extract_slice` op (generally obtained by applying the tiling
248 /// transformation). Assumes `producerOfTensor` is a Linalg op that produces
249 /// `consumerOpOperand`.
250 FailureOr<FusionInfo> fuseProducerOfTensor(OpBuilder &b,
251  OpResult producerOpResult,
252  OpOperand &consumerOpOperand);
253 
254 //===----------------------------------------------------------------------===//
255 // Distribution utilities
256 //===----------------------------------------------------------------------===//
257 
258 /// Scheme used to distribute loops to processors.
259 enum class DistributionMethod {
260  /// Cyclic distribution where no assumption is made about the dynamic
261  /// relationship between number of processors and number of iterations of
262  /// the
263  /// distributed loop. Distributes the following loop
264  ///
265  /// scf.parallel (%iv) = (%lb) to (%ub) step (%step)
266  ///
267  /// to
268  ///
269  /// scf.parallel(%iv)= (%lb + %procId * %step) to (%ub) step (%step *
270  /// %nprocs)
271  Cyclic = 0,
272 
273  /// Cyclic distribution where the number of processors can be assumed to be
274  /// more than or equal to the number of iterations of the distributed loop.
275  /// In
276  /// such cases, a simple in-bounds check is enough (instead of materializing
277  /// a
278  /// loop). Distributes the following loop
279  ///
280  /// scf.parallel (%iv) = (%lb) to (%ub) step (%step)
281  ///
282  /// to
283  ///
284  /// %iv = %lb + %procId * %step
285  /// %cond = arith.cmpi "slt", %iv, %ub
286  /// scf.if %cond {
287  /// ...
288  /// }
290 
291  /// Cyclic distribution where the number of processors can be assumed to be
292  /// equal to the number of iterations of the distributed loop. In such
293  /// cases,
294  /// no bounds check is needed. Distributes the following loop
295  ///
296  /// scf.parallel (%iv) = (%lb) to (%ub) step (%step)
297  ///
298  /// to
299  ///
300  /// %iv = %lb + %procId * %step
302 
303  /// No Distribution.
304  None = 3
305 };
306 
307 /// Callback function type used to get processor ID, and number of processors
308 /// used for distribution for all parallel loops generated.
309 struct ProcInfo {
313 };
314 using ProcInfoCallBackFn = std::function<SmallVector<ProcInfo>(
315  OpBuilder &b, Location loc, ArrayRef<Range> parallelLoopRanges)>;
316 
317 /// Options that allow distribution of loops generated in Linalg transforms to
318 /// processors while generating the loops.
320  /// Callback function that returns the Values for processor ID (`procId`),
321  /// and number of processors (`nprocs`) used to execute the parallel loops.
322  /// The number of `{procId, nprocs}` pairs returned must be equal to the
323  /// number of `parallelLoopRanges` passed into the callback. The
324  /// `parallelLoopRanges` are ranges of the outer parallel loops of the
325  /// operation that do have non-zero tile sizes specified.
327 };
328 
329 /// Update the `lb`, `ub` and `step` to get per processor `lb`, `ub` and
330 /// `step`.
332  Value procId, Value nprocs, Value &lb,
333  Value &ub, Value &step);
334 
335 //===----------------------------------------------------------------------===//
336 // Fusion on tensor utilities
337 //===----------------------------------------------------------------------===//
338 
339 //===----------------------------------------------------------------------===//
340 // Generic op region utilities
341 //===----------------------------------------------------------------------===//
342 
343 /// A struct containing common matchers over linalg op's region.
345  enum class BinaryOpKind {
346  IAdd,
347  };
348 
349  /// Matches the given linalg op if its body is performing binary operation
350  /// on int or float scalar values and returns the binary op kind.
351  ///
352  /// The linalg op's region is expected to be
353  /// ```
354  /// {
355  /// ^bb(%a: <scalar-type>, %b: <scalar-type>):
356  /// %0 = <binary-op> %a, %b: <scalar-type>
357  /// linalg.yield %0: <scalar-type>
358  /// }
359  /// ```
360  static std::optional<BinaryOpKind> matchAsScalarBinaryOp(GenericOp op);
361 };
362 
363 //===----------------------------------------------------------------------===//
364 // Loop nest utilities
365 //===----------------------------------------------------------------------===//
366 
367 /// Utility class used to generate nested loops with ranges described by
368 /// `loopRanges` and loop type described by the `iteratorTypes`.
369 /// `bodyBuilderFn` is used to generate the body of the innermost loop. It is
370 /// passed a range of loop induction variables and a range of operand values
371 /// to use.
372 template <typename LoopTy>
374  static void doit(OpBuilder &b, Location loc, ArrayRef<Range> loopRanges,
375  LinalgOp linalgOp,
376  ArrayRef<utils::IteratorType> iteratorTypes,
379  bodyBuilderFn,
380  ArrayRef<linalg::ProcInfo> procInfo = {});
381 };
382 
383 /// Returns an attribute list that excludes pre-defined attributes.
384 template <typename OpTy>
386  auto elidedAttrs = llvm::to_vector(op.getAttributeNames());
387  if (isa<linalg::LinalgOp>(op.getOperation()))
388  elidedAttrs.push_back(LinalgDialect::kMemoizedIndexingMapsAttrName);
389  return getPrunedAttributeList(op, elidedAttrs);
390 }
391 
392 } // namespace linalg
393 } // namespace mlir
394 
395 #endif // MLIR_DIALECT_LINALG_UTILS_UTILS_H
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:46
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:205
This class represents an operand of an operation.
Definition: Value.h:257
This is a value defined by a result of an operation.
Definition: Value.h:447
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
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...
Definition: PatternMatch.h:358
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:387
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
FailureOr< FusionInfo > fuseProducerOfTensor(OpBuilder &b, OpOperand &consumerOpOperand)
This implements the fusion part of the "tileAndFuse on tensors" transformation and thus requires the ...
Definition: Fusion.cpp:217
SmallVector< Value > makeTiledShapes(OpBuilder &builder, Location loc, LinalgOp linalgOp, ValueRange valuesToTile, ArrayRef< OpFoldResult > ivs, ArrayRef< OpFoldResult > tileSizes, ArrayRef< OpFoldResult > sizeBounds, bool omitPartialTileCheck)
Creates extract_slice/subview ops for all valuesToTile of the given linalgOp with builder,...
Definition: Utils.cpp:862
bool allIndexingsAreProjectedPermutation(LinalgOp op)
Check if all indexing maps are projected permutations.
Definition: Utils.cpp:200
bool isParallelIterator(utils::IteratorType iteratorType)
Check if iterator type has "parallel" semantics.
Definition: Utils.cpp:235
SmallVector< OpFoldResult > computeTileSizes(OpBuilder &b, Location loc, ArrayRef< OpFoldResult > tileSizes, ArrayRef< OpFoldResult > sizeBounds)
Computes tile sizes, given a list of tileSizes and dimension sizes (sizeBounds).
Definition: Utils.cpp:757
GenericOp makeMemRefCopyOp(OpBuilder &b, Location loc, Value from, Value to)
Returns GenericOp that copies an n-D memref.
Definition: Utils.cpp:311
SmallVector< OpFoldResult > computeTileOffsets(OpBuilder &b, Location loc, ArrayRef< OpFoldResult > ivs, ArrayRef< OpFoldResult > tileSizes)
Computes tile offsets, given a list of loop ivs and tileSizes.
Definition: Utils.cpp:743
LinalgTilingLoopType
The type of loops to be generated during tiling.
Definition: Utils.h:118
bool isReductionIterator(utils::IteratorType iteratorType)
Check if iterator type has "reduction" semantics.
Definition: Utils.cpp:239
bool hasOnlyScalarElementwiseOp(Region &r)
Detect whether r has only ConstantOp, ElementwiseMappable and YieldOp.
Definition: Utils.cpp:206
SmallVector< int64_t > getPackInverseDestPerm(linalg::PackOp packOp)
Shell function to compute the Destination Permutation of PackOp This function uses the helper functio...
std::function< SmallVector< ProcInfo >(OpBuilder &b, Location loc, ArrayRef< Range > parallelLoopRanges)> ProcInfoCallBackFn
Definition: Utils.h:315
SmallVector< NamedAttribute > getPrunedAttributeList(OpTy op)
Returns an attribute list that excludes pre-defined attributes.
Definition: Utils.h:385
std::optional< SmallVector< ReassociationIndices > > getReassociationMapForFoldingUnitDims(ArrayRef< OpFoldResult > mixedSizes)
Get the reassociation maps to fold the result of a extract_slice (or source of a insert_slice) operat...
Definition: Utils.cpp:920
DistributionMethod
Scheme used to distribute loops to processors.
Definition: Utils.h:259
@ CyclicNumProcsGeNumIters
Cyclic distribution where the number of processors can be assumed to be more than or equal to the num...
@ Cyclic
Cyclic distribution where no assumption is made about the dynamic relationship between number of proc...
@ CyclicNumProcsEqNumIters
Cyclic distribution where the number of processors can be assumed to be equal to the number of iterat...
SmallVector< Value > insertSlicesBack(OpBuilder &builder, Location loc, LinalgOp op, ValueRange operands, ValueRange results)
Creates insert_slice ops that insert results back into larger tensors they were originally extracted ...
Definition: Utils.cpp:782
bool isElementwise(LinalgOp op)
Check if a LinalgOp is an element-wise operation.
Definition: Utils.cpp:220
void offsetIndices(OpBuilder &b, LinalgOp linalgOp, ArrayRef< OpFoldResult > offests)
Add the specified offsets to any linalg.index ops contained in the given linalgOp.
Definition: Utils.cpp:884
SmallVector< std::optional< SliceParameters > > computeAllSliceParameters(OpBuilder &builder, Location loc, LinalgOp linalgOp, ValueRange valuesToTile, ArrayRef< OpFoldResult > ivs, ArrayRef< OpFoldResult > tileSizes, ArrayRef< OpFoldResult > sizeBounds, bool omitPartialTileCheck)
Computes SliceParamaters for all valuesToTile of the given linalgOp, assuming linalgOp is being fused...
Definition: Utils.cpp:811
Operation * makeTiledShape(OpBuilder &builder, Location loc, Value valueToTile, ArrayRef< OpFoldResult > tileSizes, AffineMap map, ArrayRef< OpFoldResult > lbs, ArrayRef< OpFoldResult > ubs, ArrayRef< OpFoldResult > subShapeSizes, bool omitPartialTileCheck)
Creates an extract_slice/subview op for a single valueToTile with builder.
Definition: Utils.cpp:613
SmallVector< int64_t > getUnPackInverseSrcPerm(linalg::UnPackOp unpackOp)
Shell function to compute the Source Permutation of unPackOp.
Value makeComposedPadHighOp(OpBuilder &b, Location loc, RankedTensorType type, Value source, Value padding, bool nofold, ValueRange typeDynDims={})
Create a tensor::PadOp that pads source to the shape of type whose sizes are assumed to be greater th...
Definition: Utils.cpp:243
void updateBoundsForCyclicDistribution(OpBuilder &builder, Location loc, Value procId, Value nprocs, Value &lb, Value &ub, Value &step)
Update the lb, ub and step to get per processor lb, ub and step.
Definition: Utils.cpp:410
SmallVector< Type > getTensorOutputTypes(LinalgOp op, ValueRange operands)
Returns the list of tensor output types produced when the given structured operation op is applied to...
Definition: Utils.cpp:773
SliceParameters computeSliceParameters(OpBuilder &builder, Location loc, Value valueToTile, ArrayRef< OpFoldResult > tileSizes, AffineMap map, ArrayRef< OpFoldResult > lbs, ArrayRef< OpFoldResult > ubs, ArrayRef< OpFoldResult > subShapeSizes, bool omitPartialTileCheck)
Computes SliceParameters for a single valueToTile assuming that its user is being tiled with the give...
Definition: Utils.cpp:626
SmallVector< Value > ValueVector
An owning vector of values, handy to return from functions.
Definition: SCF.h:64
Include the generated interface declarations.
A struct containing the Linalg producer before and after fusion.
Definition: Utils.h:233
LinalgOp originalProducer
Definition: Utils.h:234
LinalgOp fusedProducer
Definition: Utils.h:235
Utility class used to generate nested loops with ranges described by loopRanges and loop type describ...
Definition: Utils.h:373
static void doit(OpBuilder &b, Location loc, ArrayRef< Range > loopRanges, LinalgOp linalgOp, ArrayRef< utils::IteratorType > iteratorTypes, function_ref< scf::ValueVector(OpBuilder &, Location, ValueRange, ValueRange)> bodyBuilderFn, ArrayRef< linalg::ProcInfo > procInfo={})
Options that allow distribution of loops generated in Linalg transforms to processors while generatin...
Definition: Utils.h:319
ProcInfoCallBackFn procInfo
Callback function that returns the Values for processor ID (procId), and number of processors (nprocs...
Definition: Utils.h:326
Callback function type used to get processor ID, and number of processors used for distribution for a...
Definition: Utils.h:309
DistributionMethod distributionMethod
Definition: Utils.h:312
A struct containing common matchers over linalg op's region.
Definition: Utils.h:344
static std::optional< BinaryOpKind > matchAsScalarBinaryOp(GenericOp op)
Matches the given linalg op if its body is performing binary operation on int or float scalar values ...
Definition: Utils.cpp:93
A struct containg offsets-sizes-strides arguments of the tiled shape.
Definition: Utils.h:155
SmallVector< OpFoldResult > strides
Definition: Utils.h:158
SmallVector< OpFoldResult > sizes
Definition: Utils.h:157
SmallVector< OpFoldResult > offsets
Definition: Utils.h:156