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 
23 #include "mlir/IR/OpDefinition.h"
24 #include "mlir/IR/PatternMatch.h"
27 #include "llvm/ADT/SmallBitVector.h"
28 
29 namespace mlir {
30 namespace bufferization {
31 class AllocTensorOp;
32 class OneShotAnalysisState;
33 class BufferizationState;
34 } // namespace bufferization
35 
36 namespace linalg {
37 
38 class LinalgOp;
39 enum class WinogradConv2DFmr : uint32_t;
40 
41 //===----------------------------------------------------------------------===//
42 // Utils.
43 //===----------------------------------------------------------------------===//
44 
45 /// Return vector::CombiningKind for the given op.
46 std::optional<vector::CombiningKind> getCombinerOpKind(Operation *combinerOp);
47 
48 //===----------------------------------------------------------------------===//
49 // Bufferization-related transforms.
50 //===----------------------------------------------------------------------===//
51 
53  enum class AllocOp { MemrefAlloc = 0, MemrefAlloca = 1 };
54  AllocOp allocOp = AllocOp::MemrefAlloc;
55 
56  enum class MemcpyOp {
57  MaterializeInDestination = 0,
58  MemrefCopy = 1,
59  LinalgCopy = 2
60  };
61  MemcpyOp memcpyOp = MemcpyOp::MaterializeInDestination;
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.
66  bool bufferizeDestinationOnly = false;
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.
127 Value 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.
149 Value bufferizeToAllocation(RewriterBase &rewriter,
150  const BufferizeToAllocationOptions &options,
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 
198  tileSizeComputationFunction = std::move(fun);
199  return *this;
200  }
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  }
337  enum class CopyBackOp : int8_t {
338  None = 0,
340  LinalgCopy = 2
341  };
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]`.
368  padToMultipleOf = b;
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.
378 using 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.
422  return *this;
423  }
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.
478  int64_t ratio = 0;
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.
500 bool areElementwiseOpsFusable(OpOperand *fusedOperand);
501 
502 /// Promote memref.subviews feeding linalg-on-buffers operations.
503 LogicalResult promoteSubviewsPrecondition(Operation *op,
505 
506 /// Return success if the operation can be vectorized.
507 LogicalResult vectorizeOpPrecondition(Operation *op,
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 
541  IndexingMapOpInterface resultOp;
543 };
544 using DroppedUnitDimsBuilder = std::function<IndexingMapOpInterface(
545  Location loc, OpBuilder &, IndexingMapOpInterface,
546  ArrayRef<Value> newOperands, ArrayRef<AffineMap> newIndexingMaps,
547  const llvm::SmallDenseSet<unsigned> &droppedDims)>;
548 
549 FailureOr<DropUnitDimsResult>
550 dropUnitDims(RewriterBase &rewriter, IndexingMapOpInterface op,
551  const DroppedUnitDimsBuilder &droppedUnitDimsBuilder,
553 FailureOr<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`.
563 };
564 FailureOr<ElementwiseOpFusionResult>
565 fuseElementwiseOps(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.
572 llvm::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.
583 void 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.
598 LogicalResult 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>>(
630  const PadTilingInterfaceOptions &)>;
631 
632 /// Specific helper for Linalg ops.
633 FailureOr<SmallVector<OpFoldResult>>
635  ArrayRef<Range> iterationDomain,
636  const PadTilingInterfaceOptions &);
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.
659 FailureOr<PadTilingInterfaceResult>
660 rewriteAsPaddedOp(OpBuilder &, TilingInterface toPad,
664 
665 namespace detail {
666 
667 /// Helper struct to hold the results of building a packing loop nest.
671  TransposeOp maybeTransposeOp;
672  tensor::PadOp hoistedPadOp;
673 };
674 
675 /// Build the packing loop nest required to hoist `opToHoist` above
676 /// `outermostEnclosingForOp`.
677 /// The loop nest is built just before `outermostEnclosingForOp`.
678 FailureOr<PackingResult>
679 buildPackingLoopNest(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 /// ```
733 FailureOr<Value>
734 hoistPaddingOnTensors(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.
739 FailureOr<Value>
740 hoistPaddingOnTensors(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`.
747 FailureOr<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.
778 std::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).
799  LinalgOp op;
802 };
803 FailureOr<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.
817 FailureOr<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.
824 FailureOr<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.
829 FailureOr<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`.
841 };
842 FailureOr<PromotionInfo>
843 promoteSubviewAsNewBuffer(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.
857 FailureOr<LinalgOp> promoteSubViews(OpBuilder &b, LinalgOp op,
859 
860 /// Allocate the subview in the GPU workgroup memory.
861 std::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.
867 LogicalResult 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.
871 LogicalResult copyToWorkgroupMemory(OpBuilder &b, Value src, Value dst);
872 
873 /// Allocate the subview in the GPU private memory.
874 std::optional<Value> allocateGPUPrivateMemory(OpBuilder &builder,
875  memref::SubViewOp subview,
876  ArrayRef<Value> sizeBounds,
877  DataLayout &);
878 
879 /// Normal copy to between src and dst.
880 LogicalResult 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.
884 LogicalResult 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.
908 FailureOr<VectorizationResult>
909 vectorize(RewriterBase &rewriter, Operation *op,
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.
917 LogicalResult vectorizeCopy(RewriterBase &builder, memref::CopyOp copyOp);
918 
919 /// Emit a loop nest of `scf.for` with the proper body for `linalgOp`.
920 FailureOr<LinalgLoops> linalgOpToLoops(RewriterBase &rewriter,
921  LinalgOp linalgOp);
922 
923 /// Emit a loop nest of `scf.parallel` with the proper body for `linalgOp`.
924 FailureOr<LinalgLoops> linalgOpToParallelLoops(RewriterBase &rewriter,
925  LinalgOp linalgOp);
926 
927 /// Emit a loop nest of `affine.for` with the proper body for `linalgOp`.
928 FailureOr<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.
941 std::tuple<SmallVector<Range, 4>, LoopIndexToRangeIndexMap>
943  ArrayRef<OpFoldResult> allShapeSizes,
944  ArrayRef<OpFoldResult> allTileSizes);
945 
946 namespace detail {
947 template <typename T>
949  /// Tile sizes.
951  /// Number of tiles associated with each size.
953 };
954 
955 template <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.
969  : public detail::MultiSizeSpecificationBase<Value> {};
971  : public detail::MultiSizeSpecificationBase<int64_t> {};
972 
976  : public detail::ContinuousTileSizeSpecificationBase<int64_t> {};
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.
1005 FailureOr<MultiSizeSpecification>
1006 computeMultiTileSizes(OpBuilder &builder, LinalgOp op, unsigned dimension,
1007  OpFoldResult targetSize, OpFoldResult divisor,
1008  bool emitAssertions = true);
1009 FailureOr<StaticMultiSizeSpecification>
1010 computeStaticMultiTileSizes(LinalgOp op, unsigned dimension, int64_t targetSize,
1011  int64_t divisor);
1012 
1013 FailureOr<StaticContinuousTileSizeSpecification>
1014 computeStaticContinuousTileSizes(LinalgOp op, unsigned dimension,
1015  unsigned targetSize);
1016 FailureOr<ContinuousTileSizeSpecification>
1017 computeContinuousTileSizes(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 /// ```
1057 FailureOr<ForallReductionTilingResult>
1058 tileReductionUsingForall(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.
1115 void 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 /// ```
1162  FillOp fillOp;
1163  LinalgOp splitLinalgOp;
1165 };
1166 FailureOr<SplitReductionResult>
1167 splitReduction(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 /// ```
1218 FailureOr<SplitReductionResult>
1219 splitReductionByScaling(RewriterBase &b, LinalgOp op,
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 
1233  LinalgOp collapsedOp;
1234 };
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.
1243 FailureOr<CollapseResult>
1244 collapseOpIterationDims(LinalgOp op,
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.
1255 FailureOr<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.
1267 FailureOr<LowerUnPackOpResult>
1268 lowerUnPack(RewriterBase &rewriter, linalg::UnPackOp unPackOp,
1269  bool lowerUnpadLikeWithExtractSlice = true);
1270 
1271 /// Struct to hold the result of a `pack` call.
1272 struct PackResult {
1274  linalg::LinalgOp packedLinalgOp;
1276 };
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.
1280 FailureOr<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.
1297 FailureOr<PackTransposeResult>
1298 packTranspose(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.
1310 FailureOr<PackResult>
1311 packMatmulGreedily(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.
1372 FailureOr<PackResult>
1373 blockPackMatmul(RewriterBase &rewriter, linalg::LinalgOp linalgOp,
1374  const ControlBlockPackMatmulFn &controlPackMatmul);
1375 
1376 /// Rewrite tensor.from_elements to linalg.generic.
1377 FailureOr<Operation *>
1379  tensor::FromElementsOp fromElementsOp);
1380 
1381 /// Rewrite tensor.generate to linalg.generic.
1382 FailureOr<Operation *>
1384  tensor::GenerateOp generateOp);
1385 
1386 /// Rewrite tensor.pad to linalg.generic + tensor.insert_slice.
1387 FailureOr<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.
1424 FailureOr<std::pair<Operation *, Operation *>>
1425 rewriteInIm2Col(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.
1432 FailureOr<std::pair<Operation *, Operation *>>
1433 rewriteInIm2Col(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.
1439 FailureOr<std::pair<Operation *, Operation *>>
1440 rewriteInIm2Col(RewriterBase &rewriter,
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))
1448 FailureOr<std::pair<Operation *, Operation *>>
1449 rewriteInIm2Col(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.
1453 FailureOr<Operation *> transposeConv2D(RewriterBase &rewriter,
1454  linalg::Conv2DNhwcFhwcOp op);
1455 FailureOr<Operation *> transposeConv2D(RewriterBase &rewriter,
1456  linalg::Conv2DNhwcFhwcQOp op);
1457 
1458 /// Convert Linalg matmul ops to transposed variants.
1459 FailureOr<Operation *> transposeMatmul(RewriterBase &rewriter,
1460  linalg::MatmulOp op,
1461  bool transposeLHS = true);
1462 FailureOr<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.
1469 FailureOr<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>
1484 FailureOr<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]
1505 FailureOr<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]
1526 FailureOr<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.
1535 FailureOr<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.
1546 template <typename Conv2DOp, typename Conv1DOp>
1548  : public OpRewritePattern<Conv2DOp> {
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 
1560 extern template struct DownscaleSizeOneWindowed2DConvolution<Conv2DNhwcHwcfOp,
1561  Conv1DNwcWcfOp>;
1562 extern 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 
1583 struct 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 
1621 struct LinalgSpecializationPattern : public OpRewritePattern<GenericOp> {
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.
1636 struct CopyVectorizationPattern : public OpRewritePattern<memref::CopyOp> {
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.
1648 struct DecomposePadOpPattern : public OpRewritePattern<tensor::PadOp> {
1650  : OpRewritePattern<tensor::PadOp>(context, benefit) {}
1651  LogicalResult matchAndRewrite(tensor::PadOp padOp,
1652  PatternRewriter &rewriter) const override;
1653 
1654 protected:
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> {
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> {
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> {
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> {
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 
1822 private:
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.
1920 using 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.
1932 using 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.
2048 using 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
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.
Definition: OpDefinition.h:272
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...
Definition: PatternMatch.h:34
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Definition: PatternMatch.h:793
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
Definition: PatternMatch.h:368
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
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.
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.
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
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:380
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...
FailureOr< Operation * > decomposeWinogradFilterTransformOp(RewriterBase &rewriter, linalg::WinogradFilterTransformOp op)
Rewrite linalg.winograd_filter_transform.
DenseMap< int, int > LoopIndexToRangeIndexMap
Creates a number of ranges equal to the number of non-zero in tileSizes.
Definition: Transforms.h:940
std::optional< Value > allocateWorkgroupMemory(OpBuilder &builder, memref::SubViewOp subview, ArrayRef< Value > sizeBounds, DataLayout &)
Allocate the subview in the GPU workgroup memory.
Definition: Promotion.cpp:471
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 ...
Definition: Transforms.cpp:658
std::function< IndexingMapOpInterface(Location loc, OpBuilder &, IndexingMapOpInterface, ArrayRef< Value > newOperands, ArrayRef< AffineMap > newIndexingMaps, const llvm::SmallDenseSet< unsigned > &droppedDims)> DroppedUnitDimsBuilder
Definition: Transforms.h:547
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...
std::function< bool(OpOperand *fusedOperand)> ControlFusionFn
Function type which is used to control when to stop fusion.
Definition: Transforms.h:1920
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.
Definition: Specialize.cpp:245
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:118
FailureOr< LowerUnPackOpResult > lowerUnPack(RewriterBase &rewriter, linalg::UnPackOp unPackOp, bool lowerUnpadLikeWithExtractSlice=true)
Rewrite pack as empty + transpose + reshape + extract_slice.
Definition: Transforms.cpp:346
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:385
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...
Definition: Promotion.cpp:512
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)
Definition: Promotion.cpp:237
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::optional< Value > allocateGPUPrivateMemory(OpBuilder &builder, memref::SubViewOp subview, ArrayRef< Value > sizeBounds, DataLayout &)
Allocate the subview in the GPU private memory.
Definition: Promotion.cpp:496
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.
Definition: Transforms.cpp:69
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 * > 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< FailureOr< SmallVector< OpFoldResult > >(OpBuilder &, OpOperand &, ArrayRef< Range >, const PadTilingInterfaceOptions &)> PadSizeComputationFunction
Definition: Transforms.h:630
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...
Definition: Promotion.cpp:487
std::function< SmallVector< Value, 4 >(OpBuilder &, Operation *)> TileSizeComputationFunction
Definition: Transforms.h:188
std::function< LogicalResult(RewriterBase &, tensor::PadOp, Value)> OptimizeCopyFn
Definition: Transforms.h:1644
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.
Definition: Promotion.cpp:400
LogicalResult copyToGPUPrivateMemory(OpBuilder &b, Value src, Value dst)
Normal copy to between src and dst.
Definition: Promotion.cpp:504
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.
std::function< bool(OpOperand *opOperand)> ControlFoldIntoPackUnpackFn
Function type which is used to control folding operations like tensor.pad and tensor....
Definition: Transforms.h:2048
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).
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.
Definition: Interchange.cpp:45
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.
void populateEraseUnusedOperandsAndResultsPatterns(RewritePatternSet &patterns)
Pattern to remove dead operands and results of linalg.generic operations.
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(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:392
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 ...
std::function< bool(OpOperand *opOperand)> ControlPropagationFn
Function type which is used to control propagation of linalg.pack/unpack ops.
Definition: Transforms.h:1932
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...
Definition: Transforms.cpp:749
FailureOr< PackResult > pack(RewriterBase &rewriter, linalg::LinalgOp linalgOp, ArrayRef< OpFoldResult > packedSizes)
Implement packing of a single LinalgOp by packedSizes.
Definition: Transforms.cpp:464
void populateEraseUnnecessaryInputsPatterns(RewritePatternSet &patterns)
Patterns to promote inputs to outputs and remove unused inputs of linalg.generic ops.
FailureOr< TiledLinalgOp > tileLinalgOp(RewriterBase &b, LinalgOp op, const LinalgTilingOptions &options)
Definition: Tiling.cpp:817
std::function< SmallVector< ReassociationIndices >(linalg::LinalgOp)> GetCollapsableDimensionsFn
Function type to control generic op dimension collapsing.
Definition: Transforms.h:1959
void populateFoldReshapeOpsByExpansionPatterns(RewritePatternSet &patterns, const ControlFusionFn &controlFoldingReshapes)
Patterns to fold an expanding (collapsing) tensor_reshape operation with its producer (consumer) gene...
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.
Definition: Promotion.cpp:422
void populateConstantFoldLinalgOperations(RewritePatternSet &patterns, const ControlFusionFn &controlFn)
Patterns to constant fold Linalg operations.
std::function< SplitReductionOptions(LinalgOp op)> ControlSplitReductionFn
Function signature to control reduction splitting.
Definition: Transforms.h:490
LogicalResult deallocateWorkgroupMemory(OpBuilder &, Value)
In case of GPU group memory there is no need to deallocate.
Definition: Promotion.cpp:480
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.
Definition: Specialize.cpp:342
std::function< std::optional< BlockPackMatmulOptions >(linalg::LinalgOp)> ControlBlockPackMatmulFn
Function type which is used to control matmul packing.
Definition: Transforms.h:1349
void populateLinalgNamedToElementwisePatterns(RewritePatternSet &patterns)
Populates patterns that convert linalg named ops e.g.
enum WinogradConv2DFmr uint32_t 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.
Definition: Transforms.cpp:53
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.
Definition: Transforms.cpp:217
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.
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:498
ArrayRef< int64_t > ReassociationIndicesRef
const FrozenRewritePatternSet & patterns
OpInterfaceRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting a...
Definition: PatternMatch.h:333
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
Definition: PatternMatch.h:314
SmallVector< int64_t, 3 > mnkOrder
Permutation of matmul (M, N, K) dimensions order.
Definition: Transforms.h:1329
SmallVector< int64_t, 3 > blockFactors
Minor block factors (mb, nb, kb) for packing relayout where mb, mn are the parallel dimensions and kb...
Definition: Transforms.h:1319
bool rhsTransposeOuterBlocks
Transpose RHS outer block layout [KB][NB] -> [NB][KB].
Definition: Transforms.h:1338
bool lhsTransposeInnerBlocks
Transpose LHS inner block layout [mb][kb] -> [kb][mb].
Definition: Transforms.h:1335
SmallVector< int64_t, 3 > mnkPaddedSizesNextMultipleOf
Next multiples of the packing sizes.
Definition: Transforms.h:1326
bool lhsTransposeOuterBlocks
Transpose LHS outer block layout [MB][KB] -> [KB][MB].
Definition: Transforms.h:1332
bool allowPadding
If true, allows packing of dimensions that only partially fit into the block factors.
Definition: Transforms.h:1323
bool rhsTransposeInnerBlocks
Transpose RHS inner block layout [kb][nb] -> [nb][kb].
Definition: Transforms.h:1341
SmallVector< Value > results
Definition: Transforms.h:1232
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.
Definition: Transforms.h:1636
LogicalResult matchAndRewrite(memref::CopyOp copyOp, PatternRewriter &rewriter) const override
Definition: Transforms.cpp:894
Rewrites a linalg::PackOp into a sequence of:
Definition: Transforms.h:1698
LogicalResult matchAndRewrite(linalg::PackOp packOp, PatternRewriter &rewriter) const override
Rewrites a linalg::UnPackOp into a sequence of:
Definition: Transforms.h:1735
LogicalResult matchAndRewrite(linalg::UnPackOp unpackOp, PatternRewriter &rewriter) const override
Rewrite a tensor::PadOp into a sequence of EmptyOp, FillOp and InsertSliceOp.
Definition: Transforms.h:1648
LogicalResult matchAndRewrite(tensor::PadOp padOp, PatternRewriter &rewriter) const override
Definition: Transforms.cpp:922
Value createFillOrGenerateOp(RewriterBase &rewriter, tensor::PadOp padOp, Value dest, const SmallVector< Value > &dynSizes) const
Filling dest using FillOp constant padding value if possible.
Definition: Transforms.cpp:901
DecomposePadOpPattern(MLIRContext *context, PatternBenefit benefit=1)
Definition: Transforms.h:1649
LogicalResult matchAndRewrite(Conv2DOp convOp, PatternRewriter &rewriter) const override
Definition: Transforms.h:1590
FailureOr< Conv1DOp > returningMatchAndRewrite(Conv2DOp convOp, PatternRewriter &rewriter) const
DownscaleConv2DOp(MLIRContext *context, PatternBenefit benefit=1)
Definition: Transforms.h:1584
Rewrites 2-D depthwise convolution ops with size-1 (w, kw) or (h, kh) dimensions into 1-D depthwise c...
Definition: Transforms.h:1568
FailureOr< DepthwiseConv1DNwcWcOp > returningMatchAndRewrite(DepthwiseConv2DNhwcHwcOp convOp, PatternRewriter &rewriter) const
LogicalResult matchAndRewrite(DepthwiseConv2DNhwcHwcOp convOp, PatternRewriter &rewriter) const override
Definition: Transforms.h:1577
DownscaleDepthwiseConv2DNhwcHwcOp(MLIRContext *context, PatternBenefit benefit=1)
Definition: Transforms.h:1569
Rewrites 2-D convolution ops with size-1 window dimensions into 1-D convolution ops.
Definition: Transforms.h:1548
LogicalResult matchAndRewrite(Conv2DOp convOp, PatternRewriter &rewriter) const override
Definition: Transforms.h:1554
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
Rewrite extract_slice(tensor.pad(x)) into tensor.pad(extract_slice(x)).
Definition: Transforms.h:1802
std::function< std::optional< bool >(tensor::ExtractSliceOp)> ControlFn
A function to control pattern application and rewrite logic.
Definition: Transforms.h:1812
LogicalResult matchAndRewrite(tensor::ExtractSliceOp sliceOp, PatternRewriter &rewriter) const override
Definition: Transforms.cpp:973
ExtractSliceOfPadTensorSwapPattern(MLIRContext *context, ControlFn controlFn=nullptr, PatternBenefit benefit=1)
Definition: Transforms.h:1814
Transformation information returned after reduction tiling.
Definition: Transforms.h:1022
SmallVector< Operation * > mergeOps
The final reduction operation merging all the partial reductions.
Definition: Transforms.h:1026
SmallVector< Value > initialValues
Initial values used for partial reductions.
Definition: Transforms.h:1028
scf::ForallOp loops
The scf.forall operation that iterate over the tiles.
Definition: Transforms.h:1030
SmallVector< Operation * > parallelTiledOps
The partial reduction tiled op generated.
Definition: Transforms.h:1024
Match and rewrite for the pattern:
Definition: Transforms.h:1765
LogicalResult matchAndRewrite(vector::TransferReadOp xferOp, PatternRewriter &rewriter) const override
TODO: use interfaces, side-effects and aliasing analysis as appropriate, when available.
Match and rewrite for the pattern:
Definition: Transforms.h:1793
LogicalResult matchAndRewrite(vector::TransferWriteOp xferOp, PatternRewriter &rewriter) const override
TODO: use interfaces, side-effects and aliasing analysis as appropriate, when available.
Linalg generalization pattern.
Definition: Transforms.h:1605
LogicalResult matchAndRewrite(LinalgOp op, PatternRewriter &rewriter) const override
Definition: Transforms.h:1615
FailureOr< GenericOp > returningMatchAndRewrite(LinalgOp op, PatternRewriter &rewriter) const
matchAndRewrite implementation that returns the significant transformed pieces of IR.
Definition: Transforms.h:1611
Options that allow distribution of loops generated in Linalg transforms to processors while generatin...
Definition: Utils.h:319
SmallVector< Attribute > paddingValues
A padding value for every operand.
Definition: Transforms.h:282
LinalgPaddingOptions & setPadToMultipleOf(ArrayRef< int64_t > m)
Definition: Transforms.h:295
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
LinalgPaddingOptions & setNofoldFlags(ArrayRef< bool > pp)
Definition: Transforms.h:319
LinalgPaddingOptions & setPaddingDimensions(ArrayRef< int64_t > pd)
Definition: Transforms.h:289
LinalgPaddingOptions & setTransposePaddings(ArrayRef< SmallVector< int64_t >> tp)
Definition: Transforms.h:333
SmallVector< SmallVector< int64_t > > transposePaddings
A permutation vector for every operand used to transpose the packed PadOp results.
Definition: Transforms.h:331
LinalgPaddingOptions & setSizeToPadTo(unsigned operandIndex, unsigned dimIndex, OpFoldResult size)
Definition: Transforms.h:304
LinalgPaddingOptions & setPaddingValues(ArrayRef< Attribute > pv)
Definition: Transforms.h:283
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
LinalgPaddingOptions & setCopyBackOp(CopyBackOp op)
Definition: Transforms.h:345
LinalgPaddingOptions & setHoistPaddings(ArrayRef< int64_t > hp)
Definition: Transforms.h:325
SmallVector< int64_t > hoistPaddings
A number of loops to hoist the PadOp out for every operand.
Definition: Transforms.h:324
SmallVector< int64_t > paddingDimensions
A list of iterator dimensions to pad.
Definition: Transforms.h:288
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
LinalgPromotionOptions & setUseFullTileBuffersByDefault(bool use)
Definition: Transforms.h:420
bool useAlloca
Use alloca with the default allocation scheme.
Definition: Transforms.h:445
LinalgPromotionOptions & setAlignment(unsigned align)
Definition: Transforms.h:433
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
LinalgPromotionOptions & setUseAlloca(bool use)
Definition: Transforms.h:446
std::optional< DenseSet< unsigned > > operandsToPromote
Indices of subViews to promote.
Definition: Transforms.h:397
LinalgPromotionOptions & setCopyInOutFns(CopyCallbackFn const &copyIn, CopyCallbackFn const &copyOut)
Definition: Transforms.h:466
LinalgPromotionOptions & setUseFullTileBuffers(ArrayRef< bool > useFullTiles)
Definition: Transforms.h:409
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 & setMemorySpace(Attribute memorySpc)
Definition: Transforms.h:440
LinalgPromotionOptions & setAllocationDeallocationFns(AllocBufferCallbackFn const &allocFn, DeallocBufferCallbackFn const &deallocFn)
Definition: Transforms.h:456
LinalgPromotionOptions & setUseOriginalSubviewSize(bool originalSize)
Definition: Transforms.h:427
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
LinalgPromotionOptions & setOperandsToPromote(ArrayRef< int64_t > operands)
Definition: Transforms.h:398
LogicalResult matchAndRewrite(GenericOp op, PatternRewriter &rewriter) const override
Definition: Transforms.h:1629
FailureOr< GenericOp > returningMatchAndRewrite(GenericOp op, PatternRewriter &rewriter) const
Definition: Transforms.h:1625
std::optional< LinalgLoopDistributionOptions > tileDistribution
When specified, specifies distribution of generated tile loops to processors.
Definition: Transforms.h:272
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
LinalgTilingAndFusionOptions & setDistributionOptions(LinalgLoopDistributionOptions distributionOptions)
Definition: Transforms.h:274
SmallVector< int64_t > tileSizes
Tile sizes used to tile the root operation.
Definition: Transforms.h:263
LinalgTilingOptions & setLoopType(LinalgTilingLoopType lt)
Definition: Transforms.h:228
LinalgTilingOptions & setDistributionTypes(ArrayRef< StringRef > types)
Definition: Transforms.h:246
LinalgTilingOptions & setInterchange(ArrayRef< unsigned > interchange)
Definition: Transforms.h:220
LinalgTilingLoopType loopType
The type of tile loops to generate.
Definition: Transforms.h:226
LinalgTilingOptions & setTileSizeComputationFunction(TileSizeComputationFunction fun)
Definition: Transforms.h:197
LinalgTilingOptions & setTileSizes(const SmallVector< Value, 4 > &ts)
Set the tileSizeComputationFunction to return the values ts.
Definition: Transforms.h:204
LinalgTilingOptions & setPeeledLoops(ArrayRef< int64_t > loops)
Definition: Transforms.h:254
SmallVector< int64_t > peeledLoops
Peel the specified loops.
Definition: Transforms.h:252
LinalgTilingOptions & setDistributionOptions(LinalgLoopDistributionOptions distributionOptions)
Definition: Transforms.h:238
SmallVector< unsigned, 4 > interchangeVector
The interchange vector to reorder the tiled loops.
Definition: Transforms.h:218
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
linalg::TransposeOp transposeOp
Definition: Transforms.h:1251
tensor::ExpandShapeOp expandShapeOp
Definition: Transforms.h:1250
tensor::ExtractSliceOp extractSliceOp
Definition: Transforms.h:1263
linalg::TransposeOp transposeOp
Definition: Transforms.h:1261
tensor::CollapseShapeOp collapseShapeOp
Definition: Transforms.h:1262
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.
Definition: Transforms.h:1272
SmallVector< linalg::UnPackOp > unPackOps
Definition: Transforms.h:1275
linalg::LinalgOp packedLinalgOp
Definition: Transforms.h:1274
SmallVector< linalg::PackOp > packOps
Definition: Transforms.h:1273
Struct to hold the result of a packTranspose call.
Definition: Transforms.h:1284
linalg::LinalgOp transposedLinalgOp
Definition: Transforms.h:1286
linalg::UnPackOp transposedUnPackOp
Definition: Transforms.h:1287
PadTilingInterfaceOptions & setPaddingSizes(ArrayRef< OpFoldResult > m)
Definition: Transforms.h:360
SmallVector< Attribute > paddingValues
A padding value for every operand.
Definition: Transforms.h:353
PadTilingInterfaceOptions & setPadToMultipleOf(bool b)
Definition: Transforms.h:367
bool padToMultipleOf
Pad iterator paddingDimension[i] to next multiple of paddingSizes[i] if true.
Definition: Transforms.h:366
PadTilingInterfaceOptions & setPaddingValues(ArrayRef< Attribute > pv)
Definition: Transforms.h:354
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.
Definition: Transforms.h:1160
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