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 
79*52307109SNicolas Vasilache DiagnosedSilenceableFailure
80*52307109SNicolas Vasilache transform::DecomposeOp::applyToOne(linalg::LinalgOp target,
81*52307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
82*52307109SNicolas Vasilache                                    transform::TransformState &state) {
83ce2e198bSAlex Zinenko   FailureOr<LinalgOp> windowed =
84ce2e198bSAlex Zinenko       tryApply<DownscaleSizeOneWindowed2DConvolution>(target);
85*52307109SNicolas Vasilache   if (succeeded(windowed)) {
86*52307109SNicolas Vasilache     results.push_back(*windowed);
87*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
88*52307109SNicolas Vasilache   }
89ce2e198bSAlex Zinenko   FailureOr<LinalgOp> depthwise =
90ce2e198bSAlex Zinenko       tryApply<DownscaleDepthwiseConv2DNhwcHwcOp>(target);
91*52307109SNicolas Vasilache   if (succeeded(depthwise)) {
92*52307109SNicolas Vasilache     results.push_back(*depthwise);
93*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
94*52307109SNicolas Vasilache   }
95*52307109SNicolas Vasilache   results.assign(1, nullptr);
96*52307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
97ce2e198bSAlex Zinenko }
98ce2e198bSAlex Zinenko 
99ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
100b6c58ec4SAlex Zinenko // FuseOp
101b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
102b6c58ec4SAlex Zinenko 
103b6c58ec4SAlex Zinenko /// Apply a tiling transformation to all payload ops and store both the
104b6c58ec4SAlex Zinenko /// tiled operation as well as the created tile loops.
105b6c58ec4SAlex Zinenko static LogicalResult
106b6c58ec4SAlex Zinenko applyTilingToAll(Operation *transformOp, Value target,
107b6c58ec4SAlex Zinenko                  ArrayRef<int64_t> tileSizes,
108b6c58ec4SAlex Zinenko                  transform::TransformResults &transformResults,
109b6c58ec4SAlex Zinenko                  transform::TransformState &state,
110b6c58ec4SAlex Zinenko                  function_ref<FailureOr<TiledLinalgOp>(LinalgOp)> applyFn) {
111b6c58ec4SAlex Zinenko   // Number of loops: Number of tiles sizes that are not zero.
112b6c58ec4SAlex Zinenko   size_t numLoops = tileSizes.size() - llvm::count(tileSizes, 0);
113b6c58ec4SAlex Zinenko   // All payload ops. These should all be LinalgOps for now.
114b6c58ec4SAlex Zinenko   ArrayRef<Operation *> payloadOps = state.getPayloadOps(target);
115b6c58ec4SAlex Zinenko 
116b6c58ec4SAlex Zinenko   SmallVector<Operation *> tiledLinalgOps;
117b6c58ec4SAlex Zinenko   SmallVector<SmallVector<Operation *>> loopOps(numLoops);
118b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
119b6c58ec4SAlex Zinenko     loopOps[i].reserve(payloadOps.size());
120b6c58ec4SAlex Zinenko 
121b6c58ec4SAlex Zinenko   for (Operation *target : payloadOps) {
122b6c58ec4SAlex Zinenko     auto linalgOp = dyn_cast<linalg::LinalgOp>(target);
123b6c58ec4SAlex Zinenko     if (!linalgOp)
124b6c58ec4SAlex Zinenko       return transformOp->emitError("only LinalgOps are supported");
125b6c58ec4SAlex Zinenko 
126b6c58ec4SAlex Zinenko     FailureOr<TiledLinalgOp> tiled = applyFn(linalgOp);
127b6c58ec4SAlex Zinenko     if (failed(tiled))
128b6c58ec4SAlex Zinenko       return failure();
129b6c58ec4SAlex Zinenko 
130b6c58ec4SAlex Zinenko     tiledLinalgOps.push_back(tiled->op);
131b6c58ec4SAlex Zinenko     if (tiled->loops.size() != numLoops)
132b6c58ec4SAlex Zinenko       // Not enough loops were generated. This usually means that the input size
133b6c58ec4SAlex Zinenko       // was smaller than the tiling size.
134b6c58ec4SAlex Zinenko       // TODO: LinalgTilingPattern should return failure().
135b6c58ec4SAlex Zinenko       return failure();
136b6c58ec4SAlex Zinenko     for (unsigned int i = 0; i < numLoops; ++i)
137b6c58ec4SAlex Zinenko       loopOps[i].push_back(tiled->loops[i]);
138b6c58ec4SAlex Zinenko   }
139b6c58ec4SAlex Zinenko 
140b6c58ec4SAlex Zinenko   transformResults.set(transformOp->getOpResult(0), tiledLinalgOps);
141b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
142b6c58ec4SAlex Zinenko     transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]);
143b6c58ec4SAlex Zinenko   return success();
144b6c58ec4SAlex Zinenko }
145b6c58ec4SAlex Zinenko 
146b6c58ec4SAlex Zinenko /// Parse a tiling-like operation that returns the tiled op as well as the
147b6c58ec4SAlex Zinenko /// created tile loops. The function counts the non-zero tile sizes to compute
148b6c58ec4SAlex Zinenko /// the number of results.
149b6c58ec4SAlex Zinenko static ParseResult parseTileLikeOp(OpAsmParser &parser, OperationState &result,
150b6c58ec4SAlex Zinenko                                    StringRef sizesAttrName) {
151b6c58ec4SAlex Zinenko   OpAsmParser::UnresolvedOperand targetOperand;
152b6c58ec4SAlex Zinenko   SMLoc opLoc = parser.getCurrentLocation();
153b6c58ec4SAlex Zinenko   if (parser.parseOperand(targetOperand) ||
154b6c58ec4SAlex Zinenko       parser.parseOptionalAttrDict(result.attributes))
155b6c58ec4SAlex Zinenko     return failure();
156b6c58ec4SAlex Zinenko   Attribute sizesAttr = result.attributes.get(sizesAttrName);
157b6c58ec4SAlex Zinenko   if (!sizesAttr)
158b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
159b6c58ec4SAlex Zinenko            << "expected '" << sizesAttrName << "' attribute";
160b6c58ec4SAlex Zinenko   auto sizesArrayAttr = sizesAttr.dyn_cast<ArrayAttr>();
161b6c58ec4SAlex Zinenko   if (!sizesArrayAttr)
162b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
163b6c58ec4SAlex Zinenko            << "'" << sizesAttrName << "' attribute must be an array";
164b6c58ec4SAlex Zinenko   Type pdlOpType = parser.getBuilder().getType<pdl::OperationType>();
165b6c58ec4SAlex Zinenko   size_t numExpectedLoops =
166b6c58ec4SAlex Zinenko       sizesArrayAttr.size() - llvm::count(extractI64Array(sizesArrayAttr), 0);
167b6c58ec4SAlex Zinenko   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOpType));
168b6c58ec4SAlex Zinenko   if (parser.resolveOperand(targetOperand, pdlOpType, result.operands))
169b6c58ec4SAlex Zinenko     return failure();
170b6c58ec4SAlex Zinenko   return success();
171b6c58ec4SAlex Zinenko }
172b6c58ec4SAlex Zinenko 
1731d45282aSAlex Zinenko DiagnosedSilenceableFailure
174b6c58ec4SAlex Zinenko transform::FuseOp::apply(mlir::transform::TransformResults &transformResults,
175b6c58ec4SAlex Zinenko                          mlir::transform::TransformState &state) {
176b6c58ec4SAlex Zinenko   LinalgTilingAndFusionOptions fusionOptions;
177b6c58ec4SAlex Zinenko   fusionOptions.tileSizes = extractI64Array(getTileSizes());
178b6c58ec4SAlex Zinenko   fusionOptions.tileInterchange = extractI64Array(getTileInterchange());
179b6c58ec4SAlex Zinenko 
180e3890b7fSAlex Zinenko   LogicalResult result = applyTilingToAll(
181b6c58ec4SAlex Zinenko       getOperation(), getTarget(), fusionOptions.tileSizes, transformResults,
182b6c58ec4SAlex Zinenko       state, [&](LinalgOp linalgOp) -> FailureOr<TiledLinalgOp> {
183b6c58ec4SAlex Zinenko         LinalgTileAndFuseTensorOpsPattern pattern(getContext(), fusionOptions);
184b6c58ec4SAlex Zinenko         SimpleRewriter rewriter(getContext());
185b6c58ec4SAlex Zinenko         rewriter.setInsertionPoint(linalgOp);
186b6c58ec4SAlex Zinenko         FailureOr<TileLoopNest> tileLoopNest =
187b6c58ec4SAlex Zinenko             pattern.returningMatchAndRewrite(linalgOp, rewriter);
188b6c58ec4SAlex Zinenko         if (failed(tileLoopNest))
189b6c58ec4SAlex Zinenko           return failure();
190b6c58ec4SAlex Zinenko 
191b6c58ec4SAlex Zinenko         TiledLinalgOp tiledLinalgOp;
192b6c58ec4SAlex Zinenko         tiledLinalgOp.op = tileLoopNest->getRootOp();
193b6c58ec4SAlex Zinenko         tiledLinalgOp.loops = {tileLoopNest->getLoopOps().begin(),
194b6c58ec4SAlex Zinenko                                tileLoopNest->getLoopOps().end()};
195b6c58ec4SAlex Zinenko         return tiledLinalgOp;
196b6c58ec4SAlex Zinenko       });
1971d45282aSAlex Zinenko   return failed(result) ? DiagnosedSilenceableFailure::definiteFailure()
1981d45282aSAlex Zinenko                         : DiagnosedSilenceableFailure::success();
199b6c58ec4SAlex Zinenko }
200b6c58ec4SAlex Zinenko 
201b6c58ec4SAlex Zinenko ParseResult transform::FuseOp::parse(OpAsmParser &parser,
202b6c58ec4SAlex Zinenko                                      OperationState &result) {
203b6c58ec4SAlex Zinenko   return parseTileLikeOp(
204b6c58ec4SAlex Zinenko       parser, result,
205b6c58ec4SAlex Zinenko       transform::FuseOp::getTileSizesAttrName(result.name).getValue());
206b6c58ec4SAlex Zinenko }
207b6c58ec4SAlex Zinenko 
208b6c58ec4SAlex Zinenko void transform::FuseOp::print(OpAsmPrinter &p) {
209b6c58ec4SAlex Zinenko   p << ' ';
210b6c58ec4SAlex Zinenko   p << getTarget();
211b6c58ec4SAlex Zinenko   p.printOptionalAttrDict((*this)->getAttrs());
212b6c58ec4SAlex Zinenko }
213b6c58ec4SAlex Zinenko 
214b6c58ec4SAlex Zinenko LogicalResult transform::FuseOp::verify() {
215b6c58ec4SAlex Zinenko   SmallVector<int64_t> permutation = extractI64Array(getTileInterchange());
216b6c58ec4SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, permutation.size()));
217b6c58ec4SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
218b6c58ec4SAlex Zinenko                            permutation.begin(), permutation.end())) {
219b6c58ec4SAlex Zinenko     return emitOpError() << "expects interchange to be a permutation, found "
220b6c58ec4SAlex Zinenko                          << getTileInterchange();
221b6c58ec4SAlex Zinenko   }
222b6c58ec4SAlex Zinenko   return success();
223b6c58ec4SAlex Zinenko }
224b6c58ec4SAlex Zinenko 
225b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
226ce2e198bSAlex Zinenko // GeneralizeOp
227ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
228ce2e198bSAlex Zinenko 
229*52307109SNicolas Vasilache DiagnosedSilenceableFailure
230*52307109SNicolas Vasilache transform::GeneralizeOp::applyToOne(linalg::LinalgOp target,
231*52307109SNicolas Vasilache                                     SmallVectorImpl<Operation *> &results,
232*52307109SNicolas Vasilache                                     transform::TransformState &state) {
233ce2e198bSAlex Zinenko   // Exit early if no transformation is needed.
234*52307109SNicolas Vasilache   if (isa<GenericOp>(target)) {
235*52307109SNicolas Vasilache     results.push_back(target);
236*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
237*52307109SNicolas Vasilache   }
238ce2e198bSAlex Zinenko   FailureOr<LinalgOp> generic = tryApply<LinalgGeneralizationPattern>(target);
239*52307109SNicolas Vasilache   if (succeeded(generic)) {
240*52307109SNicolas Vasilache     results.push_back(generic->getOperation());
241*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
242*52307109SNicolas Vasilache   }
243*52307109SNicolas Vasilache   results.assign(1, nullptr);
244*52307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
245ce2e198bSAlex Zinenko }
246ce2e198bSAlex Zinenko 
2473c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
2485cde5a57SAlex Zinenko // InterchangeOp
2495cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
2505cde5a57SAlex Zinenko 
251*52307109SNicolas Vasilache DiagnosedSilenceableFailure
252*52307109SNicolas Vasilache transform::InterchangeOp::applyToOne(linalg::GenericOp target,
253*52307109SNicolas Vasilache                                      SmallVectorImpl<Operation *> &results,
254*52307109SNicolas Vasilache                                      transform::TransformState &state) {
2555cde5a57SAlex Zinenko   SmallVector<unsigned> interchangeVector =
2565cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2575cde5a57SAlex Zinenko   // Exit early if no transformation is needed.
258*52307109SNicolas Vasilache   if (interchangeVector.empty()) {
259*52307109SNicolas Vasilache     results.push_back(target);
260*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
2615cde5a57SAlex Zinenko   }
262*52307109SNicolas Vasilache   SimpleRewriter rewriter(target->getContext());
263*52307109SNicolas Vasilache   FailureOr<GenericOp> res =
264*52307109SNicolas Vasilache       interchangeGenericOp(rewriter, target, interchangeVector);
265*52307109SNicolas Vasilache   if (failed(res))
266*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure::definiteFailure();
267*52307109SNicolas Vasilache   results.push_back(res->getOperation());
268*52307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
2695cde5a57SAlex Zinenko }
2705cde5a57SAlex Zinenko 
2715cde5a57SAlex Zinenko LogicalResult transform::InterchangeOp::verify() {
2725cde5a57SAlex Zinenko   SmallVector<unsigned> permutation =
2735cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2745cde5a57SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<unsigned>(0, permutation.size()));
2755cde5a57SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
2765cde5a57SAlex Zinenko                            permutation.begin(), permutation.end())) {
2775cde5a57SAlex Zinenko     return emitOpError()
2785cde5a57SAlex Zinenko            << "expects iterator_interchange to be a permutation, found "
2795cde5a57SAlex Zinenko            << getIteratorInterchange();
2805cde5a57SAlex Zinenko   }
2815cde5a57SAlex Zinenko   return success();
2825cde5a57SAlex Zinenko }
2835cde5a57SAlex Zinenko 
2845cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2855cde5a57SAlex Zinenko // PadOp
2865cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2875cde5a57SAlex Zinenko 
288*52307109SNicolas Vasilache DiagnosedSilenceableFailure
289*52307109SNicolas Vasilache transform::PadOp::applyToOne(linalg::LinalgOp target,
290*52307109SNicolas Vasilache                              SmallVectorImpl<Operation *> &results,
291*52307109SNicolas Vasilache                              transform::TransformState &state) {
2925cde5a57SAlex Zinenko   // Convert the integer packing flags to booleans.
2935cde5a57SAlex Zinenko   SmallVector<bool> packPaddings;
2945cde5a57SAlex Zinenko   for (int64_t packPadding : extractI64Array(getPackPaddings()))
2955cde5a57SAlex Zinenko     packPaddings.push_back(static_cast<bool>(packPadding));
2965cde5a57SAlex Zinenko 
2975cde5a57SAlex Zinenko   // Convert the padding values to attributes.
2985cde5a57SAlex Zinenko   SmallVector<Attribute> paddingValues;
2995cde5a57SAlex Zinenko   for (auto const &it :
3005cde5a57SAlex Zinenko        llvm::zip(getPaddingValues(), target->getOperandTypes())) {
3015cde5a57SAlex Zinenko     Attribute attr = std::get<0>(it);
3025cde5a57SAlex Zinenko     Type elementType = getElementTypeOrSelf(std::get<1>(it));
3035cde5a57SAlex Zinenko     // Try to parse string attributes to obtain an attribute of element type.
3045cde5a57SAlex Zinenko     if (auto stringAttr = attr.dyn_cast<StringAttr>()) {
3055cde5a57SAlex Zinenko       paddingValues.push_back(
3065cde5a57SAlex Zinenko           parseAttribute(attr.cast<StringAttr>(), elementType));
3075cde5a57SAlex Zinenko       if (!paddingValues.back()) {
308*52307109SNicolas Vasilache         auto diag = this->emitOpError("expects a padding that parses to ")
3095cde5a57SAlex Zinenko                     << elementType << ", got " << std::get<0>(it);
3105cde5a57SAlex Zinenko         diag.attachNote(target.getLoc()) << "when applied to this op";
311*52307109SNicolas Vasilache         return DiagnosedSilenceableFailure::definiteFailure();
3125cde5a57SAlex Zinenko       }
3135cde5a57SAlex Zinenko       continue;
3145cde5a57SAlex Zinenko     }
3155cde5a57SAlex Zinenko     // Otherwise, add the attribute directly.
3165cde5a57SAlex Zinenko     if (attr.getType() != elementType) {
317*52307109SNicolas Vasilache       auto diag = this->emitOpError("expects a padding value of type ")
3185cde5a57SAlex Zinenko                   << elementType << ", got " << attr;
3195cde5a57SAlex Zinenko       diag.attachNote(target.getLoc()) << "when applied to this op";
320*52307109SNicolas Vasilache       return DiagnosedSilenceableFailure::definiteFailure();
3215cde5a57SAlex Zinenko     }
3225cde5a57SAlex Zinenko     paddingValues.push_back(attr);
3235cde5a57SAlex Zinenko   }
3245cde5a57SAlex Zinenko 
3255cde5a57SAlex Zinenko   // Extract the transpose vectors.
3265cde5a57SAlex Zinenko   SmallVector<SmallVector<int64_t>> transposePaddings;
3275cde5a57SAlex Zinenko   for (Attribute transposeVector : getTransposePaddings().cast<ArrayAttr>())
3285cde5a57SAlex Zinenko     transposePaddings.push_back(
3295cde5a57SAlex Zinenko         extractI64Array(transposeVector.cast<ArrayAttr>()));
3305cde5a57SAlex Zinenko 
3315cde5a57SAlex Zinenko   LinalgPaddingOptions paddingOptions;
3325cde5a57SAlex Zinenko   paddingOptions.setPaddingValues(paddingValues);
3335cde5a57SAlex Zinenko   paddingOptions.setPaddingDimensions(extractI64Array(getPaddingDimensions()));
3345cde5a57SAlex Zinenko   paddingOptions.setPackPaddings(packPaddings);
3355cde5a57SAlex Zinenko   paddingOptions.setHoistPaddings(extractI64Array(getHoistPaddings()));
3365cde5a57SAlex Zinenko   paddingOptions.setTransposePaddings(transposePaddings);
3375cde5a57SAlex Zinenko 
338ce2e198bSAlex Zinenko   FailureOr<LinalgOp> result =
339ce2e198bSAlex Zinenko       tryApply<LinalgPaddingPattern>(target, paddingOptions);
340*52307109SNicolas Vasilache   if (succeeded(result)) {
341*52307109SNicolas Vasilache     results.push_back(result->getOperation());
342*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
343*52307109SNicolas Vasilache   }
344ce2e198bSAlex Zinenko 
345*52307109SNicolas Vasilache   results.assign(1, nullptr);
346*52307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
3475cde5a57SAlex Zinenko }
3485cde5a57SAlex Zinenko 
3495cde5a57SAlex Zinenko LogicalResult transform::PadOp::verify() {
3505cde5a57SAlex Zinenko   SmallVector<int64_t> packPaddings = extractI64Array(getPackPaddings());
3515cde5a57SAlex Zinenko   if (any_of(packPaddings, [](int64_t packPadding) {
3525cde5a57SAlex Zinenko         return packPadding != 0 && packPadding != 1;
3535cde5a57SAlex Zinenko       })) {
3545cde5a57SAlex Zinenko     return emitOpError()
3555cde5a57SAlex Zinenko            << "expects pack_paddings to contain booleans (0/1), found "
3565cde5a57SAlex Zinenko            << getPackPaddings();
3575cde5a57SAlex Zinenko   }
3585cde5a57SAlex Zinenko 
3595cde5a57SAlex Zinenko   SmallVector<int64_t> paddingDimensions =
3605cde5a57SAlex Zinenko       extractI64Array(getPaddingDimensions());
3615cde5a57SAlex Zinenko   if (any_of(paddingDimensions,
3625cde5a57SAlex Zinenko              [](int64_t paddingDimension) { return paddingDimension < 0; })) {
3635cde5a57SAlex Zinenko     return emitOpError()
3645cde5a57SAlex Zinenko            << "expects padding_dimensions to contain positive integers, found "
3655cde5a57SAlex Zinenko            << getPaddingDimensions();
3665cde5a57SAlex Zinenko   }
3675cde5a57SAlex Zinenko 
3685cde5a57SAlex Zinenko   SmallVector<int64_t> hoistPaddings = extractI64Array(getHoistPaddings());
3695cde5a57SAlex Zinenko   if (any_of(hoistPaddings,
3705cde5a57SAlex Zinenko              [](int64_t hoistPadding) { return hoistPadding < 0; })) {
3715cde5a57SAlex Zinenko     return emitOpError()
3725cde5a57SAlex Zinenko            << "expects hoist_paddings to contain positive integers, found "
3735cde5a57SAlex Zinenko            << getHoistPaddings();
3745cde5a57SAlex Zinenko   }
3755cde5a57SAlex Zinenko 
3765cde5a57SAlex Zinenko   ArrayAttr transposes = getTransposePaddings();
3775cde5a57SAlex Zinenko   for (Attribute attr : transposes) {
3785cde5a57SAlex Zinenko     SmallVector<int64_t> transpose = extractFromI64ArrayAttr(attr);
3795cde5a57SAlex Zinenko     auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, transpose.size()));
3805cde5a57SAlex Zinenko     if (!std::is_permutation(sequence.begin(), sequence.end(),
3815cde5a57SAlex Zinenko                              transpose.begin(), transpose.end())) {
3825cde5a57SAlex Zinenko       return emitOpError()
3835cde5a57SAlex Zinenko              << "expects transpose_paddings to be a permutation, found "
3845cde5a57SAlex Zinenko              << attr;
3855cde5a57SAlex Zinenko     }
3865cde5a57SAlex Zinenko   }
3875cde5a57SAlex Zinenko   return success();
3885cde5a57SAlex Zinenko }
3895cde5a57SAlex Zinenko 
3905cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3915cde5a57SAlex Zinenko // ScalarizeOp
3925cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3935cde5a57SAlex Zinenko 
394*52307109SNicolas Vasilache DiagnosedSilenceableFailure
395*52307109SNicolas Vasilache transform::ScalarizeOp::applyToOne(linalg::LinalgOp target,
396*52307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
397*52307109SNicolas Vasilache                                    transform::TransformState &state) {
3985cde5a57SAlex Zinenko   LinalgTilingOptions tilingOptions;
3995cde5a57SAlex Zinenko   tilingOptions.scalarizeDynamicDims();
4005cde5a57SAlex Zinenko   // Tiling with "scalarize_dyn_dims" actually sets the same lambda as the tile
4015cde5a57SAlex Zinenko   // sizes and asserts that it is not already set.
4025cde5a57SAlex Zinenko   SmallVector<int64_t> emptyTileSizes;
4035cde5a57SAlex Zinenko   LinalgTilingPattern pattern(getContext(), tilingOptions);
4045cde5a57SAlex Zinenko   SimpleRewriter rewriter(getContext());
4055cde5a57SAlex Zinenko   rewriter.setInsertionPoint(target);
4065cde5a57SAlex Zinenko   FailureOr<TiledLinalgOp> result =
4075cde5a57SAlex Zinenko       pattern.returningMatchAndRewrite(target, rewriter);
4085cde5a57SAlex Zinenko   if (failed(result))
409*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
4105cde5a57SAlex Zinenko 
411*52307109SNicolas Vasilache   results.push_back(result->op);
412*52307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
4135cde5a57SAlex Zinenko }
4145cde5a57SAlex Zinenko 
4155cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
416ff6e5508SAlex Zinenko // SplitOp
417ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
418ff6e5508SAlex Zinenko 
419ff6e5508SAlex Zinenko DiagnosedSilenceableFailure SplitOp::apply(TransformResults &results,
420ff6e5508SAlex Zinenko                                            TransformState &state) {
421ff6e5508SAlex Zinenko   // Collect the dynamic split points if provided.
422ff6e5508SAlex Zinenko   ArrayRef<Operation *> payload = state.getPayloadOps(getTarget());
423ff6e5508SAlex Zinenko   SimpleRewriter rewriter(getContext());
424ff6e5508SAlex Zinenko   SmallVector<OpFoldResult> splitPoints;
425ff6e5508SAlex Zinenko   splitPoints.reserve(payload.size());
426ff6e5508SAlex Zinenko   if (getDynamicSplitPoint()) {
427ff6e5508SAlex Zinenko     auto diag = DiagnosedSilenceableFailure::success();
428ff6e5508SAlex Zinenko     splitPoints = llvm::to_vector(llvm::map_range(
429ff6e5508SAlex Zinenko         state.getPayloadOps(getDynamicSplitPoint()), [&](Operation *op) {
430ff6e5508SAlex Zinenko           if (op->getNumResults() != 1 ||
431ff6e5508SAlex Zinenko               !op->getResult(0).getType().isIndex()) {
432ff6e5508SAlex Zinenko             diag = emitSilenceableError()
433ff6e5508SAlex Zinenko                    << "expected dynamic split point handle to point to a "
434ff6e5508SAlex Zinenko                       "single-result index-typed op";
435ff6e5508SAlex Zinenko             diag.attachNote(op->getLoc()) << "dynamic split point";
436ff6e5508SAlex Zinenko           }
437ff6e5508SAlex Zinenko           return OpFoldResult(op->getResult(0));
438ff6e5508SAlex Zinenko         }));
439ff6e5508SAlex Zinenko     if (!diag.succeeded())
440ff6e5508SAlex Zinenko       return diag;
441ff6e5508SAlex Zinenko 
442ff6e5508SAlex Zinenko     if (splitPoints.size() != payload.size()) {
443ff6e5508SAlex Zinenko       emitError() << "expected the dynamic split point handle to point to as "
444ff6e5508SAlex Zinenko                      "many operations ("
445ff6e5508SAlex Zinenko                   << splitPoints.size() << ") as the target handle ("
446ff6e5508SAlex Zinenko                   << payload.size() << ")";
447ff6e5508SAlex Zinenko       return DiagnosedSilenceableFailure::definiteFailure();
448ff6e5508SAlex Zinenko     }
449ff6e5508SAlex Zinenko   } else {
450ff6e5508SAlex Zinenko     splitPoints.resize(payload.size(),
451ff6e5508SAlex Zinenko                        rewriter.getIndexAttr(getStaticSplitPoint()));
452ff6e5508SAlex Zinenko   }
453ff6e5508SAlex Zinenko 
454ff6e5508SAlex Zinenko   // Split each target operation.
455ff6e5508SAlex Zinenko   SmallVector<Operation *> first, second;
456ff6e5508SAlex Zinenko   for (const auto &pair : llvm::zip(payload, splitPoints)) {
457ff6e5508SAlex Zinenko     Operation *target = std::get<0>(pair);
458ff6e5508SAlex Zinenko     auto linalgOp = dyn_cast<LinalgOp>(target);
459ff6e5508SAlex Zinenko     if (!linalgOp) {
460ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "only applies to structured ops";
461ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
462ff6e5508SAlex Zinenko       return diag;
463ff6e5508SAlex Zinenko     }
464ff6e5508SAlex Zinenko 
465ff6e5508SAlex Zinenko     if (getDimension() >= linalgOp.getNumLoops()) {
466ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "dimension " << getDimension()
467ff6e5508SAlex Zinenko                                          << " does not exist in target op";
468ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
469ff6e5508SAlex Zinenko       return diag;
470ff6e5508SAlex Zinenko     }
471ff6e5508SAlex Zinenko 
472ff6e5508SAlex Zinenko     rewriter.setInsertionPoint(linalgOp);
473ff6e5508SAlex Zinenko     std::tie(first.emplace_back(), second.emplace_back()) =
474ff6e5508SAlex Zinenko         linalg::splitOp(rewriter, linalgOp, getDimension(), std::get<1>(pair));
475ff6e5508SAlex Zinenko   }
476ff6e5508SAlex Zinenko 
477ff6e5508SAlex Zinenko   results.set(getFirst().cast<OpResult>(), first);
478ff6e5508SAlex Zinenko   results.set(getSecond().cast<OpResult>(), second);
479ff6e5508SAlex Zinenko   return DiagnosedSilenceableFailure::success();
480ff6e5508SAlex Zinenko }
481ff6e5508SAlex Zinenko 
482ff6e5508SAlex Zinenko void SplitOp::getEffects(
483ff6e5508SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
484ff6e5508SAlex Zinenko   // The target handle is consumed.
485ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Read::get(), getTarget(),
486ff6e5508SAlex Zinenko                        TransformMappingResource::get());
487ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Free::get(), getTarget(),
488ff6e5508SAlex Zinenko                        TransformMappingResource::get());
489ff6e5508SAlex Zinenko 
490ff6e5508SAlex Zinenko   // The dynamic split point handle is not consumed.
491ff6e5508SAlex Zinenko   if (getDynamicSplitPoint()) {
492ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Read::get(), getDynamicSplitPoint(),
493ff6e5508SAlex Zinenko                          TransformMappingResource::get());
494ff6e5508SAlex Zinenko   }
495ff6e5508SAlex Zinenko 
496ff6e5508SAlex Zinenko   // The resulting handles are produced.
497ff6e5508SAlex Zinenko   for (Value result : getResults()) {
498ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Allocate::get(), result,
499ff6e5508SAlex Zinenko                          TransformMappingResource::get());
500ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Write::get(), result,
501ff6e5508SAlex Zinenko                          TransformMappingResource::get());
502ff6e5508SAlex Zinenko   }
503ff6e5508SAlex Zinenko 
504ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Read::get(), PayloadIRResource::get());
505ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Write::get(), PayloadIRResource::get());
506ff6e5508SAlex Zinenko }
507ff6e5508SAlex Zinenko 
508ff6e5508SAlex Zinenko ParseResult SplitOp::parse(OpAsmParser &parser, OperationState &result) {
509ff6e5508SAlex Zinenko   OpAsmParser::UnresolvedOperand target, dynamicSplitPoint;
510ff6e5508SAlex Zinenko   IntegerAttr staticSplitPoint;
511ff6e5508SAlex Zinenko   auto pdlOperationType =
512ff6e5508SAlex Zinenko       pdl::OperationType::get(parser.getBuilder().getContext());
513ff6e5508SAlex Zinenko   if (parser.parseOperand(target) ||
514ff6e5508SAlex Zinenko       parser.resolveOperand(target, pdlOperationType, result.operands) ||
515ff6e5508SAlex Zinenko       parser.parseKeyword("after"))
516ff6e5508SAlex Zinenko     return failure();
517ff6e5508SAlex Zinenko 
518ff6e5508SAlex Zinenko   OptionalParseResult dynamicPointParseResult =
519ff6e5508SAlex Zinenko       parser.parseOptionalOperand(dynamicSplitPoint);
520ff6e5508SAlex Zinenko   if (!dynamicPointParseResult.hasValue()) {
521ff6e5508SAlex Zinenko     int64_t staticSplitPointValue;
522ff6e5508SAlex Zinenko     if (failed(parser.parseInteger(staticSplitPointValue)))
523ff6e5508SAlex Zinenko       return failure();
524ff6e5508SAlex Zinenko 
525ff6e5508SAlex Zinenko     staticSplitPoint =
526ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(staticSplitPointValue);
527ff6e5508SAlex Zinenko   } else {
528ff6e5508SAlex Zinenko     if (failed(*dynamicPointParseResult) ||
529ff6e5508SAlex Zinenko         parser.resolveOperand(dynamicSplitPoint, pdlOperationType,
530ff6e5508SAlex Zinenko                               result.operands)) {
531ff6e5508SAlex Zinenko       return failure();
532ff6e5508SAlex Zinenko     }
533ff6e5508SAlex Zinenko 
534ff6e5508SAlex Zinenko     staticSplitPoint =
535ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(ShapedType::kDynamicSize);
536ff6e5508SAlex Zinenko   }
537ff6e5508SAlex Zinenko 
538ff6e5508SAlex Zinenko   result.addAttribute(
539ff6e5508SAlex Zinenko       SplitOp::getStaticSplitPointAttrName(result.name).getValue(),
540ff6e5508SAlex Zinenko       staticSplitPoint);
541ff6e5508SAlex Zinenko   if (failed(parser.parseOptionalAttrDict(result.attributes)))
542ff6e5508SAlex Zinenko     return failure();
543ff6e5508SAlex Zinenko 
544ff6e5508SAlex Zinenko   result.addTypes({pdlOperationType, pdlOperationType});
545ff6e5508SAlex Zinenko   return success();
546ff6e5508SAlex Zinenko }
547ff6e5508SAlex Zinenko 
548ff6e5508SAlex Zinenko void SplitOp::print(OpAsmPrinter &printer) {
549ff6e5508SAlex Zinenko   printer << " " << getTarget() << " after ";
550ff6e5508SAlex Zinenko   int64_t staticSplitSize = static_cast<int64_t>(getStaticSplitPoint());
551ff6e5508SAlex Zinenko   if (staticSplitSize != ShapedType::kDynamicSize)
552ff6e5508SAlex Zinenko     printer << staticSplitSize;
553ff6e5508SAlex Zinenko   else
554ff6e5508SAlex Zinenko     printer << getDynamicSplitPoint();
555ff6e5508SAlex Zinenko   printer << " ";
556ff6e5508SAlex Zinenko   printer.printOptionalAttrDict(getOperation()->getAttrs(),
557ff6e5508SAlex Zinenko                                 {getStaticSplitPointAttrName()});
558ff6e5508SAlex Zinenko }
559ff6e5508SAlex Zinenko 
560ff6e5508SAlex Zinenko LogicalResult SplitOp::verify() {
561ff6e5508SAlex Zinenko   if ((static_cast<int64_t>(getStaticSplitPoint()) !=
562ff6e5508SAlex Zinenko        ShapedType::kDynamicSize) ^
563ff6e5508SAlex Zinenko       (getDynamicSplitPoint() == nullptr)) {
564ff6e5508SAlex Zinenko     return emitOpError()
565ff6e5508SAlex Zinenko            << "expects either a dynamic or a static split point to be provided";
566ff6e5508SAlex Zinenko   }
567ff6e5508SAlex Zinenko   return success();
568ff6e5508SAlex Zinenko }
569ff6e5508SAlex Zinenko 
570ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
571f439b319SNicolas Vasilache // SplitReductionOp
572f439b319SNicolas Vasilache //===----------------------------------------------------------------------===//
573f439b319SNicolas Vasilache 
574*52307109SNicolas Vasilache DiagnosedSilenceableFailure
575*52307109SNicolas Vasilache transform::SplitReductionOp::applyToOne(linalg::LinalgOp target,
576*52307109SNicolas Vasilache                                         SmallVectorImpl<Operation *> &results,
577*52307109SNicolas Vasilache                                         transform::TransformState &state) {
578f439b319SNicolas Vasilache   ControlSplitReductionFn splitFn = [&](LinalgOp) {
579f439b319SNicolas Vasilache     return std::pair<int64_t, unsigned>(getSplitFactor(),
580f439b319SNicolas Vasilache                                         getInsertSplitDimension());
581f439b319SNicolas Vasilache   };
582f439b319SNicolas Vasilache   SimpleRewriter rewriter(getContext());
583f439b319SNicolas Vasilache   rewriter.setInsertionPoint(target);
584f439b319SNicolas Vasilache   FailureOr<SplitReductionResult> splitResult =
585178f9bd6SNicolas Vasilache       (getUseScalingAlgorithm())
586178f9bd6SNicolas Vasilache           ? splitReductionByScaling(rewriter, target, splitFn, getUseAlloc())
587178f9bd6SNicolas Vasilache           : splitReduction(rewriter, target, splitFn, getUseAlloc());
588d5716395SNicolas Vasilache   if (failed(splitResult))
589*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
590*52307109SNicolas Vasilache 
591*52307109SNicolas Vasilache   results.push_back(splitResult->initOrAlloc);
592*52307109SNicolas Vasilache   results.push_back(splitResult->fillOp);
593*52307109SNicolas Vasilache   results.push_back(splitResult->splitLinalgOp);
594*52307109SNicolas Vasilache   results.push_back(splitResult->resultCombiningLinalgOp);
595*52307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
596d5716395SNicolas Vasilache }
597d5716395SNicolas Vasilache 
598d5716395SNicolas Vasilache //===----------------------------------------------------------------------===//
5993c2a74a3SMatthias Springer // TileOp
6003c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
6013c2a74a3SMatthias Springer 
6021d45282aSAlex Zinenko DiagnosedSilenceableFailure
603e3890b7fSAlex Zinenko transform::TileOp::apply(TransformResults &transformResults,
6043c2a74a3SMatthias Springer                          TransformState &state) {
6053c2a74a3SMatthias Springer   LinalgTilingOptions tilingOptions;
6063c2a74a3SMatthias Springer   SmallVector<int64_t> tileSizes = extractI64Array(getSizes());
6073c2a74a3SMatthias Springer 
6083c2a74a3SMatthias Springer   if (!tileSizes.empty())
6093c2a74a3SMatthias Springer     tilingOptions.setTileSizes(tileSizes);
6103c2a74a3SMatthias Springer   tilingOptions.setInterchange(extractUIntArray(getInterchange()));
6113c2a74a3SMatthias Springer   LinalgTilingPattern pattern(getContext(), tilingOptions);
6123c2a74a3SMatthias Springer 
613e3890b7fSAlex Zinenko   LogicalResult result = applyTilingToAll(
614e3890b7fSAlex Zinenko       getOperation(), getTarget(), tileSizes, transformResults, state,
615e3890b7fSAlex Zinenko       [&](LinalgOp linalgOp) {
6163c2a74a3SMatthias Springer         SimpleRewriter rewriter(linalgOp.getContext());
617e3890b7fSAlex Zinenko         return pattern.returningMatchAndRewrite(linalgOp, rewriter);
6183c2a74a3SMatthias Springer       });
6191d45282aSAlex Zinenko   return DiagnosedSilenceableFailure(result);
6203c2a74a3SMatthias Springer }
6213c2a74a3SMatthias Springer 
6223c2a74a3SMatthias Springer ParseResult transform::TileOp::parse(OpAsmParser &parser,
6233c2a74a3SMatthias Springer                                      OperationState &result) {
624b6c58ec4SAlex Zinenko   return parseTileLikeOp(parser, result,
625b6c58ec4SAlex Zinenko                          TileOp::getSizesAttrName(result.name).getValue());
6263c2a74a3SMatthias Springer }
6273c2a74a3SMatthias Springer 
6283c2a74a3SMatthias Springer void TileOp::print(OpAsmPrinter &p) {
6293c2a74a3SMatthias Springer   p << ' ';
6303c2a74a3SMatthias Springer   p << getTarget();
6313c2a74a3SMatthias Springer   p.printOptionalAttrDict((*this)->getAttrs());
6323c2a74a3SMatthias Springer }
6333c2a74a3SMatthias Springer 
6343c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
635cc6c1592SAlex Zinenko // VectorizeOp
636cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
637cc6c1592SAlex Zinenko 
638*52307109SNicolas Vasilache DiagnosedSilenceableFailure
639*52307109SNicolas Vasilache transform::VectorizeOp::applyToOne(Operation *target,
640*52307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
641*52307109SNicolas Vasilache                                    transform::TransformState &state) {
642cc6c1592SAlex Zinenko   if (!target->hasTrait<OpTrait::IsIsolatedFromAbove>()) {
643*52307109SNicolas Vasilache     auto diag = this->emitOpError("requires isolated-from-above targets");
644cc6c1592SAlex Zinenko     diag.attachNote(target->getLoc()) << "non-isolated target";
645*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure::definiteFailure();
646cc6c1592SAlex Zinenko   }
647cc6c1592SAlex Zinenko 
648cc6c1592SAlex Zinenko   MLIRContext *ctx = getContext();
649cc6c1592SAlex Zinenko   RewritePatternSet patterns(ctx);
650cc6c1592SAlex Zinenko   patterns.add<LinalgVectorizationPattern>(ctx);
651cc6c1592SAlex Zinenko 
652cc6c1592SAlex Zinenko   vector::populateVectorTransferPermutationMapLoweringPatterns(patterns);
653cc6c1592SAlex Zinenko   vector::populateVectorReductionToContractPatterns(patterns);
654cc6c1592SAlex Zinenko   patterns.add<linalg::LinalgCopyVTRForwardingPattern,
655cc6c1592SAlex Zinenko                linalg::LinalgCopyVTWForwardingPattern>(ctx,
656cc6c1592SAlex Zinenko                                                        /*benefit=*/2);
657cc6c1592SAlex Zinenko   vector::TransferReadOp::getCanonicalizationPatterns(patterns, ctx);
658cc6c1592SAlex Zinenko   vector::TransferWriteOp::getCanonicalizationPatterns(patterns, ctx);
659cc6c1592SAlex Zinenko   if (getVectorizePadding())
660cc6c1592SAlex Zinenko     linalg::populatePadOpVectorizationPatterns(patterns);
661cc6c1592SAlex Zinenko 
6625f0d4f20SAlex Zinenko   if (failed(applyPatternsAndFoldGreedily(target, std::move(patterns))))
663*52307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
664*52307109SNicolas Vasilache 
665*52307109SNicolas Vasilache   results.push_back(target);
666*52307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
667cc6c1592SAlex Zinenko }
668cc6c1592SAlex Zinenko 
669cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
6703c2a74a3SMatthias Springer // Transform op registration
6713c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
6723c2a74a3SMatthias Springer 
6733c2a74a3SMatthias Springer namespace {
6743c2a74a3SMatthias Springer /// Registers new ops and declares PDL as dependent dialect since the additional
6753c2a74a3SMatthias Springer /// ops are using PDL types for operands and results.
6763c2a74a3SMatthias Springer class LinalgTransformDialectExtension
6773c2a74a3SMatthias Springer     : public transform::TransformDialectExtension<
6783c2a74a3SMatthias Springer           LinalgTransformDialectExtension> {
6793c2a74a3SMatthias Springer public:
6803c2a74a3SMatthias Springer   LinalgTransformDialectExtension() {
6813c2a74a3SMatthias Springer     declareDependentDialect<pdl::PDLDialect>();
6823c2a74a3SMatthias Springer     declareDependentDialect<scf::SCFDialect>();
683cc6c1592SAlex Zinenko     declareDependentDialect<vector::VectorDialect>();
6843c2a74a3SMatthias Springer     registerTransformOps<
6853c2a74a3SMatthias Springer #define GET_OP_LIST
6863c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
6873c2a74a3SMatthias Springer         >();
6883c2a74a3SMatthias Springer   }
6893c2a74a3SMatthias Springer };
6903c2a74a3SMatthias Springer } // namespace
6913c2a74a3SMatthias Springer 
6923c2a74a3SMatthias Springer #define GET_OP_CLASSES
6933c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
6943c2a74a3SMatthias Springer 
6953c2a74a3SMatthias Springer void mlir::linalg::registerTransformDialectExtension(
6963c2a74a3SMatthias Springer     DialectRegistry &registry) {
6973c2a74a3SMatthias Springer   registry.addExtensions<LinalgTransformDialectExtension>();
6983c2a74a3SMatthias Springer }
699