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 
113963b4d0SAlex Zinenko #include "mlir/Dialect/Affine/IR/AffineOps.h"
124e4a4c05SAlex Zinenko #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h"
133c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/IR/Linalg.h"
143c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/Transforms/Transforms.h"
153c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDL.h"
163c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDLTypes.h"
173c2a74a3SMatthias Springer #include "mlir/Dialect/Transform/IR/TransformDialect.h"
183963b4d0SAlex Zinenko #include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
19*18b92c66SNicolas Vasilache #include "mlir/Interfaces/TilingInterface.h"
203c2a74a3SMatthias Springer #include "mlir/Parser/Parser.h"
21cc6c1592SAlex Zinenko #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
223c2a74a3SMatthias Springer 
233c2a74a3SMatthias Springer using namespace mlir;
243c2a74a3SMatthias Springer using namespace mlir::linalg;
253c2a74a3SMatthias Springer using namespace mlir::transform;
263c2a74a3SMatthias Springer 
273c2a74a3SMatthias Springer /// Extracts a vector of unsigned from an array attribute. Asserts if the
283c2a74a3SMatthias Springer /// attribute contains values other than intergers. May truncate.
293c2a74a3SMatthias Springer static SmallVector<unsigned> extractUIntArray(ArrayAttr attr) {
303c2a74a3SMatthias Springer   SmallVector<unsigned> result;
313c2a74a3SMatthias Springer   result.reserve(attr.size());
323c2a74a3SMatthias Springer   for (APInt value : attr.getAsValueRange<IntegerAttr>())
333c2a74a3SMatthias Springer     result.push_back(value.getZExtValue());
343c2a74a3SMatthias Springer   return result;
353c2a74a3SMatthias Springer }
363c2a74a3SMatthias Springer 
373c2a74a3SMatthias Springer namespace {
383c2a74a3SMatthias Springer /// A simple pattern rewriter that implements no special logic.
393c2a74a3SMatthias Springer class SimpleRewriter : public PatternRewriter {
403c2a74a3SMatthias Springer public:
413c2a74a3SMatthias Springer   SimpleRewriter(MLIRContext *context) : PatternRewriter(context) {}
423c2a74a3SMatthias Springer };
433c2a74a3SMatthias Springer } // namespace
443c2a74a3SMatthias Springer 
45ce2e198bSAlex Zinenko /// Attempts to apply the pattern specified as template argument to the given
46ce2e198bSAlex Zinenko /// operation. The pattern is expected to have a `returningMatchAndRewrite`
47ce2e198bSAlex Zinenko /// function that returns the "main" result or failure. Returns failure if the
48ce2e198bSAlex Zinenko /// pattern failed to apply. Extra arguments are forwarded to the pattern
49ce2e198bSAlex Zinenko /// constructor.
50ce2e198bSAlex Zinenko template <typename PatternTy, typename... Args>
51ce2e198bSAlex Zinenko static FailureOr<LinalgOp> tryApply(Operation *operation, Args &&...args) {
52ce2e198bSAlex Zinenko   // Check if the given operation has the type expected by the pattern.
53ce2e198bSAlex Zinenko   using OpTy = typename llvm::function_traits<
54ce2e198bSAlex Zinenko       decltype(&PatternTy::returningMatchAndRewrite)>::template arg_t<0>;
55ce2e198bSAlex Zinenko   auto op = dyn_cast<OpTy>(operation);
56ce2e198bSAlex Zinenko   if (!op)
57ce2e198bSAlex Zinenko     return failure();
58ce2e198bSAlex Zinenko 
59ce2e198bSAlex Zinenko   // Apply the pattern directly to the op.
60ce2e198bSAlex Zinenko   PatternTy pattern(operation->getContext(), std::forward<Args>(args)...);
61ce2e198bSAlex Zinenko   SimpleRewriter rewriter(operation->getContext());
62ce2e198bSAlex Zinenko   rewriter.setInsertionPoint(operation);
63ce2e198bSAlex Zinenko   auto result = pattern.returningMatchAndRewrite(op, rewriter);
64ce2e198bSAlex Zinenko   if (failed(result))
65ce2e198bSAlex Zinenko     return failure();
66ce2e198bSAlex Zinenko   return cast<LinalgOp>(result->getOperation());
67ce2e198bSAlex Zinenko }
68ce2e198bSAlex Zinenko 
69ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
70ce2e198bSAlex Zinenko // DecomposeOp
71ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
72ce2e198bSAlex Zinenko 
7352307109SNicolas Vasilache DiagnosedSilenceableFailure
7452307109SNicolas Vasilache transform::DecomposeOp::applyToOne(linalg::LinalgOp target,
7552307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
7652307109SNicolas Vasilache                                    transform::TransformState &state) {
77ce2e198bSAlex Zinenko   FailureOr<LinalgOp> windowed =
78ce2e198bSAlex Zinenko       tryApply<DownscaleSizeOneWindowed2DConvolution>(target);
7952307109SNicolas Vasilache   if (succeeded(windowed)) {
8052307109SNicolas Vasilache     results.push_back(*windowed);
8152307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
8252307109SNicolas Vasilache   }
83ce2e198bSAlex Zinenko   FailureOr<LinalgOp> depthwise =
84ce2e198bSAlex Zinenko       tryApply<DownscaleDepthwiseConv2DNhwcHwcOp>(target);
8552307109SNicolas Vasilache   if (succeeded(depthwise)) {
8652307109SNicolas Vasilache     results.push_back(*depthwise);
8752307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
8852307109SNicolas Vasilache   }
8952307109SNicolas Vasilache   results.assign(1, nullptr);
9052307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
91ce2e198bSAlex Zinenko }
92ce2e198bSAlex Zinenko 
93ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
94b6c58ec4SAlex Zinenko // FuseOp
95b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
96b6c58ec4SAlex Zinenko 
97b6c58ec4SAlex Zinenko /// Apply a tiling transformation to all payload ops and store both the
98b6c58ec4SAlex Zinenko /// tiled operation as well as the created tile loops.
99b6c58ec4SAlex Zinenko static LogicalResult
1004e4a4c05SAlex Zinenko applyTilingToAll(Operation *transformOp, ArrayRef<Operation *> payloadOps,
1014e4a4c05SAlex Zinenko                  unsigned numLoops,
102b6c58ec4SAlex Zinenko                  transform::TransformResults &transformResults,
103b6c58ec4SAlex Zinenko                  function_ref<FailureOr<TiledLinalgOp>(LinalgOp)> applyFn) {
104b6c58ec4SAlex Zinenko   SmallVector<Operation *> tiledLinalgOps;
105b6c58ec4SAlex Zinenko   SmallVector<SmallVector<Operation *>> loopOps(numLoops);
106b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
107b6c58ec4SAlex Zinenko     loopOps[i].reserve(payloadOps.size());
108b6c58ec4SAlex Zinenko 
109b6c58ec4SAlex Zinenko   for (Operation *target : payloadOps) {
110b6c58ec4SAlex Zinenko     auto linalgOp = dyn_cast<linalg::LinalgOp>(target);
111b6c58ec4SAlex Zinenko     if (!linalgOp)
112b6c58ec4SAlex Zinenko       return transformOp->emitError("only LinalgOps are supported");
113b6c58ec4SAlex Zinenko 
114b6c58ec4SAlex Zinenko     FailureOr<TiledLinalgOp> tiled = applyFn(linalgOp);
115b6c58ec4SAlex Zinenko     if (failed(tiled))
116b6c58ec4SAlex Zinenko       return failure();
117b6c58ec4SAlex Zinenko 
118b6c58ec4SAlex Zinenko     tiledLinalgOps.push_back(tiled->op);
119b6c58ec4SAlex Zinenko     if (tiled->loops.size() != numLoops)
120b6c58ec4SAlex Zinenko       // Not enough loops were generated. This usually means that the input size
121b6c58ec4SAlex Zinenko       // was smaller than the tiling size.
122b6c58ec4SAlex Zinenko       // TODO: LinalgTilingPattern should return failure().
123b6c58ec4SAlex Zinenko       return failure();
124b6c58ec4SAlex Zinenko     for (unsigned int i = 0; i < numLoops; ++i)
125b6c58ec4SAlex Zinenko       loopOps[i].push_back(tiled->loops[i]);
126b6c58ec4SAlex Zinenko   }
127b6c58ec4SAlex Zinenko 
128b6c58ec4SAlex Zinenko   transformResults.set(transformOp->getOpResult(0), tiledLinalgOps);
129b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
130b6c58ec4SAlex Zinenko     transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]);
131b6c58ec4SAlex Zinenko   return success();
132b6c58ec4SAlex Zinenko }
133b6c58ec4SAlex Zinenko 
134b6c58ec4SAlex Zinenko /// Parse a tiling-like operation that returns the tiled op as well as the
135b6c58ec4SAlex Zinenko /// created tile loops. The function counts the non-zero tile sizes to compute
136b6c58ec4SAlex Zinenko /// the number of results.
137b6c58ec4SAlex Zinenko static ParseResult parseTileLikeOp(OpAsmParser &parser, OperationState &result,
138b6c58ec4SAlex Zinenko                                    StringRef sizesAttrName) {
139b6c58ec4SAlex Zinenko   OpAsmParser::UnresolvedOperand targetOperand;
140b6c58ec4SAlex Zinenko   SMLoc opLoc = parser.getCurrentLocation();
141b6c58ec4SAlex Zinenko   if (parser.parseOperand(targetOperand) ||
142b6c58ec4SAlex Zinenko       parser.parseOptionalAttrDict(result.attributes))
143b6c58ec4SAlex Zinenko     return failure();
144b6c58ec4SAlex Zinenko   Attribute sizesAttr = result.attributes.get(sizesAttrName);
145b6c58ec4SAlex Zinenko   if (!sizesAttr)
146b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
147b6c58ec4SAlex Zinenko            << "expected '" << sizesAttrName << "' attribute";
148b6c58ec4SAlex Zinenko   auto sizesArrayAttr = sizesAttr.dyn_cast<ArrayAttr>();
149b6c58ec4SAlex Zinenko   if (!sizesArrayAttr)
150b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
151b6c58ec4SAlex Zinenko            << "'" << sizesAttrName << "' attribute must be an array";
152b6c58ec4SAlex Zinenko   Type pdlOpType = parser.getBuilder().getType<pdl::OperationType>();
153b6c58ec4SAlex Zinenko   size_t numExpectedLoops =
154*18b92c66SNicolas Vasilache       sizesArrayAttr.size() -
155*18b92c66SNicolas Vasilache       llvm::count(extractFromI64ArrayAttr(sizesArrayAttr), 0);
156b6c58ec4SAlex Zinenko   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOpType));
157b6c58ec4SAlex Zinenko   if (parser.resolveOperand(targetOperand, pdlOpType, result.operands))
158b6c58ec4SAlex Zinenko     return failure();
159b6c58ec4SAlex Zinenko   return success();
160b6c58ec4SAlex Zinenko }
161b6c58ec4SAlex Zinenko 
1621d45282aSAlex Zinenko DiagnosedSilenceableFailure
163b6c58ec4SAlex Zinenko transform::FuseOp::apply(mlir::transform::TransformResults &transformResults,
164b6c58ec4SAlex Zinenko                          mlir::transform::TransformState &state) {
165b6c58ec4SAlex Zinenko   LinalgTilingAndFusionOptions fusionOptions;
166*18b92c66SNicolas Vasilache   fusionOptions.tileSizes = extractFromI64ArrayAttr(getTileSizes());
167*18b92c66SNicolas Vasilache   fusionOptions.tileInterchange = extractFromI64ArrayAttr(getTileInterchange());
168b6c58ec4SAlex Zinenko 
169e3890b7fSAlex Zinenko   LogicalResult result = applyTilingToAll(
1704e4a4c05SAlex Zinenko       getOperation(), state.getPayloadOps(getTarget()),
1714e4a4c05SAlex Zinenko       fusionOptions.tileSizes.size() - llvm::count(fusionOptions.tileSizes, 0),
1724e4a4c05SAlex Zinenko       transformResults, [&](LinalgOp linalgOp) -> FailureOr<TiledLinalgOp> {
173b6c58ec4SAlex Zinenko         LinalgTileAndFuseTensorOpsPattern pattern(getContext(), fusionOptions);
174b6c58ec4SAlex Zinenko         SimpleRewriter rewriter(getContext());
175b6c58ec4SAlex Zinenko         rewriter.setInsertionPoint(linalgOp);
176b6c58ec4SAlex Zinenko         FailureOr<TileLoopNest> tileLoopNest =
177b6c58ec4SAlex Zinenko             pattern.returningMatchAndRewrite(linalgOp, rewriter);
178b6c58ec4SAlex Zinenko         if (failed(tileLoopNest))
179b6c58ec4SAlex Zinenko           return failure();
180b6c58ec4SAlex Zinenko 
181b6c58ec4SAlex Zinenko         TiledLinalgOp tiledLinalgOp;
182b6c58ec4SAlex Zinenko         tiledLinalgOp.op = tileLoopNest->getRootOp();
183b6c58ec4SAlex Zinenko         tiledLinalgOp.loops = {tileLoopNest->getLoopOps().begin(),
184b6c58ec4SAlex Zinenko                                tileLoopNest->getLoopOps().end()};
185b6c58ec4SAlex Zinenko         return tiledLinalgOp;
186b6c58ec4SAlex Zinenko       });
1874e4a4c05SAlex Zinenko   return DiagnosedSilenceableFailure(result);
188b6c58ec4SAlex Zinenko }
189b6c58ec4SAlex Zinenko 
190b6c58ec4SAlex Zinenko ParseResult transform::FuseOp::parse(OpAsmParser &parser,
191b6c58ec4SAlex Zinenko                                      OperationState &result) {
192b6c58ec4SAlex Zinenko   return parseTileLikeOp(
193b6c58ec4SAlex Zinenko       parser, result,
194b6c58ec4SAlex Zinenko       transform::FuseOp::getTileSizesAttrName(result.name).getValue());
195b6c58ec4SAlex Zinenko }
196b6c58ec4SAlex Zinenko 
197b6c58ec4SAlex Zinenko void transform::FuseOp::print(OpAsmPrinter &p) {
198b6c58ec4SAlex Zinenko   p << ' ';
199b6c58ec4SAlex Zinenko   p << getTarget();
200b6c58ec4SAlex Zinenko   p.printOptionalAttrDict((*this)->getAttrs());
201b6c58ec4SAlex Zinenko }
202b6c58ec4SAlex Zinenko 
203b6c58ec4SAlex Zinenko LogicalResult transform::FuseOp::verify() {
204*18b92c66SNicolas Vasilache   SmallVector<int64_t> permutation =
205*18b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getTileInterchange());
206b6c58ec4SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, permutation.size()));
207b6c58ec4SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
208b6c58ec4SAlex Zinenko                            permutation.begin(), permutation.end())) {
209b6c58ec4SAlex Zinenko     return emitOpError() << "expects interchange to be a permutation, found "
210b6c58ec4SAlex Zinenko                          << getTileInterchange();
211b6c58ec4SAlex Zinenko   }
212b6c58ec4SAlex Zinenko   return success();
213b6c58ec4SAlex Zinenko }
214b6c58ec4SAlex Zinenko 
215b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
216ce2e198bSAlex Zinenko // GeneralizeOp
217ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
218ce2e198bSAlex Zinenko 
21952307109SNicolas Vasilache DiagnosedSilenceableFailure
22052307109SNicolas Vasilache transform::GeneralizeOp::applyToOne(linalg::LinalgOp target,
22152307109SNicolas Vasilache                                     SmallVectorImpl<Operation *> &results,
22252307109SNicolas Vasilache                                     transform::TransformState &state) {
223ce2e198bSAlex Zinenko   // Exit early if no transformation is needed.
22452307109SNicolas Vasilache   if (isa<GenericOp>(target)) {
22552307109SNicolas Vasilache     results.push_back(target);
22652307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
22752307109SNicolas Vasilache   }
228ce2e198bSAlex Zinenko   FailureOr<LinalgOp> generic = tryApply<LinalgGeneralizationPattern>(target);
22952307109SNicolas Vasilache   if (succeeded(generic)) {
23052307109SNicolas Vasilache     results.push_back(generic->getOperation());
23152307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
23252307109SNicolas Vasilache   }
23352307109SNicolas Vasilache   results.assign(1, nullptr);
23452307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
235ce2e198bSAlex Zinenko }
236ce2e198bSAlex Zinenko 
2373c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
2385cde5a57SAlex Zinenko // InterchangeOp
2395cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
2405cde5a57SAlex Zinenko 
24152307109SNicolas Vasilache DiagnosedSilenceableFailure
24252307109SNicolas Vasilache transform::InterchangeOp::applyToOne(linalg::GenericOp target,
24352307109SNicolas Vasilache                                      SmallVectorImpl<Operation *> &results,
24452307109SNicolas Vasilache                                      transform::TransformState &state) {
2455cde5a57SAlex Zinenko   SmallVector<unsigned> interchangeVector =
2465cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2475cde5a57SAlex Zinenko   // Exit early if no transformation is needed.
24852307109SNicolas Vasilache   if (interchangeVector.empty()) {
24952307109SNicolas Vasilache     results.push_back(target);
25052307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
2515cde5a57SAlex Zinenko   }
25252307109SNicolas Vasilache   SimpleRewriter rewriter(target->getContext());
25352307109SNicolas Vasilache   FailureOr<GenericOp> res =
25452307109SNicolas Vasilache       interchangeGenericOp(rewriter, target, interchangeVector);
25552307109SNicolas Vasilache   if (failed(res))
25652307109SNicolas Vasilache     return DiagnosedSilenceableFailure::definiteFailure();
25752307109SNicolas Vasilache   results.push_back(res->getOperation());
25852307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
2595cde5a57SAlex Zinenko }
2605cde5a57SAlex Zinenko 
2615cde5a57SAlex Zinenko LogicalResult transform::InterchangeOp::verify() {
2625cde5a57SAlex Zinenko   SmallVector<unsigned> permutation =
2635cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2645cde5a57SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<unsigned>(0, permutation.size()));
2655cde5a57SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
2665cde5a57SAlex Zinenko                            permutation.begin(), permutation.end())) {
2675cde5a57SAlex Zinenko     return emitOpError()
2685cde5a57SAlex Zinenko            << "expects iterator_interchange to be a permutation, found "
2695cde5a57SAlex Zinenko            << getIteratorInterchange();
2705cde5a57SAlex Zinenko   }
2715cde5a57SAlex Zinenko   return success();
2725cde5a57SAlex Zinenko }
2735cde5a57SAlex Zinenko 
2745cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2753963b4d0SAlex Zinenko // MultiTileSizesOp
2763963b4d0SAlex Zinenko //===---------------------------------------------------------------------===//
2773963b4d0SAlex Zinenko 
2783963b4d0SAlex Zinenko DiagnosedSilenceableFailure transform::MultiTileSizesOp::applyToOne(
2793963b4d0SAlex Zinenko     LinalgOp target, SmallVector<Operation *> &results, TransformState &state) {
2803963b4d0SAlex Zinenko   OpBuilder builder(target.getContext());
2813963b4d0SAlex Zinenko   builder.setInsertionPoint(target);
2823963b4d0SAlex Zinenko   OpFoldResult targetSize = builder.getIndexAttr(getTargetSize());
2833963b4d0SAlex Zinenko   OpFoldResult divisor = builder.getIndexAttr(getDivisor());
2843963b4d0SAlex Zinenko   FailureOr<MultiSizeSpecification> spec = computeMultiTileSizes(
2853963b4d0SAlex Zinenko       builder, target, getDimension(), targetSize, divisor);
2863963b4d0SAlex Zinenko   if (failed(spec)) {
2873963b4d0SAlex Zinenko     return emitSilenceableError() << "could not generate tile size computation";
2883963b4d0SAlex Zinenko   }
2893963b4d0SAlex Zinenko 
290a5c802a4SAlex Zinenko   AffineExpr s0 = builder.getAffineSymbolExpr(0);
291a5c802a4SAlex Zinenko   AffineExpr s1 = builder.getAffineSymbolExpr(1);
2923963b4d0SAlex Zinenko   Operation *splitPoint =
293a5c802a4SAlex Zinenko       makeComposedAffineApply(builder, target.getLoc(), s0 * s1,
294a5c802a4SAlex Zinenko                               {spec->lowTileSize, spec->lowTripCount});
2953963b4d0SAlex Zinenko   Operation *lowTileSize = spec->lowTileSize.getDefiningOp();
2963963b4d0SAlex Zinenko   Operation *highTileSize = spec->highTileSize.getDefiningOp();
2973963b4d0SAlex Zinenko   assert(lowTileSize && highTileSize && splitPoint &&
2983963b4d0SAlex Zinenko          "tile sizes are not produced by operations");
2993963b4d0SAlex Zinenko   results.reserve(results.size() + 3);
3003963b4d0SAlex Zinenko   results.push_back(lowTileSize);
3013963b4d0SAlex Zinenko   results.push_back(highTileSize);
3023963b4d0SAlex Zinenko   results.push_back(splitPoint);
3033963b4d0SAlex Zinenko   return DiagnosedSilenceableFailure::success();
3043963b4d0SAlex Zinenko }
3053963b4d0SAlex Zinenko 
3063963b4d0SAlex Zinenko void transform::MultiTileSizesOp::getEffects(
3073963b4d0SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
308e15b855eSAlex Zinenko   onlyReadsHandle(getTarget(), effects);
309e15b855eSAlex Zinenko   producesHandle(getResults(), effects);
310e15b855eSAlex Zinenko   modifiesPayload(effects);
3113963b4d0SAlex Zinenko }
3123963b4d0SAlex Zinenko 
3133963b4d0SAlex Zinenko //===---------------------------------------------------------------------===//
3145cde5a57SAlex Zinenko // PadOp
3155cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
3165cde5a57SAlex Zinenko 
31752307109SNicolas Vasilache DiagnosedSilenceableFailure
31852307109SNicolas Vasilache transform::PadOp::applyToOne(linalg::LinalgOp target,
31952307109SNicolas Vasilache                              SmallVectorImpl<Operation *> &results,
32052307109SNicolas Vasilache                              transform::TransformState &state) {
3215cde5a57SAlex Zinenko   // Convert the integer packing flags to booleans.
3225cde5a57SAlex Zinenko   SmallVector<bool> packPaddings;
323*18b92c66SNicolas Vasilache   for (int64_t packPadding : extractFromI64ArrayAttr(getPackPaddings()))
3245cde5a57SAlex Zinenko     packPaddings.push_back(static_cast<bool>(packPadding));
3255cde5a57SAlex Zinenko 
3265cde5a57SAlex Zinenko   // Convert the padding values to attributes.
3275cde5a57SAlex Zinenko   SmallVector<Attribute> paddingValues;
3285cde5a57SAlex Zinenko   for (auto const &it :
3295cde5a57SAlex Zinenko        llvm::zip(getPaddingValues(), target->getOperandTypes())) {
3305cde5a57SAlex Zinenko     Attribute attr = std::get<0>(it);
3315cde5a57SAlex Zinenko     Type elementType = getElementTypeOrSelf(std::get<1>(it));
3325cde5a57SAlex Zinenko     // Try to parse string attributes to obtain an attribute of element type.
3335cde5a57SAlex Zinenko     if (auto stringAttr = attr.dyn_cast<StringAttr>()) {
3345cde5a57SAlex Zinenko       paddingValues.push_back(
3355cde5a57SAlex Zinenko           parseAttribute(attr.cast<StringAttr>(), elementType));
3365cde5a57SAlex Zinenko       if (!paddingValues.back()) {
33752307109SNicolas Vasilache         auto diag = this->emitOpError("expects a padding that parses to ")
3385cde5a57SAlex Zinenko                     << elementType << ", got " << std::get<0>(it);
3395cde5a57SAlex Zinenko         diag.attachNote(target.getLoc()) << "when applied to this op";
34052307109SNicolas Vasilache         return DiagnosedSilenceableFailure::definiteFailure();
3415cde5a57SAlex Zinenko       }
3425cde5a57SAlex Zinenko       continue;
3435cde5a57SAlex Zinenko     }
3445cde5a57SAlex Zinenko     // Otherwise, add the attribute directly.
3455cde5a57SAlex Zinenko     if (attr.getType() != elementType) {
34652307109SNicolas Vasilache       auto diag = this->emitOpError("expects a padding value of type ")
3475cde5a57SAlex Zinenko                   << elementType << ", got " << attr;
3485cde5a57SAlex Zinenko       diag.attachNote(target.getLoc()) << "when applied to this op";
34952307109SNicolas Vasilache       return DiagnosedSilenceableFailure::definiteFailure();
3505cde5a57SAlex Zinenko     }
3515cde5a57SAlex Zinenko     paddingValues.push_back(attr);
3525cde5a57SAlex Zinenko   }
3535cde5a57SAlex Zinenko 
3545cde5a57SAlex Zinenko   // Extract the transpose vectors.
3555cde5a57SAlex Zinenko   SmallVector<SmallVector<int64_t>> transposePaddings;
3565cde5a57SAlex Zinenko   for (Attribute transposeVector : getTransposePaddings().cast<ArrayAttr>())
3575cde5a57SAlex Zinenko     transposePaddings.push_back(
358*18b92c66SNicolas Vasilache         extractFromI64ArrayAttr(transposeVector.cast<ArrayAttr>()));
3595cde5a57SAlex Zinenko 
3605cde5a57SAlex Zinenko   LinalgPaddingOptions paddingOptions;
3615cde5a57SAlex Zinenko   paddingOptions.setPaddingValues(paddingValues);
362*18b92c66SNicolas Vasilache   paddingOptions.setPaddingDimensions(
363*18b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getPaddingDimensions()));
3645cde5a57SAlex Zinenko   paddingOptions.setPackPaddings(packPaddings);
365*18b92c66SNicolas Vasilache   paddingOptions.setHoistPaddings(extractFromI64ArrayAttr(getHoistPaddings()));
3665cde5a57SAlex Zinenko   paddingOptions.setTransposePaddings(transposePaddings);
3675cde5a57SAlex Zinenko 
368ce2e198bSAlex Zinenko   FailureOr<LinalgOp> result =
369ce2e198bSAlex Zinenko       tryApply<LinalgPaddingPattern>(target, paddingOptions);
37052307109SNicolas Vasilache   if (succeeded(result)) {
37152307109SNicolas Vasilache     results.push_back(result->getOperation());
37252307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
37352307109SNicolas Vasilache   }
374ce2e198bSAlex Zinenko 
37552307109SNicolas Vasilache   results.assign(1, nullptr);
37652307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
3775cde5a57SAlex Zinenko }
3785cde5a57SAlex Zinenko 
3795cde5a57SAlex Zinenko LogicalResult transform::PadOp::verify() {
380*18b92c66SNicolas Vasilache   SmallVector<int64_t> packPaddings =
381*18b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getPackPaddings());
3825cde5a57SAlex Zinenko   if (any_of(packPaddings, [](int64_t packPadding) {
3835cde5a57SAlex Zinenko         return packPadding != 0 && packPadding != 1;
3845cde5a57SAlex Zinenko       })) {
3855cde5a57SAlex Zinenko     return emitOpError()
3865cde5a57SAlex Zinenko            << "expects pack_paddings to contain booleans (0/1), found "
3875cde5a57SAlex Zinenko            << getPackPaddings();
3885cde5a57SAlex Zinenko   }
3895cde5a57SAlex Zinenko 
3905cde5a57SAlex Zinenko   SmallVector<int64_t> paddingDimensions =
391*18b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getPaddingDimensions());
3925cde5a57SAlex Zinenko   if (any_of(paddingDimensions,
3935cde5a57SAlex Zinenko              [](int64_t paddingDimension) { return paddingDimension < 0; })) {
3945cde5a57SAlex Zinenko     return emitOpError()
3955cde5a57SAlex Zinenko            << "expects padding_dimensions to contain positive integers, found "
3965cde5a57SAlex Zinenko            << getPaddingDimensions();
3975cde5a57SAlex Zinenko   }
3985cde5a57SAlex Zinenko 
399*18b92c66SNicolas Vasilache   SmallVector<int64_t> hoistPaddings =
400*18b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getHoistPaddings());
4015cde5a57SAlex Zinenko   if (any_of(hoistPaddings,
4025cde5a57SAlex Zinenko              [](int64_t hoistPadding) { return hoistPadding < 0; })) {
4035cde5a57SAlex Zinenko     return emitOpError()
4045cde5a57SAlex Zinenko            << "expects hoist_paddings to contain positive integers, found "
4055cde5a57SAlex Zinenko            << getHoistPaddings();
4065cde5a57SAlex Zinenko   }
4075cde5a57SAlex Zinenko 
4085cde5a57SAlex Zinenko   ArrayAttr transposes = getTransposePaddings();
4095cde5a57SAlex Zinenko   for (Attribute attr : transposes) {
4105cde5a57SAlex Zinenko     SmallVector<int64_t> transpose = extractFromI64ArrayAttr(attr);
4115cde5a57SAlex Zinenko     auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, transpose.size()));
4125cde5a57SAlex Zinenko     if (!std::is_permutation(sequence.begin(), sequence.end(),
4135cde5a57SAlex Zinenko                              transpose.begin(), transpose.end())) {
4145cde5a57SAlex Zinenko       return emitOpError()
4155cde5a57SAlex Zinenko              << "expects transpose_paddings to be a permutation, found "
4165cde5a57SAlex Zinenko              << attr;
4175cde5a57SAlex Zinenko     }
4185cde5a57SAlex Zinenko   }
4195cde5a57SAlex Zinenko   return success();
4205cde5a57SAlex Zinenko }
4215cde5a57SAlex Zinenko 
4225cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
4235a001136SNicolas Vasilache // PromoteOp
4245a001136SNicolas Vasilache //===----------------------------------------------------------------------===//
4255a001136SNicolas Vasilache 
4265a001136SNicolas Vasilache DiagnosedSilenceableFailure
4275a001136SNicolas Vasilache transform::PromoteOp::applyToOne(linalg::LinalgOp target,
4285a001136SNicolas Vasilache                                  SmallVectorImpl<Operation *> &results,
4295a001136SNicolas Vasilache                                  transform::TransformState &state) {
4305a001136SNicolas Vasilache   LinalgPromotionOptions promotionOptions;
4315a001136SNicolas Vasilache   if (!getOperandsToPromote().empty())
4325a001136SNicolas Vasilache     promotionOptions = promotionOptions.setOperandsToPromote(
4335a001136SNicolas Vasilache         extractFromI64ArrayAttr(getOperandsToPromote()));
4345a001136SNicolas Vasilache   if (getUseFullTilesByDefault())
4355a001136SNicolas Vasilache     promotionOptions = promotionOptions.setUseFullTileBuffersByDefault(
4365a001136SNicolas Vasilache         getUseFullTilesByDefault());
4375a001136SNicolas Vasilache   if (getUseAlloca())
4385a001136SNicolas Vasilache     promotionOptions = promotionOptions.setUseAlloca(getUseAlloca());
4395a001136SNicolas Vasilache   if (!getUseFullTileBuffers().empty())
4405a001136SNicolas Vasilache     promotionOptions = promotionOptions.setUseFullTileBuffers(
4415a001136SNicolas Vasilache         llvm::to_vector(getUseFullTileBuffers().getAsValueRange<BoolAttr>()));
4421a5d0076SKazu Hirata   if (getAlignment().has_value())
4435a001136SNicolas Vasilache     promotionOptions = promotionOptions.setAlignment(*getAlignment());
4445a001136SNicolas Vasilache 
4455a001136SNicolas Vasilache   if (failed(promoteSubviewsPrecondition(target, promotionOptions)))
4465a001136SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
4475a001136SNicolas Vasilache 
4485a001136SNicolas Vasilache   SimpleRewriter rewriter(target->getContext());
4495a001136SNicolas Vasilache   rewriter.setInsertionPoint(target);
4505a001136SNicolas Vasilache   FailureOr<LinalgOp> res = promoteSubViews(rewriter, target, promotionOptions);
4515a001136SNicolas Vasilache   if (failed(res))
4525a001136SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
4535a001136SNicolas Vasilache   results.push_back(target);
4545a001136SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
4555a001136SNicolas Vasilache }
4565a001136SNicolas Vasilache 
4575a001136SNicolas Vasilache //===----------------------------------------------------------------------===//
4585cde5a57SAlex Zinenko // ScalarizeOp
4595cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
4605cde5a57SAlex Zinenko 
46152307109SNicolas Vasilache DiagnosedSilenceableFailure
46252307109SNicolas Vasilache transform::ScalarizeOp::applyToOne(linalg::LinalgOp target,
46352307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
46452307109SNicolas Vasilache                                    transform::TransformState &state) {
4655cde5a57SAlex Zinenko   LinalgTilingOptions tilingOptions;
4665cde5a57SAlex Zinenko   tilingOptions.scalarizeDynamicDims();
4675cde5a57SAlex Zinenko   // Tiling with "scalarize_dyn_dims" actually sets the same lambda as the tile
4685cde5a57SAlex Zinenko   // sizes and asserts that it is not already set.
4695cde5a57SAlex Zinenko   SmallVector<int64_t> emptyTileSizes;
4705cde5a57SAlex Zinenko   LinalgTilingPattern pattern(getContext(), tilingOptions);
4715cde5a57SAlex Zinenko   SimpleRewriter rewriter(getContext());
4725cde5a57SAlex Zinenko   rewriter.setInsertionPoint(target);
4735cde5a57SAlex Zinenko   FailureOr<TiledLinalgOp> result =
4745cde5a57SAlex Zinenko       pattern.returningMatchAndRewrite(target, rewriter);
4755cde5a57SAlex Zinenko   if (failed(result))
47652307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
4775cde5a57SAlex Zinenko 
47852307109SNicolas Vasilache   results.push_back(result->op);
47952307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
4805cde5a57SAlex Zinenko }
4815cde5a57SAlex Zinenko 
4825cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
483ff6e5508SAlex Zinenko // SplitOp
484ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
485ff6e5508SAlex Zinenko 
486ff6e5508SAlex Zinenko DiagnosedSilenceableFailure SplitOp::apply(TransformResults &results,
487ff6e5508SAlex Zinenko                                            TransformState &state) {
488ff6e5508SAlex Zinenko   // Collect the dynamic split points if provided.
489ff6e5508SAlex Zinenko   ArrayRef<Operation *> payload = state.getPayloadOps(getTarget());
490ff6e5508SAlex Zinenko   SimpleRewriter rewriter(getContext());
491ff6e5508SAlex Zinenko   SmallVector<OpFoldResult> splitPoints;
492ff6e5508SAlex Zinenko   splitPoints.reserve(payload.size());
493ff6e5508SAlex Zinenko   if (getDynamicSplitPoint()) {
494ff6e5508SAlex Zinenko     auto diag = DiagnosedSilenceableFailure::success();
495ff6e5508SAlex Zinenko     splitPoints = llvm::to_vector(llvm::map_range(
496ff6e5508SAlex Zinenko         state.getPayloadOps(getDynamicSplitPoint()), [&](Operation *op) {
497ff6e5508SAlex Zinenko           if (op->getNumResults() != 1 ||
498ff6e5508SAlex Zinenko               !op->getResult(0).getType().isIndex()) {
499ff6e5508SAlex Zinenko             diag = emitSilenceableError()
500ff6e5508SAlex Zinenko                    << "expected dynamic split point handle to point to a "
501ff6e5508SAlex Zinenko                       "single-result index-typed op";
502ff6e5508SAlex Zinenko             diag.attachNote(op->getLoc()) << "dynamic split point";
503ff6e5508SAlex Zinenko           }
504ff6e5508SAlex Zinenko           return OpFoldResult(op->getResult(0));
505ff6e5508SAlex Zinenko         }));
506ff6e5508SAlex Zinenko     if (!diag.succeeded())
507ff6e5508SAlex Zinenko       return diag;
508ff6e5508SAlex Zinenko 
509ff6e5508SAlex Zinenko     if (splitPoints.size() != payload.size()) {
510ff6e5508SAlex Zinenko       emitError() << "expected the dynamic split point handle to point to as "
511ff6e5508SAlex Zinenko                      "many operations ("
512ff6e5508SAlex Zinenko                   << splitPoints.size() << ") as the target handle ("
513ff6e5508SAlex Zinenko                   << payload.size() << ")";
514ff6e5508SAlex Zinenko       return DiagnosedSilenceableFailure::definiteFailure();
515ff6e5508SAlex Zinenko     }
516ff6e5508SAlex Zinenko   } else {
517ff6e5508SAlex Zinenko     splitPoints.resize(payload.size(),
518ff6e5508SAlex Zinenko                        rewriter.getIndexAttr(getStaticSplitPoint()));
519ff6e5508SAlex Zinenko   }
520ff6e5508SAlex Zinenko 
521ff6e5508SAlex Zinenko   // Split each target operation.
522ff6e5508SAlex Zinenko   SmallVector<Operation *> first, second;
523ff6e5508SAlex Zinenko   for (const auto &pair : llvm::zip(payload, splitPoints)) {
524ff6e5508SAlex Zinenko     Operation *target = std::get<0>(pair);
525ff6e5508SAlex Zinenko     auto linalgOp = dyn_cast<LinalgOp>(target);
526ff6e5508SAlex Zinenko     if (!linalgOp) {
527ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "only applies to structured ops";
528ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
529ff6e5508SAlex Zinenko       return diag;
530ff6e5508SAlex Zinenko     }
531ff6e5508SAlex Zinenko 
532ff6e5508SAlex Zinenko     if (getDimension() >= linalgOp.getNumLoops()) {
533ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "dimension " << getDimension()
534ff6e5508SAlex Zinenko                                          << " does not exist in target op";
535ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
536ff6e5508SAlex Zinenko       return diag;
537ff6e5508SAlex Zinenko     }
538ff6e5508SAlex Zinenko 
539ff6e5508SAlex Zinenko     rewriter.setInsertionPoint(linalgOp);
540ff6e5508SAlex Zinenko     std::tie(first.emplace_back(), second.emplace_back()) =
541ff6e5508SAlex Zinenko         linalg::splitOp(rewriter, linalgOp, getDimension(), std::get<1>(pair));
542ff6e5508SAlex Zinenko   }
543ff6e5508SAlex Zinenko 
544ff6e5508SAlex Zinenko   results.set(getFirst().cast<OpResult>(), first);
545ff6e5508SAlex Zinenko   results.set(getSecond().cast<OpResult>(), second);
546ff6e5508SAlex Zinenko   return DiagnosedSilenceableFailure::success();
547ff6e5508SAlex Zinenko }
548ff6e5508SAlex Zinenko 
549ff6e5508SAlex Zinenko void SplitOp::getEffects(
550ff6e5508SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
551e15b855eSAlex Zinenko   consumesHandle(getTarget(), effects);
552e15b855eSAlex Zinenko   if (getDynamicSplitPoint())
553e15b855eSAlex Zinenko     onlyReadsHandle(getDynamicSplitPoint(), effects);
554e15b855eSAlex Zinenko   producesHandle(getResults(), effects);
555e15b855eSAlex Zinenko   modifiesPayload(effects);
556ff6e5508SAlex Zinenko }
557ff6e5508SAlex Zinenko 
558ff6e5508SAlex Zinenko ParseResult SplitOp::parse(OpAsmParser &parser, OperationState &result) {
559ff6e5508SAlex Zinenko   OpAsmParser::UnresolvedOperand target, dynamicSplitPoint;
560ff6e5508SAlex Zinenko   IntegerAttr staticSplitPoint;
561ff6e5508SAlex Zinenko   auto pdlOperationType =
562ff6e5508SAlex Zinenko       pdl::OperationType::get(parser.getBuilder().getContext());
563ff6e5508SAlex Zinenko   if (parser.parseOperand(target) ||
564ff6e5508SAlex Zinenko       parser.resolveOperand(target, pdlOperationType, result.operands) ||
565ff6e5508SAlex Zinenko       parser.parseKeyword("after"))
566ff6e5508SAlex Zinenko     return failure();
567ff6e5508SAlex Zinenko 
568ff6e5508SAlex Zinenko   OptionalParseResult dynamicPointParseResult =
569ff6e5508SAlex Zinenko       parser.parseOptionalOperand(dynamicSplitPoint);
570ff6e5508SAlex Zinenko   if (!dynamicPointParseResult.hasValue()) {
571ff6e5508SAlex Zinenko     int64_t staticSplitPointValue;
572ff6e5508SAlex Zinenko     if (failed(parser.parseInteger(staticSplitPointValue)))
573ff6e5508SAlex Zinenko       return failure();
574ff6e5508SAlex Zinenko 
575ff6e5508SAlex Zinenko     staticSplitPoint =
576ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(staticSplitPointValue);
577ff6e5508SAlex Zinenko   } else {
578ff6e5508SAlex Zinenko     if (failed(*dynamicPointParseResult) ||
579ff6e5508SAlex Zinenko         parser.resolveOperand(dynamicSplitPoint, pdlOperationType,
580ff6e5508SAlex Zinenko                               result.operands)) {
581ff6e5508SAlex Zinenko       return failure();
582ff6e5508SAlex Zinenko     }
583ff6e5508SAlex Zinenko 
584ff6e5508SAlex Zinenko     staticSplitPoint =
585ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(ShapedType::kDynamicSize);
586ff6e5508SAlex Zinenko   }
587ff6e5508SAlex Zinenko 
588ff6e5508SAlex Zinenko   result.addAttribute(
589ff6e5508SAlex Zinenko       SplitOp::getStaticSplitPointAttrName(result.name).getValue(),
590ff6e5508SAlex Zinenko       staticSplitPoint);
591ff6e5508SAlex Zinenko   if (failed(parser.parseOptionalAttrDict(result.attributes)))
592ff6e5508SAlex Zinenko     return failure();
593ff6e5508SAlex Zinenko 
594ff6e5508SAlex Zinenko   result.addTypes({pdlOperationType, pdlOperationType});
595ff6e5508SAlex Zinenko   return success();
596ff6e5508SAlex Zinenko }
597ff6e5508SAlex Zinenko 
598ff6e5508SAlex Zinenko void SplitOp::print(OpAsmPrinter &printer) {
599ff6e5508SAlex Zinenko   printer << " " << getTarget() << " after ";
600ff6e5508SAlex Zinenko   int64_t staticSplitSize = static_cast<int64_t>(getStaticSplitPoint());
601ff6e5508SAlex Zinenko   if (staticSplitSize != ShapedType::kDynamicSize)
602ff6e5508SAlex Zinenko     printer << staticSplitSize;
603ff6e5508SAlex Zinenko   else
604ff6e5508SAlex Zinenko     printer << getDynamicSplitPoint();
605ff6e5508SAlex Zinenko   printer << " ";
606ff6e5508SAlex Zinenko   printer.printOptionalAttrDict(getOperation()->getAttrs(),
607ff6e5508SAlex Zinenko                                 {getStaticSplitPointAttrName()});
608ff6e5508SAlex Zinenko }
609ff6e5508SAlex Zinenko 
610ff6e5508SAlex Zinenko LogicalResult SplitOp::verify() {
611ff6e5508SAlex Zinenko   if ((static_cast<int64_t>(getStaticSplitPoint()) !=
612ff6e5508SAlex Zinenko        ShapedType::kDynamicSize) ^
613ff6e5508SAlex Zinenko       (getDynamicSplitPoint() == nullptr)) {
614ff6e5508SAlex Zinenko     return emitOpError()
615ff6e5508SAlex Zinenko            << "expects either a dynamic or a static split point to be provided";
616ff6e5508SAlex Zinenko   }
617ff6e5508SAlex Zinenko   return success();
618ff6e5508SAlex Zinenko }
619ff6e5508SAlex Zinenko 
620ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
621f439b319SNicolas Vasilache // SplitReductionOp
622f439b319SNicolas Vasilache //===----------------------------------------------------------------------===//
623f439b319SNicolas Vasilache 
62452307109SNicolas Vasilache DiagnosedSilenceableFailure
62552307109SNicolas Vasilache transform::SplitReductionOp::applyToOne(linalg::LinalgOp target,
62652307109SNicolas Vasilache                                         SmallVectorImpl<Operation *> &results,
62752307109SNicolas Vasilache                                         transform::TransformState &state) {
628f439b319SNicolas Vasilache   ControlSplitReductionFn splitFn = [&](LinalgOp) {
629f439b319SNicolas Vasilache     return std::pair<int64_t, unsigned>(getSplitFactor(),
630f439b319SNicolas Vasilache                                         getInsertSplitDimension());
631f439b319SNicolas Vasilache   };
632f439b319SNicolas Vasilache   SimpleRewriter rewriter(getContext());
633f439b319SNicolas Vasilache   rewriter.setInsertionPoint(target);
634f439b319SNicolas Vasilache   FailureOr<SplitReductionResult> splitResult =
635178f9bd6SNicolas Vasilache       (getUseScalingAlgorithm())
636178f9bd6SNicolas Vasilache           ? splitReductionByScaling(rewriter, target, splitFn, getUseAlloc())
637178f9bd6SNicolas Vasilache           : splitReduction(rewriter, target, splitFn, getUseAlloc());
638d5716395SNicolas Vasilache   if (failed(splitResult))
63952307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
64052307109SNicolas Vasilache 
64152307109SNicolas Vasilache   results.push_back(splitResult->initOrAlloc);
64252307109SNicolas Vasilache   results.push_back(splitResult->fillOp);
64352307109SNicolas Vasilache   results.push_back(splitResult->splitLinalgOp);
64452307109SNicolas Vasilache   results.push_back(splitResult->resultCombiningLinalgOp);
64552307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
646d5716395SNicolas Vasilache }
647d5716395SNicolas Vasilache 
648d5716395SNicolas Vasilache //===----------------------------------------------------------------------===//
6493c2a74a3SMatthias Springer // TileOp
6503c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
6513c2a74a3SMatthias Springer 
6521d45282aSAlex Zinenko DiagnosedSilenceableFailure
653e3890b7fSAlex Zinenko transform::TileOp::apply(TransformResults &transformResults,
6543c2a74a3SMatthias Springer                          TransformState &state) {
6553c2a74a3SMatthias Springer   LinalgTilingOptions tilingOptions;
656*18b92c66SNicolas Vasilache   SmallVector<int64_t> tileSizes = extractFromI64ArrayAttr(getStaticSizes());
6573c2a74a3SMatthias Springer 
6584e4a4c05SAlex Zinenko   ArrayRef<Operation *> targets = state.getPayloadOps(getTarget());
6594e4a4c05SAlex Zinenko   SmallVector<ArrayRef<Operation *>> dynamicSizeProducers;
6604e4a4c05SAlex Zinenko   dynamicSizeProducers.reserve(getDynamicSizes().size());
6614e4a4c05SAlex Zinenko   for (Value dynamicSizeProducerHandle : getDynamicSizes()) {
6624e4a4c05SAlex Zinenko     dynamicSizeProducers.push_back(
6634e4a4c05SAlex Zinenko         state.getPayloadOps(dynamicSizeProducerHandle));
6644e4a4c05SAlex Zinenko 
6654e4a4c05SAlex Zinenko     if (dynamicSizeProducers.back().size() != targets.size()) {
6664e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag =
6674e4a4c05SAlex Zinenko           emitSilenceableError()
6684e4a4c05SAlex Zinenko           << "expected as many dynamic size-producing operations ("
6694e4a4c05SAlex Zinenko           << dynamicSizeProducers.back().size() << ") as target ops ("
6704e4a4c05SAlex Zinenko           << targets.size() << ")";
6714e4a4c05SAlex Zinenko       diag.attachNote(dynamicSizeProducerHandle.getLoc()) << "for this handle";
6724e4a4c05SAlex Zinenko       return diag;
6734e4a4c05SAlex Zinenko     }
6744e4a4c05SAlex Zinenko 
6754e4a4c05SAlex Zinenko     for (Operation *op : dynamicSizeProducers.back()) {
6764e4a4c05SAlex Zinenko       if (op->getNumResults() == 1 &&
6774e4a4c05SAlex Zinenko           op->getResult(0).getType().isa<IndexType>())
6784e4a4c05SAlex Zinenko         continue;
6794e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag =
6804e4a4c05SAlex Zinenko           emitSilenceableError() << "expected sizes to be produced by ops "
6814e4a4c05SAlex Zinenko                                     "with a single index-type result";
6824e4a4c05SAlex Zinenko       diag.attachNote(op->getLoc()) << "size producer op";
6834e4a4c05SAlex Zinenko       diag.attachNote(dynamicSizeProducerHandle.getLoc()) << "for this handle";
6844e4a4c05SAlex Zinenko       return diag;
6854e4a4c05SAlex Zinenko     }
6864e4a4c05SAlex Zinenko   }
6874e4a4c05SAlex Zinenko 
6884e4a4c05SAlex Zinenko   SmallVector<Operation *> tiled;
6894e4a4c05SAlex Zinenko   SmallVector<SmallVector<Operation *, 4>, 4> loops;
6904e4a4c05SAlex Zinenko   loops.resize(getLoops().size());
6914e4a4c05SAlex Zinenko   for (auto &en : llvm::enumerate(targets)) {
6924e4a4c05SAlex Zinenko     auto linalgOp = dyn_cast<LinalgOp>(en.value());
6934e4a4c05SAlex Zinenko     if (!linalgOp) {
6944e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag = emitSilenceableError()
6954e4a4c05SAlex Zinenko                                          << "only linalg ops are supported";
6964e4a4c05SAlex Zinenko       diag.attachNote(en.value()->getLoc()) << "target op";
6974e4a4c05SAlex Zinenko       return diag;
6984e4a4c05SAlex Zinenko     }
6994e4a4c05SAlex Zinenko 
7004e4a4c05SAlex Zinenko     unsigned index = en.index();
7014e4a4c05SAlex Zinenko     if (!tileSizes.empty()) {
7024e4a4c05SAlex Zinenko       tilingOptions.setTileSizeComputationFunction(
7034e4a4c05SAlex Zinenko           [&, index](OpBuilder &b, Operation *) {
7044e4a4c05SAlex Zinenko             SmallVector<Value, 4> sizes;
7054e4a4c05SAlex Zinenko             sizes.reserve(tileSizes.size());
7064e4a4c05SAlex Zinenko             unsigned dynamicIdx = 0;
7074e4a4c05SAlex Zinenko             for (OpFoldResult ofr : getMixedSizes()) {
7084e4a4c05SAlex Zinenko               if (auto attr = ofr.dyn_cast<Attribute>()) {
7094e4a4c05SAlex Zinenko                 sizes.push_back(b.create<arith::ConstantIndexOp>(
7104e4a4c05SAlex Zinenko                     getLoc(), attr.cast<IntegerAttr>().getInt()));
7114e4a4c05SAlex Zinenko               } else {
7124e4a4c05SAlex Zinenko                 sizes.push_back(
7134e4a4c05SAlex Zinenko                     dynamicSizeProducers[dynamicIdx++][index]->getResult(0));
7144e4a4c05SAlex Zinenko               }
7154e4a4c05SAlex Zinenko             }
7164e4a4c05SAlex Zinenko             return sizes;
7174e4a4c05SAlex Zinenko           });
7184e4a4c05SAlex Zinenko     }
7194e4a4c05SAlex Zinenko 
7203c2a74a3SMatthias Springer     tilingOptions.setInterchange(extractUIntArray(getInterchange()));
7213c2a74a3SMatthias Springer     LinalgTilingPattern pattern(getContext(), tilingOptions);
7223c2a74a3SMatthias Springer     SimpleRewriter rewriter(linalgOp.getContext());
7234e4a4c05SAlex Zinenko     FailureOr<TiledLinalgOp> tiledOp =
7244e4a4c05SAlex Zinenko         pattern.returningMatchAndRewrite(linalgOp, rewriter);
7254e4a4c05SAlex Zinenko     if (failed(tiledOp))
7264e4a4c05SAlex Zinenko       return DiagnosedSilenceableFailure::definiteFailure();
7274e4a4c05SAlex Zinenko 
7284e4a4c05SAlex Zinenko     tiled.push_back(tiledOp->op);
7294e4a4c05SAlex Zinenko     for (const auto &en2 : llvm::enumerate(tiledOp->loops))
7304e4a4c05SAlex Zinenko       loops[en2.index()].push_back(en2.value());
7314e4a4c05SAlex Zinenko   }
7324e4a4c05SAlex Zinenko 
7334e4a4c05SAlex Zinenko   transformResults.set(getTiledLinalgOp().cast<OpResult>(), tiled);
7344e4a4c05SAlex Zinenko   for (const auto &en : llvm::enumerate(loops))
7354e4a4c05SAlex Zinenko     transformResults.set(getLoops()[en.index()].cast<OpResult>(), en.value());
7364e4a4c05SAlex Zinenko 
7374e4a4c05SAlex Zinenko   return DiagnosedSilenceableFailure::success();
7384e4a4c05SAlex Zinenko }
7394e4a4c05SAlex Zinenko 
7404e4a4c05SAlex Zinenko SmallVector<OpFoldResult> transform::TileOp::getMixedSizes() {
7414e4a4c05SAlex Zinenko   ValueRange dynamic = getDynamicSizes();
742*18b92c66SNicolas Vasilache   SmallVector<int64_t> tileSizes = extractFromI64ArrayAttr(getStaticSizes());
7434e4a4c05SAlex Zinenko   SmallVector<OpFoldResult> results;
7444e4a4c05SAlex Zinenko   results.reserve(tileSizes.size());
7454e4a4c05SAlex Zinenko   unsigned dynamicPos = 0;
7464e4a4c05SAlex Zinenko   Builder builder(getContext());
7474e4a4c05SAlex Zinenko   for (int64_t size : tileSizes) {
7484e4a4c05SAlex Zinenko     if (size == ShapedType::kDynamicSize) {
7494e4a4c05SAlex Zinenko       results.push_back(dynamic[dynamicPos++]);
7504e4a4c05SAlex Zinenko     } else {
7514e4a4c05SAlex Zinenko       results.push_back(builder.getIndexAttr(size));
7524e4a4c05SAlex Zinenko     }
7534e4a4c05SAlex Zinenko   }
7544e4a4c05SAlex Zinenko   return results;
7553c2a74a3SMatthias Springer }
7563c2a74a3SMatthias Springer 
7573c2a74a3SMatthias Springer ParseResult transform::TileOp::parse(OpAsmParser &parser,
7583c2a74a3SMatthias Springer                                      OperationState &result) {
7594e4a4c05SAlex Zinenko   OpAsmParser::UnresolvedOperand target;
7604e4a4c05SAlex Zinenko   SmallVector<OpAsmParser::UnresolvedOperand> dynamicSizes;
7614e4a4c05SAlex Zinenko   ArrayAttr staticSizes;
7624e4a4c05SAlex Zinenko   auto pdlOperationType = pdl::OperationType::get(parser.getContext());
7634e4a4c05SAlex Zinenko   if (parser.parseOperand(target) ||
7644e4a4c05SAlex Zinenko       parser.resolveOperand(target, pdlOperationType, result.operands) ||
7654e4a4c05SAlex Zinenko       parseOperandsOrIntegersSizesList(parser, dynamicSizes, staticSizes) ||
7664e4a4c05SAlex Zinenko       parser.resolveOperands(dynamicSizes, pdlOperationType, result.operands) ||
7674e4a4c05SAlex Zinenko       parser.parseOptionalAttrDict(result.attributes))
7684e4a4c05SAlex Zinenko     return ParseResult::failure();
7694e4a4c05SAlex Zinenko 
7704e4a4c05SAlex Zinenko   result.addAttribute(getStaticSizesAttrName(result.name), staticSizes);
7714e4a4c05SAlex Zinenko   size_t numExpectedLoops =
772*18b92c66SNicolas Vasilache       staticSizes.size() - llvm::count(extractFromI64ArrayAttr(staticSizes), 0);
7734e4a4c05SAlex Zinenko   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOperationType));
7744e4a4c05SAlex Zinenko   return success();
7753c2a74a3SMatthias Springer }
7763c2a74a3SMatthias Springer 
7773c2a74a3SMatthias Springer void TileOp::print(OpAsmPrinter &p) {
7784e4a4c05SAlex Zinenko   p << ' ' << getTarget();
7794e4a4c05SAlex Zinenko   printOperandsOrIntegersSizesList(p, getOperation(), getDynamicSizes(),
7804e4a4c05SAlex Zinenko                                    getStaticSizes());
7814e4a4c05SAlex Zinenko   p.printOptionalAttrDict((*this)->getAttrs(), {getStaticSizesAttrName()});
7824e4a4c05SAlex Zinenko }
7834e4a4c05SAlex Zinenko 
7844e4a4c05SAlex Zinenko void transform::TileOp::getEffects(
7854e4a4c05SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
7864e4a4c05SAlex Zinenko   consumesHandle(getTarget(), effects);
7874e4a4c05SAlex Zinenko   onlyReadsHandle(getDynamicSizes(), effects);
7884e4a4c05SAlex Zinenko   producesHandle(getTiledLinalgOp(), effects);
7894e4a4c05SAlex Zinenko   producesHandle(getLoops(), effects);
7904e4a4c05SAlex Zinenko   modifiesPayload(effects);
7913c2a74a3SMatthias Springer }
7923c2a74a3SMatthias Springer 
7933c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
794*18b92c66SNicolas Vasilache // TileToForeachThreadOp
795*18b92c66SNicolas Vasilache //===----------------------------------------------------------------------===//
796*18b92c66SNicolas Vasilache 
797*18b92c66SNicolas Vasilache DiagnosedSilenceableFailure transform::TileToForeachThreadOp::applyToOne(
798*18b92c66SNicolas Vasilache     TilingInterface target, SmallVectorImpl<Operation *> &results,
799*18b92c66SNicolas Vasilache     transform::TransformState &state) {
800*18b92c66SNicolas Vasilache   IRRewriter rewriter(getContext());
801*18b92c66SNicolas Vasilache   rewriter.setInsertionPoint(target);
802*18b92c66SNicolas Vasilache   auto maybeThreadDimMappingAttr = getThreadDimMapping();
803*18b92c66SNicolas Vasilache   FailureOr<ForeachThreadTilingResult> tilingResult =
804*18b92c66SNicolas Vasilache       linalg::tileToForeachThreadOp(
805*18b92c66SNicolas Vasilache           rewriter, target, getAsOpFoldResult(getNumThreads()),
806*18b92c66SNicolas Vasilache           maybeThreadDimMappingAttr
807*18b92c66SNicolas Vasilache               ? extractFromI64ArrayAttr(*maybeThreadDimMappingAttr)
808*18b92c66SNicolas Vasilache               : ArrayRef<int64_t>{});
809*18b92c66SNicolas Vasilache   if (failed(tilingResult))
810*18b92c66SNicolas Vasilache     return emitDefaultSilenceableFailure(target);
811*18b92c66SNicolas Vasilache   rewriter.replaceOp(target, tilingResult->tileOp->getResults());
812*18b92c66SNicolas Vasilache   results.assign({tilingResult->tileOp, tilingResult->tiledOp});
813*18b92c66SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
814*18b92c66SNicolas Vasilache }
815*18b92c66SNicolas Vasilache 
816*18b92c66SNicolas Vasilache //===----------------------------------------------------------------------===//
817cc6c1592SAlex Zinenko // VectorizeOp
818cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
819cc6c1592SAlex Zinenko 
82052307109SNicolas Vasilache DiagnosedSilenceableFailure
82152307109SNicolas Vasilache transform::VectorizeOp::applyToOne(Operation *target,
82252307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
82352307109SNicolas Vasilache                                    transform::TransformState &state) {
824cc6c1592SAlex Zinenko   if (!target->hasTrait<OpTrait::IsIsolatedFromAbove>()) {
82552307109SNicolas Vasilache     auto diag = this->emitOpError("requires isolated-from-above targets");
826cc6c1592SAlex Zinenko     diag.attachNote(target->getLoc()) << "non-isolated target";
82752307109SNicolas Vasilache     return DiagnosedSilenceableFailure::definiteFailure();
828cc6c1592SAlex Zinenko   }
829cc6c1592SAlex Zinenko 
830cc6c1592SAlex Zinenko   MLIRContext *ctx = getContext();
831cc6c1592SAlex Zinenko   RewritePatternSet patterns(ctx);
832cc6c1592SAlex Zinenko   patterns.add<LinalgVectorizationPattern>(ctx);
833cc6c1592SAlex Zinenko 
834cc6c1592SAlex Zinenko   vector::populateVectorTransferPermutationMapLoweringPatterns(patterns);
835cc6c1592SAlex Zinenko   vector::populateVectorReductionToContractPatterns(patterns);
836cc6c1592SAlex Zinenko   patterns.add<linalg::LinalgCopyVTRForwardingPattern,
837cc6c1592SAlex Zinenko                linalg::LinalgCopyVTWForwardingPattern>(ctx,
838cc6c1592SAlex Zinenko                                                        /*benefit=*/2);
839cc6c1592SAlex Zinenko   vector::TransferReadOp::getCanonicalizationPatterns(patterns, ctx);
840cc6c1592SAlex Zinenko   vector::TransferWriteOp::getCanonicalizationPatterns(patterns, ctx);
841cc6c1592SAlex Zinenko   if (getVectorizePadding())
842cc6c1592SAlex Zinenko     linalg::populatePadOpVectorizationPatterns(patterns);
843cc6c1592SAlex Zinenko 
8445f0d4f20SAlex Zinenko   if (failed(applyPatternsAndFoldGreedily(target, std::move(patterns))))
84552307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
84652307109SNicolas Vasilache 
84752307109SNicolas Vasilache   results.push_back(target);
84852307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
849cc6c1592SAlex Zinenko }
850cc6c1592SAlex Zinenko 
851cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
8523c2a74a3SMatthias Springer // Transform op registration
8533c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
8543c2a74a3SMatthias Springer 
8553c2a74a3SMatthias Springer namespace {
8563c2a74a3SMatthias Springer /// Registers new ops and declares PDL as dependent dialect since the additional
8573c2a74a3SMatthias Springer /// ops are using PDL types for operands and results.
8583c2a74a3SMatthias Springer class LinalgTransformDialectExtension
8593c2a74a3SMatthias Springer     : public transform::TransformDialectExtension<
8603c2a74a3SMatthias Springer           LinalgTransformDialectExtension> {
8613c2a74a3SMatthias Springer public:
8623c2a74a3SMatthias Springer   LinalgTransformDialectExtension() {
8633963b4d0SAlex Zinenko     declareDependentDialect<AffineDialect>();
8644e4a4c05SAlex Zinenko     declareDependentDialect<arith::ArithmeticDialect>();
8653c2a74a3SMatthias Springer     declareDependentDialect<pdl::PDLDialect>();
8663c2a74a3SMatthias Springer     declareDependentDialect<scf::SCFDialect>();
867cc6c1592SAlex Zinenko     declareDependentDialect<vector::VectorDialect>();
8683c2a74a3SMatthias Springer     registerTransformOps<
8693c2a74a3SMatthias Springer #define GET_OP_LIST
8703c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
8713c2a74a3SMatthias Springer         >();
8723c2a74a3SMatthias Springer   }
8733c2a74a3SMatthias Springer };
8743c2a74a3SMatthias Springer } // namespace
8753c2a74a3SMatthias Springer 
8763c2a74a3SMatthias Springer #define GET_OP_CLASSES
8773c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
8783c2a74a3SMatthias Springer 
8793c2a74a3SMatthias Springer void mlir::linalg::registerTransformDialectExtension(
8803c2a74a3SMatthias Springer     DialectRegistry &registry) {
8813c2a74a3SMatthias Springer   registry.addExtensions<LinalgTransformDialectExtension>();
8823c2a74a3SMatthias Springer }
883