MLIR 22.0.0git
Transforms.h
Go to the documentation of this file.
1//===- Transforms.h - Linalg transformations as patterns --------*- 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_TRANSFORMS_TRANSFORMS_H
10#define MLIR_DIALECT_LINALG_TRANSFORMS_TRANSFORMS_H
11
12#include <utility>
13
27#include "llvm/ADT/SmallBitVector.h"
28
29namespace mlir {
30namespace bufferization {
31class AllocTensorOp;
33class BufferizationState;
34} // namespace bufferization
35
36namespace linalg {
37
38class LinalgOp;
39enum class WinogradConv2DFmr : uint32_t;
40
41//===----------------------------------------------------------------------===//
42// Utils.
43//===----------------------------------------------------------------------===//
44
45/// Return vector::CombiningKind for the given op.
46std::optional<vector::CombiningKind> getCombinerOpKind(Operation *combinerOp);
47
48//===----------------------------------------------------------------------===//
49// Bufferization-related transforms.
50//===----------------------------------------------------------------------===//
51
53 enum class AllocOp { MemrefAlloc = 0, MemrefAlloca = 1 };
55
62
63 /// If set to "true", only the destination tensor operands are bufferized to
64 /// a new allocation (and wrapped in "bufferization.to_tensor"), but not the
65 /// targeted op itself.
67
68 /// If set to "true", a `memref.dealloc` operation will be emitted for each
69 /// allocated buffer. Otherwise, the memory is leaked, which is useful if
70 /// the buffer deallocation pipeline should be run after bufferization is
71 /// done.
72 bool emitDealloc = false;
73};
74
75/// Materialize a buffer allocation for the given tensor.pad op and lower the
76/// op to linalg.fill/linalg.generic + bufferization.materialize_in_destination.
77/// E.g.:
78///
79/// %0 = tensor.pad low[%l] high[%h] %t ...
80///
81/// is lowered to:
82///
83/// %alloc = memref.alloc
84/// linalg.fill ... outs(%alloc)
85/// %subview = memref.subview %alloc [%l] [...] [1]
86/// bufferization.materialize_in_destination %t in %subview
87/// %0 = bufferization.to_tensor %alloc restrict writable
88///
89/// In addition to rewriting the IR as shown above, this function returns the
90/// newly allocated buffer. The `insertionPoint` parameter can be used to
91/// specify a custom insertion point for the buffer allocation.
94 tensor::PadOp padOp, Attribute memorySpace = {},
95 Operation *insertionPoint = nullptr);
96
97/// Materialize a buffer allocation for the given vector.mask op and bufferize
98/// the op, including its region. E.g.:
99///
100/// %0 = vector.mask {
101/// vector.transfer_write %v, %t : vector<16xf32>, tensor<?xf32>
102/// } : vector<16xi1> -> tensor<?xf32>
103///
104/// is lowered to:
105///
106/// %alloc = memref.alloc
107/// bufferization.materialize_in_destination %t in %subview
108/// vector.mask {
109/// vector.transfer_write %arg0, %alloc : vector<16xf32>, memref<?xf32>
110/// } : vector<16xi1>
111/// %0 = bufferization.to_tensor %alloc restrict writable
112///
113/// In addition to rewriting the IR as shown above, this function returns the
114/// newly allocated buffer. The `insertionPoint` parameter can be used to
115/// specify a custom insertion point for the buffer allocation.
117 const BufferizeToAllocationOptions &options,
118 vector::MaskOp maskOp, Attribute memorySpace = {},
119 Operation *insertionPoint = nullptr);
120
121/// Materialize a buffer allocation for the given bufferization.alloc_tensor op
122/// and lower the op to memref.alloc + memref.tensor_store.
123///
124/// In addition to rewriting the IR, this function returns the newly allocated
125/// buffer. The `insertionPoint` parameter can be used to specify a custom
126/// insertion point for the buffer allocation.
127Value bufferizeToAllocation(RewriterBase &rewriter,
128 const BufferizeToAllocationOptions &options,
129 bufferization::AllocTensorOp allocTensorOp,
130 Attribute memorySpace = {},
131 Operation *insertionPoint = nullptr);
132
133/// Bufferize the given op with tensor semantics and materialize the result in
134/// a newly allocated buffer.
135///
136/// Only bufferizable ops that bufferize to a memory write or have an
137/// aliasing OpOperand (and do not themselves bufferize to an allocation) are
138/// supported. They are bufferized using their BufferizableOpInterface
139/// implementation.
140///
141/// Selected ops that bufferize to an allocation (or need special handling) are
142/// also supported:
143/// - tensor.pad
144/// - vector.mask
145///
146/// This function returns the newly allocated buffer. The `insertionPoint`
147/// parameter can be used to specify a custom insertion point for the buffer
148/// allocation.
149Value bufferizeToAllocation(RewriterBase &rewriter,
151 Operation *op, Attribute memorySpace = {},
152 Operation *insertionPoint = nullptr);
153
154/// Try to eliminate tensor::EmptyOps inside `op` that are anchored on a
155/// LinalgOp. This transforms looks for LinalgOps that have an unused output
156/// operand and an input operand that is rooted in a tensor::EmptyOp. The
157/// tensor::EmptyOp uses are replaced with the output operand and the two
158/// operands of the LinalgOp are swapped.
159///
160/// Example:
161/// %0 = tensor.empty()
162/// %1 = linalg.matmul ins(...) outs(%0)
163/// %2 = linalg.generic ins(%1) outs(%dest) {
164/// ^bb0(%in: f32, %out: f32):
165/// // out not used
166/// }
167///
168/// The IR is transformed as follows:
169/// %0 = tensor.empty()
170/// %1 = linalg.matmul ins(...) outs(%dest)
171/// %2 = linalg.generic ins(%0) outs(%1) {
172/// ^bb0(%in: f32, %out: f32):
173/// // Use %out instead of %in
174/// }
175///
176/// The "ins" operand has no uses inside the body of the LinalgOp and can be
177/// folded away with existing cleanup patterns. Afterwards, the tensor::EmptyOp
178/// can also fold away.
180 RewriterBase &rewriter, Operation *op,
181 bufferization::OneShotAnalysisState &state);
182
183//===----------------------------------------------------------------------===//
184// Structs that configure the behavior of various transformations.
185//===----------------------------------------------------------------------===//
186
188 std::function<SmallVector<Value, 4>(OpBuilder &, Operation *)>;
189
191 /// Computation function that returns the tile sizes for each operation.
192 /// Delayed construction of constant tile sizes should occur to interoperate
193 /// with folding.
195
201 /// Set the `tileSizeComputationFunction` to return the values `ts`. The
202 /// values must not fold away when tiling. Otherwise, use a more robust
203 /// `tileSizeComputationFunction`.
205 tileSizeComputationFunction = [=](OpBuilder &, Operation *) { return ts; };
206 return *this;
207 }
208 /// Convenience function to set the `tileSizeComputationFunction` to a
209 /// function that computes tile sizes at the point they are needed. Allows
210 /// proper interaction with folding.
212
213 /// Tile all dynamic dimensions by 1. I.e., scalarize those dimensions.
214 /// Note: `scalarizeDynamicDims` and `setTileSizes` cannot be used together.
216
217 /// The interchange vector to reorder the tiled loops.
219
221 interchangeVector.assign(interchange.begin(), interchange.end());
222 return *this;
223 }
224
225 /// The type of tile loops to generate.
227
229 loopType = lt;
230 return *this;
231 }
232
233 /// When specified, specifies distribution of generated tile loops to
234 /// processors.
235 std::optional<LinalgLoopDistributionOptions> distribution;
236
239 distribution = std::move(distributionOptions);
240 return *this;
241 }
242
243 /// Specification markers of how to distribute the `linalg.tiled_loop`.
245
247 distributionTypes.assign(types.begin(), types.end());
248 return *this;
249 }
250
251 /// Peel the specified loops.
253
255 peeledLoops.clear();
256 peeledLoops.append(loops.begin(), loops.end());
257 return *this;
258 }
259};
260
262 /// Tile sizes used to tile the root operation.
265 tileSizes.assign(ts.begin(), ts.end());
266 return *this;
267 }
268 /// Tile interchange used to permute the tile loops.
270 /// When specified, specifies distribution of generated tile loops to
271 /// processors.
272 std::optional<LinalgLoopDistributionOptions> tileDistribution;
275 tileDistribution = std::move(distributionOptions);
276 return *this;
277 }
278};
279
281 /// A padding value for every operand.
284 paddingValues.assign(pv.begin(), pv.end());
285 return *this;
286 }
287 /// A list of iterator dimensions to pad.
290 paddingDimensions.assign(pd.begin(), pd.end());
291 return *this;
292 }
293 /// A list of multiples to which each padding dimension should be padded to.
294 std::optional<SmallVector<int64_t>> padToMultipleOf;
296 padToMultipleOf.emplace(m.begin(), m.end());
297 return *this;
298 }
299 /// A mapping between an operand and shape dim, and a size for a padding
300 /// dimension. Each size is expected to be greater or equal than the
301 /// corresponding shape dim. If no value is provided then the constant upper
302 /// bound will be used.
304 LinalgPaddingOptions &setSizeToPadTo(unsigned operandIndex, unsigned dimIndex,
305 OpFoldResult size) {
306 assert(size && "expected non-null size");
307 sizeToPadTo[{operandIndex, dimIndex}] = size;
308 return *this;
309 }
310 /// Given the operand index and shape dim it returns the size to pad to.
311 OpFoldResult getSizeToPadTo(unsigned operandIndex, unsigned dimIndex) const {
312 return sizeToPadTo.lookup_or(
313 std::pair<unsigned, unsigned>(operandIndex, dimIndex), nullptr);
314 }
315
316 /// A flag for every operand to mark the PadOp as nofold which enables
317 /// packing for statically shaped operands.
320 nofoldFlags.assign(pp.begin(), pp.end());
321 return *this;
322 }
323 /// A number of loops to hoist the PadOp out for every operand.
326 hoistPaddings.assign(hp.begin(), hp.end());
327 return *this;
328 }
329 /// A permutation vector for every operand used to transpose the packed
330 /// PadOp results.
334 transposePaddings.assign(tp.begin(), tp.end());
335 return *this;
336 }
342 /// The op to be used for copying the padded result to the original
343 /// destination tensor.
346 copyBackOp = op;
347 return *this;
348 }
349};
350
352 /// A padding value for every operand.
355 paddingValues.assign(pv.begin(), pv.end());
356 return *this;
357 }
358 /// A list of iterator dimensions sizes to pad to.
361 paddingSizes.assign(m.begin(), m.end());
362 return *this;
363 }
364 /// Pad iterator `paddingDimension[i]` to next multiple of `paddingSizes[i]`
365 /// if true. Otherwise pad to `paddingSizes[i]`.
369 return *this;
370 }
371};
372
373/// Callback function type used to perform the allocation for the promoted
374/// `subView`. In `boundingSubViewsize` a best attempt is made to find the
375/// smallest constant value for the size of the buffer needed for each
376/// dimension. If that is not possible, contains the dynamic size of the
377/// subview. The call back should return the buffer to use.
378using AllocBufferCallbackFn = std::function<std::optional<Value>(
379 OpBuilder &b, memref::SubViewOp subView,
380 ArrayRef<Value> boundingSubViewSize, DataLayout &layout)>;
381
382/// Callback function type used to deallocate the buffers used to hold the
383/// promoted subview.
385 std::function<LogicalResult(OpBuilder &b, Value buffer)>;
386
387/// Callback function type used to insert copy from original subview to
388/// subview of the promoted region for the read operands/subview of promoted
389/// region to original subview for the results. The copy has to happen from
390/// `src` to `dst`.
392 std::function<LogicalResult(OpBuilder &b, Value src, Value dst)>;
393
395 /// Indices of subViews to promote. If `std::nullopt`, try to promote all
396 /// operands.
397 std::optional<DenseSet<unsigned>> operandsToPromote;
400 operandsToPromote->insert_range(operands);
401 return *this;
402 }
403 /// If ith element of `useFullTiles` is true the full view should be used
404 /// for the promoted buffer of the ith operand in `operandsToPromote`.
405 /// Otherwise the partial view will be used. The decision is defaulted to
406 /// `useFullTileBuffersDefault` when `useFullTileBuffers` is std::nullopt and
407 /// for operands missing from `useFullTileBuffers`.
408 std::optional<llvm::SmallBitVector> useFullTileBuffers;
410 unsigned size = useFullTiles.size();
411 llvm::SmallBitVector tmp(size, false);
412 for (unsigned i = 0; i < size; ++i)
413 tmp[i] = useFullTiles[i];
414 useFullTileBuffers = tmp;
415 return *this;
416 }
417 /// If true all operands unspecified by `useFullTileBuffers` will use the
418 /// full view, otherwise the partial view.
424 /// If true, buffers will be allocated with the original subview size. This
425 /// may result in more dynamic allocations, in case of dynamic sizes.
428 useOriginalSubviewSize = originalSize;
429 return *this;
430 }
431 /// Alignment of promoted buffer. If `std::nullopt` do not specify alignment.
432 std::optional<unsigned> alignment;
434 alignment = align;
435 return *this;
436 }
437 /// Memory space of promoted buffer. If `std::nullopt` do not specify memory
438 /// space.
439 std::optional<Attribute> memorySpace;
441 memorySpace = memorySpc;
442 return *this;
443 }
444 /// Use alloca with the default allocation scheme.
445 bool useAlloca = false;
447 useAlloca = use;
448 return *this;
449 }
450 /// Callback function to do the allocation of the promoted buffer. If
451 /// std::nullopt, then the default allocation scheme of allocating a
452 /// memref<?xi8> buffer followed by a view operation is used.
453 std::optional<AllocBufferCallbackFn> allocationFn;
454 std::optional<DeallocBufferCallbackFn> deallocationFn;
457 DeallocBufferCallbackFn const &deallocFn) {
458 allocationFn = allocFn;
459 deallocationFn = deallocFn;
460 return *this;
461 }
462 /// Callback function to do the copy of data to and from the promoted
463 /// subview. If std::nullopt then a memref.copy is used.
464 std::optional<CopyCallbackFn> copyInFn;
465 std::optional<CopyCallbackFn> copyOutFn;
467 CopyCallbackFn const &copyOut) {
468 copyInFn = copyIn;
469 copyOutFn = copyOut;
470 return *this;
471 }
472};
473
474/// Split Reduction options.
476 // Ratio used to split the reduction dimension. If the ratio is <= 1,
477 // nothing will be done.
479 // Index where the extra dimension is added to the intermediate tensor
480 // shape.
481 unsigned index = 0;
482 // If the inner dimension after splitting is parallel or reduction.
483 bool innerParallel = false;
484};
485
486/// Function signature to control reduction splitting. This returns
487/// `SplitReductionOptions`.
488// TODO: don't use unsigned unless doing bit manipulation.
490 std::function<SplitReductionOptions(LinalgOp op)>;
491
492//===----------------------------------------------------------------------===//
493// Preconditions that ensure the corresponding transformation succeeds and can
494// be applied as a rewrite pattern.
495//===----------------------------------------------------------------------===//
496
497/// Return true if two `linalg.generic` operations with producer/consumer
498/// relationship through `fusedOperand` can be fused using elementwise op
499/// fusion.
500bool areElementwiseOpsFusable(OpOperand *fusedOperand);
501
502/// Promote memref.subviews feeding linalg-on-buffers operations.
503LogicalResult promoteSubviewsPrecondition(Operation *op,
505
506/// Return success if the operation can be vectorized.
508 ArrayRef<int64_t> inputVectorSizes = {},
509 ArrayRef<bool> inputScalableVecDims = {},
510 bool vectorizeNDExtract = false,
511 bool flatten1DDepthwiseConv = false);
512
513//===----------------------------------------------------------------------===//
514// Transformations exposed as functional-style API calls.
515//===----------------------------------------------------------------------===//
516
518
519/// Transformation to drop unit-extent dimensions from `linalg.generic`
520/// operations.
523
526
527 using ControlFnTy = std::function<SmallVector<unsigned>(Operation *)>;
529 if (auto genericOp = dyn_cast_or_null<GenericOp>(op)) {
530 return llvm::to_vector(llvm::seq<unsigned>(0, genericOp.getNumLoops()));
531 }
532 if (auto padOp = dyn_cast_or_null<tensor::PadOp>(op)) {
533 return llvm::to_vector(
534 llvm::seq<unsigned>(0, padOp.getSourceType().getRank()));
535 }
536 return SmallVector<unsigned>{};
537 };
538};
539
544using DroppedUnitDimsBuilder = std::function<IndexingMapOpInterface(
545 Location loc, OpBuilder &, IndexingMapOpInterface,
546 ArrayRef<Value> newOperands, ArrayRef<AffineMap> newIndexingMaps,
547 const llvm::SmallDenseSet<unsigned> &droppedDims)>;
548
549FailureOr<DropUnitDimsResult>
550dropUnitDims(RewriterBase &rewriter, IndexingMapOpInterface op,
551 const DroppedUnitDimsBuilder &droppedUnitDimsBuilder,
553FailureOr<DropUnitDimsResult> dropUnitDims(RewriterBase &rewriter,
554 GenericOp genericOp,
556
557/// Fuse two `linalg.generic` operations that have a producer-consumer
558/// relationship captured through `fusedOperand`. The method expects
559/// that `areElementwiseOpsFusable` returns true for the given `fusedOperand`.
564FailureOr<ElementwiseOpFusionResult>
565fuseElementwiseOps(RewriterBase &rewriter, OpOperand *fusedOperand);
566
567/// Returns a set of indices of the producer's results which would
568/// be preserved after the fusion.
569/// * There is a chance that the implementation of the transformation does not
570/// agree with the result of this method. This function gives a prediction based
571/// on an optimized fusion.
572llvm::SmallDenseSet<int> getPreservedProducerResults(GenericOp producer,
573 GenericOp consumer,
574 OpOperand *fusedOperand);
575
576/// Try to peel and canonicalize loop `op` and return the new result.
577/// Also applies affine_min/max bounds simplification on the fly where relevant.
578// TODO: Add support for scf.parallel and affine.for loops.
580
581/// Peel 'loops' and applies affine_min/max bounds simplification on the fly
582/// where relevant.
583void peelLoops(RewriterBase &rewriter, ArrayRef<scf::ForOp> loops);
584
585/// Pad the iterator dimensions `options.paddingDimensions` of all `opToPad`
586/// operands to a static bounding box. The original `opToPad` is cloned and
587/// operates on the padded tensors.
588///
589/// * "options.padToMultipleOf" indicates that each padding dimension should be
590/// padded to the specified multiple.
591/// * Use "options.paddingValues" and "options.nofoldFlags" to set padding
592/// value and nofold attribute of the created tensor::PadOps, respectively.
593/// * The unpadded results (extracted slice of the cloned operation) are
594/// returned via `replacements`.
595/// * The tensor::PadOps are returned via `padOps`.
596/// * "options.copyBackOp" specifies the op type for copying back the unpadded
597/// result to the original destination tensor.
598LogicalResult rewriteAsPaddedOp(RewriterBase &rewriter, LinalgOp opToPad,
600 LinalgOp &paddedOp,
601 SmallVector<Value> &replacements,
603
604/// Helper function to compute the padded shape of the given value `v` of
605/// `RankedTensorType` given:
606/// - the `indexingSizes` as a list of OpFoldResult.
607/// - an `indexingMap` that encodes how the padded shape varies with
608/// increases in `indexingSizes`.
609/// The implementation iteratively combines increases from contributing using
610/// affine.apply operations.
611/// The `indexingMap` + `indexingSizes` encoding suits StructuredOps and
612/// provides a gentle portability path for Linalg-like ops with affine maps.
613/// The padded shape is computed by evaluating the maximum accessed index per
614/// dimension, which may involve multiplying by constant factors derived from
615/// the affine indexing expressions. Currently, only a limited set of projected
616/// permuation indexing maps are supported, such as
617/// - affine_map<(d0, d1, d2) -> (d0, d1)>
618/// - affine_map<(d0, d1, d2) -> (d0, d1 + d2)>
619/// - affine_map<(d0, d1) -> (d0 * 3 + d1)>
620/// In the future, more general interfaces can be devised to encode similar
621/// shape evolutions and map between an op and its operands.
624 AffineMap indexingMap, ArrayRef<OpFoldResult> indexingSizes,
626
628 std::function<FailureOr<SmallVector<OpFoldResult>>(
631
632/// Specific helper for Linalg ops.
633FailureOr<SmallVector<OpFoldResult>>
635 ArrayRef<Range> iterationDomain,
637
638/// Operations and values created in the process of padding a TilingInterface
639/// operation.
641 /// The operands of the padded op.
643 /// The padded op, a clone of `toPad` with padded operands.
644 TilingInterface paddedOp;
645 /// Slices of the padded op's results, same types as `toPad`.
647};
648
649/// Pad the iterator dimensions of `toPad`.
650/// * "options.paddingSizes" indicates that each padding dimension should be
651/// padded to the specified padding size.
652/// * "options.padToMultipleOf" indicates that the paddingSizes should be
653// interpreted as the bounding box (dynamic) value to pad to.
654/// * Use "options.paddingValues" to set the padding value of the created
655// tensor::PadOp.
656//
657// The transformation assumes that the insertion point is set after the
658// operation to pad.
659FailureOr<PadTilingInterfaceResult>
660rewriteAsPaddedOp(OpBuilder &, TilingInterface toPad,
664
665namespace detail {
666
667/// Helper struct to hold the results of building a packing loop nest.
674
675/// Build the packing loop nest required to hoist `opToHoist` above
676/// `outermostEnclosingForOp`.
677/// The loop nest is built just before `outermostEnclosingForOp`.
678FailureOr<PackingResult>
679buildPackingLoopNest(RewriterBase &rewriter, tensor::PadOp opToHoist,
680 scf::ForOp outermostEnclosingForOp,
681 ArrayRef<int64_t> transposeVector);
682
683} // namespace detail
684
685/// Mechanically hoist padding operations on tensors by `numLoops` into a new,
686/// generally larger tensor. This achieves packing of multiple padding ops into
687/// a larger tensor. On success, `opToHoist` is replaced by the cloned version
688/// in the packing loop so the caller can continue reasoning about the padding
689/// operation. If `transposeVector` is non-empty, hoist padding introduces a
690/// TransposeOp to transpose the padded tensor before inserting it into the
691/// packed tensor. A `transposeVector` can change the storage order of the
692/// padded tensor but does not change the order of the pack or compute loops.
693///
694/// TODO: In the future, we should consider rewriting as a linalg.pack after
695/// hoisting since this abstraction is now available.
696///
697/// Example in pseudo-mlir:
698/// =======================
699///
700/// If hoistPaddingOnTensors is called with `nLoops` = 2 on the following IR.
701/// ```
702/// scf.for (%i, %j, %k)
703/// %st0 = tensor.extract_slice f(%i, %k) : ... to tensor<?x?xf32>
704/// %0 = tensor.pad %st0 low[0, 0] high[...] {
705/// ^bb0( ... ):
706/// linalg.yield %pad
707/// } : tensor<?x?xf32> to tensor<4x8xf32>
708/// compute(%0)
709/// ```
710///
711/// IR resembling the following is produced:
712///
713/// ```
714/// scf.for (%i) {
715/// %packed_init = tensor.empty range(%j) : tensor<?x4x8xf32>
716/// %packed = scf.for (%k) iter_args(%p : %packed_init) {
717/// %st0 = tensor.extract_slice f(%i, %k) : ... to tensor<?x?xf32>
718/// %0 = tensor.pad %st0 low[0, 0] high[...] {
719/// ^bb0( ... ):
720/// linalg.yield %pad
721/// } : tensor<?x?xf32> to tensor<4x8xf32>
722/// %1 = tensor.insert_slice %0 ...
723/// : tensor<4x8xf32> to tensor<?x4x8xf32>
724/// scf.yield %1: tensor<?x4x8xf32>
725/// } -> tensor<?x4x8xf32>
726/// scf.for (%j, %k) {
727/// %st0 = tensor.extract_slice %packed [%k, 0, 0][1, 4, 8][1, 1, 1] :
728/// tensor<?x4x8xf32> to tensor<4x8xf32>
729/// compute(%st0)
730/// }
731/// }
732/// ```
733FailureOr<Value>
734hoistPaddingOnTensors(RewriterBase &rewriter, tensor::PadOp opToHoist,
735 int64_t numLoops, ArrayRef<int64_t> transposeVector,
736 tensor::PadOp &hoistedOp,
737 SmallVectorImpl<TransposeOp> &transposeOps);
738/// Calls into `hoistPaddingOnTensors` with a local IRRewriter.
739FailureOr<Value>
740hoistPaddingOnTensors(tensor::PadOp opToHoist, int64_t numLoops,
741 ArrayRef<int64_t> transposeVector,
742 tensor::PadOp &hoistedOp,
743 SmallVectorImpl<TransposeOp> &transposeOps);
744
745/// Apply padding and hoisting to `linalgOp` according to the configuration
746/// specified in `options`.
747FailureOr<LinalgOp> padAndHoistLinalgOp(RewriterBase &rewriter,
748 LinalgOp linalgOp,
750
751/// Split the given `op` into two parts along the given iteration space
752/// `dimension` at the specified `splitPoint`, and return the two parts.
753/// If the second part is statically known to be empty, do not create it
754/// and return nullptr instead. Error state is signalled by returning
755/// a pair of nullptrs.
756///
757/// For example, the following op:
758///
759/// linalg.matmul ins(%0, %1 : tensor<128x32xf32>, tensor<32x64xf32>)
760/// outs(%2 : tensor<128x64xf32>)
761///
762/// split along the first dimension at position 42 will result in:
763///
764/// %3 = tensor.extract_slice %0[0, 0][42, 32][1, 1]
765/// %4 = tensor.extract_slice %2[0, 0][42, 64][1, 1]
766/// %5 = linalg.matmul ins(%3, %1 : tensor<42x32xf32>, tensor<32x64xf32>)
767/// outs(%5 : tensor<42x64xf32>)
768/// %6 = tensor.insert_slice %5 into %2[0, 0][42, 64][1, 1]
769///
770/// %7 = tensor.extract_slice %0[42, 0][86, 32][1, 1]
771/// %8 = tensor.extract_slice %6[42, 0][86, 64][1, 1]
772/// %9 = linalg.matmul ins(%7, %1 : tensor<86x32xf32>, tensor<32x64xf32>)
773/// outs(%8 : tensor<86x64xf32>)
774/// tensor.insert_slice %5 into %6[42, 0][86, 64][1, 1]
775///
776/// Note that there is no simplification other than constant propagation applied
777/// to slice extraction and insertion.
778std::pair<TilingInterface, TilingInterface> splitOp(RewriterBase &rewriter,
779 TilingInterface op,
780 unsigned dimension,
781 OpFoldResult splitPoint);
782
783/// Perform standalone tiling of a single LinalgOp by `tileSizes`.
784/// and permute the loop nest according to `interchangeVector`
785/// The permutation is expressed as a list of integers that specify
786/// the new ordering of the loop nest. The length of `interchangeVector`
787/// must be equal to the length of `tileSizes`.
788/// An empty vector is interpreted as the identity permutation and the
789/// transformation returns early.
790///
791/// Return a struct containing the tiled loops in the specified order
792/// and the cloned op if successful, std::nullopt otherwise.
793///
794/// E.g. the permutation `(i,j,k) -> (j,k,i)` is expressed by
795/// `interchangeVector = [1,2,0]`. All values in `interchangeVector` must be
796/// integers, in the range 0..`tileSizes.size()` without duplications
797/// (i.e. `[1,1,2]` is an invalid permutation).
803FailureOr<TiledLinalgOp> tileLinalgOp(RewriterBase &b, LinalgOp op,
805
806/// Interchange the `iterator_types` and `iterator_maps` dimensions and adapts
807/// the index accesses of `op`. This is an in-place transformation controlled
808/// by `interchangeVector`. An empty vector is interpreted as the identity
809/// permutation and the transformation returns early.
810///
811/// E.g. the permutation `(i,j,k) -> (j,k,i)` is expressed with
812/// `interchangeVector = [1,2,0]`. All values in `interchangeVector` must be
813/// integers, in the range 0..`op.rank` without duplications
814/// (i.e. `[1,1,2]` is an invalid permutation).
815///
816/// Return failure if the permutation is not valid.
817FailureOr<GenericOp> interchangeGenericOp(RewriterBase &rewriter,
818 GenericOp genericOp,
819 ArrayRef<unsigned> interchangeVector);
820
821/// Create a GenericOp from the given named operation `linalgOp` and replace
822/// the given `linalgOp`.
823/// Return failure if `linalgOp` is a GenericOp or misses a region builder.
824FailureOr<GenericOp> generalizeNamedOp(RewriterBase &rewriter,
825 LinalgOp linalgOp);
826
827/// Create a namedOp from the given GenericOp and replace the GenericOp.
828/// Currently we can specialize only trivial linalg copy operations.
829FailureOr<LinalgOp> specializeGenericOp(RewriterBase &rewriter,
830 GenericOp genericOp);
831
832/// Create a new buffer using the `allocationFn` provided. The size of this
833/// buffer is either the original subview size when 'useOriginalSubviewSize' is
834/// set to true or the smallest constant bounding size along each dimension that
835/// can be computed for the size of the result of `subView`. Returns the
836/// allocated buffer as `fullLocalView` and the view that matches the size of
837/// the result of subview operation as `partialLocalView`.
842FailureOr<PromotionInfo>
843promoteSubviewAsNewBuffer(OpBuilder &b, Location loc, memref::SubViewOp subView,
844 bool useOriginalSubviewSize,
845 const AllocBufferCallbackFn &allocationFn,
846 DataLayout &layout);
847
848/// Promote the `subViews` into a new buffer allocated at the insertion point
849/// `b`. Promotion occurs in 3 steps:
850/// 1. Create a new buffer for a full tile (i.e. not clipped at the
851/// boundary).
852/// 2. Take a full view on the buffer.
853/// 3. Take a partial slice of the full view in step 2. and copy into it.
854///
855/// Return the modified linalg op (the modification happens in place) as well
856/// as all the copy ops created.
857FailureOr<LinalgOp> promoteSubViews(OpBuilder &b, LinalgOp op,
859
860/// Allocate the subview in the GPU workgroup memory.
861std::optional<Value> allocateWorkgroupMemory(OpBuilder &builder,
862 memref::SubViewOp subview,
863 ArrayRef<Value> sizeBounds,
864 DataLayout &);
865
866/// In case of GPU group memory there is no need to deallocate.
867LogicalResult deallocateWorkgroupMemory(OpBuilder &, Value /*buffer*/);
868
869/// Create Memref copy operations and add gpu barrier guards before and after
870/// the copy operation to ensure data integrity.
871LogicalResult copyToWorkgroupMemory(OpBuilder &b, Value src, Value dst);
872
873/// Allocate the subview in the GPU private memory.
874std::optional<Value> allocateGPUPrivateMemory(OpBuilder &builder,
875 memref::SubViewOp subview,
876 ArrayRef<Value> sizeBounds,
877 DataLayout &);
878
879/// Normal copy to between src and dst.
880LogicalResult copyToGPUPrivateMemory(OpBuilder &b, Value src, Value dst);
881
882/// In case of GPU private memory there is no need to deallocate since the
883/// memory is freed when going outside of the scope.
884LogicalResult deallocateGPUPrivateMemory(OpBuilder &, Value /*buffer*/);
885
886/// Return true if there's dedicated logic in the Linalg Vectorizer to
887/// vectorize this Op, false otherwise.
888///
889/// Note that this helper merely implements a very high level check and that the
890/// vectorizer also requires various additional pre-conditions to be met for it
891/// to work (these are checked by the vectorizer itself).
893
894/// Transformation information returned after vectorizing.
896 /// Results of the vectorization transform to replace the original operation.
898};
899/// Returns a `VectorizationResult` containing the results of the vectorized op,
900/// or failure if the transformation fails. If provided, `inputVectorSizes` are
901/// used to vectorize this operation. `inputVectorSizes` must match the rank of
902/// the iteration space of the operation and the input vector sizes must be
903/// greater than or equal to their counterpart iteration space sizes, if static.
904/// `inputVectorShapes` also allows the vectorization of operations with dynamic
905/// shapes.
906/// Optionally, `createNamedContraction` can force compatible contractions to be
907/// vectorized directly to vector.contract operation.
908FailureOr<VectorizationResult>
910 ArrayRef<int64_t> inputVectorSizes = {},
911 ArrayRef<bool> inputScalableVecDims = {},
912 bool vectorizeNDExtract = false, bool flatten1DDepthwiseConv = false,
913 bool assumeDynamicDimsMatchVecSizes = false,
914 bool createNamedContraction = false);
915
916/// Emit a suitable vector form for a Copy op with fully static shape.
917LogicalResult vectorizeCopy(RewriterBase &builder, memref::CopyOp copyOp);
918
919/// Emit a loop nest of `scf.for` with the proper body for `linalgOp`.
920FailureOr<LinalgLoops> linalgOpToLoops(RewriterBase &rewriter,
921 LinalgOp linalgOp);
922
923/// Emit a loop nest of `scf.parallel` with the proper body for `linalgOp`.
924FailureOr<LinalgLoops> linalgOpToParallelLoops(RewriterBase &rewriter,
925 LinalgOp linalgOp);
926
927/// Emit a loop nest of `affine.for` with the proper body for `linalgOp`.
928FailureOr<LinalgLoops> linalgOpToAffineLoops(RewriterBase &rewriter,
929 LinalgOp linalgOp);
930
931/// Creates a number of ranges equal to the number of non-zero in `tileSizes`.
932/// One for each loop of the LinalgOp that is tiled. The `tileSizes` argument
933/// has one entry per surrounding loop. It uses zero as the convention that a
934/// particular loop is not tiled. This convention simplifies implementations
935/// by avoiding affine map manipulations. The returned ranges correspond to
936/// the loop ranges, in the proper order, that are tiled and for which new
937/// loops will be created. Also the function returns a map from loop indices
938/// of the LinalgOp to the corresponding non-empty range indices of newly
939/// created loops.
941std::tuple<SmallVector<Range, 4>, LoopIndexToRangeIndexMap>
943 ArrayRef<OpFoldResult> allShapeSizes,
944 ArrayRef<OpFoldResult> allTileSizes);
945
946namespace detail {
947template <typename T>
949 /// Tile sizes.
951 /// Number of tiles associated with each size.
953};
954
955template <typename T>
957 /// Tile sizes.
959 /// Number of tiles associated with each size.
961};
962
963} // namespace detail
964
965/// A description of a multi-size tiling comprising tile sizes and numbers of
966/// tiles, expressed as Values which may or may not be constant. Multi-size
967/// currently means two-size.
972
977
978/// Emits the IR computing the multi-sized tiling specification with two tile
979/// sizes not exceeding `targetSize`, each divisible by `sizeDivisor`, such
980/// that there exist numbers of tiles with these sizes that fully cover the
981/// given iteration space `dimension` of the structured `op`.
982///
983/// The computation is as follows:
984///
985/// b = originalTripCount floordiv sizeDivisor
986/// t = (targetSize + sizeDivisor - 1) floordiv sizeDivisor
987/// d = (b + t - 1) floordiv t
988/// s = (b floordiv d) * sizeDivisor
989/// v = b % d
990/// u = d - v
991///
992/// where the tile sizes are `s` and `s` + `sizeDivisor`, and the numbers of
993/// the corresponding tiles are `u` and `v`, respectively. Alternatively,
994///
995/// s * u + (s + sizeDivisor) * v == original size,
996/// where s mod sizeDivisor = 0.
997///
998/// Expects all values to be positive. In some cases with the target tile size
999/// sufficiently close to the dimension shape and non-unit divisor, it is
1000/// impossible to compute such sizes. If `emitAssertion` is set, also emit the
1001/// assertion that size computation succeeded.
1002///
1003/// Returns the specification consisting of both tile values and the number of
1004/// tiles of each size.
1005FailureOr<MultiSizeSpecification>
1006computeMultiTileSizes(OpBuilder &builder, LinalgOp op, unsigned dimension,
1007 OpFoldResult targetSize, OpFoldResult divisor,
1008 bool emitAssertions = true);
1009FailureOr<StaticMultiSizeSpecification>
1010computeStaticMultiTileSizes(LinalgOp op, unsigned dimension, int64_t targetSize,
1011 int64_t divisor);
1012
1013FailureOr<StaticContinuousTileSizeSpecification>
1014computeStaticContinuousTileSizes(LinalgOp op, unsigned dimension,
1015 unsigned targetSize);
1016FailureOr<ContinuousTileSizeSpecification>
1017computeContinuousTileSizes(OpBuilder &builder, TilingInterface op,
1018 unsigned dimension, OpFoldResult targetSize,
1019 bool emitAssertions);
1020
1021/// Transformation information returned after reduction tiling.
1023 /// The partial reduction tiled op generated.
1025 /// The final reduction operation merging all the partial reductions.
1027 /// Initial values used for partial reductions.
1029 /// The `scf.forall` operation that iterate over the tiles.
1030 scf::ForallOp loops;
1031};
1032
1033/// Method to tile a reduction to parallel iterations computing partial
1034/// reductions. After the loop all the partial reduction are merged into a final
1035/// reduction. For example for the following sequence
1036///
1037/// ```mlir
1038/// %0 = linalg.generic %in ["parallel", "reduction"]
1039/// : tensor<7x9xf32> -> tensor<7xf32>
1040/// ```
1041///
1042/// into:
1043///
1044/// ```mlir
1045/// %0 = linalg.fill ... : tensor<7x4xf32>
1046/// %1 = scf.forall (%iv) in (%c4) shared_outs(%arg0 = %0)
1047/// -> (tensor<7x4xf32>) {
1048/// %2 = tensor.extract_slice %arg3 : tensor<7x4xf32> to tensor<7xf32>
1049/// %3 = tensor.extract_slice %in : tensor<7x9xf32> -> tensor<7x?xf32>
1050/// %4 = linalg.generic %2, %3 ["parallel", "reduction"]
1051/// : tensor<7x?xf32> -> tensor<7xf32>
1052/// %5 = tensor.insert_slice %3, %arg0[0, %iv] : tensor<7x4xf32>
1053/// }
1054/// %6 = linalg.generic %1 ["parallel", "reduction"]
1055/// : tensor<7x4xf32> -> tensor<7xf32>
1056/// ```
1057FailureOr<ForallReductionTilingResult>
1058tileReductionUsingForall(RewriterBase &b, PartialReductionOpInterface op,
1059 ArrayRef<OpFoldResult> numThreads,
1060 ArrayRef<OpFoldResult> tileSizes = {},
1061 std::optional<ArrayAttr> mapping = std::nullopt);
1062
1063/// All indices returned by IndexOp should be invariant with respect to
1064/// tiling. Therefore, if an operation is tiled, we have to transform the
1065/// indices accordingly, i.e. offset them by the values of the corresponding
1066/// induction variables that are captured implicitly in the body of the op.
1067///
1068/// Example. `linalg.generic` before tiling:
1069///
1070/// #id_2d = (i, j) -> (i, j)
1071/// #pointwise_2d_trait = {
1072/// indexing_maps = [#id_2d, #id_2d],
1073/// iterator_types = ["parallel", "parallel"]
1074/// }
1075/// linalg.generic #pointwise_2d_trait %operand, %result {
1076/// ^bb0(%operand_in: f32, %result_in: f32):
1077/// %i = linalg.index 0 : index
1078/// %j = linalg.index 1 : index
1079/// <some operations that use %i, %j>
1080/// }: memref<50x100xf32>, memref<50x100xf32>
1081///
1082/// After tiling pass with tiles sizes 10 and 25:
1083///
1084/// #strided = (i, j)[s0, s1, s2] -> (i * s1 + s0 + j * s2)
1085///
1086/// %c1 = arith.constant 1 : index
1087/// %c0 = arith.constant 0 : index
1088/// %c25 = arith.constant 25 : index
1089/// %c10 = arith.constant 10 : index
1090/// operand_dim_0 = dim %operand, 0 : memref<50x100xf32>
1091/// operand_dim_1 = dim %operand, 1 : memref<50x100xf32>
1092/// scf.for %k = %c0 to operand_dim_0 step %c10 {
1093/// scf.for %l = %c0 to operand_dim_1 step %c25 {
1094/// %4 = memref.subview %operand[%k, %l][%c10, %c25][%c1, %c1]
1095/// : memref<50x100xf32> to memref<?x?xf32, #strided>
1096/// %5 = memref.subview %result[%k, %l][%c10, %c25][%c1, %c1]
1097/// : memref<50x100xf32> to memref<?x?xf32, #strided>
1098/// linalg.generic pointwise_2d_trait %4, %5 {
1099/// ^bb0(%operand_in: f32, %result_in: f32):
1100/// %i = linalg.index 0 : index
1101/// %j = linalg.index 1 : index
1102/// // Indices `k` and `l` are implicitly captured in the body.
1103/// %transformed_i = arith.addi %i, %k : index // index `i` is offset by
1104/// %k %transformed_j = arith.addi %j, %l : index // index `j` is offset
1105/// by %l
1106/// // Every use of %i, %j is replaced with %transformed_i,
1107/// %transformed_j <some operations that use %transformed_i,
1108/// %transformed_j>
1109/// }: memref<?x?xf32, #strided>, memref<?x?xf32, #strided>
1110/// }
1111/// }
1112///
1113/// TODO: Investigate whether mixing implicit and explicit indices
1114/// does not lead to losing information.
1115void transformIndexOps(RewriterBase &b, LinalgOp op,
1117 const LoopIndexToRangeIndexMap &loopIndexToRangeIndex);
1118
1119/// Apply transformation to split the single linalg op reduction into a
1120/// parallel and reduction dimension. Then create a new linalg.generic op
1121/// doing the rest of the reduction. Return the new linalg op with an extra
1122/// parallel dimension or failure if the transformation didn't happen.
1123///
1124/// Example:
1125/// ```
1126/// %r = linalg.generic {indexing_maps = [affine_map<(d0) -> (d0)>,
1127/// affine_map<(d0) -> ()>],
1128/// iterator_types = ["reduction"]}
1129/// ins(%in : tensor<32xf32>)
1130/// outs(%out : tensor<f32>) {
1131/// ^bb0(%arg1: f32, %arg2: f32):
1132/// %y = arith.addf %arg1, %arg2 : f32
1133/// linalg.yield %y : f32
1134/// } -> tensor<f32>
1135/// ```
1136/// To:
1137/// ```
1138/// %cst = arith.constant 0.000000e+00 : f32
1139/// %0 = tensor.expand_shape %in [[0, 1]]: tensor<32xf32> into tensor<4x8xf32>
1140/// %1 = tensor.empty [4] : tensor<4xf32>
1141/// %2 = linalg.fill ins(%cst : f32)
1142/// outs(%1 : tensor<4xf32>) -> tensor<4xf32>
1143/// %3 = linalg.generic {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>,
1144/// affine_map<(d0, d1) -> (d0)>],
1145/// iterator_types = ["parallel", "reduction"]}
1146/// ins(%0 : tensor<4x8xf32>) outs(%2 : tensor<4xf32>) {
1147/// ^bb0(%arg3: f32, %arg5: f32):
1148/// %5 = arith.addf %arg3, %arg4 : f32
1149/// linalg.yield %5 : f32
1150/// } -> tensor<4xf32>
1151/// %r = linalg.generic {indexing_maps = [affine_map<(d0) -> (d0)>,
1152/// affine_map<(d0) -> ()>],
1153/// iterator_types = ["reduction"]}
1154/// ins(%3 : tensor<4xf32>) outs(%out : tensor<f32>) {
1155/// ^bb0(%arg3: f32, %arg4: f32):
1156/// %5 = arith.addf %arg3, %arg4 : f32
1157/// linalg.yield %5 : f32
1158/// } -> tensor<f32>
1159/// ```
1166FailureOr<SplitReductionResult>
1167splitReduction(RewriterBase &b, LinalgOp op,
1168 const ControlSplitReductionFn &controlSplitReductionFn,
1169 bool useAlloc = false);
1170
1171/// Scaling-based implementation of the split reduction transformation.
1172/// Instead of introducing an ExpandShapeOp, this rewrites a reduction
1173/// dimension `k` into `k * scale + kk`.
1174///
1175/// Example:
1176/// ```
1177/// %0 = linalg.matmul ins(%A, %B: tensor<16x256xf32>, tensor<256x32xf32>)
1178/// outs(%C: tensor<16x32xf32>) -> tensor<16x32xf32>
1179/// ```
1180///
1181/// Is transformed to:
1182///
1183/// ```
1184/// #map0 = affine_map<(d0, d1, d2, d3) -> (d0, d2 * 4 + d3)>
1185/// #map1 = affine_map<(d0, d1, d2, d3) -> (d2 * 4 + d3, d1)>
1186/// #map2 = affine_map<(d0, d1, d2, d3) -> (d2, d3)>
1187/// #map3 = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2)>
1188/// #map4 = affine_map<(d0, d1, d2) -> (d0, d1, d2)>
1189/// #map5 = affine_map<(d0, d1, d2) -> (d0, d1)>
1190/// %0 = tensor.empty [16, 32, 64] : tensor<16x32x64xf32>
1191/// %cst = arith.constant 0.000000e+00 : f32
1192/// %1 = linalg.fill ins(%cst : f32) outs(%0 : tensor<16x32x64xf32>) ->
1193/// tensor<16x32x64xf32>
1194/// %2 = tensor.empty [64, 4] : tensor<64x4xi1>
1195///
1196/// %3 = linalg.generic {indexing_maps = [#map0, #map1, #map2, #map3],
1197/// iterator_types = ["parallel", "parallel", "parallel", "reduction"]}
1198/// ins(%A, %B, %2 : tensor<16x256xf32>, tensor<256x32xf32>,
1199/// tensor<64x4xi1>)
1200/// outs(%1 : tensor<16x32x64xf32>) {
1201/// ^bb0(%arg3: f32, %arg4: f32, %arg5: i1, %arg6: f32):
1202/// %5 = arith.mulf %arg3, %arg4 : f32
1203/// %6 = arith.addf %arg6, %5 : f32
1204/// linalg.yield %6 : f32
1205/// } -> tensor<16x32x64xf32>
1206///
1207/// %4 = linalg.generic {indexing_maps = [#map4, #map5],
1208/// iterator_types = ["parallel", "parallel", "reduction"]}
1209// ins(%3 : tensor<16x32x64xf32>)
1210/// outs(%C : tensor<16x32xf32>) {
1211/// ^bb0(%arg3: f32, %arg4: f32):
1212/// %5 = arith.addf %arg3, %arg4 : f32
1213/// linalg.yield %5 : f32
1214/// } -> tensor<16x32xf32>
1215///
1216/// return %4 : tensor<16x32xf32>
1217/// ```
1218FailureOr<SplitReductionResult>
1220 const ControlSplitReductionFn &controlSplitReductionFn,
1221 bool useAlloc = false);
1222
1223/// Return `true` if a given sequence of dimensions are contiguous in the
1224/// range of the specified indexing map.
1226/// Return `true` if all sequences of dimensions specified in `dimSequences` are
1227/// contiguous in all the ranges of the `maps`.
1229 ArrayRef<ReassociationIndices> dimSequences);
1230
1235
1236/// Collapses dimensions of linalg.generic/linalg.copy operation. A precondition
1237/// to calling this method is that for each list in `foldedIterationDim`, the
1238/// sequence of dimensions is contiguous in domains of all `indexing_maps` of
1239/// the `linalgOp`. This can be checked using `areDimSequencePreserved` method.
1240/// When valid, the method also collapses the operands of the op. Returns
1241/// replacement values of the results of the original `linalgOp` by inserting
1242/// reshapes to get back values of compatible types.
1243FailureOr<CollapseResult>
1245 ArrayRef<ReassociationIndices> foldedIterationDims,
1246 RewriterBase &rewriter);
1247
1249 tensor::PadOp padOp;
1250 tensor::ExpandShapeOp expandShapeOp;
1251 linalg::TransposeOp transposeOp;
1252};
1253
1254/// Rewrite pack as pad + reshape + transpose.
1255FailureOr<LowerPackResult> lowerPack(RewriterBase &rewriter,
1256 linalg::PackOp packOp,
1257 bool lowerPadLikeWithInsertSlice = true);
1258
1260 tensor::EmptyOp emptyOp;
1261 linalg::TransposeOp transposeOp;
1262 tensor::CollapseShapeOp collapseShapeOp;
1263 tensor::ExtractSliceOp extractSliceOp;
1264};
1265
1266/// Rewrite pack as empty + transpose + reshape + extract_slice.
1267FailureOr<LowerUnPackOpResult>
1268lowerUnPack(RewriterBase &rewriter, linalg::UnPackOp unPackOp,
1269 bool lowerUnpadLikeWithExtractSlice = true);
1270
1271/// Struct to hold the result of a `pack` call.
1277/// Implement packing of a single LinalgOp by `packedSizes`.
1278/// There must be one packedSizes entry per `linalgOp` iterator.
1279/// Return the packed Linalg op on success, failure otherwise.
1280FailureOr<PackResult> pack(RewriterBase &rewriter, linalg::LinalgOp linalgOp,
1281 ArrayRef<OpFoldResult> packedSizes);
1282
1283/// Struct to hold the result of a `packTranspose` call.
1285 linalg::PackOp transposedPackOp;
1286 linalg::LinalgOp transposedLinalgOp;
1287 linalg::UnPackOp transposedUnPackOp;
1288};
1289/// Transpose a single PackOp -> LinalgOp -> UnPackOp chain and return the
1290/// transposed PackOp -> LinalgOp -> UnPackOp chain after replacements.
1291/// Return failure if either:
1292/// 1. the `packOp` does not have the `linalgOp` as its unique use.
1293/// 2. the `maybeUnPackOp`, if specified must be a consumer of the result tied
1294/// to the unique `packOp` use.
1295/// 3. `outerPerm` (resp. `innerPerm`) must be valid permutations of
1296/// `packOp.getOuterDimsPerm` (resp. `packOp.getInnerDimsPerm`) or empty.
1297FailureOr<PackTransposeResult>
1298packTranspose(RewriterBase &rewriter, linalg::PackOp packOp,
1299 linalg::LinalgOp linalgOp, linalg::UnPackOp maybeUnPackOp,
1300 ArrayRef<int64_t> outerPerm, ArrayRef<int64_t> innerPerm);
1301
1302/// Pack a LinalgOp by greedily inferring matmul dimensions (m, n, k) where m
1303/// and n are proper parallel dimensions and k is a proper reduction
1304/// dimension. Packing occurs by rewriting the op as a linalg.generic and
1305/// calling linalg::pack by `mnkPackedSizes`. The order of the packed
1306/// dimensions is customizable: the `mnkOrder` is a permutation of {0, 1, 2}
1307/// to reorder {m, n, k} into one of the 8 possible forms. The outer
1308/// dimensions of the operands are not permuted at this time, this is left for
1309/// future work.
1310FailureOr<PackResult>
1311packMatmulGreedily(RewriterBase &rewriter, LinalgOp linalgOp,
1312 ArrayRef<OpFoldResult> mnkPackedSizes,
1313 ArrayRef<int64_t> mnkPaddedSizesNextMultipleOf,
1314 ArrayRef<int64_t> mnkOrder);
1315
1317 /// Minor block factors (mb, nb, kb) for packing relayout where mb, mn are
1318 /// the parallel dimensions and kb is the reduction dimension.
1320
1321 /// If true, allows packing of dimensions that only partially fit into the
1322 /// block factors.
1323 bool allowPadding = true;
1324
1325 /// Next multiples of the packing sizes.
1327
1328 /// Permutation of matmul (M, N, K) dimensions order.
1330
1331 /// Transpose LHS outer block layout [MB][KB] -> [KB][MB].
1333
1334 /// Transpose LHS inner block layout [mb][kb] -> [kb][mb].
1336
1337 /// Transpose RHS outer block layout [KB][NB] -> [NB][KB].
1339
1340 /// Transpose RHS inner block layout [kb][nb] -> [nb][kb].
1342};
1343
1344/// Function type which is used to control matmul packing.
1345/// It is expected to return valid packing configuration for each operation.
1346/// Lack of packing options indicates that no valid configuration could be
1347/// assigned and the operation will not be packed.
1349 std::function<std::optional<BlockPackMatmulOptions>(linalg::LinalgOp)>;
1350
1351/// Pack a matmul operation into blocked 4D layout.
1352///
1353/// Relayout a matmul operation into blocked layout with two levels of
1354/// subdivision:
1355/// - major 2D blocks - outer dimensions, consist of minor blocks
1356/// - minor 2D blocks - inner dimensions, consist of scalar elements
1357///
1358/// A 2D matmul MxNxK gets reshaped into blocked 4D representation
1359/// as: [MB][NB][mb][nb] += [MB][KB][mb][kb] * [NB][KB][nb][kb]
1360/// where the (MB, NB, KB) dimensions represent the major blocks,
1361/// and the (mb, nb, kb) are the minor blocks of their respective
1362/// original 2D dimensions (M, N, K).
1363///
1364/// Depending on the initial operands' data layout and the specified
1365/// packing options, the major blocks dimensions might get transposed
1366/// e.g., [MB][KB] -> [KB][MB]. The minor blocks can also be transposed
1367/// e.g., [mb][kb] -> [kb][mb].
1368/// Any present batch dimensions remain unchanged.
1369/// The final result is unpacked back to the original shape.
1370///
1371/// Return failure if no valid packing options are provided.
1372FailureOr<PackResult>
1373blockPackMatmul(RewriterBase &rewriter, linalg::LinalgOp linalgOp,
1374 const ControlBlockPackMatmulFn &controlPackMatmul);
1375
1376/// Rewrite tensor.from_elements to linalg.generic.
1377FailureOr<Operation *>
1379 tensor::FromElementsOp fromElementsOp);
1380
1381/// Rewrite tensor.generate to linalg.generic.
1382FailureOr<Operation *>
1384 tensor::GenerateOp generateOp);
1385
1386/// Rewrite tensor.pad to linalg.generic + tensor.insert_slice.
1387FailureOr<Operation *> rewriteInDestinationPassingStyle(RewriterBase &rewriter,
1388 tensor::PadOp padOp);
1389
1390/// Convert linalg.conv_2d_nhwc_hwcf into linalg.generic (for img2col packing)
1391/// and linalg.matmul.
1392///
1393/// A convolution operation can be written as a matrix-matrix multiplication by
1394/// unfolding the cross-correlation between input and filter and explicitly copy
1395/// overlapped sliding window inputs.
1396///
1397/// Consider 2D input X with single channel input and output and 2x2 filter W:
1398/// [x(0, 0) , x(0, 1) , ..., x(0, n) ]
1399/// [x(1, 0) , x(1, 1) , ..., x(1, n) ]
1400/// [. , . ,. , . ] [w(0, 0), w(0, 1)]
1401/// [. , . , . , . ] (conv) [w(1, 0), w(1, 1)]
1402/// [. , . , ., . ]
1403/// [x(n-1, 0), x(n-1, 1), ..., x(n-1, n-1)]
1404///
1405/// The packed input data (img2col) is a matrix with |rows| = output spatial
1406/// size, |columns| = filter spatial size. To compute the output Y(i, j) we need
1407/// to calculate the dot product between filter window at input X(x, y)) and the
1408/// filter which will look like the following where r.h.s is the img2col matrix
1409/// and l.h.s is the flattened filter:
1410///
1411/// [x(0,0), x(0,1), x(1,0), x(1,1)]
1412/// [x(0,1), x(1,1), x(0,2), x(1,2)] (matmul) [w(0,0), w(0,1), w(1,0), w(1,1)]
1413/// [x(0,1), x(1,1), x(0,2), x(1,2)]
1414/// [ . , . , . , . ]
1415///
1416/// In general for 2D case with (N, H, W, C) input and (Kh, Kw, C, D) filter
1417/// and output (N, Ho, Wo, D) the convolution is the following matrix-matrix
1418/// multiplication (Ho x Wo, Kh x Kw x C) * (Kh x Kw x C, D) for each input in
1419/// the N input. For the case where N > 1 its a batched matrix-matrix
1420/// multiplication.
1421///
1422/// On success, return both the operation that produces the img2col tensor and
1423/// the final operation of the sequence that replaces the original convolution.
1424FailureOr<std::pair<Operation *, Operation *>>
1425rewriteInIm2Col(RewriterBase &rewriter, linalg::Conv2DNhwcHwcfOp convOp);
1426
1427/// Same as the above but for Fhwc channel orderings in the filter. In this case
1428/// the matrix multiplication is actually a row-wise dot-product rather than a
1429/// row-column dot-product. This is to avoid transposing the filter matrix which
1430/// would be required for a regular matrix multiplication to produce the correct
1431/// output dimensions.
1432FailureOr<std::pair<Operation *, Operation *>>
1433rewriteInIm2Col(RewriterBase &rewriter, linalg::Conv2DNhwcFhwcOp convOp);
1434
1435/// Similar to rewriteInIm2Col with linalg::Conv2DNhwcHwcfOp except there is no
1436/// reduction among the input channels so each convolution can be a
1437/// matrix-vector product and by transposing both input filter so channels are
1438/// outer most the computation is a batched matrix-vector product.
1439FailureOr<std::pair<Operation *, Operation *>>
1441 linalg::DepthwiseConv2DNhwcHwcOp convOp);
1442
1443/// Similar to rewriteInIm2Col with linalg::Conv2DNhwcHwcfOp except because the
1444/// channels are to the left of the image shape dimensions, the position of the
1445/// contraction dimension in the resulting matmul is reversed. This swaps the
1446/// LHS and RHS of the matmul when compared with nhwc (i.e. (D, C x Kh x Kw) *
1447/// (C x Kh x Kw, Ho x Wo))
1448FailureOr<std::pair<Operation *, Operation *>>
1449rewriteInIm2Col(RewriterBase &rewriter, linalg::Conv2DNchwFchwOp convOp);
1450
1451/// Convert linalg.conv_2d_nhwc_fhwc(_q) to linalg.conv_2d_nhwc_hwcf(_q) by
1452/// materializing transpose.
1453FailureOr<Operation *> transposeConv2D(RewriterBase &rewriter,
1454 linalg::Conv2DNhwcFhwcOp op);
1455FailureOr<Operation *> transposeConv2D(RewriterBase &rewriter,
1456 linalg::Conv2DNhwcFhwcQOp op);
1457
1458/// Convert Linalg matmul ops to transposed variants.
1459FailureOr<Operation *> transposeMatmul(RewriterBase &rewriter,
1460 linalg::MatmulOp op,
1461 bool transposeLHS = true);
1462FailureOr<Operation *> transposeBatchMatmul(RewriterBase &rewriter,
1463 linalg::BatchMatmulOp op,
1464 bool transposeLHS = true);
1465
1466/// Convert linalg.conv_2d_nhwc_fhwc to Winograd Conv2D algorithm
1467/// F(m x m, r x r). m is the dimension size of output and r is the dimension
1468/// size of filter.
1469FailureOr<Operation *> winogradConv2D(RewriterBase &rewriter,
1470 linalg::Conv2DNhwcFhwcOp op,
1471 WinogradConv2DFmr fmr);
1472
1473/// Rewrite linalg.winograd_filter_transform. The data layout of the filter is
1474/// FHWC. The transformation matrix is 2-dimension. We need to extract H x W
1475/// from FHWC first. We generate 2 levels of loops to iterate on F and C. After
1476/// the rewriting, we get
1477///
1478/// scf.for %f = lo_f to hi_f step 1
1479/// scf.for %c = lo_c to hi_c step 1
1480/// %extracted = extract filter<h x w> from filter<f x h x w x c>
1481/// %ret = linalg.matmul G, %extracted
1482/// %ret = linalg.matmul %ret, GT
1483/// %inserted = insert %ret into filter<h x w x c x f>
1484FailureOr<Operation *>
1486 linalg::WinogradFilterTransformOp op);
1487
1488/// Rewrite linalg.winograd_input_transform. The data layout of the input is
1489/// NHWC. The transformation matrix is 2-dimension. We need to extract H x W
1490/// from NHWC first. We generate 4 levels of loops to iterate on N, C, tileH,
1491/// and tileW. After the rewriting, we get
1492///
1493/// scf.for %h = 0 to tileH step 1
1494/// scf.for %w = 0 to tileW step 1
1495/// scf.for %n = 0 to N step 1
1496/// scf.for %c = 0 to C step 1
1497/// %extracted = extract %extracted<alphaH x alphaW> from
1498/// %input<N x H x W x C>
1499/// at [%n, (%h x m), (%w x m), %c]
1500/// %ret = linalg.matmul BT, %extracted
1501/// %ret = linalg.matmul %ret, B
1502/// %inserted = insert %ret<alphaH x alphaW> into
1503/// %output<alphaH x alphaW x tileH x tileW x N x C>
1504/// at [0, 0, %h, %w, %n, %c]
1505FailureOr<Operation *>
1507 linalg::WinogradInputTransformOp op);
1508
1509/// Rewrite linalg.winograd_output_transform. The data layout of the output is
1510/// HWNF. The transformation matrix is 2-dimension. We need to extract H x W
1511/// from HWNF first. We generate 4 levels of loops to iterate on N, F, tileH,
1512/// and tileW. After the transformation, we get
1513///
1514/// scf.for %h = 0 to tileH step 1
1515/// scf.for %w = 0 to tileW step 1
1516/// scf.for %n = 0 to N step 1
1517/// scf.for %f = 0 to F step 1
1518/// %extracted = extract %extracted<alphaH x alphaW> from
1519/// %input<alphaH x alphaW x tileH x tileW x N x F>
1520/// at [0, 0, %h, %w, %n, %f]
1521/// %ret = linalg.matmul AT, %extracted
1522/// %ret = linalg.matmul %ret, A
1523/// %inserted = insert %ret<alphaH x alphaW> into
1524/// output<N x H x W x F>
1525/// at [%n, (%h x m), (%w x m), %f]
1526FailureOr<Operation *>
1528 linalg::WinogradOutputTransformOp op);
1529
1530/// Method to deduplicate operands and remove dead results of `linalg.generic`
1531/// operations. This is effectively DCE for a linalg.generic op. If there is
1532/// deduplication of operands orremoval of results, replaces the `genericOp`
1533/// with a new op and returns it. Returns the same operation if there is no
1534/// deduplication/removal.
1535FailureOr<linalg::GenericOp> deduplicateOperandsAndRemoveDeadResults(
1536 RewriterBase &rewriter, linalg::GenericOp genericOp, bool removeOutputs);
1537
1538//===----------------------------------------------------------------------===//
1539// Rewrite patterns wrapping transformations.
1540// TODO: every single such pattern should be a close to noop wrapper around a
1541// functional-stye API call.
1542//===----------------------------------------------------------------------===//
1543
1544/// Rewrites 2-D convolution ops with size-1 window dimensions into 1-D
1545/// convolution ops.
1546template <typename Conv2DOp, typename Conv1DOp>
1548 : public OpRewritePattern<Conv2DOp> {
1549 using OpRewritePattern<Conv2DOp>::OpRewritePattern;
1550
1551 FailureOr<Conv1DOp> returningMatchAndRewrite(Conv2DOp convOp,
1552 PatternRewriter &rewriter) const;
1553
1554 LogicalResult matchAndRewrite(Conv2DOp convOp,
1555 PatternRewriter &rewriter) const override {
1556 return returningMatchAndRewrite(convOp, rewriter);
1557 }
1558};
1559
1560extern template struct DownscaleSizeOneWindowed2DConvolution<Conv2DNhwcHwcfOp,
1561 Conv1DNwcWcfOp>;
1562extern template struct DownscaleSizeOneWindowed2DConvolution<Conv2DNchwFchwOp,
1563 Conv1DNcwFcwOp>;
1564
1565/// Rewrites 2-D depthwise convolution ops with size-1 (w, kw) or (h, kh)
1566/// dimensions into 1-D depthwise convolution ops.
1568 : public OpRewritePattern<DepthwiseConv2DNhwcHwcOp> {
1570 PatternBenefit benefit = 1)
1571 : OpRewritePattern<DepthwiseConv2DNhwcHwcOp>(context, benefit) {}
1572
1573 FailureOr<DepthwiseConv1DNwcWcOp>
1574 returningMatchAndRewrite(DepthwiseConv2DNhwcHwcOp convOp,
1575 PatternRewriter &rewriter) const;
1576
1577 LogicalResult matchAndRewrite(DepthwiseConv2DNhwcHwcOp convOp,
1578 PatternRewriter &rewriter) const override {
1579 return returningMatchAndRewrite(convOp, rewriter);
1580 }
1581};
1582
1583struct DownscaleConv2DOp final : public OpRewritePattern<Conv2DOp> {
1585 : OpRewritePattern<Conv2DOp>(context, benefit) {}
1586
1587 FailureOr<Conv1DOp> returningMatchAndRewrite(Conv2DOp convOp,
1588 PatternRewriter &rewriter) const;
1589
1590 LogicalResult matchAndRewrite(Conv2DOp convOp,
1591 PatternRewriter &rewriter) const override {
1592 return returningMatchAndRewrite(convOp, rewriter);
1593 }
1594};
1595
1596///
1597/// Linalg generalization pattern.
1598///
1599/// Apply the `generalization` transformation as a pattern.
1600/// See `generalization` for more details.
1601//
1602// TODO: Automatic default pattern class that just unwraps a function
1603// returning FailureOr<GenericOp>.
1605 : public OpInterfaceRewritePattern<LinalgOp> {
1607
1608 /// `matchAndRewrite` implementation that returns the significant
1609 /// transformed pieces of IR.
1610 FailureOr<GenericOp>
1611 returningMatchAndRewrite(LinalgOp op, PatternRewriter &rewriter) const {
1612 return generalizeNamedOp(rewriter, op);
1613 }
1614
1615 LogicalResult matchAndRewrite(LinalgOp op,
1616 PatternRewriter &rewriter) const override {
1617 return returningMatchAndRewrite(op, rewriter);
1618 }
1619};
1620
1622 using OpRewritePattern<GenericOp>::OpRewritePattern;
1623
1624 FailureOr<GenericOp>
1625 returningMatchAndRewrite(GenericOp op, PatternRewriter &rewriter) const {
1626 return specializeGenericOp(rewriter, op);
1627 }
1628
1629 LogicalResult matchAndRewrite(GenericOp op,
1630 PatternRewriter &rewriter) const override {
1631 return returningMatchAndRewrite(op, rewriter);
1632 }
1633};
1634
1635/// Vectorization pattern for memref::CopyOp.
1636struct CopyVectorizationPattern : public OpRewritePattern<memref::CopyOp> {
1637 using OpRewritePattern<memref::CopyOp>::OpRewritePattern;
1638
1639 LogicalResult matchAndRewrite(memref::CopyOp copyOp,
1640 PatternRewriter &rewriter) const override;
1641};
1642
1644 std::function<LogicalResult(RewriterBase &, tensor::PadOp, Value)>;
1645
1646/// Rewrite a tensor::PadOp into a sequence of EmptyOp, FillOp and
1647/// InsertSliceOp. For now, only constant padding values are supported.
1648struct DecomposePadOpPattern : public OpRewritePattern<tensor::PadOp> {
1650 : OpRewritePattern<tensor::PadOp>(context, benefit) {}
1651 LogicalResult matchAndRewrite(tensor::PadOp padOp,
1652 PatternRewriter &rewriter) const override;
1653
1654protected:
1655 Value createFillOrGenerateOp(RewriterBase &rewriter, tensor::PadOp padOp,
1656 Value dest,
1657 const SmallVector<Value> &dynSizes) const;
1658};
1659
1660/// Rewrites a linalg::PackOp into a sequence of:
1661/// * tensor::PadOp + linalg::TransposeOp + tensor::EmptyOp +
1662/// tensor::InsertSliceOp ops.
1663/// (InsertSliceOp is rank-expanding).
1664///
1665/// Requires that all the tiled-outer-dims of the input linalg::PackOp are 1.
1666/// Note that this constraint means that effectively exactly one tile is packed.
1667///
1668/// In addition, assumes that the un-tiled-outer-dims are not permuted.
1669///
1670/// Before:
1671/// ```
1672/// %packed = linalg.pack %input
1673/// padding_value(%pad : f32)
1674/// inner_dims_pos = [1, 0]
1675/// inner_tiles = [2, %high]
1676/// into %output : tensor<5x1xf32> -> tensor<1x1x2x?xf32>
1677/// ```
1678///
1679/// After:
1680/// ```
1681/// // PadOp
1682/// %padded = tensor.pad %arg0 low[0, 0] high[%0, 1] {
1683/// ^bb0(...):
1684/// tensor.yield %arg2 : f32
1685/// } : tensor<5x1xf32> to tensor<?x2xf32>
1686/// // EmptyOp + TransposeOp
1687/// %empty = tensor.empty(%arg3) : tensor<2x?xf32>
1688/// %transposed = linalg.transpose
1689/// ins(%extracted_slice : tensor<?x2xf32>)
1690/// outs(%empty : tensor<2x?xf32>)
1691/// permutation = [1, 0]
1692/// // InsertSliceOp
1693/// %inserted_slice = tensor.insert_slice %transposed
1694/// into %arg1[0, 0, 0, 0] [1, 1, 2, %tile_dim_1] [1, 1, 1, 1]
1695/// : tensor<2x?xf32> into tensor<1x1x2x?xf32>
1696/// ```
1698 : public OpRewritePattern<linalg::PackOp> {
1699 using OpRewritePattern<linalg::PackOp>::OpRewritePattern;
1700 LogicalResult matchAndRewrite(linalg::PackOp packOp,
1701 PatternRewriter &rewriter) const override;
1702};
1703
1704/// Rewrites a linalg::UnPackOp into a sequence of:
1705/// * tensor::ExtractSliceOp + linalg::TransposeOp + tensor::InsertSliceOp
1706/// (ExtractSliceOp is rank-reducing).
1707///
1708/// Requires that all the tiled-outer-dims of the input linalg::UnPackOp are 1.
1709/// Note that this constraint means that effectively exactly one tile is
1710/// unpacked.
1711///
1712/// Before:
1713/// ```
1714/// %packed = linalg.unpack %input
1715/// inner_dims_pos = [1, 0]
1716/// inner_tiles = [2, 8]
1717/// into %output : tensor<1x1x2x8xf32> -> tensor<5x1xf32>
1718/// ```
1719///
1720/// After:
1721/// ```
1722/// // Rank-reduced extract to obtain the tile
1723/// %slice = tensor.extract_slice %arg0[0, 0, 0, 0] [1, 1, 2, 8] [1, 1, 1, 1]
1724/// : tensor<1x1x2x8xf32> to tensor<2x8xf32>
1725/// // EmptyOp + TransposeOp
1726/// %init = tensor.empty() : tensor<8x2xf32>
1727/// %transposed = linalg.transpose
1728/// ins(%extracted_slice : tensor<2x8xf32>)
1729/// outs(%0 : tensor<8x2xf32>) permutation = [1, 0]
1730/// // Extract a slice matching the specified output size
1731/// %result = tensor.extract_slice %transposed[0, 0] [5, 1] [1, 1]
1732/// : tensor<8x2xf32> to tensor<5x1xf32>
1733/// ```
1735 : public OpRewritePattern<linalg::UnPackOp> {
1736 using OpRewritePattern<linalg::UnPackOp>::OpRewritePattern;
1737 LogicalResult matchAndRewrite(linalg::UnPackOp unpackOp,
1738 PatternRewriter &rewriter) const override;
1739};
1740
1741/// Match and rewrite for the pattern:
1742/// ```
1743/// %alloc = ...
1744/// [optional] %view = memref.view %alloc ...
1745/// %subView = subview %allocOrView ...
1746/// [optional] linalg.fill(%allocOrView, %cst) ...
1747/// ...
1748/// memref.copy(%in, %subView) ...
1749/// vector.transfer_read %allocOrView[...], %cst ...
1750/// ```
1751/// into
1752/// ```
1753/// [unchanged] %alloc = ...
1754/// [unchanged] [optional] %view = memref.view %alloc ...
1755/// [unchanged] [unchanged] %subView = subview %allocOrView ...
1756/// ...
1757/// vector.transfer_read %in[...], %cst ...
1758/// ```
1759/// Where there is no interleaved use between memref.copy and transfer_read as
1760/// well as no interleaved use between linalg.fill and memref.copy (if
1761/// linalg.fill is specified).
1762/// This is a custom rewrite to forward partial reads (with optional fills) to
1763/// vector.transfer_read.
1765 : public OpRewritePattern<vector::TransferReadOp> {
1766 using OpRewritePattern<vector::TransferReadOp>::OpRewritePattern;
1767
1768 LogicalResult matchAndRewrite(vector::TransferReadOp xferOp,
1769 PatternRewriter &rewriter) const override;
1770};
1771
1772/// Match and rewrite for the pattern:
1773/// ```
1774/// %alloc = ...
1775/// [optional] %view = memref.view %alloc ...
1776/// %subView = subview %allocOrView...
1777/// ...
1778/// vector.transfer_write %..., %allocOrView[...]
1779/// memref.copy(%subView, %out)
1780/// ```
1781/// into
1782/// ```
1783/// [unchanged] %alloc = ...
1784/// [unchanged] [optional] %view = memref.view %alloc ...
1785/// [unchanged] %subView = subview %allocOrView...
1786/// ...
1787/// vector.transfer_write %..., %out[...]
1788/// ```
1789/// Where there is no interleaved use between transfer_write and memref.copy.
1790/// This is a custom rewrite to forward partial writes to
1791/// vector.transfer_write.
1793 : public OpRewritePattern<vector::TransferWriteOp> {
1794 using OpRewritePattern<vector::TransferWriteOp>::OpRewritePattern;
1795
1796 LogicalResult matchAndRewrite(vector::TransferWriteOp xferOp,
1797 PatternRewriter &rewriter) const override;
1798};
1799
1800/// Rewrite extract_slice(tensor.pad(x)) into tensor.pad(extract_slice(x)).
1802 : public OpRewritePattern<tensor::ExtractSliceOp> {
1803 /// A function to control pattern application and rewrite logic.
1804 ///
1805 /// The function will be given the slice op and should return:
1806 /// - std::nullopt: to fail the match and not apply the pattern;
1807 /// - true: to apply the pattern with zero slice guard;
1808 /// - false: to apply the pattern without zero slice guard.
1809 ///
1810 /// See the documentation for tensor::bubbleUpPadSlice regarding zero slice
1811 /// guard.
1812 using ControlFn = std::function<std::optional<bool>(tensor::ExtractSliceOp)>;
1813
1815 ControlFn controlFn = nullptr,
1816 PatternBenefit benefit = 1)
1817 : OpRewritePattern(context, benefit), controlFn(std::move(controlFn)) {}
1818
1819 LogicalResult matchAndRewrite(tensor::ExtractSliceOp sliceOp,
1820 PatternRewriter &rewriter) const override;
1821
1822private:
1823 ControlFn controlFn;
1824};
1825
1826//===----------------------------------------------------------------------===//
1827// Populate functions.
1828//===----------------------------------------------------------------------===//
1829
1830/// Canonicalization patterns relevant to apply after tiling patterns. These
1831/// are applied automatically by the tiling pass but need to be applied
1832/// manually when tiling is called programmatically.
1835
1836/// Linalg generalization patterns
1837
1838/// Populates `patterns` with patterns to convert spec-generated named ops to
1839/// linalg.generic ops.
1841
1842/// Populates `patterns` with patterns to convert linalg.generic ops to named
1843/// ops where possible. A linalg.generic can represent wide range and complex
1844/// computations for which equivalent linalg named op may not exist e.g.
1845/// linalg.generic that takes a tensor and computes a polynomial such as:
1846/// p(x) = an*x^n + ... + a1x + a0
1847/// There is no equivalent named op to convert to. Many such cases exist.
1850
1851/// Populates `patterns` that convert linalg named ops e.g. `linalg.add`
1852/// to equivalent `linalg.elementwise`.
1854
1855/// Populates `patterns` with patterns that fold operations like
1856/// `linalg.transform` into elementwise op map.
1858
1859/// Linalg decompose convolutions patterns
1860
1861/// Populates patterns to decompose high-D convolution ops into low-D ones.
1862/// This is a step in progressive lowering for convolution ops, afterwards we
1863/// can vectorize the low-D convolution ops.
1865 PatternBenefit benefit = 1);
1866
1867/// Populates patterns to decompose linalg.pack and linalg.unpack Ops into e.g.
1868/// tensor.pad, linalg.transpose, tensor.{insert|extract}_slice. Require all
1869/// outer dims to be unit.
1871
1872/// Populates patterns to decompose tensor.pad into e.g.
1873/// tensor.empty, linalg.fill, tensor.insert_slice.
1875
1876/// Populates patterns to transform linalg.conv_2d_xxx operations into
1877/// linalg.generic (for img2col packing) and linalg.matmul.
1878/// Note: currently limited to Tensor semantics only.
1879/// \see rewriteInIm2Col for more details.
1881
1882/// Populates `patterns` with patterns that vectorize tensor.pad.
1883/// These patterns are meant to apply in a complementary fashion. Benefits
1884/// are used to encode a certain ordering of pattern application. To avoid
1885/// scattering magic constants throughout the code base, the patterns must be
1886/// added with this function. `baseBenefit` can be used to offset the benefit
1887/// of all tensor::PadOp vectorization patterns by a certain value.
1889 PatternBenefit baseBenefit = 1);
1890
1891/// Populate patterns for splitting a `LinalgOp` with multiple statements within
1892/// its payload into multiple `GenericOp` that have a single statement.
1893/// The option `removeDeadArgsAndResults` adds patterns to remove dead arguments
1894/// and results from the generated decomposed ops. This is default `true` since
1895/// the core decomposition patterns relies on these clean up patterns. It is set
1896/// to false only for testing purposes.
1898 bool removeDeadArgsAndResults = true);
1899
1900/// Populate patterns that convert non-destination-style ops to destination
1901/// style ops.
1903
1904/// Populate patterns for vectorizing low-D convolution ops. This is a step in
1905/// progressive lowering for convolution ops, it assume high-D convolution ops
1906/// were decomposed previously.
1908 PatternBenefit benefit = 1);
1909
1910/// Populate patterns that convert `ElementwiseMappable` ops to linalg
1911/// parallel loops.
1913
1914/// Populate patterns that are only useful in the context of sparse tensors.
1916
1917/// Function type which is used to control when to stop fusion. It is expected
1918/// that OpOperand is not modified in the callback. The OpOperand is not marked
1919/// as const to allow callers to use non-const methods.
1920using ControlFusionFn = std::function<bool(OpOperand *fusedOperand)>;
1921
1922/// Patterns for fusing linalg operation on tensors.
1923
1924/// Pattern to fuse `linalg.generic` -> `linalg.generic` operations
1925/// when both operations are fusable elementwise operations.
1928 const ControlFusionFn &controlElementwiseOpFusion);
1929
1930/// Function type which is used to control propagation of linalg.pack/unpack
1931/// ops.
1932using ControlPropagationFn = std::function<bool(OpOperand *opOperand)>;
1933
1934/// Patterns to bubble up or down data layout ops across other operations.
1935/// The function also has an option to allow the patterns to propagate with
1936/// poison padding if requested by the caller.
1939 const ControlPropagationFn &controlPackUnPackPropagation,
1940 bool PoisonPaddingOk = false);
1941
1942/// Patterns to sink extract slice across other operations.
1945 const ControlPropagationFn &controlPackUnPackPropagation);
1946
1947/// Pattern to remove dead operands and results of `linalg.generic` operations.
1948/// This is a pattern wrapper for `deduplicateOperandsAndRemoveDeadResults`.
1950
1951/// Patterns to promote inputs to outputs and remove unused inputs of
1952/// `linalg.generic` ops.
1954
1955/// Function type to control generic op dimension collapsing. It is expected
1956/// to return an array of `ReassociationIndices` representing dimensions that
1957/// should be merged.
1959 std::function<SmallVector<ReassociationIndices>(linalg::LinalgOp)>;
1960
1961/// Pattern to collapse dimensions in a linalg.generic op. This will collapse
1962/// tensor operands when needed and expand back the result tensors.
1965 const GetCollapsableDimensionsFn &controlCollapseDimensions);
1966
1967/// Patterns to fold an expanding (collapsing) tensor_reshape operation with its
1968/// producer (consumer) generic operation by expanding the dimensionality of the
1969/// loop in the generic op.
1971 RewritePatternSet &patterns, const ControlFusionFn &controlFoldingReshapes);
1972
1973/// Patterns to fold an expanding tensor.expand_shape operation with its
1974/// producer generic operation by collapsing the dimensions of the generic op.
1976 RewritePatternSet &patterns, const ControlFusionFn &controlFoldingReshapes);
1977
1978/// Patterns to constant fold Linalg operations.
1980 const ControlFusionFn &controlFn);
1981
1982/// Pattern to replace `linalg.add` when destination passing on a contraction op
1983/// suffices for achieving the sum.
1985
1986/// Pattern to fuse a `tensor.pad` operation with the producer of its source,
1987/// if the producer is a `linalg` operation with all parallel iterator types.
1990
1991/// Patterns to simplify depthwise convolutions.
1993
1994/// Patterns to fold unit-extent dimensions in operands/results of linalg ops on
1995/// tensors via reassociative reshape ops.
1998
1999/// A pattern that converts init operands to input operands.
2001
2002/// Patterns that are used to inline constant operands into linalg generic ops.
2004
2005/// Patterns that are used to bubble up extract slice op above linalg op.
2007
2008/// Adds patterns that waps tensor.extract_slice(linalg.fill(%cst, %init)) into
2009/// linalg.fill(%cst, tensor.extract_slice(%init)).
2011
2012/// Add patterns to make explicit broadcasts and transforms in the
2013/// input operands of a genericOp.
2015
2016/// Patterns to apply `splitReduction` below.
2019 const ControlSplitReductionFn &controlSplitReductionFn,
2020 bool useAlloc = false);
2021
2022/// Patterns to convert Linalg matmul ops to transposed variants.
2024 bool transposeLHS = true);
2025
2026/// Patterns to block pack Linalg matmul ops.
2028 const ControlBlockPackMatmulFn &controlFn);
2029
2030/// Patterns to apply Winograd Conv2D algorithm F(m x m, r x r).
2032 WinogradConv2DFmr fmr);
2033
2034/// Patterns to decompose Winograd operators.
2036
2037/// Adds patterns that reduce the rank of named contraction ops that have
2038/// unit dimensions in the operand(s) by converting to a sequence of
2039/// `collapse_shape`,
2040/// `<corresponding linalg named op>`, `expand_shape` (if on tensors). For
2041/// example a `linalg.batch_matmul` with unit batch size will convert to
2042/// `linalg.matmul` and a `linalg.matvec` with with unit spatial dim in lhs will
2043/// convert to a `linalg.dot`.
2045
2046/// Function type which is used to control folding operations like `tensor.pad`
2047/// and `tensor.extract_slice` into linalg.pack/unpack ops.
2048using ControlFoldIntoPackUnpackFn = std::function<bool(OpOperand *opOperand)>;
2049/// Populates `patterns` with patterns that fold operations like `tensor.pad`
2050/// and `tensor.extract_slice` into `tensor.pack` and `tensor.unpack` operations
2051/// respectively.
2054 const ControlFoldIntoPackUnpackFn &controlFn = nullptr);
2055
2056/// Populates `patterns` with patterns that fold operations like `linalg.pack`
2057/// and `linalg.unpack` into `tensor.empty`.
2059
2060/// Populates `patterns` with patterns that simplify `tensor.pack` and
2061/// `tensor.unpack` operations.
2063
2064} // namespace linalg
2065} // namespace mlir
2066
2067#endif // MLIR_DIALECT_LINALG_TRANSFORMS_TRANSFORMS_H
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
static llvm::ManagedStatic< PassManagerOptions > options
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
Attributes are known-constant values of operations.
Definition Attributes.h:25
The main mechanism for performing data layout queries.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
This class helps build Operations.
Definition Builders.h:207
This class represents a single result from folding an operation.
This class represents an operand of an operation.
Definition Value.h:257
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
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...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
State for analysis-enabled bufferization.
FailureOr< PackingResult > buildPackingLoopNest(RewriterBase &rewriter, tensor::PadOp opToHoist, scf::ForOp outermostEnclosingForOp, ArrayRef< int64_t > transposeVector)
Build the packing loop nest required to hoist opToHoist above outermostEnclosingForOp.
void populateDataLayoutPropagationPatterns(RewritePatternSet &patterns, const ControlPropagationFn &controlPackUnPackPropagation, bool PoisonPaddingOk=false)
Patterns to bubble up or down data layout ops across other operations.
void populateMoveInitOperandsToInputPattern(RewritePatternSet &patterns)
A pattern that converts init operands to input operands.
std::function< IndexingMapOpInterface( Location loc, OpBuilder &, IndexingMapOpInterface, ArrayRef< Value > newOperands, ArrayRef< AffineMap > newIndexingMaps, const llvm::SmallDenseSet< unsigned > &droppedDims)> DroppedUnitDimsBuilder
Definition Transforms.h:544
void populateTransposeMatmulPatterns(RewritePatternSet &patterns, bool transposeLHS=true)
Patterns to convert Linalg matmul ops to transposed variants.
void populateContractionOpRankReducingPatterns(RewritePatternSet &patterns)
Adds patterns that reduce the rank of named contraction ops that have unit dimensions in the operand(...
LogicalResult rewriteAsPaddedOp(RewriterBase &rewriter, LinalgOp opToPad, const LinalgPaddingOptions &options, LinalgOp &paddedOp, SmallVector< Value > &replacements, SmallVector< tensor::PadOp > &padOps)
Pad the iterator dimensions options.paddingDimensions of all opToPad operands to a static bounding bo...
Definition Padding.cpp:244
void populateSplitReductionPattern(RewritePatternSet &patterns, const ControlSplitReductionFn &controlSplitReductionFn, bool useAlloc=false)
Patterns to apply splitReduction below.
void populateFuseTensorPadWithProducerLinalgOpPatterns(RewritePatternSet &patterns)
Pattern to fuse a tensor.pad operation with the producer of its source, if the producer is a linalg o...
FailureOr< std::pair< Operation *, Operation * > > rewriteInIm2Col(RewriterBase &rewriter, linalg::Conv2DNhwcHwcfOp convOp)
Convert linalg.conv_2d_nhwc_hwcf into linalg.generic (for img2col packing) and linalg....
bool areDimSequencesPreserved(ArrayRef< AffineMap > maps, ArrayRef< ReassociationIndices > dimSequences)
Return true if all sequences of dimensions specified in dimSequences are contiguous in all the ranges...
bool hasVectorizationImpl(Operation *)
Return true if there's dedicated logic in the Linalg Vectorizer to vectorize this Op,...
void populateExtractSliceSinkingPatterns(RewritePatternSet &patterns, const ControlPropagationFn &controlPackUnPackPropagation)
Patterns to sink extract slice across other operations.
void populateBubbleUpExtractSliceOpPatterns(RewritePatternSet &patterns)
Patterns that are used to bubble up extract slice op above linalg op.
SmallVector< Operation *, 4 > LinalgLoops
Definition Transforms.h:517
void transformIndexOps(RewriterBase &b, LinalgOp op, SmallVectorImpl< Value > &ivs, const LoopIndexToRangeIndexMap &loopIndexToRangeIndex)
All indices returned by IndexOp should be invariant with respect to tiling.
Definition Tiling.cpp:73
void populateBlockPackMatmulPatterns(RewritePatternSet &patterns, const ControlBlockPackMatmulFn &controlFn)
Patterns to block pack Linalg matmul ops.
void populateConvertConv2DToImg2ColPatterns(RewritePatternSet &patterns)
Populates patterns to transform linalg.conv_2d_xxx operations into linalg.generic (for img2col packin...
std::function< FailureOr< SmallVector< OpFoldResult > >( OpBuilder &, OpOperand &, ArrayRef< Range >, const PadTilingInterfaceOptions &)> PadSizeComputationFunction
Definition Transforms.h:627
FailureOr< Operation * > decomposeWinogradFilterTransformOp(RewriterBase &rewriter, linalg::WinogradFilterTransformOp op)
Rewrite linalg.winograd_filter_transform.
std::optional< Value > allocateWorkgroupMemory(OpBuilder &builder, memref::SubViewOp subview, ArrayRef< Value > sizeBounds, DataLayout &)
Allocate the subview in the GPU workgroup memory.
FailureOr< PackTransposeResult > packTranspose(RewriterBase &rewriter, linalg::PackOp packOp, linalg::LinalgOp linalgOp, linalg::UnPackOp maybeUnPackOp, ArrayRef< int64_t > outerPerm, ArrayRef< int64_t > innerPerm)
Transpose a single PackOp -> LinalgOp -> UnPackOp chain and return the transposed PackOp -> LinalgOp ...
Value bufferizeToAllocation(RewriterBase &rewriter, const BufferizeToAllocationOptions &options, tensor::PadOp padOp, Attribute memorySpace={}, Operation *insertionPoint=nullptr)
Materialize a buffer allocation for the given tensor.pad op and lower the op to linalg....
FailureOr< VectorizationResult > vectorize(RewriterBase &rewriter, Operation *op, ArrayRef< int64_t > inputVectorSizes={}, ArrayRef< bool > inputScalableVecDims={}, bool vectorizeNDExtract=false, bool flatten1DDepthwiseConv=false, bool assumeDynamicDimsMatchVecSizes=false, bool createNamedContraction=false)
Returns a VectorizationResult containing the results of the vectorized op, or failure if the transfor...
bool isDimSequencePreserved(AffineMap map, ReassociationIndicesRef dimSequence)
Return true if a given sequence of dimensions are contiguous in the range of the specified indexing m...
FailureOr< Value > hoistPaddingOnTensors(RewriterBase &rewriter, tensor::PadOp opToHoist, int64_t numLoops, ArrayRef< int64_t > transposeVector, tensor::PadOp &hoistedOp, SmallVectorImpl< TransposeOp > &transposeOps)
Mechanically hoist padding operations on tensors by numLoops into a new, generally larger tensor.
void populateDecomposeProjectedPermutationPatterns(RewritePatternSet &patterns)
Add patterns to make explicit broadcasts and transforms in the input operands of a genericOp.
FailureOr< LinalgOp > specializeGenericOp(RewriterBase &rewriter, GenericOp genericOp)
Create a namedOp from the given GenericOp and replace the GenericOp.
void populateFoldReshapeOpsByCollapsingPatterns(RewritePatternSet &patterns, const ControlFusionFn &controlFoldingReshapes)
Patterns to fold an expanding tensor.expand_shape operation with its producer generic operation by co...
LinalgTilingLoopType
The type of loops to be generated during tiling.
Definition Utils.h:121
FailureOr< LowerUnPackOpResult > lowerUnPack(RewriterBase &rewriter, linalg::UnPackOp unPackOp, bool lowerUnpadLikeWithExtractSlice=true)
Rewrite pack as empty + transpose + reshape + extract_slice.
std::function< std::optional< BlockPackMatmulOptions >(linalg::LinalgOp)> ControlBlockPackMatmulFn
Function type which is used to control matmul packing.
void populatePadOpVectorizationPatterns(RewritePatternSet &patterns, PatternBenefit baseBenefit=1)
Populates patterns with patterns that vectorize tensor.pad.
void populateLinalgTilingCanonicalizationPatterns(RewritePatternSet &patterns)
Definition Tiling.cpp:857
void populateLinalgFoldIntoElementwisePatterns(RewritePatternSet &patterns)
Populates patterns with patterns that fold operations like linalg.transform into elementwise op map.
LogicalResult deallocateGPUPrivateMemory(OpBuilder &, Value)
In case of GPU private memory there is no need to deallocate since the memory is freed when going out...
void populateSparseTensorRewriting(RewritePatternSet &patterns)
Populate patterns that are only useful in the context of sparse tensors.
FailureOr< Operation * > decomposeWinogradOutputTransformOp(RewriterBase &rewriter, linalg::WinogradOutputTransformOp op)
Rewrite linalg.winograd_output_transform.
void populateWinogradConv2DPatterns(RewritePatternSet &patterns, WinogradConv2DFmr fmr)
Patterns to apply Winograd Conv2D algorithm F(m x m, r x r).
FailureOr< ElementwiseOpFusionResult > fuseElementwiseOps(RewriterBase &rewriter, OpOperand *fusedOperand)
FailureOr< PromotionInfo > promoteSubviewAsNewBuffer(OpBuilder &b, Location loc, memref::SubViewOp subView, bool useOriginalSubviewSize, const AllocBufferCallbackFn &allocationFn, DataLayout &layout)
llvm::SmallDenseSet< int > getPreservedProducerResults(GenericOp producer, GenericOp consumer, OpOperand *fusedOperand)
Returns a set of indices of the producer's results which would be preserved after the fusion.
std::function< SplitReductionOptions(LinalgOp op)> ControlSplitReductionFn
Function signature to control reduction splitting.
Definition Transforms.h:489
std::optional< Value > allocateGPUPrivateMemory(OpBuilder &builder, memref::SubViewOp subview, ArrayRef< Value > sizeBounds, DataLayout &)
Allocate the subview in the GPU private memory.
std::function< SmallVector< ReassociationIndices >(linalg::LinalgOp)> GetCollapsableDimensionsFn
Function type to control generic op dimension collapsing.
void populateSimplifyDepthwiseConvPatterns(RewritePatternSet &patterns)
Patterns to simplify depthwise convolutions.
FailureOr< Operation * > rewriteInDestinationPassingStyle(RewriterBase &rewriter, tensor::FromElementsOp fromElementsOp)
Rewrite tensor.from_elements to linalg.generic.
FailureOr< PackResult > blockPackMatmul(RewriterBase &rewriter, linalg::LinalgOp linalgOp, const ControlBlockPackMatmulFn &controlPackMatmul)
Pack a matmul operation into blocked 4D layout.
void peelLoops(RewriterBase &rewriter, ArrayRef< scf::ForOp > loops)
Peel 'loops' and applies affine_min/max bounds simplification on the fly where relevant.
SmallVector< OpFoldResult > computePaddedShape(OpBuilder &, TypedValue< RankedTensorType > v, AffineMap indexingMap, ArrayRef< OpFoldResult > indexingSizes, const PadTilingInterfaceOptions &options)
Helper function to compute the padded shape of the given value v of RankedTensorType given:
void populateConvertToDestinationStylePatterns(RewritePatternSet &patterns)
Populate patterns that convert non-destination-style ops to destination style ops.
FailureOr< Operation * > winogradConv2D(RewriterBase &rewriter, linalg::Conv2DNhwcFhwcOp op, WinogradConv2DFmr fmr)
Convert linalg.conv_2d_nhwc_fhwc to Winograd Conv2D algorithm F(m x m, r x r).
FailureOr< Operation * > transposeConv2D(RewriterBase &rewriter, linalg::Conv2DNhwcFhwcOp op)
Convert linalg.conv_2d_nhwc_fhwc(_q) to linalg.conv_2d_nhwc_hwcf(_q) by materializing transpose.
void populateFoldUnitExtentDimsPatterns(RewritePatternSet &patterns, ControlDropUnitDims &options)
Patterns to fold unit-extent dimensions in operands/results of linalg ops on tensors via reassociativ...
std::function< SmallVector< Value, 4 >(OpBuilder &, Operation *)> TileSizeComputationFunction
Definition Transforms.h:187
LogicalResult copyToWorkgroupMemory(OpBuilder &b, Value src, Value dst)
Create Memref copy operations and add gpu barrier guards before and after the copy operation to ensur...
void populateElementwiseToLinalgConversionPatterns(RewritePatternSet &patterns)
Populate patterns that convert ElementwiseMappable ops to linalg parallel loops.
LogicalResult linalgOpAnchoredEmptyTensorEliminationStep(RewriterBase &rewriter, Operation *op, bufferization::OneShotAnalysisState &state)
Try to eliminate tensor::EmptyOps inside op that are anchored on a LinalgOp.
FailureOr< LinalgLoops > linalgOpToLoops(RewriterBase &rewriter, LinalgOp linalgOp)
Emit a loop nest of scf.for with the proper body for linalgOp.
Definition Loops.cpp:368
FailureOr< GenericOp > generalizeNamedOp(RewriterBase &rewriter, LinalgOp linalgOp)
Create a GenericOp from the given named operation linalgOp and replace the given linalgOp.
std::tuple< SmallVector< Range, 4 >, LoopIndexToRangeIndexMap > makeTiledLoopRanges(RewriterBase &b, Location loc, AffineMap map, ArrayRef< OpFoldResult > allShapeSizes, ArrayRef< OpFoldResult > allTileSizes)
Definition Tiling.cpp:44
FailureOr< Operation * > transposeBatchMatmul(RewriterBase &rewriter, linalg::BatchMatmulOp op, bool transposeLHS=true)
Pattern to replace.
LogicalResult promoteSubviewsPrecondition(Operation *op, LinalgPromotionOptions options)
Promote memref.subviews feeding linalg-on-buffers operations.
LogicalResult copyToGPUPrivateMemory(OpBuilder &b, Value src, Value dst)
Normal copy to between src and dst.
FailureOr< linalg::GenericOp > deduplicateOperandsAndRemoveDeadResults(RewriterBase &rewriter, linalg::GenericOp genericOp, bool removeOutputs)
Method to deduplicate operands and remove dead results of linalg.generic operations.
void populateDecomposeConvolutionPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Linalg decompose convolutions patterns.
void populateDecomposeWinogradOpsPatterns(RewritePatternSet &patterns)
Patterns to decompose Winograd operators.
void populateConvolutionVectorizationPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Populate patterns for vectorizing low-D convolution ops.
LogicalResult vectorizeCopy(RewriterBase &builder, memref::CopyOp copyOp)
Emit a suitable vector form for a Copy op with fully static shape.
LogicalResult vectorizeOpPrecondition(Operation *op, ArrayRef< int64_t > inputVectorSizes={}, ArrayRef< bool > inputScalableVecDims={}, bool vectorizeNDExtract=false, bool flatten1DDepthwiseConv=false)
Return success if the operation can be vectorized.
FailureOr< GenericOp > interchangeGenericOp(RewriterBase &rewriter, GenericOp genericOp, ArrayRef< unsigned > interchangeVector)
Interchange the iterator_types and iterator_maps dimensions and adapts the index accesses of op.
void populateCollapseDimensions(RewritePatternSet &patterns, const GetCollapsableDimensionsFn &controlCollapseDimensions)
Pattern to collapse dimensions in a linalg.generic op.
bool areElementwiseOpsFusable(OpOperand *fusedOperand)
Return true if two linalg.generic operations with producer/consumer relationship through fusedOperand...
FailureOr< StaticMultiSizeSpecification > computeStaticMultiTileSizes(LinalgOp op, unsigned dimension, int64_t targetSize, int64_t divisor)
Definition Tiling.cpp:236
FailureOr< LinalgLoops > linalgOpToAffineLoops(RewriterBase &rewriter, LinalgOp linalgOp)
Emit a loop nest of affine.for with the proper body for linalgOp.
Definition Loops.cpp:363
void populateDecomposePackUnpackPatterns(RewritePatternSet &patterns)
Populates patterns to decompose linalg.pack and linalg.unpack Ops into e.g.
std::function< std::optional< Value >( OpBuilder &b, memref::SubViewOp subView, ArrayRef< Value > boundingSubViewSize, DataLayout &layout)> AllocBufferCallbackFn
Callback function type used to perform the allocation for the promoted subView.
Definition Transforms.h:378
void populateEraseUnusedOperandsAndResultsPatterns(RewritePatternSet &patterns)
Pattern to remove dead operands and results of linalg.generic operations.
std::function< bool(OpOperand *fusedOperand)> ControlFusionFn
Function type which is used to control when to stop fusion.
FailureOr< ContinuousTileSizeSpecification > computeContinuousTileSizes(OpBuilder &builder, TilingInterface op, unsigned dimension, OpFoldResult targetSize, bool emitAssertions)
Definition Tiling.cpp:156
FailureOr< SmallVector< OpFoldResult > > computeIndexingMapOpInterfacePaddedShape(OpBuilder &, OpOperand &operandToPad, ArrayRef< Range > iterationDomain, const PadTilingInterfaceOptions &)
Specific helper for Linalg ops.
FailureOr< StaticContinuousTileSizeSpecification > computeStaticContinuousTileSizes(LinalgOp op, unsigned dimension, unsigned targetSize)
Definition Tiling.cpp:106
std::function< LogicalResult(RewriterBase &, tensor::PadOp, Value)> OptimizeCopyFn
FailureOr< SplitReductionResult > splitReduction(RewriterBase &b, LinalgOp op, const ControlSplitReductionFn &controlSplitReductionFn, bool useAlloc=false)
void populateSimplifyPackAndUnpackPatterns(RewritePatternSet &patterns)
Populates patterns with patterns that simplify tensor.pack and tensor.unpack operations.
void populateFoldPackUnpackIntoTensorEmptyPatterns(RewritePatternSet &patterns)
Populates patterns with patterns that fold operations like linalg.pack and linalg....
FailureOr< LinalgOp > padAndHoistLinalgOp(RewriterBase &rewriter, LinalgOp linalgOp, const LinalgPaddingOptions &options)
Apply padding and hoisting to linalgOp according to the configuration specified in options.
Definition Padding.cpp:355
void populateDecomposeLinalgOpsPattern(RewritePatternSet &patterns, bool removeDeadArgsAndResults=true)
Populate patterns for splitting a LinalgOp with multiple statements within its payload into multiple ...
void populateFoldIntoPackAndUnpackPatterns(RewritePatternSet &patterns, const ControlFoldIntoPackUnpackFn &controlFn=nullptr)
Populates patterns with patterns that fold operations like tensor.pad and tensor.extract_slice into t...
FailureOr< ForallReductionTilingResult > tileReductionUsingForall(RewriterBase &b, PartialReductionOpInterface op, ArrayRef< OpFoldResult > numThreads, ArrayRef< OpFoldResult > tileSizes={}, std::optional< ArrayAttr > mapping=std::nullopt)
Method to tile a reduction to parallel iterations computing partial reductions.
Definition Tiling.cpp:589
FailureOr< PackResult > packMatmulGreedily(RewriterBase &rewriter, LinalgOp linalgOp, ArrayRef< OpFoldResult > mnkPackedSizes, ArrayRef< int64_t > mnkPaddedSizesNextMultipleOf, ArrayRef< int64_t > mnkOrder)
Pack a LinalgOp by greedily inferring matmul dimensions (m, n, k) where m and n are proper parallel d...
std::function< LogicalResult(OpBuilder &b, Value buffer)> DeallocBufferCallbackFn
Callback function type used to deallocate the buffers used to hold the promoted subview.
Definition Transforms.h:384
FailureOr< PackResult > pack(RewriterBase &rewriter, linalg::LinalgOp linalgOp, ArrayRef< OpFoldResult > packedSizes)
Implement packing of a single LinalgOp by packedSizes.
void populateEraseUnnecessaryInputsPatterns(RewritePatternSet &patterns)
Patterns to promote inputs to outputs and remove unused inputs of linalg.generic ops.
std::function< bool(OpOperand *opOperand)> ControlFoldIntoPackUnpackFn
Function type which is used to control folding operations like tensor.pad and tensor....
FailureOr< TiledLinalgOp > tileLinalgOp(RewriterBase &b, LinalgOp op, const LinalgTilingOptions &options)
Definition Tiling.cpp:817
DenseMap< int, int > LoopIndexToRangeIndexMap
Creates a number of ranges equal to the number of non-zero in tileSizes.
Definition Transforms.h:940
void populateFoldReshapeOpsByExpansionPatterns(RewritePatternSet &patterns, const ControlFusionFn &controlFoldingReshapes)
Patterns to fold an expanding (collapsing) tensor_reshape operation with its producer (consumer) gene...
std::function< bool(OpOperand *opOperand)> ControlPropagationFn
Function type which is used to control propagation of linalg.pack/unpack ops.
void populateSwapExtractSliceWithFillPatterns(RewritePatternSet &patterns)
Adds patterns that waps tensor.extract_slice(linalg.fill(cst, init)) into linalg.fill(cst,...
FailureOr< DropUnitDimsResult > dropUnitDims(RewriterBase &rewriter, IndexingMapOpInterface op, const DroppedUnitDimsBuilder &droppedUnitDimsBuilder, const ControlDropUnitDims &options)
void populateInlineConstantOperandsPatterns(RewritePatternSet &patterns)
Patterns that are used to inline constant operands into linalg generic ops.
FailureOr< LinalgOp > promoteSubViews(OpBuilder &b, LinalgOp op, const LinalgPromotionOptions &options)
Promote the subViews into a new buffer allocated at the insertion point b.
void populateConstantFoldLinalgOperations(RewritePatternSet &patterns, const ControlFusionFn &controlFn)
Patterns to constant fold Linalg operations.
LogicalResult deallocateWorkgroupMemory(OpBuilder &, Value)
In case of GPU group memory there is no need to deallocate.
FailureOr< Operation * > transposeMatmul(RewriterBase &rewriter, linalg::MatmulOp op, bool transposeLHS=true)
Convert Linalg matmul ops to transposed variants.
void populateLinalgNamedOpsGeneralizationPatterns(RewritePatternSet &patterns)
Linalg generalization patterns.
void populateLinalgGenericOpsSpecializationPatterns(RewritePatternSet &patterns)
Populates patterns with patterns to convert linalg.generic ops to named ops where possible.
void populateLinalgNamedToElementwisePatterns(RewritePatternSet &patterns)
Populates patterns that convert linalg named ops e.g.
std::optional< vector::CombiningKind > getCombinerOpKind(Operation *combinerOp)
Return vector::CombiningKind for the given op.
SmallVector< Value > peelLoop(RewriterBase &rewriter, Operation *op)
Try to peel and canonicalize loop op and return the new result.
std::function< LogicalResult(OpBuilder &b, Value src, Value dst)> CopyCallbackFn
Callback function type used to insert copy from original subview to subview of the promoted region fo...
Definition Transforms.h:391
RewritePatternSet getLinalgTilingCanonicalizationPatterns(MLIRContext *ctx)
Canonicalization patterns relevant to apply after tiling patterns.
Definition Tiling.cpp:851
FailureOr< CollapseResult > collapseOpIterationDims(LinalgOp op, ArrayRef< ReassociationIndices > foldedIterationDims, RewriterBase &rewriter)
Collapses dimensions of linalg.generic/linalg.copy operation.
FailureOr< Operation * > decomposeWinogradInputTransformOp(RewriterBase &rewriter, linalg::WinogradInputTransformOp op)
Rewrite linalg.winograd_input_transform.
void populateDecomposePadPatterns(RewritePatternSet &patterns)
Populates patterns to decompose tensor.pad into e.g.
void populateFoldAddIntoDestPatterns(RewritePatternSet &patterns)
Pattern to replace linalg.add when destination passing on a contraction op suffices for achieving the...
std::pair< TilingInterface, TilingInterface > splitOp(RewriterBase &rewriter, TilingInterface op, unsigned dimension, OpFoldResult splitPoint)
Split the given op into two parts along the given iteration space dimension at the specified splitPoi...
Definition Split.cpp:67
void populateElementwiseOpsFusionPatterns(RewritePatternSet &patterns, const ControlFusionFn &controlElementwiseOpFusion)
Patterns for fusing linalg operation on tensors.
FailureOr< SplitReductionResult > splitReductionByScaling(RewriterBase &b, LinalgOp op, const ControlSplitReductionFn &controlSplitReductionFn, bool useAlloc=false)
Scaling-based implementation of the split reduction transformation.
FailureOr< MultiSizeSpecification > computeMultiTileSizes(OpBuilder &builder, LinalgOp op, unsigned dimension, OpFoldResult targetSize, OpFoldResult divisor, bool emitAssertions=true)
Emits the IR computing the multi-sized tiling specification with two tile sizes not exceeding targetS...
Definition Tiling.cpp:262
FailureOr< LowerPackResult > lowerPack(RewriterBase &rewriter, linalg::PackOp packOp, bool lowerPadLikeWithInsertSlice=true)
Rewrite pack as pad + reshape + transpose.
FailureOr< LinalgLoops > linalgOpToParallelLoops(RewriterBase &rewriter, LinalgOp linalgOp)
Emit a loop nest of scf.parallel with the proper body for linalgOp.
Definition Loops.cpp:375
Include the generated interface declarations.
ArrayRef< int64_t > ReassociationIndicesRef
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
Definition LLVM.h:128
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
Definition Value.h:497
const FrozenRewritePatternSet & patterns
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:126
OpInterfaceRewritePattern(MLIRContext *context, PatternBenefit benefit=1)
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
SmallVector< int64_t, 3 > mnkOrder
Permutation of matmul (M, N, K) dimensions order.
SmallVector< int64_t, 3 > blockFactors
Minor block factors (mb, nb, kb) for packing relayout where mb, mn are the parallel dimensions and kb...
bool rhsTransposeOuterBlocks
Transpose RHS outer block layout [KB][NB] -> [NB][KB].
bool lhsTransposeInnerBlocks
Transpose LHS inner block layout [mb][kb] -> [kb][mb].
SmallVector< int64_t, 3 > mnkPaddedSizesNextMultipleOf
Next multiples of the packing sizes.
bool lhsTransposeOuterBlocks
Transpose LHS outer block layout [MB][KB] -> [KB][MB].
bool allowPadding
If true, allows packing of dimensions that only partially fit into the block factors.
bool rhsTransposeInnerBlocks
Transpose RHS inner block layout [kb][nb] -> [nb][kb].
bool bufferizeDestinationOnly
If set to "true", only the destination tensor operands are bufferized to a new allocation (and wrappe...
Definition Transforms.h:66
bool emitDealloc
If set to "true", a memref.dealloc operation will be emitted for each allocated buffer.
Definition Transforms.h:72
SmallVector< Value > results
Transformation to drop unit-extent dimensions from linalg.generic operations.
Definition Transforms.h:521
RankReductionStrategy rankReductionStrategy
Definition Transforms.h:524
std::function< SmallVector< unsigned >(Operation *)> ControlFnTy
Definition Transforms.h:527
Vectorization pattern for memref::CopyOp.
LogicalResult matchAndRewrite(memref::CopyOp copyOp, PatternRewriter &rewriter) const override
Rewrites a linalg::PackOp into a sequence of:
LogicalResult matchAndRewrite(linalg::PackOp packOp, PatternRewriter &rewriter) const override
Rewrites a linalg::UnPackOp into a sequence of:
LogicalResult matchAndRewrite(linalg::UnPackOp unpackOp, PatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(tensor::PadOp padOp, PatternRewriter &rewriter) const override
Value createFillOrGenerateOp(RewriterBase &rewriter, tensor::PadOp padOp, Value dest, const SmallVector< Value > &dynSizes) const
Filling dest using FillOp constant padding value if possible.
DecomposePadOpPattern(MLIRContext *context, PatternBenefit benefit=1)
LogicalResult matchAndRewrite(Conv2DOp convOp, PatternRewriter &rewriter) const override
FailureOr< Conv1DOp > returningMatchAndRewrite(Conv2DOp convOp, PatternRewriter &rewriter) const
DownscaleConv2DOp(MLIRContext *context, PatternBenefit benefit=1)
FailureOr< DepthwiseConv1DNwcWcOp > returningMatchAndRewrite(DepthwiseConv2DNhwcHwcOp convOp, PatternRewriter &rewriter) const
LogicalResult matchAndRewrite(DepthwiseConv2DNhwcHwcOp convOp, PatternRewriter &rewriter) const override
DownscaleDepthwiseConv2DNhwcHwcOp(MLIRContext *context, PatternBenefit benefit=1)
Rewrites 2-D convolution ops with size-1 window dimensions into 1-D convolution ops.
LogicalResult matchAndRewrite(Conv2DOp convOp, PatternRewriter &rewriter) const override
FailureOr< Conv1DOp > returningMatchAndRewrite(Conv2DOp convOp, PatternRewriter &rewriter) const
IndexingMapOpInterface resultOp
Definition Transforms.h:541
SmallVector< Value > replacements
Definition Transforms.h:542
Fuse two linalg.generic operations that have a producer-consumer relationship captured through fusedO...
Definition Transforms.h:560
llvm::DenseMap< Value, Value > replacements
Definition Transforms.h:562
std::function< std::optional< bool >(tensor::ExtractSliceOp)> ControlFn
A function to control pattern application and rewrite logic.
LogicalResult matchAndRewrite(tensor::ExtractSliceOp sliceOp, PatternRewriter &rewriter) const override
ExtractSliceOfPadTensorSwapPattern(MLIRContext *context, ControlFn controlFn=nullptr, PatternBenefit benefit=1)
Transformation information returned after reduction tiling.
SmallVector< Operation * > mergeOps
The final reduction operation merging all the partial reductions.
SmallVector< Value > initialValues
Initial values used for partial reductions.
scf::ForallOp loops
The scf.forall operation that iterate over the tiles.
SmallVector< Operation * > parallelTiledOps
The partial reduction tiled op generated.
Match and rewrite for the pattern:
LogicalResult matchAndRewrite(vector::TransferReadOp xferOp, PatternRewriter &rewriter) const override
Match and rewrite for the pattern:
LogicalResult matchAndRewrite(vector::TransferWriteOp xferOp, PatternRewriter &rewriter) const override
Linalg generalization pattern.
LogicalResult matchAndRewrite(LinalgOp op, PatternRewriter &rewriter) const override
FailureOr< GenericOp > returningMatchAndRewrite(LinalgOp op, PatternRewriter &rewriter) const
matchAndRewrite implementation that returns the significant transformed pieces of IR.
Options that allow distribution of loops generated in Linalg transforms to processors while generatin...
Definition Utils.h:322
SmallVector< Attribute > paddingValues
A padding value for every operand.
Definition Transforms.h:282
LinalgPaddingOptions & setSizeToPadTo(unsigned operandIndex, unsigned dimIndex, OpFoldResult size)
Definition Transforms.h:304
DenseMap< std::pair< unsigned, unsigned >, OpFoldResult > sizeToPadTo
A mapping between an operand and shape dim, and a size for a padding dimension.
Definition Transforms.h:303
std::optional< SmallVector< int64_t > > padToMultipleOf
A list of multiples to which each padding dimension should be padded to.
Definition Transforms.h:294
OpFoldResult getSizeToPadTo(unsigned operandIndex, unsigned dimIndex) const
Given the operand index and shape dim it returns the size to pad to.
Definition Transforms.h:311
SmallVector< SmallVector< int64_t > > transposePaddings
A permutation vector for every operand used to transpose the packed PadOp results.
Definition Transforms.h:331
LinalgPaddingOptions & setPaddingValues(ArrayRef< Attribute > pv)
Definition Transforms.h:283
LinalgPaddingOptions & setPadToMultipleOf(ArrayRef< int64_t > m)
Definition Transforms.h:295
LinalgPaddingOptions & setHoistPaddings(ArrayRef< int64_t > hp)
Definition Transforms.h:325
LinalgPaddingOptions & setCopyBackOp(CopyBackOp op)
Definition Transforms.h:345
SmallVector< bool > nofoldFlags
A flag for every operand to mark the PadOp as nofold which enables packing for statically shaped oper...
Definition Transforms.h:318
SmallVector< int64_t > hoistPaddings
A number of loops to hoist the PadOp out for every operand.
Definition Transforms.h:324
LinalgPaddingOptions & setTransposePaddings(ArrayRef< SmallVector< int64_t > > tp)
Definition Transforms.h:333
LinalgPaddingOptions & setPaddingDimensions(ArrayRef< int64_t > pd)
Definition Transforms.h:289
SmallVector< int64_t > paddingDimensions
A list of iterator dimensions to pad.
Definition Transforms.h:288
LinalgPaddingOptions & setNofoldFlags(ArrayRef< bool > pp)
Definition Transforms.h:319
CopyBackOp copyBackOp
The op to be used for copying the padded result to the original destination tensor.
Definition Transforms.h:344
std::optional< unsigned > alignment
Alignment of promoted buffer. If std::nullopt do not specify alignment.
Definition Transforms.h:432
bool useAlloca
Use alloca with the default allocation scheme.
Definition Transforms.h:445
LinalgPromotionOptions & setUseFullTileBuffers(ArrayRef< bool > useFullTiles)
Definition Transforms.h:409
LinalgPromotionOptions & setAllocationDeallocationFns(AllocBufferCallbackFn const &allocFn, DeallocBufferCallbackFn const &deallocFn)
Definition Transforms.h:456
LinalgPromotionOptions & setAlignment(unsigned align)
Definition Transforms.h:433
LinalgPromotionOptions & setMemorySpace(Attribute memorySpc)
Definition Transforms.h:440
std::optional< Attribute > memorySpace
Memory space of promoted buffer.
Definition Transforms.h:439
bool useOriginalSubviewSize
If true, buffers will be allocated with the original subview size.
Definition Transforms.h:426
std::optional< CopyCallbackFn > copyOutFn
Definition Transforms.h:465
std::optional< CopyCallbackFn > copyInFn
Callback function to do the copy of data to and from the promoted subview.
Definition Transforms.h:464
std::optional< DenseSet< unsigned > > operandsToPromote
Indices of subViews to promote.
Definition Transforms.h:397
LinalgPromotionOptions & setOperandsToPromote(ArrayRef< int64_t > operands)
Definition Transforms.h:398
LinalgPromotionOptions & setUseFullTileBuffersByDefault(bool use)
Definition Transforms.h:420
std::optional< AllocBufferCallbackFn > allocationFn
Callback function to do the allocation of the promoted buffer.
Definition Transforms.h:453
bool useFullTileBuffersDefault
If true all operands unspecified by useFullTileBuffers will use the full view, otherwise the partial ...
Definition Transforms.h:419
std::optional< DeallocBufferCallbackFn > deallocationFn
Definition Transforms.h:454
LinalgPromotionOptions & setUseOriginalSubviewSize(bool originalSize)
Definition Transforms.h:427
LinalgPromotionOptions & setUseAlloca(bool use)
Definition Transforms.h:446
LinalgPromotionOptions & setCopyInOutFns(CopyCallbackFn const &copyIn, CopyCallbackFn const &copyOut)
Definition Transforms.h:466
std::optional< llvm::SmallBitVector > useFullTileBuffers
If ith element of useFullTiles is true the full view should be used for the promoted buffer of the it...
Definition Transforms.h:408
LogicalResult matchAndRewrite(GenericOp op, PatternRewriter &rewriter) const override
FailureOr< GenericOp > returningMatchAndRewrite(GenericOp op, PatternRewriter &rewriter) const
std::optional< LinalgLoopDistributionOptions > tileDistribution
When specified, specifies distribution of generated tile loops to processors.
Definition Transforms.h:272
LinalgTilingAndFusionOptions & setDistributionOptions(LinalgLoopDistributionOptions distributionOptions)
Definition Transforms.h:274
LinalgTilingAndFusionOptions & setTileSizes(ArrayRef< int64_t > ts)
Definition Transforms.h:264
SmallVector< int64_t > tileInterchange
Tile interchange used to permute the tile loops.
Definition Transforms.h:269
SmallVector< int64_t > tileSizes
Tile sizes used to tile the root operation.
Definition Transforms.h:263
LinalgTilingOptions & setDistributionOptions(LinalgLoopDistributionOptions distributionOptions)
Definition Transforms.h:238
LinalgTilingOptions & setTileSizes(const SmallVector< Value, 4 > &ts)
Set the tileSizeComputationFunction to return the values ts.
Definition Transforms.h:204
LinalgTilingOptions & setTileSizeComputationFunction(TileSizeComputationFunction fun)
Definition Transforms.h:197
LinalgTilingLoopType loopType
The type of tile loops to generate.
Definition Transforms.h:226
LinalgTilingOptions & setInterchange(ArrayRef< unsigned > interchange)
Definition Transforms.h:220
SmallVector< int64_t > peeledLoops
Peel the specified loops.
Definition Transforms.h:252
LinalgTilingOptions & setLoopType(LinalgTilingLoopType lt)
Definition Transforms.h:228
SmallVector< unsigned, 4 > interchangeVector
The interchange vector to reorder the tiled loops.
Definition Transforms.h:218
LinalgTilingOptions & setDistributionTypes(ArrayRef< StringRef > types)
Definition Transforms.h:246
TileSizeComputationFunction tileSizeComputationFunction
Computation function that returns the tile sizes for each operation.
Definition Transforms.h:194
LinalgTilingOptions & scalarizeDynamicDims()
Tile all dynamic dimensions by 1.
std::optional< LinalgLoopDistributionOptions > distribution
When specified, specifies distribution of generated tile loops to processors.
Definition Transforms.h:235
SmallVector< StringRef, 2 > distributionTypes
Specification markers of how to distribute the linalg.tiled_loop.
Definition Transforms.h:244
LinalgTilingOptions & setPeeledLoops(ArrayRef< int64_t > loops)
Definition Transforms.h:254
linalg::TransposeOp transposeOp
tensor::ExpandShapeOp expandShapeOp
tensor::ExtractSliceOp extractSliceOp
linalg::TransposeOp transposeOp
tensor::CollapseShapeOp collapseShapeOp
A description of a multi-size tiling comprising tile sizes and numbers of tiles, expressed as Values ...
Definition Transforms.h:969
Struct to hold the result of a pack call.
SmallVector< linalg::UnPackOp > unPackOps
linalg::LinalgOp packedLinalgOp
SmallVector< linalg::PackOp > packOps
Struct to hold the result of a packTranspose call.
SmallVector< Attribute > paddingValues
A padding value for every operand.
Definition Transforms.h:353
PadTilingInterfaceOptions & setPaddingValues(ArrayRef< Attribute > pv)
Definition Transforms.h:354
PadTilingInterfaceOptions & setPadToMultipleOf(bool b)
Definition Transforms.h:367
PadTilingInterfaceOptions & setPaddingSizes(ArrayRef< OpFoldResult > m)
Definition Transforms.h:360
bool padToMultipleOf
Pad iterator paddingDimension[i] to next multiple of paddingSizes[i] if true.
Definition Transforms.h:366
SmallVector< OpFoldResult > paddingSizes
A list of iterator dimensions sizes to pad to.
Definition Transforms.h:359
Operations and values created in the process of padding a TilingInterface operation.
Definition Transforms.h:640
SmallVector< Value > replacements
Slices of the padded op's results, same types as toPad.
Definition Transforms.h:646
TilingInterface paddedOp
The padded op, a clone of toPad with padded operands.
Definition Transforms.h:644
SmallVector< tensor::PadOp > padOps
The operands of the padded op.
Definition Transforms.h:642
Create a new buffer using the allocationFn provided.
Definition Transforms.h:838
Split Reduction options.
Definition Transforms.h:475
Apply transformation to split the single linalg op reduction into a parallel and reduction dimension.
Perform standalone tiling of a single LinalgOp by tileSizes.
Definition Transforms.h:798
SmallVector< Operation *, 8 > loops
Definition Transforms.h:800
SmallVector< Value, 4 > tensorResults
Definition Transforms.h:801
Transformation information returned after vectorizing.
Definition Transforms.h:895
SmallVector< Value > replacements
Results of the vectorization transform to replace the original operation.
Definition Transforms.h:897
SmallVector< T > tripCounts
Number of tiles associated with each size.
Definition Transforms.h:960
T lowTripCount
Number of tiles associated with each size.
Definition Transforms.h:952
Helper struct to hold the results of building a packing loop nest.
Definition Transforms.h:668
SmallVector< OpFoldResult > strides
Definition Transforms.h:669
SmallVector< Value > leadingPackedTensorIndexings
Definition Transforms.h:670
SmallVector< Value > clonedLoopIvs
Definition Transforms.h:670
SmallVector< OpFoldResult > sizes
Definition Transforms.h:669
SmallVector< OpFoldResult > offsets
Definition Transforms.h:669