13c2a74a3SMatthias Springer //===- LinalgTransformOps.cpp - Implementation of Linalg transform ops ----===//
23c2a74a3SMatthias Springer //
33c2a74a3SMatthias Springer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43c2a74a3SMatthias Springer // See https://llvm.org/LICENSE.txt for license information.
53c2a74a3SMatthias Springer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63c2a74a3SMatthias Springer //
73c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
83c2a74a3SMatthias Springer 
93c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h"
103c2a74a3SMatthias Springer 
113c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/IR/Linalg.h"
123c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/Transforms/Transforms.h"
133c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDL.h"
143c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDLTypes.h"
153c2a74a3SMatthias Springer #include "mlir/Dialect/Transform/IR/TransformDialect.h"
163c2a74a3SMatthias Springer #include "mlir/Parser/Parser.h"
17cc6c1592SAlex Zinenko #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
183c2a74a3SMatthias Springer 
193c2a74a3SMatthias Springer using namespace mlir;
203c2a74a3SMatthias Springer using namespace mlir::linalg;
213c2a74a3SMatthias Springer using namespace mlir::transform;
223c2a74a3SMatthias Springer 
233c2a74a3SMatthias Springer /// Extracts a vector of int64_t from an array attribute. Asserts if the
243c2a74a3SMatthias Springer /// attribute contains values other than integers.
253c2a74a3SMatthias Springer static SmallVector<int64_t> extractI64Array(ArrayAttr attr) {
263c2a74a3SMatthias Springer   SmallVector<int64_t> result;
273c2a74a3SMatthias Springer   result.reserve(attr.size());
283c2a74a3SMatthias Springer   for (APInt value : attr.getAsValueRange<IntegerAttr>())
293c2a74a3SMatthias Springer     result.push_back(value.getSExtValue());
303c2a74a3SMatthias Springer   return result;
313c2a74a3SMatthias Springer }
323c2a74a3SMatthias Springer 
333c2a74a3SMatthias Springer /// Extracts a vector of unsigned from an array attribute. Asserts if the
343c2a74a3SMatthias Springer /// attribute contains values other than intergers. May truncate.
353c2a74a3SMatthias Springer static SmallVector<unsigned> extractUIntArray(ArrayAttr attr) {
363c2a74a3SMatthias Springer   SmallVector<unsigned> result;
373c2a74a3SMatthias Springer   result.reserve(attr.size());
383c2a74a3SMatthias Springer   for (APInt value : attr.getAsValueRange<IntegerAttr>())
393c2a74a3SMatthias Springer     result.push_back(value.getZExtValue());
403c2a74a3SMatthias Springer   return result;
413c2a74a3SMatthias Springer }
423c2a74a3SMatthias Springer 
433c2a74a3SMatthias Springer namespace {
443c2a74a3SMatthias Springer /// A simple pattern rewriter that implements no special logic.
453c2a74a3SMatthias Springer class SimpleRewriter : public PatternRewriter {
463c2a74a3SMatthias Springer public:
473c2a74a3SMatthias Springer   SimpleRewriter(MLIRContext *context) : PatternRewriter(context) {}
483c2a74a3SMatthias Springer };
493c2a74a3SMatthias Springer } // namespace
503c2a74a3SMatthias Springer 
51ce2e198bSAlex Zinenko /// Attempts to apply the pattern specified as template argument to the given
52ce2e198bSAlex Zinenko /// operation. The pattern is expected to have a `returningMatchAndRewrite`
53ce2e198bSAlex Zinenko /// function that returns the "main" result or failure. Returns failure if the
54ce2e198bSAlex Zinenko /// pattern failed to apply. Extra arguments are forwarded to the pattern
55ce2e198bSAlex Zinenko /// constructor.
56ce2e198bSAlex Zinenko template <typename PatternTy, typename... Args>
57ce2e198bSAlex Zinenko static FailureOr<LinalgOp> tryApply(Operation *operation, Args &&...args) {
58ce2e198bSAlex Zinenko   // Check if the given operation has the type expected by the pattern.
59ce2e198bSAlex Zinenko   using OpTy = typename llvm::function_traits<
60ce2e198bSAlex Zinenko       decltype(&PatternTy::returningMatchAndRewrite)>::template arg_t<0>;
61ce2e198bSAlex Zinenko   auto op = dyn_cast<OpTy>(operation);
62ce2e198bSAlex Zinenko   if (!op)
63ce2e198bSAlex Zinenko     return failure();
64ce2e198bSAlex Zinenko 
65ce2e198bSAlex Zinenko   // Apply the pattern directly to the op.
66ce2e198bSAlex Zinenko   PatternTy pattern(operation->getContext(), std::forward<Args>(args)...);
67ce2e198bSAlex Zinenko   SimpleRewriter rewriter(operation->getContext());
68ce2e198bSAlex Zinenko   rewriter.setInsertionPoint(operation);
69ce2e198bSAlex Zinenko   auto result = pattern.returningMatchAndRewrite(op, rewriter);
70ce2e198bSAlex Zinenko   if (failed(result))
71ce2e198bSAlex Zinenko     return failure();
72ce2e198bSAlex Zinenko   return cast<LinalgOp>(result->getOperation());
73ce2e198bSAlex Zinenko }
74ce2e198bSAlex Zinenko 
75ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
76ce2e198bSAlex Zinenko // DecomposeOp
77ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
78ce2e198bSAlex Zinenko 
7974f06601SNicolas Vasilache FailureOr<LinalgOp> transform::DecomposeOp::applyToOne(LinalgOp target,
8074f06601SNicolas Vasilache                                                        TransformState &state) {
81ce2e198bSAlex Zinenko   FailureOr<LinalgOp> windowed =
82ce2e198bSAlex Zinenko       tryApply<DownscaleSizeOneWindowed2DConvolution>(target);
83ce2e198bSAlex Zinenko   if (succeeded(windowed))
84ce2e198bSAlex Zinenko     return windowed;
85ce2e198bSAlex Zinenko 
86ce2e198bSAlex Zinenko   FailureOr<LinalgOp> depthwise =
87ce2e198bSAlex Zinenko       tryApply<DownscaleDepthwiseConv2DNhwcHwcOp>(target);
88ce2e198bSAlex Zinenko   if (succeeded(depthwise))
89ce2e198bSAlex Zinenko     return depthwise;
90ce2e198bSAlex Zinenko 
915f0d4f20SAlex Zinenko   return reportUnknownTransformError(target);
92ce2e198bSAlex Zinenko }
93ce2e198bSAlex Zinenko 
94ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
95b6c58ec4SAlex Zinenko // FuseOp
96b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
97b6c58ec4SAlex Zinenko 
98b6c58ec4SAlex Zinenko /// Apply a tiling transformation to all payload ops and store both the
99b6c58ec4SAlex Zinenko /// tiled operation as well as the created tile loops.
100b6c58ec4SAlex Zinenko static LogicalResult
101b6c58ec4SAlex Zinenko applyTilingToAll(Operation *transformOp, Value target,
102b6c58ec4SAlex Zinenko                  ArrayRef<int64_t> tileSizes,
103b6c58ec4SAlex Zinenko                  transform::TransformResults &transformResults,
104b6c58ec4SAlex Zinenko                  transform::TransformState &state,
105b6c58ec4SAlex Zinenko                  function_ref<FailureOr<TiledLinalgOp>(LinalgOp)> applyFn) {
106b6c58ec4SAlex Zinenko   // Number of loops: Number of tiles sizes that are not zero.
107b6c58ec4SAlex Zinenko   size_t numLoops = tileSizes.size() - llvm::count(tileSizes, 0);
108b6c58ec4SAlex Zinenko   // All payload ops. These should all be LinalgOps for now.
109b6c58ec4SAlex Zinenko   ArrayRef<Operation *> payloadOps = state.getPayloadOps(target);
110b6c58ec4SAlex Zinenko 
111b6c58ec4SAlex Zinenko   SmallVector<Operation *> tiledLinalgOps;
112b6c58ec4SAlex Zinenko   SmallVector<SmallVector<Operation *>> loopOps(numLoops);
113b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
114b6c58ec4SAlex Zinenko     loopOps[i].reserve(payloadOps.size());
115b6c58ec4SAlex Zinenko 
116b6c58ec4SAlex Zinenko   for (Operation *target : payloadOps) {
117b6c58ec4SAlex Zinenko     auto linalgOp = dyn_cast<linalg::LinalgOp>(target);
118b6c58ec4SAlex Zinenko     if (!linalgOp)
119b6c58ec4SAlex Zinenko       return transformOp->emitError("only LinalgOps are supported");
120b6c58ec4SAlex Zinenko 
121b6c58ec4SAlex Zinenko     FailureOr<TiledLinalgOp> tiled = applyFn(linalgOp);
122b6c58ec4SAlex Zinenko     if (failed(tiled))
123b6c58ec4SAlex Zinenko       return failure();
124b6c58ec4SAlex Zinenko 
125b6c58ec4SAlex Zinenko     tiledLinalgOps.push_back(tiled->op);
126b6c58ec4SAlex Zinenko     if (tiled->loops.size() != numLoops)
127b6c58ec4SAlex Zinenko       // Not enough loops were generated. This usually means that the input size
128b6c58ec4SAlex Zinenko       // was smaller than the tiling size.
129b6c58ec4SAlex Zinenko       // TODO: LinalgTilingPattern should return failure().
130b6c58ec4SAlex Zinenko       return failure();
131b6c58ec4SAlex Zinenko     for (unsigned int i = 0; i < numLoops; ++i)
132b6c58ec4SAlex Zinenko       loopOps[i].push_back(tiled->loops[i]);
133b6c58ec4SAlex Zinenko   }
134b6c58ec4SAlex Zinenko 
135b6c58ec4SAlex Zinenko   transformResults.set(transformOp->getOpResult(0), tiledLinalgOps);
136b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
137b6c58ec4SAlex Zinenko     transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]);
138b6c58ec4SAlex Zinenko   return success();
139b6c58ec4SAlex Zinenko }
140b6c58ec4SAlex Zinenko 
141b6c58ec4SAlex Zinenko /// Parse a tiling-like operation that returns the tiled op as well as the
142b6c58ec4SAlex Zinenko /// created tile loops. The function counts the non-zero tile sizes to compute
143b6c58ec4SAlex Zinenko /// the number of results.
144b6c58ec4SAlex Zinenko static ParseResult parseTileLikeOp(OpAsmParser &parser, OperationState &result,
145b6c58ec4SAlex Zinenko                                    StringRef sizesAttrName) {
146b6c58ec4SAlex Zinenko   OpAsmParser::UnresolvedOperand targetOperand;
147b6c58ec4SAlex Zinenko   SMLoc opLoc = parser.getCurrentLocation();
148b6c58ec4SAlex Zinenko   if (parser.parseOperand(targetOperand) ||
149b6c58ec4SAlex Zinenko       parser.parseOptionalAttrDict(result.attributes))
150b6c58ec4SAlex Zinenko     return failure();
151b6c58ec4SAlex Zinenko   Attribute sizesAttr = result.attributes.get(sizesAttrName);
152b6c58ec4SAlex Zinenko   if (!sizesAttr)
153b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
154b6c58ec4SAlex Zinenko            << "expected '" << sizesAttrName << "' attribute";
155b6c58ec4SAlex Zinenko   auto sizesArrayAttr = sizesAttr.dyn_cast<ArrayAttr>();
156b6c58ec4SAlex Zinenko   if (!sizesArrayAttr)
157b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
158b6c58ec4SAlex Zinenko            << "'" << sizesAttrName << "' attribute must be an array";
159b6c58ec4SAlex Zinenko   Type pdlOpType = parser.getBuilder().getType<pdl::OperationType>();
160b6c58ec4SAlex Zinenko   size_t numExpectedLoops =
161b6c58ec4SAlex Zinenko       sizesArrayAttr.size() - llvm::count(extractI64Array(sizesArrayAttr), 0);
162b6c58ec4SAlex Zinenko   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOpType));
163b6c58ec4SAlex Zinenko   if (parser.resolveOperand(targetOperand, pdlOpType, result.operands))
164b6c58ec4SAlex Zinenko     return failure();
165b6c58ec4SAlex Zinenko   return success();
166b6c58ec4SAlex Zinenko }
167b6c58ec4SAlex Zinenko 
1681d45282aSAlex Zinenko DiagnosedSilenceableFailure
169b6c58ec4SAlex Zinenko transform::FuseOp::apply(mlir::transform::TransformResults &transformResults,
170b6c58ec4SAlex Zinenko                          mlir::transform::TransformState &state) {
171b6c58ec4SAlex Zinenko   LinalgTilingAndFusionOptions fusionOptions;
172b6c58ec4SAlex Zinenko   fusionOptions.tileSizes = extractI64Array(getTileSizes());
173b6c58ec4SAlex Zinenko   fusionOptions.tileInterchange = extractI64Array(getTileInterchange());
174b6c58ec4SAlex Zinenko 
175e3890b7fSAlex Zinenko   LogicalResult result = applyTilingToAll(
176b6c58ec4SAlex Zinenko       getOperation(), getTarget(), fusionOptions.tileSizes, transformResults,
177b6c58ec4SAlex Zinenko       state, [&](LinalgOp linalgOp) -> FailureOr<TiledLinalgOp> {
178b6c58ec4SAlex Zinenko         LinalgTileAndFuseTensorOpsPattern pattern(getContext(), fusionOptions);
179b6c58ec4SAlex Zinenko         SimpleRewriter rewriter(getContext());
180b6c58ec4SAlex Zinenko         rewriter.setInsertionPoint(linalgOp);
181b6c58ec4SAlex Zinenko         FailureOr<TileLoopNest> tileLoopNest =
182b6c58ec4SAlex Zinenko             pattern.returningMatchAndRewrite(linalgOp, rewriter);
183b6c58ec4SAlex Zinenko         if (failed(tileLoopNest))
184b6c58ec4SAlex Zinenko           return failure();
185b6c58ec4SAlex Zinenko 
186b6c58ec4SAlex Zinenko         TiledLinalgOp tiledLinalgOp;
187b6c58ec4SAlex Zinenko         tiledLinalgOp.op = tileLoopNest->getRootOp();
188b6c58ec4SAlex Zinenko         tiledLinalgOp.loops = {tileLoopNest->getLoopOps().begin(),
189b6c58ec4SAlex Zinenko                                tileLoopNest->getLoopOps().end()};
190b6c58ec4SAlex Zinenko         return tiledLinalgOp;
191b6c58ec4SAlex Zinenko       });
1921d45282aSAlex Zinenko   return failed(result) ? DiagnosedSilenceableFailure::definiteFailure()
1931d45282aSAlex Zinenko                         : DiagnosedSilenceableFailure::success();
194b6c58ec4SAlex Zinenko }
195b6c58ec4SAlex Zinenko 
196b6c58ec4SAlex Zinenko ParseResult transform::FuseOp::parse(OpAsmParser &parser,
197b6c58ec4SAlex Zinenko                                      OperationState &result) {
198b6c58ec4SAlex Zinenko   return parseTileLikeOp(
199b6c58ec4SAlex Zinenko       parser, result,
200b6c58ec4SAlex Zinenko       transform::FuseOp::getTileSizesAttrName(result.name).getValue());
201b6c58ec4SAlex Zinenko }
202b6c58ec4SAlex Zinenko 
203b6c58ec4SAlex Zinenko void transform::FuseOp::print(OpAsmPrinter &p) {
204b6c58ec4SAlex Zinenko   p << ' ';
205b6c58ec4SAlex Zinenko   p << getTarget();
206b6c58ec4SAlex Zinenko   p.printOptionalAttrDict((*this)->getAttrs());
207b6c58ec4SAlex Zinenko }
208b6c58ec4SAlex Zinenko 
209b6c58ec4SAlex Zinenko LogicalResult transform::FuseOp::verify() {
210b6c58ec4SAlex Zinenko   SmallVector<int64_t> permutation = extractI64Array(getTileInterchange());
211b6c58ec4SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, permutation.size()));
212b6c58ec4SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
213b6c58ec4SAlex Zinenko                            permutation.begin(), permutation.end())) {
214b6c58ec4SAlex Zinenko     return emitOpError() << "expects interchange to be a permutation, found "
215b6c58ec4SAlex Zinenko                          << getTileInterchange();
216b6c58ec4SAlex Zinenko   }
217b6c58ec4SAlex Zinenko   return success();
218b6c58ec4SAlex Zinenko }
219b6c58ec4SAlex Zinenko 
220b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
221ce2e198bSAlex Zinenko // GeneralizeOp
222ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
223ce2e198bSAlex Zinenko 
22474f06601SNicolas Vasilache FailureOr<LinalgOp> transform::GeneralizeOp::applyToOne(LinalgOp target,
22574f06601SNicolas Vasilache                                                         TransformState &state) {
226ce2e198bSAlex Zinenko   // Exit early if no transformation is needed.
227ce2e198bSAlex Zinenko   if (isa<GenericOp>(target))
228ce2e198bSAlex Zinenko     return target;
229ce2e198bSAlex Zinenko 
230ce2e198bSAlex Zinenko   FailureOr<LinalgOp> generic = tryApply<LinalgGeneralizationPattern>(target);
231ce2e198bSAlex Zinenko   if (succeeded(generic))
232ce2e198bSAlex Zinenko     return generic;
233ce2e198bSAlex Zinenko 
2345f0d4f20SAlex Zinenko   return reportUnknownTransformError(target);
235ce2e198bSAlex Zinenko }
236ce2e198bSAlex Zinenko 
2373c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
2385cde5a57SAlex Zinenko // InterchangeOp
2395cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
2405cde5a57SAlex Zinenko 
24174f06601SNicolas Vasilache FailureOr<LinalgOp>
24274f06601SNicolas Vasilache transform::InterchangeOp::applyToOne(LinalgOp target, TransformState &state) {
2435cde5a57SAlex Zinenko   SmallVector<unsigned> interchangeVector =
2445cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2455cde5a57SAlex Zinenko   // Exit early if no transformation is needed.
2465cde5a57SAlex Zinenko   if (interchangeVector.empty())
2475cde5a57SAlex Zinenko     return target;
2485cde5a57SAlex Zinenko 
2495cde5a57SAlex Zinenko   auto genericTarget = dyn_cast<GenericOp>(target.getOperation());
2505cde5a57SAlex Zinenko   if (!genericTarget) {
2515cde5a57SAlex Zinenko     InFlightDiagnostic diag = emitOpError()
2525cde5a57SAlex Zinenko                               << "applies to " << GenericOp::getOperationName()
2535cde5a57SAlex Zinenko                               << " ops";
2545cde5a57SAlex Zinenko     diag.attachNote(target.getLoc()) << "attempted to apply to this op";
2555cde5a57SAlex Zinenko     return diag;
2565cde5a57SAlex Zinenko   }
2575cde5a57SAlex Zinenko 
258ce2e198bSAlex Zinenko   return tryApply<GenericOpInterchangePattern>(target, interchangeVector);
2595cde5a57SAlex Zinenko }
2605cde5a57SAlex Zinenko 
2615cde5a57SAlex Zinenko LogicalResult transform::InterchangeOp::verify() {
2625cde5a57SAlex Zinenko   SmallVector<unsigned> permutation =
2635cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2645cde5a57SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<unsigned>(0, permutation.size()));
2655cde5a57SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
2665cde5a57SAlex Zinenko                            permutation.begin(), permutation.end())) {
2675cde5a57SAlex Zinenko     return emitOpError()
2685cde5a57SAlex Zinenko            << "expects iterator_interchange to be a permutation, found "
2695cde5a57SAlex Zinenko            << getIteratorInterchange();
2705cde5a57SAlex Zinenko   }
2715cde5a57SAlex Zinenko   return success();
2725cde5a57SAlex Zinenko }
2735cde5a57SAlex Zinenko 
2745cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2755cde5a57SAlex Zinenko // PadOp
2765cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2775cde5a57SAlex Zinenko 
27874f06601SNicolas Vasilache FailureOr<LinalgOp> transform::PadOp::applyToOne(LinalgOp target,
27974f06601SNicolas Vasilache                                                  TransformState &state) {
2805cde5a57SAlex Zinenko   // Convert the integer packing flags to booleans.
2815cde5a57SAlex Zinenko   SmallVector<bool> packPaddings;
2825cde5a57SAlex Zinenko   for (int64_t packPadding : extractI64Array(getPackPaddings()))
2835cde5a57SAlex Zinenko     packPaddings.push_back(static_cast<bool>(packPadding));
2845cde5a57SAlex Zinenko 
2855cde5a57SAlex Zinenko   // Convert the padding values to attributes.
2865cde5a57SAlex Zinenko   SmallVector<Attribute> paddingValues;
2875cde5a57SAlex Zinenko   for (auto const &it :
2885cde5a57SAlex Zinenko        llvm::zip(getPaddingValues(), target->getOperandTypes())) {
2895cde5a57SAlex Zinenko     Attribute attr = std::get<0>(it);
2905cde5a57SAlex Zinenko     Type elementType = getElementTypeOrSelf(std::get<1>(it));
2915cde5a57SAlex Zinenko     // Try to parse string attributes to obtain an attribute of element type.
2925cde5a57SAlex Zinenko     if (auto stringAttr = attr.dyn_cast<StringAttr>()) {
2935cde5a57SAlex Zinenko       paddingValues.push_back(
2945cde5a57SAlex Zinenko           parseAttribute(attr.cast<StringAttr>(), elementType));
2955cde5a57SAlex Zinenko       if (!paddingValues.back()) {
2965cde5a57SAlex Zinenko         InFlightDiagnostic diag = emitOpError()
2975cde5a57SAlex Zinenko                                   << "expects a padding value that parses to "
2985cde5a57SAlex Zinenko                                   << elementType << ", got " << std::get<0>(it);
2995cde5a57SAlex Zinenko         diag.attachNote(target.getLoc()) << "when applied to this op";
3005cde5a57SAlex Zinenko         return diag;
3015cde5a57SAlex Zinenko       }
3025cde5a57SAlex Zinenko       continue;
3035cde5a57SAlex Zinenko     }
3045cde5a57SAlex Zinenko     // Otherwise, add the attribute directly.
3055cde5a57SAlex Zinenko     if (attr.getType() != elementType) {
3065cde5a57SAlex Zinenko       InFlightDiagnostic diag = emitOpError()
3075cde5a57SAlex Zinenko                                 << "expects a padding value of type "
3085cde5a57SAlex Zinenko                                 << elementType << ", got " << attr;
3095cde5a57SAlex Zinenko       diag.attachNote(target.getLoc()) << "when applied to this op";
3105cde5a57SAlex Zinenko       return diag;
3115cde5a57SAlex Zinenko     }
3125cde5a57SAlex Zinenko     paddingValues.push_back(attr);
3135cde5a57SAlex Zinenko   }
3145cde5a57SAlex Zinenko 
3155cde5a57SAlex Zinenko   // Extract the transpose vectors.
3165cde5a57SAlex Zinenko   SmallVector<SmallVector<int64_t>> transposePaddings;
3175cde5a57SAlex Zinenko   for (Attribute transposeVector : getTransposePaddings().cast<ArrayAttr>())
3185cde5a57SAlex Zinenko     transposePaddings.push_back(
3195cde5a57SAlex Zinenko         extractI64Array(transposeVector.cast<ArrayAttr>()));
3205cde5a57SAlex Zinenko 
3215cde5a57SAlex Zinenko   LinalgPaddingOptions paddingOptions;
3225cde5a57SAlex Zinenko   paddingOptions.setPaddingValues(paddingValues);
3235cde5a57SAlex Zinenko   paddingOptions.setPaddingDimensions(extractI64Array(getPaddingDimensions()));
3245cde5a57SAlex Zinenko   paddingOptions.setPackPaddings(packPaddings);
3255cde5a57SAlex Zinenko   paddingOptions.setHoistPaddings(extractI64Array(getHoistPaddings()));
3265cde5a57SAlex Zinenko   paddingOptions.setTransposePaddings(transposePaddings);
3275cde5a57SAlex Zinenko 
328ce2e198bSAlex Zinenko   FailureOr<LinalgOp> result =
329ce2e198bSAlex Zinenko       tryApply<LinalgPaddingPattern>(target, paddingOptions);
330ce2e198bSAlex Zinenko   if (succeeded(result))
331ce2e198bSAlex Zinenko     return result;
332ce2e198bSAlex Zinenko 
3335cde5a57SAlex Zinenko   InFlightDiagnostic diag = emitError()
3345cde5a57SAlex Zinenko                             << "failed to apply pattern to target op";
3355cde5a57SAlex Zinenko   diag.attachNote(target.getLoc()) << "target op";
3365cde5a57SAlex Zinenko   return diag;
3375cde5a57SAlex Zinenko }
3385cde5a57SAlex Zinenko 
3395cde5a57SAlex Zinenko LogicalResult transform::PadOp::verify() {
3405cde5a57SAlex Zinenko   SmallVector<int64_t> packPaddings = extractI64Array(getPackPaddings());
3415cde5a57SAlex Zinenko   if (any_of(packPaddings, [](int64_t packPadding) {
3425cde5a57SAlex Zinenko         return packPadding != 0 && packPadding != 1;
3435cde5a57SAlex Zinenko       })) {
3445cde5a57SAlex Zinenko     return emitOpError()
3455cde5a57SAlex Zinenko            << "expects pack_paddings to contain booleans (0/1), found "
3465cde5a57SAlex Zinenko            << getPackPaddings();
3475cde5a57SAlex Zinenko   }
3485cde5a57SAlex Zinenko 
3495cde5a57SAlex Zinenko   SmallVector<int64_t> paddingDimensions =
3505cde5a57SAlex Zinenko       extractI64Array(getPaddingDimensions());
3515cde5a57SAlex Zinenko   if (any_of(paddingDimensions,
3525cde5a57SAlex Zinenko              [](int64_t paddingDimension) { return paddingDimension < 0; })) {
3535cde5a57SAlex Zinenko     return emitOpError()
3545cde5a57SAlex Zinenko            << "expects padding_dimensions to contain positive integers, found "
3555cde5a57SAlex Zinenko            << getPaddingDimensions();
3565cde5a57SAlex Zinenko   }
3575cde5a57SAlex Zinenko 
3585cde5a57SAlex Zinenko   SmallVector<int64_t> hoistPaddings = extractI64Array(getHoistPaddings());
3595cde5a57SAlex Zinenko   if (any_of(hoistPaddings,
3605cde5a57SAlex Zinenko              [](int64_t hoistPadding) { return hoistPadding < 0; })) {
3615cde5a57SAlex Zinenko     return emitOpError()
3625cde5a57SAlex Zinenko            << "expects hoist_paddings to contain positive integers, found "
3635cde5a57SAlex Zinenko            << getHoistPaddings();
3645cde5a57SAlex Zinenko   }
3655cde5a57SAlex Zinenko 
3665cde5a57SAlex Zinenko   ArrayAttr transposes = getTransposePaddings();
3675cde5a57SAlex Zinenko   for (Attribute attr : transposes) {
3685cde5a57SAlex Zinenko     SmallVector<int64_t> transpose = extractFromI64ArrayAttr(attr);
3695cde5a57SAlex Zinenko     auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, transpose.size()));
3705cde5a57SAlex Zinenko     if (!std::is_permutation(sequence.begin(), sequence.end(),
3715cde5a57SAlex Zinenko                              transpose.begin(), transpose.end())) {
3725cde5a57SAlex Zinenko       return emitOpError()
3735cde5a57SAlex Zinenko              << "expects transpose_paddings to be a permutation, found "
3745cde5a57SAlex Zinenko              << attr;
3755cde5a57SAlex Zinenko     }
3765cde5a57SAlex Zinenko   }
3775cde5a57SAlex Zinenko   return success();
3785cde5a57SAlex Zinenko }
3795cde5a57SAlex Zinenko 
3805cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3815cde5a57SAlex Zinenko // ScalarizeOp
3825cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3835cde5a57SAlex Zinenko 
38474f06601SNicolas Vasilache FailureOr<LinalgOp> transform::ScalarizeOp::applyToOne(LinalgOp target,
38574f06601SNicolas Vasilache                                                        TransformState &state) {
3865cde5a57SAlex Zinenko   LinalgTilingOptions tilingOptions;
3875cde5a57SAlex Zinenko   tilingOptions.scalarizeDynamicDims();
3885cde5a57SAlex Zinenko   // Tiling with "scalarize_dyn_dims" actually sets the same lambda as the tile
3895cde5a57SAlex Zinenko   // sizes and asserts that it is not already set.
3905cde5a57SAlex Zinenko   SmallVector<int64_t> emptyTileSizes;
3915cde5a57SAlex Zinenko   LinalgTilingPattern pattern(getContext(), tilingOptions);
3925cde5a57SAlex Zinenko   SimpleRewriter rewriter(getContext());
3935cde5a57SAlex Zinenko   rewriter.setInsertionPoint(target);
3945cde5a57SAlex Zinenko   FailureOr<TiledLinalgOp> result =
3955cde5a57SAlex Zinenko       pattern.returningMatchAndRewrite(target, rewriter);
3965cde5a57SAlex Zinenko   if (failed(result))
3975cde5a57SAlex Zinenko     return failure();
3985cde5a57SAlex Zinenko 
3995cde5a57SAlex Zinenko   return result->op;
4005cde5a57SAlex Zinenko }
4015cde5a57SAlex Zinenko 
4025cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
403*ff6e5508SAlex Zinenko // SplitOp
404*ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
405*ff6e5508SAlex Zinenko 
406*ff6e5508SAlex Zinenko DiagnosedSilenceableFailure SplitOp::apply(TransformResults &results,
407*ff6e5508SAlex Zinenko                                            TransformState &state) {
408*ff6e5508SAlex Zinenko   // Collect the dynamic split points if provided.
409*ff6e5508SAlex Zinenko   ArrayRef<Operation *> payload = state.getPayloadOps(getTarget());
410*ff6e5508SAlex Zinenko   SimpleRewriter rewriter(getContext());
411*ff6e5508SAlex Zinenko   SmallVector<OpFoldResult> splitPoints;
412*ff6e5508SAlex Zinenko   splitPoints.reserve(payload.size());
413*ff6e5508SAlex Zinenko   if (getDynamicSplitPoint()) {
414*ff6e5508SAlex Zinenko     auto diag = DiagnosedSilenceableFailure::success();
415*ff6e5508SAlex Zinenko     splitPoints = llvm::to_vector(llvm::map_range(
416*ff6e5508SAlex Zinenko         state.getPayloadOps(getDynamicSplitPoint()), [&](Operation *op) {
417*ff6e5508SAlex Zinenko           if (op->getNumResults() != 1 ||
418*ff6e5508SAlex Zinenko               !op->getResult(0).getType().isIndex()) {
419*ff6e5508SAlex Zinenko             diag = emitSilenceableError()
420*ff6e5508SAlex Zinenko                    << "expected dynamic split point handle to point to a "
421*ff6e5508SAlex Zinenko                       "single-result index-typed op";
422*ff6e5508SAlex Zinenko             diag.attachNote(op->getLoc()) << "dynamic split point";
423*ff6e5508SAlex Zinenko           }
424*ff6e5508SAlex Zinenko           return OpFoldResult(op->getResult(0));
425*ff6e5508SAlex Zinenko         }));
426*ff6e5508SAlex Zinenko     if (!diag.succeeded())
427*ff6e5508SAlex Zinenko       return diag;
428*ff6e5508SAlex Zinenko 
429*ff6e5508SAlex Zinenko     if (splitPoints.size() != payload.size()) {
430*ff6e5508SAlex Zinenko       emitError() << "expected the dynamic split point handle to point to as "
431*ff6e5508SAlex Zinenko                      "many operations ("
432*ff6e5508SAlex Zinenko                   << splitPoints.size() << ") as the target handle ("
433*ff6e5508SAlex Zinenko                   << payload.size() << ")";
434*ff6e5508SAlex Zinenko       return DiagnosedSilenceableFailure::definiteFailure();
435*ff6e5508SAlex Zinenko     }
436*ff6e5508SAlex Zinenko   } else {
437*ff6e5508SAlex Zinenko     splitPoints.resize(payload.size(),
438*ff6e5508SAlex Zinenko                        rewriter.getIndexAttr(getStaticSplitPoint()));
439*ff6e5508SAlex Zinenko   }
440*ff6e5508SAlex Zinenko 
441*ff6e5508SAlex Zinenko   // Split each target operation.
442*ff6e5508SAlex Zinenko   SmallVector<Operation *> first, second;
443*ff6e5508SAlex Zinenko   for (const auto &pair : llvm::zip(payload, splitPoints)) {
444*ff6e5508SAlex Zinenko     Operation *target = std::get<0>(pair);
445*ff6e5508SAlex Zinenko     auto linalgOp = dyn_cast<LinalgOp>(target);
446*ff6e5508SAlex Zinenko     if (!linalgOp) {
447*ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "only applies to structured ops";
448*ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
449*ff6e5508SAlex Zinenko       return diag;
450*ff6e5508SAlex Zinenko     }
451*ff6e5508SAlex Zinenko 
452*ff6e5508SAlex Zinenko     if (getDimension() >= linalgOp.getNumLoops()) {
453*ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "dimension " << getDimension()
454*ff6e5508SAlex Zinenko                                          << " does not exist in target op";
455*ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
456*ff6e5508SAlex Zinenko       return diag;
457*ff6e5508SAlex Zinenko     }
458*ff6e5508SAlex Zinenko 
459*ff6e5508SAlex Zinenko     rewriter.setInsertionPoint(linalgOp);
460*ff6e5508SAlex Zinenko     std::tie(first.emplace_back(), second.emplace_back()) =
461*ff6e5508SAlex Zinenko         linalg::splitOp(rewriter, linalgOp, getDimension(), std::get<1>(pair));
462*ff6e5508SAlex Zinenko   }
463*ff6e5508SAlex Zinenko 
464*ff6e5508SAlex Zinenko   results.set(getFirst().cast<OpResult>(), first);
465*ff6e5508SAlex Zinenko   results.set(getSecond().cast<OpResult>(), second);
466*ff6e5508SAlex Zinenko   return DiagnosedSilenceableFailure::success();
467*ff6e5508SAlex Zinenko }
468*ff6e5508SAlex Zinenko 
469*ff6e5508SAlex Zinenko void SplitOp::getEffects(
470*ff6e5508SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
471*ff6e5508SAlex Zinenko   // The target handle is consumed.
472*ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Read::get(), getTarget(),
473*ff6e5508SAlex Zinenko                        TransformMappingResource::get());
474*ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Free::get(), getTarget(),
475*ff6e5508SAlex Zinenko                        TransformMappingResource::get());
476*ff6e5508SAlex Zinenko 
477*ff6e5508SAlex Zinenko   // The dynamic split point handle is not consumed.
478*ff6e5508SAlex Zinenko   if (getDynamicSplitPoint()) {
479*ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Read::get(), getDynamicSplitPoint(),
480*ff6e5508SAlex Zinenko                          TransformMappingResource::get());
481*ff6e5508SAlex Zinenko   }
482*ff6e5508SAlex Zinenko 
483*ff6e5508SAlex Zinenko   // The resulting handles are produced.
484*ff6e5508SAlex Zinenko   for (Value result : getResults()) {
485*ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Allocate::get(), result,
486*ff6e5508SAlex Zinenko                          TransformMappingResource::get());
487*ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Write::get(), result,
488*ff6e5508SAlex Zinenko                          TransformMappingResource::get());
489*ff6e5508SAlex Zinenko   }
490*ff6e5508SAlex Zinenko 
491*ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Read::get(), PayloadIRResource::get());
492*ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Write::get(), PayloadIRResource::get());
493*ff6e5508SAlex Zinenko }
494*ff6e5508SAlex Zinenko 
495*ff6e5508SAlex Zinenko ParseResult SplitOp::parse(OpAsmParser &parser, OperationState &result) {
496*ff6e5508SAlex Zinenko   OpAsmParser::UnresolvedOperand target, dynamicSplitPoint;
497*ff6e5508SAlex Zinenko   IntegerAttr staticSplitPoint;
498*ff6e5508SAlex Zinenko   auto pdlOperationType =
499*ff6e5508SAlex Zinenko       pdl::OperationType::get(parser.getBuilder().getContext());
500*ff6e5508SAlex Zinenko   if (parser.parseOperand(target) ||
501*ff6e5508SAlex Zinenko       parser.resolveOperand(target, pdlOperationType, result.operands) ||
502*ff6e5508SAlex Zinenko       parser.parseKeyword("after"))
503*ff6e5508SAlex Zinenko     return failure();
504*ff6e5508SAlex Zinenko 
505*ff6e5508SAlex Zinenko   OptionalParseResult dynamicPointParseResult =
506*ff6e5508SAlex Zinenko       parser.parseOptionalOperand(dynamicSplitPoint);
507*ff6e5508SAlex Zinenko   if (!dynamicPointParseResult.hasValue()) {
508*ff6e5508SAlex Zinenko     int64_t staticSplitPointValue;
509*ff6e5508SAlex Zinenko     if (failed(parser.parseInteger(staticSplitPointValue)))
510*ff6e5508SAlex Zinenko       return failure();
511*ff6e5508SAlex Zinenko 
512*ff6e5508SAlex Zinenko     staticSplitPoint =
513*ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(staticSplitPointValue);
514*ff6e5508SAlex Zinenko   } else {
515*ff6e5508SAlex Zinenko     if (failed(*dynamicPointParseResult) ||
516*ff6e5508SAlex Zinenko         parser.resolveOperand(dynamicSplitPoint, pdlOperationType,
517*ff6e5508SAlex Zinenko                               result.operands)) {
518*ff6e5508SAlex Zinenko       return failure();
519*ff6e5508SAlex Zinenko     }
520*ff6e5508SAlex Zinenko 
521*ff6e5508SAlex Zinenko     staticSplitPoint =
522*ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(ShapedType::kDynamicSize);
523*ff6e5508SAlex Zinenko   }
524*ff6e5508SAlex Zinenko 
525*ff6e5508SAlex Zinenko   result.addAttribute(
526*ff6e5508SAlex Zinenko       SplitOp::getStaticSplitPointAttrName(result.name).getValue(),
527*ff6e5508SAlex Zinenko       staticSplitPoint);
528*ff6e5508SAlex Zinenko   if (failed(parser.parseOptionalAttrDict(result.attributes)))
529*ff6e5508SAlex Zinenko     return failure();
530*ff6e5508SAlex Zinenko 
531*ff6e5508SAlex Zinenko   result.addTypes({pdlOperationType, pdlOperationType});
532*ff6e5508SAlex Zinenko   return success();
533*ff6e5508SAlex Zinenko }
534*ff6e5508SAlex Zinenko 
535*ff6e5508SAlex Zinenko void SplitOp::print(OpAsmPrinter &printer) {
536*ff6e5508SAlex Zinenko   printer << " " << getTarget() << " after ";
537*ff6e5508SAlex Zinenko   int64_t staticSplitSize = static_cast<int64_t>(getStaticSplitPoint());
538*ff6e5508SAlex Zinenko   if (staticSplitSize != ShapedType::kDynamicSize)
539*ff6e5508SAlex Zinenko     printer << staticSplitSize;
540*ff6e5508SAlex Zinenko   else
541*ff6e5508SAlex Zinenko     printer << getDynamicSplitPoint();
542*ff6e5508SAlex Zinenko   printer << " ";
543*ff6e5508SAlex Zinenko   printer.printOptionalAttrDict(getOperation()->getAttrs(),
544*ff6e5508SAlex Zinenko                                 {getStaticSplitPointAttrName()});
545*ff6e5508SAlex Zinenko }
546*ff6e5508SAlex Zinenko 
547*ff6e5508SAlex Zinenko LogicalResult SplitOp::verify() {
548*ff6e5508SAlex Zinenko   if ((static_cast<int64_t>(getStaticSplitPoint()) !=
549*ff6e5508SAlex Zinenko        ShapedType::kDynamicSize) ^
550*ff6e5508SAlex Zinenko       (getDynamicSplitPoint() == nullptr)) {
551*ff6e5508SAlex Zinenko     return emitOpError()
552*ff6e5508SAlex Zinenko            << "expects either a dynamic or a static split point to be provided";
553*ff6e5508SAlex Zinenko   }
554*ff6e5508SAlex Zinenko   return success();
555*ff6e5508SAlex Zinenko }
556*ff6e5508SAlex Zinenko 
557*ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
558f439b319SNicolas Vasilache // SplitReductionOp
559f439b319SNicolas Vasilache //===----------------------------------------------------------------------===//
560f439b319SNicolas Vasilache 
561f439b319SNicolas Vasilache FailureOr<SmallVector<Operation *>>
56274f06601SNicolas Vasilache transform::SplitReductionOp::applyToOne(LinalgOp target,
56374f06601SNicolas Vasilache                                         TransformState &state) {
564f439b319SNicolas Vasilache   ControlSplitReductionFn splitFn = [&](LinalgOp) {
565f439b319SNicolas Vasilache     return std::pair<int64_t, unsigned>(getSplitFactor(),
566f439b319SNicolas Vasilache                                         getInsertSplitDimension());
567f439b319SNicolas Vasilache   };
568f439b319SNicolas Vasilache   SimpleRewriter rewriter(getContext());
569f439b319SNicolas Vasilache   rewriter.setInsertionPoint(target);
570f439b319SNicolas Vasilache   FailureOr<SplitReductionResult> splitResult =
571178f9bd6SNicolas Vasilache       (getUseScalingAlgorithm())
572178f9bd6SNicolas Vasilache           ? splitReductionByScaling(rewriter, target, splitFn, getUseAlloc())
573178f9bd6SNicolas Vasilache           : splitReduction(rewriter, target, splitFn, getUseAlloc());
574d5716395SNicolas Vasilache   if (failed(splitResult))
575d5716395SNicolas Vasilache     return getOperation()->emitError("failed to apply");
576d5716395SNicolas Vasilache   return SmallVector<Operation *>{splitResult->fillOp,
577d5716395SNicolas Vasilache                                   splitResult->splitLinalgOp,
578d5716395SNicolas Vasilache                                   splitResult->resultCombiningLinalgOp};
579d5716395SNicolas Vasilache }
580d5716395SNicolas Vasilache 
581d5716395SNicolas Vasilache //===----------------------------------------------------------------------===//
5823c2a74a3SMatthias Springer // TileOp
5833c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
5843c2a74a3SMatthias Springer 
5851d45282aSAlex Zinenko DiagnosedSilenceableFailure
586e3890b7fSAlex Zinenko transform::TileOp::apply(TransformResults &transformResults,
5873c2a74a3SMatthias Springer                          TransformState &state) {
5883c2a74a3SMatthias Springer   LinalgTilingOptions tilingOptions;
5893c2a74a3SMatthias Springer   SmallVector<int64_t> tileSizes = extractI64Array(getSizes());
5903c2a74a3SMatthias Springer 
5913c2a74a3SMatthias Springer   if (!tileSizes.empty())
5923c2a74a3SMatthias Springer     tilingOptions.setTileSizes(tileSizes);
5933c2a74a3SMatthias Springer   tilingOptions.setInterchange(extractUIntArray(getInterchange()));
5943c2a74a3SMatthias Springer   LinalgTilingPattern pattern(getContext(), tilingOptions);
5953c2a74a3SMatthias Springer 
596e3890b7fSAlex Zinenko   LogicalResult result = applyTilingToAll(
597e3890b7fSAlex Zinenko       getOperation(), getTarget(), tileSizes, transformResults, state,
598e3890b7fSAlex Zinenko       [&](LinalgOp linalgOp) {
5993c2a74a3SMatthias Springer         SimpleRewriter rewriter(linalgOp.getContext());
600e3890b7fSAlex Zinenko         return pattern.returningMatchAndRewrite(linalgOp, rewriter);
6013c2a74a3SMatthias Springer       });
6021d45282aSAlex Zinenko   return DiagnosedSilenceableFailure(result);
6033c2a74a3SMatthias Springer }
6043c2a74a3SMatthias Springer 
6053c2a74a3SMatthias Springer ParseResult transform::TileOp::parse(OpAsmParser &parser,
6063c2a74a3SMatthias Springer                                      OperationState &result) {
607b6c58ec4SAlex Zinenko   return parseTileLikeOp(parser, result,
608b6c58ec4SAlex Zinenko                          TileOp::getSizesAttrName(result.name).getValue());
6093c2a74a3SMatthias Springer }
6103c2a74a3SMatthias Springer 
6113c2a74a3SMatthias Springer void TileOp::print(OpAsmPrinter &p) {
6123c2a74a3SMatthias Springer   p << ' ';
6133c2a74a3SMatthias Springer   p << getTarget();
6143c2a74a3SMatthias Springer   p.printOptionalAttrDict((*this)->getAttrs());
6153c2a74a3SMatthias Springer }
6163c2a74a3SMatthias Springer 
6173c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
618cc6c1592SAlex Zinenko // VectorizeOp
619cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
620cc6c1592SAlex Zinenko 
62174f06601SNicolas Vasilache FailureOr<Operation *> VectorizeOp::applyToOne(Operation *target,
62274f06601SNicolas Vasilache                                                TransformState &state) {
623cc6c1592SAlex Zinenko   if (!target->hasTrait<OpTrait::IsIsolatedFromAbove>()) {
624cc6c1592SAlex Zinenko     InFlightDiagnostic diag = emitOpError()
625cc6c1592SAlex Zinenko                               << "applies only to isolated-from-above targets";
626cc6c1592SAlex Zinenko     diag.attachNote(target->getLoc()) << "non-isolated target";
627cc6c1592SAlex Zinenko     return diag;
628cc6c1592SAlex Zinenko   }
629cc6c1592SAlex Zinenko 
630cc6c1592SAlex Zinenko   MLIRContext *ctx = getContext();
631cc6c1592SAlex Zinenko   RewritePatternSet patterns(ctx);
632cc6c1592SAlex Zinenko   patterns.add<LinalgVectorizationPattern>(ctx);
633cc6c1592SAlex Zinenko 
634cc6c1592SAlex Zinenko   vector::populateVectorTransferPermutationMapLoweringPatterns(patterns);
635cc6c1592SAlex Zinenko   vector::populateVectorReductionToContractPatterns(patterns);
636cc6c1592SAlex Zinenko   patterns.add<linalg::LinalgCopyVTRForwardingPattern,
637cc6c1592SAlex Zinenko                linalg::LinalgCopyVTWForwardingPattern>(ctx,
638cc6c1592SAlex Zinenko                                                        /*benefit=*/2);
639cc6c1592SAlex Zinenko   vector::TransferReadOp::getCanonicalizationPatterns(patterns, ctx);
640cc6c1592SAlex Zinenko   vector::TransferWriteOp::getCanonicalizationPatterns(patterns, ctx);
641cc6c1592SAlex Zinenko   if (getVectorizePadding())
642cc6c1592SAlex Zinenko     linalg::populatePadOpVectorizationPatterns(patterns);
643cc6c1592SAlex Zinenko 
6445f0d4f20SAlex Zinenko   if (failed(applyPatternsAndFoldGreedily(target, std::move(patterns))))
6455f0d4f20SAlex Zinenko     return reportUnknownTransformError(target);
646cc6c1592SAlex Zinenko   return target;
647cc6c1592SAlex Zinenko }
648cc6c1592SAlex Zinenko 
649cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
6503c2a74a3SMatthias Springer // Transform op registration
6513c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
6523c2a74a3SMatthias Springer 
6533c2a74a3SMatthias Springer namespace {
6543c2a74a3SMatthias Springer /// Registers new ops and declares PDL as dependent dialect since the additional
6553c2a74a3SMatthias Springer /// ops are using PDL types for operands and results.
6563c2a74a3SMatthias Springer class LinalgTransformDialectExtension
6573c2a74a3SMatthias Springer     : public transform::TransformDialectExtension<
6583c2a74a3SMatthias Springer           LinalgTransformDialectExtension> {
6593c2a74a3SMatthias Springer public:
6603c2a74a3SMatthias Springer   LinalgTransformDialectExtension() {
6613c2a74a3SMatthias Springer     declareDependentDialect<pdl::PDLDialect>();
6623c2a74a3SMatthias Springer     declareDependentDialect<scf::SCFDialect>();
663cc6c1592SAlex Zinenko     declareDependentDialect<vector::VectorDialect>();
6643c2a74a3SMatthias Springer     registerTransformOps<
6653c2a74a3SMatthias Springer #define GET_OP_LIST
6663c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
6673c2a74a3SMatthias Springer         >();
6683c2a74a3SMatthias Springer   }
6693c2a74a3SMatthias Springer };
6703c2a74a3SMatthias Springer } // namespace
6713c2a74a3SMatthias Springer 
6723c2a74a3SMatthias Springer #define GET_OP_CLASSES
6733c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
6743c2a74a3SMatthias Springer 
6753c2a74a3SMatthias Springer void mlir::linalg::registerTransformDialectExtension(
6763c2a74a3SMatthias Springer     DialectRegistry &registry) {
6773c2a74a3SMatthias Springer   registry.addExtensions<LinalgTransformDialectExtension>();
6783c2a74a3SMatthias Springer }
679