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 
11*4e4a4c05SAlex Zinenko #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h"
123c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/IR/Linalg.h"
133c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/Transforms/Transforms.h"
143c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDL.h"
153c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDLTypes.h"
163c2a74a3SMatthias Springer #include "mlir/Dialect/Transform/IR/TransformDialect.h"
173c2a74a3SMatthias Springer #include "mlir/Parser/Parser.h"
18cc6c1592SAlex Zinenko #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
193c2a74a3SMatthias Springer 
203c2a74a3SMatthias Springer using namespace mlir;
213c2a74a3SMatthias Springer using namespace mlir::linalg;
223c2a74a3SMatthias Springer using namespace mlir::transform;
233c2a74a3SMatthias Springer 
243c2a74a3SMatthias Springer /// Extracts a vector of int64_t from an array attribute. Asserts if the
253c2a74a3SMatthias Springer /// attribute contains values other than integers.
263c2a74a3SMatthias Springer static SmallVector<int64_t> extractI64Array(ArrayAttr attr) {
273c2a74a3SMatthias Springer   SmallVector<int64_t> result;
283c2a74a3SMatthias Springer   result.reserve(attr.size());
293c2a74a3SMatthias Springer   for (APInt value : attr.getAsValueRange<IntegerAttr>())
303c2a74a3SMatthias Springer     result.push_back(value.getSExtValue());
313c2a74a3SMatthias Springer   return result;
323c2a74a3SMatthias Springer }
333c2a74a3SMatthias Springer 
343c2a74a3SMatthias Springer /// Extracts a vector of unsigned from an array attribute. Asserts if the
353c2a74a3SMatthias Springer /// attribute contains values other than intergers. May truncate.
363c2a74a3SMatthias Springer static SmallVector<unsigned> extractUIntArray(ArrayAttr attr) {
373c2a74a3SMatthias Springer   SmallVector<unsigned> result;
383c2a74a3SMatthias Springer   result.reserve(attr.size());
393c2a74a3SMatthias Springer   for (APInt value : attr.getAsValueRange<IntegerAttr>())
403c2a74a3SMatthias Springer     result.push_back(value.getZExtValue());
413c2a74a3SMatthias Springer   return result;
423c2a74a3SMatthias Springer }
433c2a74a3SMatthias Springer 
443c2a74a3SMatthias Springer namespace {
453c2a74a3SMatthias Springer /// A simple pattern rewriter that implements no special logic.
463c2a74a3SMatthias Springer class SimpleRewriter : public PatternRewriter {
473c2a74a3SMatthias Springer public:
483c2a74a3SMatthias Springer   SimpleRewriter(MLIRContext *context) : PatternRewriter(context) {}
493c2a74a3SMatthias Springer };
503c2a74a3SMatthias Springer } // namespace
513c2a74a3SMatthias Springer 
52ce2e198bSAlex Zinenko /// Attempts to apply the pattern specified as template argument to the given
53ce2e198bSAlex Zinenko /// operation. The pattern is expected to have a `returningMatchAndRewrite`
54ce2e198bSAlex Zinenko /// function that returns the "main" result or failure. Returns failure if the
55ce2e198bSAlex Zinenko /// pattern failed to apply. Extra arguments are forwarded to the pattern
56ce2e198bSAlex Zinenko /// constructor.
57ce2e198bSAlex Zinenko template <typename PatternTy, typename... Args>
58ce2e198bSAlex Zinenko static FailureOr<LinalgOp> tryApply(Operation *operation, Args &&...args) {
59ce2e198bSAlex Zinenko   // Check if the given operation has the type expected by the pattern.
60ce2e198bSAlex Zinenko   using OpTy = typename llvm::function_traits<
61ce2e198bSAlex Zinenko       decltype(&PatternTy::returningMatchAndRewrite)>::template arg_t<0>;
62ce2e198bSAlex Zinenko   auto op = dyn_cast<OpTy>(operation);
63ce2e198bSAlex Zinenko   if (!op)
64ce2e198bSAlex Zinenko     return failure();
65ce2e198bSAlex Zinenko 
66ce2e198bSAlex Zinenko   // Apply the pattern directly to the op.
67ce2e198bSAlex Zinenko   PatternTy pattern(operation->getContext(), std::forward<Args>(args)...);
68ce2e198bSAlex Zinenko   SimpleRewriter rewriter(operation->getContext());
69ce2e198bSAlex Zinenko   rewriter.setInsertionPoint(operation);
70ce2e198bSAlex Zinenko   auto result = pattern.returningMatchAndRewrite(op, rewriter);
71ce2e198bSAlex Zinenko   if (failed(result))
72ce2e198bSAlex Zinenko     return failure();
73ce2e198bSAlex Zinenko   return cast<LinalgOp>(result->getOperation());
74ce2e198bSAlex Zinenko }
75ce2e198bSAlex Zinenko 
76ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
77ce2e198bSAlex Zinenko // DecomposeOp
78ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
79ce2e198bSAlex Zinenko 
8052307109SNicolas Vasilache DiagnosedSilenceableFailure
8152307109SNicolas Vasilache transform::DecomposeOp::applyToOne(linalg::LinalgOp target,
8252307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
8352307109SNicolas Vasilache                                    transform::TransformState &state) {
84ce2e198bSAlex Zinenko   FailureOr<LinalgOp> windowed =
85ce2e198bSAlex Zinenko       tryApply<DownscaleSizeOneWindowed2DConvolution>(target);
8652307109SNicolas Vasilache   if (succeeded(windowed)) {
8752307109SNicolas Vasilache     results.push_back(*windowed);
8852307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
8952307109SNicolas Vasilache   }
90ce2e198bSAlex Zinenko   FailureOr<LinalgOp> depthwise =
91ce2e198bSAlex Zinenko       tryApply<DownscaleDepthwiseConv2DNhwcHwcOp>(target);
9252307109SNicolas Vasilache   if (succeeded(depthwise)) {
9352307109SNicolas Vasilache     results.push_back(*depthwise);
9452307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
9552307109SNicolas Vasilache   }
9652307109SNicolas Vasilache   results.assign(1, nullptr);
9752307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
98ce2e198bSAlex Zinenko }
99ce2e198bSAlex Zinenko 
100ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
101b6c58ec4SAlex Zinenko // FuseOp
102b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
103b6c58ec4SAlex Zinenko 
104b6c58ec4SAlex Zinenko /// Apply a tiling transformation to all payload ops and store both the
105b6c58ec4SAlex Zinenko /// tiled operation as well as the created tile loops.
106b6c58ec4SAlex Zinenko static LogicalResult
107*4e4a4c05SAlex Zinenko applyTilingToAll(Operation *transformOp, ArrayRef<Operation *> payloadOps,
108*4e4a4c05SAlex Zinenko                  unsigned numLoops,
109b6c58ec4SAlex Zinenko                  transform::TransformResults &transformResults,
110b6c58ec4SAlex Zinenko                  function_ref<FailureOr<TiledLinalgOp>(LinalgOp)> applyFn) {
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(
176*4e4a4c05SAlex Zinenko       getOperation(), state.getPayloadOps(getTarget()),
177*4e4a4c05SAlex Zinenko       fusionOptions.tileSizes.size() - llvm::count(fusionOptions.tileSizes, 0),
178*4e4a4c05SAlex Zinenko       transformResults, [&](LinalgOp linalgOp) -> FailureOr<TiledLinalgOp> {
179b6c58ec4SAlex Zinenko         LinalgTileAndFuseTensorOpsPattern pattern(getContext(), fusionOptions);
180b6c58ec4SAlex Zinenko         SimpleRewriter rewriter(getContext());
181b6c58ec4SAlex Zinenko         rewriter.setInsertionPoint(linalgOp);
182b6c58ec4SAlex Zinenko         FailureOr<TileLoopNest> tileLoopNest =
183b6c58ec4SAlex Zinenko             pattern.returningMatchAndRewrite(linalgOp, rewriter);
184b6c58ec4SAlex Zinenko         if (failed(tileLoopNest))
185b6c58ec4SAlex Zinenko           return failure();
186b6c58ec4SAlex Zinenko 
187b6c58ec4SAlex Zinenko         TiledLinalgOp tiledLinalgOp;
188b6c58ec4SAlex Zinenko         tiledLinalgOp.op = tileLoopNest->getRootOp();
189b6c58ec4SAlex Zinenko         tiledLinalgOp.loops = {tileLoopNest->getLoopOps().begin(),
190b6c58ec4SAlex Zinenko                                tileLoopNest->getLoopOps().end()};
191b6c58ec4SAlex Zinenko         return tiledLinalgOp;
192b6c58ec4SAlex Zinenko       });
193*4e4a4c05SAlex Zinenko   return DiagnosedSilenceableFailure(result);
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 
22452307109SNicolas Vasilache DiagnosedSilenceableFailure
22552307109SNicolas Vasilache transform::GeneralizeOp::applyToOne(linalg::LinalgOp target,
22652307109SNicolas Vasilache                                     SmallVectorImpl<Operation *> &results,
22752307109SNicolas Vasilache                                     transform::TransformState &state) {
228ce2e198bSAlex Zinenko   // Exit early if no transformation is needed.
22952307109SNicolas Vasilache   if (isa<GenericOp>(target)) {
23052307109SNicolas Vasilache     results.push_back(target);
23152307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
23252307109SNicolas Vasilache   }
233ce2e198bSAlex Zinenko   FailureOr<LinalgOp> generic = tryApply<LinalgGeneralizationPattern>(target);
23452307109SNicolas Vasilache   if (succeeded(generic)) {
23552307109SNicolas Vasilache     results.push_back(generic->getOperation());
23652307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
23752307109SNicolas Vasilache   }
23852307109SNicolas Vasilache   results.assign(1, nullptr);
23952307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
240ce2e198bSAlex Zinenko }
241ce2e198bSAlex Zinenko 
2423c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
2435cde5a57SAlex Zinenko // InterchangeOp
2445cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
2455cde5a57SAlex Zinenko 
24652307109SNicolas Vasilache DiagnosedSilenceableFailure
24752307109SNicolas Vasilache transform::InterchangeOp::applyToOne(linalg::GenericOp target,
24852307109SNicolas Vasilache                                      SmallVectorImpl<Operation *> &results,
24952307109SNicolas Vasilache                                      transform::TransformState &state) {
2505cde5a57SAlex Zinenko   SmallVector<unsigned> interchangeVector =
2515cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2525cde5a57SAlex Zinenko   // Exit early if no transformation is needed.
25352307109SNicolas Vasilache   if (interchangeVector.empty()) {
25452307109SNicolas Vasilache     results.push_back(target);
25552307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
2565cde5a57SAlex Zinenko   }
25752307109SNicolas Vasilache   SimpleRewriter rewriter(target->getContext());
25852307109SNicolas Vasilache   FailureOr<GenericOp> res =
25952307109SNicolas Vasilache       interchangeGenericOp(rewriter, target, interchangeVector);
26052307109SNicolas Vasilache   if (failed(res))
26152307109SNicolas Vasilache     return DiagnosedSilenceableFailure::definiteFailure();
26252307109SNicolas Vasilache   results.push_back(res->getOperation());
26352307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
2645cde5a57SAlex Zinenko }
2655cde5a57SAlex Zinenko 
2665cde5a57SAlex Zinenko LogicalResult transform::InterchangeOp::verify() {
2675cde5a57SAlex Zinenko   SmallVector<unsigned> permutation =
2685cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2695cde5a57SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<unsigned>(0, permutation.size()));
2705cde5a57SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
2715cde5a57SAlex Zinenko                            permutation.begin(), permutation.end())) {
2725cde5a57SAlex Zinenko     return emitOpError()
2735cde5a57SAlex Zinenko            << "expects iterator_interchange to be a permutation, found "
2745cde5a57SAlex Zinenko            << getIteratorInterchange();
2755cde5a57SAlex Zinenko   }
2765cde5a57SAlex Zinenko   return success();
2775cde5a57SAlex Zinenko }
2785cde5a57SAlex Zinenko 
2795cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2805cde5a57SAlex Zinenko // PadOp
2815cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2825cde5a57SAlex Zinenko 
28352307109SNicolas Vasilache DiagnosedSilenceableFailure
28452307109SNicolas Vasilache transform::PadOp::applyToOne(linalg::LinalgOp target,
28552307109SNicolas Vasilache                              SmallVectorImpl<Operation *> &results,
28652307109SNicolas Vasilache                              transform::TransformState &state) {
2875cde5a57SAlex Zinenko   // Convert the integer packing flags to booleans.
2885cde5a57SAlex Zinenko   SmallVector<bool> packPaddings;
2895cde5a57SAlex Zinenko   for (int64_t packPadding : extractI64Array(getPackPaddings()))
2905cde5a57SAlex Zinenko     packPaddings.push_back(static_cast<bool>(packPadding));
2915cde5a57SAlex Zinenko 
2925cde5a57SAlex Zinenko   // Convert the padding values to attributes.
2935cde5a57SAlex Zinenko   SmallVector<Attribute> paddingValues;
2945cde5a57SAlex Zinenko   for (auto const &it :
2955cde5a57SAlex Zinenko        llvm::zip(getPaddingValues(), target->getOperandTypes())) {
2965cde5a57SAlex Zinenko     Attribute attr = std::get<0>(it);
2975cde5a57SAlex Zinenko     Type elementType = getElementTypeOrSelf(std::get<1>(it));
2985cde5a57SAlex Zinenko     // Try to parse string attributes to obtain an attribute of element type.
2995cde5a57SAlex Zinenko     if (auto stringAttr = attr.dyn_cast<StringAttr>()) {
3005cde5a57SAlex Zinenko       paddingValues.push_back(
3015cde5a57SAlex Zinenko           parseAttribute(attr.cast<StringAttr>(), elementType));
3025cde5a57SAlex Zinenko       if (!paddingValues.back()) {
30352307109SNicolas Vasilache         auto diag = this->emitOpError("expects a padding that parses to ")
3045cde5a57SAlex Zinenko                     << elementType << ", got " << std::get<0>(it);
3055cde5a57SAlex Zinenko         diag.attachNote(target.getLoc()) << "when applied to this op";
30652307109SNicolas Vasilache         return DiagnosedSilenceableFailure::definiteFailure();
3075cde5a57SAlex Zinenko       }
3085cde5a57SAlex Zinenko       continue;
3095cde5a57SAlex Zinenko     }
3105cde5a57SAlex Zinenko     // Otherwise, add the attribute directly.
3115cde5a57SAlex Zinenko     if (attr.getType() != elementType) {
31252307109SNicolas Vasilache       auto diag = this->emitOpError("expects a padding value of type ")
3135cde5a57SAlex Zinenko                   << elementType << ", got " << attr;
3145cde5a57SAlex Zinenko       diag.attachNote(target.getLoc()) << "when applied to this op";
31552307109SNicolas Vasilache       return DiagnosedSilenceableFailure::definiteFailure();
3165cde5a57SAlex Zinenko     }
3175cde5a57SAlex Zinenko     paddingValues.push_back(attr);
3185cde5a57SAlex Zinenko   }
3195cde5a57SAlex Zinenko 
3205cde5a57SAlex Zinenko   // Extract the transpose vectors.
3215cde5a57SAlex Zinenko   SmallVector<SmallVector<int64_t>> transposePaddings;
3225cde5a57SAlex Zinenko   for (Attribute transposeVector : getTransposePaddings().cast<ArrayAttr>())
3235cde5a57SAlex Zinenko     transposePaddings.push_back(
3245cde5a57SAlex Zinenko         extractI64Array(transposeVector.cast<ArrayAttr>()));
3255cde5a57SAlex Zinenko 
3265cde5a57SAlex Zinenko   LinalgPaddingOptions paddingOptions;
3275cde5a57SAlex Zinenko   paddingOptions.setPaddingValues(paddingValues);
3285cde5a57SAlex Zinenko   paddingOptions.setPaddingDimensions(extractI64Array(getPaddingDimensions()));
3295cde5a57SAlex Zinenko   paddingOptions.setPackPaddings(packPaddings);
3305cde5a57SAlex Zinenko   paddingOptions.setHoistPaddings(extractI64Array(getHoistPaddings()));
3315cde5a57SAlex Zinenko   paddingOptions.setTransposePaddings(transposePaddings);
3325cde5a57SAlex Zinenko 
333ce2e198bSAlex Zinenko   FailureOr<LinalgOp> result =
334ce2e198bSAlex Zinenko       tryApply<LinalgPaddingPattern>(target, paddingOptions);
33552307109SNicolas Vasilache   if (succeeded(result)) {
33652307109SNicolas Vasilache     results.push_back(result->getOperation());
33752307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
33852307109SNicolas Vasilache   }
339ce2e198bSAlex Zinenko 
34052307109SNicolas Vasilache   results.assign(1, nullptr);
34152307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
3425cde5a57SAlex Zinenko }
3435cde5a57SAlex Zinenko 
3445cde5a57SAlex Zinenko LogicalResult transform::PadOp::verify() {
3455cde5a57SAlex Zinenko   SmallVector<int64_t> packPaddings = extractI64Array(getPackPaddings());
3465cde5a57SAlex Zinenko   if (any_of(packPaddings, [](int64_t packPadding) {
3475cde5a57SAlex Zinenko         return packPadding != 0 && packPadding != 1;
3485cde5a57SAlex Zinenko       })) {
3495cde5a57SAlex Zinenko     return emitOpError()
3505cde5a57SAlex Zinenko            << "expects pack_paddings to contain booleans (0/1), found "
3515cde5a57SAlex Zinenko            << getPackPaddings();
3525cde5a57SAlex Zinenko   }
3535cde5a57SAlex Zinenko 
3545cde5a57SAlex Zinenko   SmallVector<int64_t> paddingDimensions =
3555cde5a57SAlex Zinenko       extractI64Array(getPaddingDimensions());
3565cde5a57SAlex Zinenko   if (any_of(paddingDimensions,
3575cde5a57SAlex Zinenko              [](int64_t paddingDimension) { return paddingDimension < 0; })) {
3585cde5a57SAlex Zinenko     return emitOpError()
3595cde5a57SAlex Zinenko            << "expects padding_dimensions to contain positive integers, found "
3605cde5a57SAlex Zinenko            << getPaddingDimensions();
3615cde5a57SAlex Zinenko   }
3625cde5a57SAlex Zinenko 
3635cde5a57SAlex Zinenko   SmallVector<int64_t> hoistPaddings = extractI64Array(getHoistPaddings());
3645cde5a57SAlex Zinenko   if (any_of(hoistPaddings,
3655cde5a57SAlex Zinenko              [](int64_t hoistPadding) { return hoistPadding < 0; })) {
3665cde5a57SAlex Zinenko     return emitOpError()
3675cde5a57SAlex Zinenko            << "expects hoist_paddings to contain positive integers, found "
3685cde5a57SAlex Zinenko            << getHoistPaddings();
3695cde5a57SAlex Zinenko   }
3705cde5a57SAlex Zinenko 
3715cde5a57SAlex Zinenko   ArrayAttr transposes = getTransposePaddings();
3725cde5a57SAlex Zinenko   for (Attribute attr : transposes) {
3735cde5a57SAlex Zinenko     SmallVector<int64_t> transpose = extractFromI64ArrayAttr(attr);
3745cde5a57SAlex Zinenko     auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, transpose.size()));
3755cde5a57SAlex Zinenko     if (!std::is_permutation(sequence.begin(), sequence.end(),
3765cde5a57SAlex Zinenko                              transpose.begin(), transpose.end())) {
3775cde5a57SAlex Zinenko       return emitOpError()
3785cde5a57SAlex Zinenko              << "expects transpose_paddings to be a permutation, found "
3795cde5a57SAlex Zinenko              << attr;
3805cde5a57SAlex Zinenko     }
3815cde5a57SAlex Zinenko   }
3825cde5a57SAlex Zinenko   return success();
3835cde5a57SAlex Zinenko }
3845cde5a57SAlex Zinenko 
3855cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3865cde5a57SAlex Zinenko // ScalarizeOp
3875cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3885cde5a57SAlex Zinenko 
38952307109SNicolas Vasilache DiagnosedSilenceableFailure
39052307109SNicolas Vasilache transform::ScalarizeOp::applyToOne(linalg::LinalgOp target,
39152307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
39252307109SNicolas Vasilache                                    transform::TransformState &state) {
3935cde5a57SAlex Zinenko   LinalgTilingOptions tilingOptions;
3945cde5a57SAlex Zinenko   tilingOptions.scalarizeDynamicDims();
3955cde5a57SAlex Zinenko   // Tiling with "scalarize_dyn_dims" actually sets the same lambda as the tile
3965cde5a57SAlex Zinenko   // sizes and asserts that it is not already set.
3975cde5a57SAlex Zinenko   SmallVector<int64_t> emptyTileSizes;
3985cde5a57SAlex Zinenko   LinalgTilingPattern pattern(getContext(), tilingOptions);
3995cde5a57SAlex Zinenko   SimpleRewriter rewriter(getContext());
4005cde5a57SAlex Zinenko   rewriter.setInsertionPoint(target);
4015cde5a57SAlex Zinenko   FailureOr<TiledLinalgOp> result =
4025cde5a57SAlex Zinenko       pattern.returningMatchAndRewrite(target, rewriter);
4035cde5a57SAlex Zinenko   if (failed(result))
40452307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
4055cde5a57SAlex Zinenko 
40652307109SNicolas Vasilache   results.push_back(result->op);
40752307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
4085cde5a57SAlex Zinenko }
4095cde5a57SAlex Zinenko 
4105cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
411ff6e5508SAlex Zinenko // SplitOp
412ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
413ff6e5508SAlex Zinenko 
414ff6e5508SAlex Zinenko DiagnosedSilenceableFailure SplitOp::apply(TransformResults &results,
415ff6e5508SAlex Zinenko                                            TransformState &state) {
416ff6e5508SAlex Zinenko   // Collect the dynamic split points if provided.
417ff6e5508SAlex Zinenko   ArrayRef<Operation *> payload = state.getPayloadOps(getTarget());
418ff6e5508SAlex Zinenko   SimpleRewriter rewriter(getContext());
419ff6e5508SAlex Zinenko   SmallVector<OpFoldResult> splitPoints;
420ff6e5508SAlex Zinenko   splitPoints.reserve(payload.size());
421ff6e5508SAlex Zinenko   if (getDynamicSplitPoint()) {
422ff6e5508SAlex Zinenko     auto diag = DiagnosedSilenceableFailure::success();
423ff6e5508SAlex Zinenko     splitPoints = llvm::to_vector(llvm::map_range(
424ff6e5508SAlex Zinenko         state.getPayloadOps(getDynamicSplitPoint()), [&](Operation *op) {
425ff6e5508SAlex Zinenko           if (op->getNumResults() != 1 ||
426ff6e5508SAlex Zinenko               !op->getResult(0).getType().isIndex()) {
427ff6e5508SAlex Zinenko             diag = emitSilenceableError()
428ff6e5508SAlex Zinenko                    << "expected dynamic split point handle to point to a "
429ff6e5508SAlex Zinenko                       "single-result index-typed op";
430ff6e5508SAlex Zinenko             diag.attachNote(op->getLoc()) << "dynamic split point";
431ff6e5508SAlex Zinenko           }
432ff6e5508SAlex Zinenko           return OpFoldResult(op->getResult(0));
433ff6e5508SAlex Zinenko         }));
434ff6e5508SAlex Zinenko     if (!diag.succeeded())
435ff6e5508SAlex Zinenko       return diag;
436ff6e5508SAlex Zinenko 
437ff6e5508SAlex Zinenko     if (splitPoints.size() != payload.size()) {
438ff6e5508SAlex Zinenko       emitError() << "expected the dynamic split point handle to point to as "
439ff6e5508SAlex Zinenko                      "many operations ("
440ff6e5508SAlex Zinenko                   << splitPoints.size() << ") as the target handle ("
441ff6e5508SAlex Zinenko                   << payload.size() << ")";
442ff6e5508SAlex Zinenko       return DiagnosedSilenceableFailure::definiteFailure();
443ff6e5508SAlex Zinenko     }
444ff6e5508SAlex Zinenko   } else {
445ff6e5508SAlex Zinenko     splitPoints.resize(payload.size(),
446ff6e5508SAlex Zinenko                        rewriter.getIndexAttr(getStaticSplitPoint()));
447ff6e5508SAlex Zinenko   }
448ff6e5508SAlex Zinenko 
449ff6e5508SAlex Zinenko   // Split each target operation.
450ff6e5508SAlex Zinenko   SmallVector<Operation *> first, second;
451ff6e5508SAlex Zinenko   for (const auto &pair : llvm::zip(payload, splitPoints)) {
452ff6e5508SAlex Zinenko     Operation *target = std::get<0>(pair);
453ff6e5508SAlex Zinenko     auto linalgOp = dyn_cast<LinalgOp>(target);
454ff6e5508SAlex Zinenko     if (!linalgOp) {
455ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "only applies to structured ops";
456ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
457ff6e5508SAlex Zinenko       return diag;
458ff6e5508SAlex Zinenko     }
459ff6e5508SAlex Zinenko 
460ff6e5508SAlex Zinenko     if (getDimension() >= linalgOp.getNumLoops()) {
461ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "dimension " << getDimension()
462ff6e5508SAlex Zinenko                                          << " does not exist in target op";
463ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
464ff6e5508SAlex Zinenko       return diag;
465ff6e5508SAlex Zinenko     }
466ff6e5508SAlex Zinenko 
467ff6e5508SAlex Zinenko     rewriter.setInsertionPoint(linalgOp);
468ff6e5508SAlex Zinenko     std::tie(first.emplace_back(), second.emplace_back()) =
469ff6e5508SAlex Zinenko         linalg::splitOp(rewriter, linalgOp, getDimension(), std::get<1>(pair));
470ff6e5508SAlex Zinenko   }
471ff6e5508SAlex Zinenko 
472ff6e5508SAlex Zinenko   results.set(getFirst().cast<OpResult>(), first);
473ff6e5508SAlex Zinenko   results.set(getSecond().cast<OpResult>(), second);
474ff6e5508SAlex Zinenko   return DiagnosedSilenceableFailure::success();
475ff6e5508SAlex Zinenko }
476ff6e5508SAlex Zinenko 
477ff6e5508SAlex Zinenko void SplitOp::getEffects(
478ff6e5508SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
479ff6e5508SAlex Zinenko   // The target handle is consumed.
480ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Read::get(), getTarget(),
481ff6e5508SAlex Zinenko                        TransformMappingResource::get());
482ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Free::get(), getTarget(),
483ff6e5508SAlex Zinenko                        TransformMappingResource::get());
484ff6e5508SAlex Zinenko 
485ff6e5508SAlex Zinenko   // The dynamic split point handle is not consumed.
486ff6e5508SAlex Zinenko   if (getDynamicSplitPoint()) {
487ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Read::get(), getDynamicSplitPoint(),
488ff6e5508SAlex Zinenko                          TransformMappingResource::get());
489ff6e5508SAlex Zinenko   }
490ff6e5508SAlex Zinenko 
491ff6e5508SAlex Zinenko   // The resulting handles are produced.
492ff6e5508SAlex Zinenko   for (Value result : getResults()) {
493ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Allocate::get(), result,
494ff6e5508SAlex Zinenko                          TransformMappingResource::get());
495ff6e5508SAlex Zinenko     effects.emplace_back(MemoryEffects::Write::get(), result,
496ff6e5508SAlex Zinenko                          TransformMappingResource::get());
497ff6e5508SAlex Zinenko   }
498ff6e5508SAlex Zinenko 
499ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Read::get(), PayloadIRResource::get());
500ff6e5508SAlex Zinenko   effects.emplace_back(MemoryEffects::Write::get(), PayloadIRResource::get());
501ff6e5508SAlex Zinenko }
502ff6e5508SAlex Zinenko 
503ff6e5508SAlex Zinenko ParseResult SplitOp::parse(OpAsmParser &parser, OperationState &result) {
504ff6e5508SAlex Zinenko   OpAsmParser::UnresolvedOperand target, dynamicSplitPoint;
505ff6e5508SAlex Zinenko   IntegerAttr staticSplitPoint;
506ff6e5508SAlex Zinenko   auto pdlOperationType =
507ff6e5508SAlex Zinenko       pdl::OperationType::get(parser.getBuilder().getContext());
508ff6e5508SAlex Zinenko   if (parser.parseOperand(target) ||
509ff6e5508SAlex Zinenko       parser.resolveOperand(target, pdlOperationType, result.operands) ||
510ff6e5508SAlex Zinenko       parser.parseKeyword("after"))
511ff6e5508SAlex Zinenko     return failure();
512ff6e5508SAlex Zinenko 
513ff6e5508SAlex Zinenko   OptionalParseResult dynamicPointParseResult =
514ff6e5508SAlex Zinenko       parser.parseOptionalOperand(dynamicSplitPoint);
515ff6e5508SAlex Zinenko   if (!dynamicPointParseResult.hasValue()) {
516ff6e5508SAlex Zinenko     int64_t staticSplitPointValue;
517ff6e5508SAlex Zinenko     if (failed(parser.parseInteger(staticSplitPointValue)))
518ff6e5508SAlex Zinenko       return failure();
519ff6e5508SAlex Zinenko 
520ff6e5508SAlex Zinenko     staticSplitPoint =
521ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(staticSplitPointValue);
522ff6e5508SAlex Zinenko   } else {
523ff6e5508SAlex Zinenko     if (failed(*dynamicPointParseResult) ||
524ff6e5508SAlex Zinenko         parser.resolveOperand(dynamicSplitPoint, pdlOperationType,
525ff6e5508SAlex Zinenko                               result.operands)) {
526ff6e5508SAlex Zinenko       return failure();
527ff6e5508SAlex Zinenko     }
528ff6e5508SAlex Zinenko 
529ff6e5508SAlex Zinenko     staticSplitPoint =
530ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(ShapedType::kDynamicSize);
531ff6e5508SAlex Zinenko   }
532ff6e5508SAlex Zinenko 
533ff6e5508SAlex Zinenko   result.addAttribute(
534ff6e5508SAlex Zinenko       SplitOp::getStaticSplitPointAttrName(result.name).getValue(),
535ff6e5508SAlex Zinenko       staticSplitPoint);
536ff6e5508SAlex Zinenko   if (failed(parser.parseOptionalAttrDict(result.attributes)))
537ff6e5508SAlex Zinenko     return failure();
538ff6e5508SAlex Zinenko 
539ff6e5508SAlex Zinenko   result.addTypes({pdlOperationType, pdlOperationType});
540ff6e5508SAlex Zinenko   return success();
541ff6e5508SAlex Zinenko }
542ff6e5508SAlex Zinenko 
543ff6e5508SAlex Zinenko void SplitOp::print(OpAsmPrinter &printer) {
544ff6e5508SAlex Zinenko   printer << " " << getTarget() << " after ";
545ff6e5508SAlex Zinenko   int64_t staticSplitSize = static_cast<int64_t>(getStaticSplitPoint());
546ff6e5508SAlex Zinenko   if (staticSplitSize != ShapedType::kDynamicSize)
547ff6e5508SAlex Zinenko     printer << staticSplitSize;
548ff6e5508SAlex Zinenko   else
549ff6e5508SAlex Zinenko     printer << getDynamicSplitPoint();
550ff6e5508SAlex Zinenko   printer << " ";
551ff6e5508SAlex Zinenko   printer.printOptionalAttrDict(getOperation()->getAttrs(),
552ff6e5508SAlex Zinenko                                 {getStaticSplitPointAttrName()});
553ff6e5508SAlex Zinenko }
554ff6e5508SAlex Zinenko 
555ff6e5508SAlex Zinenko LogicalResult SplitOp::verify() {
556ff6e5508SAlex Zinenko   if ((static_cast<int64_t>(getStaticSplitPoint()) !=
557ff6e5508SAlex Zinenko        ShapedType::kDynamicSize) ^
558ff6e5508SAlex Zinenko       (getDynamicSplitPoint() == nullptr)) {
559ff6e5508SAlex Zinenko     return emitOpError()
560ff6e5508SAlex Zinenko            << "expects either a dynamic or a static split point to be provided";
561ff6e5508SAlex Zinenko   }
562ff6e5508SAlex Zinenko   return success();
563ff6e5508SAlex Zinenko }
564ff6e5508SAlex Zinenko 
565ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
566f439b319SNicolas Vasilache // SplitReductionOp
567f439b319SNicolas Vasilache //===----------------------------------------------------------------------===//
568f439b319SNicolas Vasilache 
56952307109SNicolas Vasilache DiagnosedSilenceableFailure
57052307109SNicolas Vasilache transform::SplitReductionOp::applyToOne(linalg::LinalgOp target,
57152307109SNicolas Vasilache                                         SmallVectorImpl<Operation *> &results,
57252307109SNicolas Vasilache                                         transform::TransformState &state) {
573f439b319SNicolas Vasilache   ControlSplitReductionFn splitFn = [&](LinalgOp) {
574f439b319SNicolas Vasilache     return std::pair<int64_t, unsigned>(getSplitFactor(),
575f439b319SNicolas Vasilache                                         getInsertSplitDimension());
576f439b319SNicolas Vasilache   };
577f439b319SNicolas Vasilache   SimpleRewriter rewriter(getContext());
578f439b319SNicolas Vasilache   rewriter.setInsertionPoint(target);
579f439b319SNicolas Vasilache   FailureOr<SplitReductionResult> splitResult =
580178f9bd6SNicolas Vasilache       (getUseScalingAlgorithm())
581178f9bd6SNicolas Vasilache           ? splitReductionByScaling(rewriter, target, splitFn, getUseAlloc())
582178f9bd6SNicolas Vasilache           : splitReduction(rewriter, target, splitFn, getUseAlloc());
583d5716395SNicolas Vasilache   if (failed(splitResult))
58452307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
58552307109SNicolas Vasilache 
58652307109SNicolas Vasilache   results.push_back(splitResult->initOrAlloc);
58752307109SNicolas Vasilache   results.push_back(splitResult->fillOp);
58852307109SNicolas Vasilache   results.push_back(splitResult->splitLinalgOp);
58952307109SNicolas Vasilache   results.push_back(splitResult->resultCombiningLinalgOp);
59052307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
591d5716395SNicolas Vasilache }
592d5716395SNicolas Vasilache 
593d5716395SNicolas Vasilache //===----------------------------------------------------------------------===//
5943c2a74a3SMatthias Springer // TileOp
5953c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
5963c2a74a3SMatthias Springer 
5971d45282aSAlex Zinenko DiagnosedSilenceableFailure
598e3890b7fSAlex Zinenko transform::TileOp::apply(TransformResults &transformResults,
5993c2a74a3SMatthias Springer                          TransformState &state) {
6003c2a74a3SMatthias Springer   LinalgTilingOptions tilingOptions;
601*4e4a4c05SAlex Zinenko   SmallVector<int64_t> tileSizes = extractI64Array(getStaticSizes());
6023c2a74a3SMatthias Springer 
603*4e4a4c05SAlex Zinenko   ArrayRef<Operation *> targets = state.getPayloadOps(getTarget());
604*4e4a4c05SAlex Zinenko   SmallVector<ArrayRef<Operation *>> dynamicSizeProducers;
605*4e4a4c05SAlex Zinenko   dynamicSizeProducers.reserve(getDynamicSizes().size());
606*4e4a4c05SAlex Zinenko   for (Value dynamicSizeProducerHandle : getDynamicSizes()) {
607*4e4a4c05SAlex Zinenko     dynamicSizeProducers.push_back(
608*4e4a4c05SAlex Zinenko         state.getPayloadOps(dynamicSizeProducerHandle));
609*4e4a4c05SAlex Zinenko 
610*4e4a4c05SAlex Zinenko     if (dynamicSizeProducers.back().size() != targets.size()) {
611*4e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag =
612*4e4a4c05SAlex Zinenko           emitSilenceableError()
613*4e4a4c05SAlex Zinenko           << "expected as many dynamic size-producing operations ("
614*4e4a4c05SAlex Zinenko           << dynamicSizeProducers.back().size() << ") as target ops ("
615*4e4a4c05SAlex Zinenko           << targets.size() << ")";
616*4e4a4c05SAlex Zinenko       diag.attachNote(dynamicSizeProducerHandle.getLoc()) << "for this handle";
617*4e4a4c05SAlex Zinenko       return diag;
618*4e4a4c05SAlex Zinenko     }
619*4e4a4c05SAlex Zinenko 
620*4e4a4c05SAlex Zinenko     for (Operation *op : dynamicSizeProducers.back()) {
621*4e4a4c05SAlex Zinenko       if (op->getNumResults() == 1 &&
622*4e4a4c05SAlex Zinenko           op->getResult(0).getType().isa<IndexType>())
623*4e4a4c05SAlex Zinenko         continue;
624*4e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag =
625*4e4a4c05SAlex Zinenko           emitSilenceableError() << "expected sizes to be produced by ops "
626*4e4a4c05SAlex Zinenko                                     "with a single index-type result";
627*4e4a4c05SAlex Zinenko       diag.attachNote(op->getLoc()) << "size producer op";
628*4e4a4c05SAlex Zinenko       diag.attachNote(dynamicSizeProducerHandle.getLoc()) << "for this handle";
629*4e4a4c05SAlex Zinenko       return diag;
630*4e4a4c05SAlex Zinenko     }
631*4e4a4c05SAlex Zinenko   }
632*4e4a4c05SAlex Zinenko 
633*4e4a4c05SAlex Zinenko   SmallVector<Operation *> tiled;
634*4e4a4c05SAlex Zinenko   SmallVector<SmallVector<Operation *, 4>, 4> loops;
635*4e4a4c05SAlex Zinenko   loops.resize(getLoops().size());
636*4e4a4c05SAlex Zinenko   for (auto &en : llvm::enumerate(targets)) {
637*4e4a4c05SAlex Zinenko     auto linalgOp = dyn_cast<LinalgOp>(en.value());
638*4e4a4c05SAlex Zinenko     if (!linalgOp) {
639*4e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag = emitSilenceableError()
640*4e4a4c05SAlex Zinenko                                          << "only linalg ops are supported";
641*4e4a4c05SAlex Zinenko       diag.attachNote(en.value()->getLoc()) << "target op";
642*4e4a4c05SAlex Zinenko       return diag;
643*4e4a4c05SAlex Zinenko     }
644*4e4a4c05SAlex Zinenko 
645*4e4a4c05SAlex Zinenko     unsigned index = en.index();
646*4e4a4c05SAlex Zinenko     if (!tileSizes.empty()) {
647*4e4a4c05SAlex Zinenko       tilingOptions.setTileSizeComputationFunction(
648*4e4a4c05SAlex Zinenko           [&, index](OpBuilder &b, Operation *) {
649*4e4a4c05SAlex Zinenko             SmallVector<Value, 4> sizes;
650*4e4a4c05SAlex Zinenko             sizes.reserve(tileSizes.size());
651*4e4a4c05SAlex Zinenko             unsigned dynamicIdx = 0;
652*4e4a4c05SAlex Zinenko             for (OpFoldResult ofr : getMixedSizes()) {
653*4e4a4c05SAlex Zinenko               if (auto attr = ofr.dyn_cast<Attribute>()) {
654*4e4a4c05SAlex Zinenko                 sizes.push_back(b.create<arith::ConstantIndexOp>(
655*4e4a4c05SAlex Zinenko                     getLoc(), attr.cast<IntegerAttr>().getInt()));
656*4e4a4c05SAlex Zinenko               } else {
657*4e4a4c05SAlex Zinenko                 sizes.push_back(
658*4e4a4c05SAlex Zinenko                     dynamicSizeProducers[dynamicIdx++][index]->getResult(0));
659*4e4a4c05SAlex Zinenko               }
660*4e4a4c05SAlex Zinenko             }
661*4e4a4c05SAlex Zinenko             return sizes;
662*4e4a4c05SAlex Zinenko           });
663*4e4a4c05SAlex Zinenko     }
664*4e4a4c05SAlex Zinenko 
6653c2a74a3SMatthias Springer     tilingOptions.setInterchange(extractUIntArray(getInterchange()));
6663c2a74a3SMatthias Springer     LinalgTilingPattern pattern(getContext(), tilingOptions);
6673c2a74a3SMatthias Springer     SimpleRewriter rewriter(linalgOp.getContext());
668*4e4a4c05SAlex Zinenko     FailureOr<TiledLinalgOp> tiledOp =
669*4e4a4c05SAlex Zinenko         pattern.returningMatchAndRewrite(linalgOp, rewriter);
670*4e4a4c05SAlex Zinenko     if (failed(tiledOp))
671*4e4a4c05SAlex Zinenko       return DiagnosedSilenceableFailure::definiteFailure();
672*4e4a4c05SAlex Zinenko 
673*4e4a4c05SAlex Zinenko     tiled.push_back(tiledOp->op);
674*4e4a4c05SAlex Zinenko     for (const auto &en2 : llvm::enumerate(tiledOp->loops))
675*4e4a4c05SAlex Zinenko       loops[en2.index()].push_back(en2.value());
676*4e4a4c05SAlex Zinenko   }
677*4e4a4c05SAlex Zinenko 
678*4e4a4c05SAlex Zinenko   transformResults.set(getTiledLinalgOp().cast<OpResult>(), tiled);
679*4e4a4c05SAlex Zinenko   for (const auto &en : llvm::enumerate(loops))
680*4e4a4c05SAlex Zinenko     transformResults.set(getLoops()[en.index()].cast<OpResult>(), en.value());
681*4e4a4c05SAlex Zinenko 
682*4e4a4c05SAlex Zinenko   return DiagnosedSilenceableFailure::success();
683*4e4a4c05SAlex Zinenko }
684*4e4a4c05SAlex Zinenko 
685*4e4a4c05SAlex Zinenko SmallVector<OpFoldResult> transform::TileOp::getMixedSizes() {
686*4e4a4c05SAlex Zinenko   ValueRange dynamic = getDynamicSizes();
687*4e4a4c05SAlex Zinenko   SmallVector<int64_t> tileSizes = extractI64Array(getStaticSizes());
688*4e4a4c05SAlex Zinenko   SmallVector<OpFoldResult> results;
689*4e4a4c05SAlex Zinenko   results.reserve(tileSizes.size());
690*4e4a4c05SAlex Zinenko   unsigned dynamicPos = 0;
691*4e4a4c05SAlex Zinenko   Builder builder(getContext());
692*4e4a4c05SAlex Zinenko   for (int64_t size : tileSizes) {
693*4e4a4c05SAlex Zinenko     if (size == ShapedType::kDynamicSize) {
694*4e4a4c05SAlex Zinenko       results.push_back(dynamic[dynamicPos++]);
695*4e4a4c05SAlex Zinenko     } else {
696*4e4a4c05SAlex Zinenko       results.push_back(builder.getIndexAttr(size));
697*4e4a4c05SAlex Zinenko     }
698*4e4a4c05SAlex Zinenko   }
699*4e4a4c05SAlex Zinenko   return results;
7003c2a74a3SMatthias Springer }
7013c2a74a3SMatthias Springer 
7023c2a74a3SMatthias Springer ParseResult transform::TileOp::parse(OpAsmParser &parser,
7033c2a74a3SMatthias Springer                                      OperationState &result) {
704*4e4a4c05SAlex Zinenko   OpAsmParser::UnresolvedOperand target;
705*4e4a4c05SAlex Zinenko   SmallVector<OpAsmParser::UnresolvedOperand> dynamicSizes;
706*4e4a4c05SAlex Zinenko   ArrayAttr staticSizes;
707*4e4a4c05SAlex Zinenko   auto pdlOperationType = pdl::OperationType::get(parser.getContext());
708*4e4a4c05SAlex Zinenko   if (parser.parseOperand(target) ||
709*4e4a4c05SAlex Zinenko       parser.resolveOperand(target, pdlOperationType, result.operands) ||
710*4e4a4c05SAlex Zinenko       parseOperandsOrIntegersSizesList(parser, dynamicSizes, staticSizes) ||
711*4e4a4c05SAlex Zinenko       parser.resolveOperands(dynamicSizes, pdlOperationType, result.operands) ||
712*4e4a4c05SAlex Zinenko       parser.parseOptionalAttrDict(result.attributes))
713*4e4a4c05SAlex Zinenko     return ParseResult::failure();
714*4e4a4c05SAlex Zinenko 
715*4e4a4c05SAlex Zinenko   result.addAttribute(getStaticSizesAttrName(result.name), staticSizes);
716*4e4a4c05SAlex Zinenko   size_t numExpectedLoops =
717*4e4a4c05SAlex Zinenko       staticSizes.size() - llvm::count(extractI64Array(staticSizes), 0);
718*4e4a4c05SAlex Zinenko   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOperationType));
719*4e4a4c05SAlex Zinenko   return success();
7203c2a74a3SMatthias Springer }
7213c2a74a3SMatthias Springer 
7223c2a74a3SMatthias Springer void TileOp::print(OpAsmPrinter &p) {
723*4e4a4c05SAlex Zinenko   p << ' ' << getTarget();
724*4e4a4c05SAlex Zinenko   printOperandsOrIntegersSizesList(p, getOperation(), getDynamicSizes(),
725*4e4a4c05SAlex Zinenko                                    getStaticSizes());
726*4e4a4c05SAlex Zinenko   p.printOptionalAttrDict((*this)->getAttrs(), {getStaticSizesAttrName()});
727*4e4a4c05SAlex Zinenko }
728*4e4a4c05SAlex Zinenko 
729*4e4a4c05SAlex Zinenko void transform::TileOp::getEffects(
730*4e4a4c05SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
731*4e4a4c05SAlex Zinenko   consumesHandle(getTarget(), effects);
732*4e4a4c05SAlex Zinenko   onlyReadsHandle(getDynamicSizes(), effects);
733*4e4a4c05SAlex Zinenko   producesHandle(getTiledLinalgOp(), effects);
734*4e4a4c05SAlex Zinenko   producesHandle(getLoops(), effects);
735*4e4a4c05SAlex Zinenko   modifiesPayload(effects);
7363c2a74a3SMatthias Springer }
7373c2a74a3SMatthias Springer 
7383c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
739cc6c1592SAlex Zinenko // VectorizeOp
740cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
741cc6c1592SAlex Zinenko 
74252307109SNicolas Vasilache DiagnosedSilenceableFailure
74352307109SNicolas Vasilache transform::VectorizeOp::applyToOne(Operation *target,
74452307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
74552307109SNicolas Vasilache                                    transform::TransformState &state) {
746cc6c1592SAlex Zinenko   if (!target->hasTrait<OpTrait::IsIsolatedFromAbove>()) {
74752307109SNicolas Vasilache     auto diag = this->emitOpError("requires isolated-from-above targets");
748cc6c1592SAlex Zinenko     diag.attachNote(target->getLoc()) << "non-isolated target";
74952307109SNicolas Vasilache     return DiagnosedSilenceableFailure::definiteFailure();
750cc6c1592SAlex Zinenko   }
751cc6c1592SAlex Zinenko 
752cc6c1592SAlex Zinenko   MLIRContext *ctx = getContext();
753cc6c1592SAlex Zinenko   RewritePatternSet patterns(ctx);
754cc6c1592SAlex Zinenko   patterns.add<LinalgVectorizationPattern>(ctx);
755cc6c1592SAlex Zinenko 
756cc6c1592SAlex Zinenko   vector::populateVectorTransferPermutationMapLoweringPatterns(patterns);
757cc6c1592SAlex Zinenko   vector::populateVectorReductionToContractPatterns(patterns);
758cc6c1592SAlex Zinenko   patterns.add<linalg::LinalgCopyVTRForwardingPattern,
759cc6c1592SAlex Zinenko                linalg::LinalgCopyVTWForwardingPattern>(ctx,
760cc6c1592SAlex Zinenko                                                        /*benefit=*/2);
761cc6c1592SAlex Zinenko   vector::TransferReadOp::getCanonicalizationPatterns(patterns, ctx);
762cc6c1592SAlex Zinenko   vector::TransferWriteOp::getCanonicalizationPatterns(patterns, ctx);
763cc6c1592SAlex Zinenko   if (getVectorizePadding())
764cc6c1592SAlex Zinenko     linalg::populatePadOpVectorizationPatterns(patterns);
765cc6c1592SAlex Zinenko 
7665f0d4f20SAlex Zinenko   if (failed(applyPatternsAndFoldGreedily(target, std::move(patterns))))
76752307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
76852307109SNicolas Vasilache 
76952307109SNicolas Vasilache   results.push_back(target);
77052307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
771cc6c1592SAlex Zinenko }
772cc6c1592SAlex Zinenko 
773cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
7743c2a74a3SMatthias Springer // Transform op registration
7753c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
7763c2a74a3SMatthias Springer 
7773c2a74a3SMatthias Springer namespace {
7783c2a74a3SMatthias Springer /// Registers new ops and declares PDL as dependent dialect since the additional
7793c2a74a3SMatthias Springer /// ops are using PDL types for operands and results.
7803c2a74a3SMatthias Springer class LinalgTransformDialectExtension
7813c2a74a3SMatthias Springer     : public transform::TransformDialectExtension<
7823c2a74a3SMatthias Springer           LinalgTransformDialectExtension> {
7833c2a74a3SMatthias Springer public:
7843c2a74a3SMatthias Springer   LinalgTransformDialectExtension() {
785*4e4a4c05SAlex Zinenko     declareDependentDialect<arith::ArithmeticDialect>();
7863c2a74a3SMatthias Springer     declareDependentDialect<pdl::PDLDialect>();
7873c2a74a3SMatthias Springer     declareDependentDialect<scf::SCFDialect>();
788cc6c1592SAlex Zinenko     declareDependentDialect<vector::VectorDialect>();
7893c2a74a3SMatthias Springer     registerTransformOps<
7903c2a74a3SMatthias Springer #define GET_OP_LIST
7913c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
7923c2a74a3SMatthias Springer         >();
7933c2a74a3SMatthias Springer   }
7943c2a74a3SMatthias Springer };
7953c2a74a3SMatthias Springer } // namespace
7963c2a74a3SMatthias Springer 
7973c2a74a3SMatthias Springer #define GET_OP_CLASSES
7983c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
7993c2a74a3SMatthias Springer 
8003c2a74a3SMatthias Springer void mlir::linalg::registerTransformDialectExtension(
8013c2a74a3SMatthias Springer     DialectRegistry &registry) {
8023c2a74a3SMatthias Springer   registry.addExtensions<LinalgTransformDialectExtension>();
8033c2a74a3SMatthias Springer }
804