13c2a74a3SMatthias Springer //===- LinalgTransformOps.cpp - Implementation of Linalg transform ops ----===//
23c2a74a3SMatthias Springer //
33c2a74a3SMatthias Springer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43c2a74a3SMatthias Springer // See https://llvm.org/LICENSE.txt for license information.
53c2a74a3SMatthias Springer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63c2a74a3SMatthias Springer //
73c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
83c2a74a3SMatthias Springer 
93c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h"
103c2a74a3SMatthias Springer 
113c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/IR/Linalg.h"
123c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/Transforms/Transforms.h"
133c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDL.h"
143c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDLTypes.h"
153c2a74a3SMatthias Springer #include "mlir/Dialect/Transform/IR/TransformDialect.h"
163c2a74a3SMatthias Springer #include "mlir/Interfaces/SideEffectInterfaces.h"
173c2a74a3SMatthias Springer #include "mlir/Parser/Parser.h"
18cc6c1592SAlex Zinenko #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
193c2a74a3SMatthias Springer #include "llvm/Support/FormatVariadic.h"
203c2a74a3SMatthias Springer 
213c2a74a3SMatthias Springer using namespace mlir;
223c2a74a3SMatthias Springer using namespace mlir::linalg;
233c2a74a3SMatthias Springer using namespace mlir::transform;
243c2a74a3SMatthias Springer 
253c2a74a3SMatthias Springer /// Extracts a vector of int64_t from an array attribute. Asserts if the
263c2a74a3SMatthias Springer /// attribute contains values other than integers.
273c2a74a3SMatthias Springer static SmallVector<int64_t> extractI64Array(ArrayAttr attr) {
283c2a74a3SMatthias Springer   SmallVector<int64_t> result;
293c2a74a3SMatthias Springer   result.reserve(attr.size());
303c2a74a3SMatthias Springer   for (APInt value : attr.getAsValueRange<IntegerAttr>())
313c2a74a3SMatthias Springer     result.push_back(value.getSExtValue());
323c2a74a3SMatthias Springer   return result;
333c2a74a3SMatthias Springer }
343c2a74a3SMatthias Springer 
353c2a74a3SMatthias Springer /// Extracts a vector of unsigned from an array attribute. Asserts if the
363c2a74a3SMatthias Springer /// attribute contains values other than intergers. May truncate.
373c2a74a3SMatthias Springer static SmallVector<unsigned> extractUIntArray(ArrayAttr attr) {
383c2a74a3SMatthias Springer   SmallVector<unsigned> result;
393c2a74a3SMatthias Springer   result.reserve(attr.size());
403c2a74a3SMatthias Springer   for (APInt value : attr.getAsValueRange<IntegerAttr>())
413c2a74a3SMatthias Springer     result.push_back(value.getZExtValue());
423c2a74a3SMatthias Springer   return result;
433c2a74a3SMatthias Springer }
443c2a74a3SMatthias Springer 
453c2a74a3SMatthias Springer namespace {
463c2a74a3SMatthias Springer /// A simple pattern rewriter that implements no special logic.
473c2a74a3SMatthias Springer class SimpleRewriter : public PatternRewriter {
483c2a74a3SMatthias Springer public:
493c2a74a3SMatthias Springer   SimpleRewriter(MLIRContext *context) : PatternRewriter(context) {}
503c2a74a3SMatthias Springer };
513c2a74a3SMatthias Springer } // namespace
523c2a74a3SMatthias Springer 
53*ce2e198bSAlex Zinenko /// Attempts to apply the pattern specified as template argument to the given
54*ce2e198bSAlex Zinenko /// operation. The pattern is expected to have a `returningMatchAndRewrite`
55*ce2e198bSAlex Zinenko /// function that returns the "main" result or failure. Returns failure if the
56*ce2e198bSAlex Zinenko /// pattern failed to apply. Extra arguments are forwarded to the pattern
57*ce2e198bSAlex Zinenko /// constructor.
58*ce2e198bSAlex Zinenko template <typename PatternTy, typename... Args>
59*ce2e198bSAlex Zinenko static FailureOr<LinalgOp> tryApply(Operation *operation, Args &&...args) {
60*ce2e198bSAlex Zinenko   // Check if the given operation has the type expected by the pattern.
61*ce2e198bSAlex Zinenko   using OpTy = typename llvm::function_traits<
62*ce2e198bSAlex Zinenko       decltype(&PatternTy::returningMatchAndRewrite)>::template arg_t<0>;
63*ce2e198bSAlex Zinenko   auto op = dyn_cast<OpTy>(operation);
64*ce2e198bSAlex Zinenko   if (!op)
65*ce2e198bSAlex Zinenko     return failure();
66*ce2e198bSAlex Zinenko 
67*ce2e198bSAlex Zinenko   // Apply the pattern directly to the op.
68*ce2e198bSAlex Zinenko   PatternTy pattern(operation->getContext(), std::forward<Args>(args)...);
69*ce2e198bSAlex Zinenko   SimpleRewriter rewriter(operation->getContext());
70*ce2e198bSAlex Zinenko   rewriter.setInsertionPoint(operation);
71*ce2e198bSAlex Zinenko   auto result = pattern.returningMatchAndRewrite(op, rewriter);
72*ce2e198bSAlex Zinenko   if (failed(result))
73*ce2e198bSAlex Zinenko     return failure();
74*ce2e198bSAlex Zinenko   return cast<LinalgOp>(result->getOperation());
75*ce2e198bSAlex Zinenko }
76*ce2e198bSAlex Zinenko 
77*ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
78*ce2e198bSAlex Zinenko // DecomposeOp
79*ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
80*ce2e198bSAlex Zinenko 
81*ce2e198bSAlex Zinenko FailureOr<LinalgOp> transform::DecomposeOp::applyToOne(LinalgOp target) {
82*ce2e198bSAlex Zinenko   FailureOr<LinalgOp> windowed =
83*ce2e198bSAlex Zinenko       tryApply<DownscaleSizeOneWindowed2DConvolution>(target);
84*ce2e198bSAlex Zinenko   if (succeeded(windowed))
85*ce2e198bSAlex Zinenko     return windowed;
86*ce2e198bSAlex Zinenko 
87*ce2e198bSAlex Zinenko   FailureOr<LinalgOp> depthwise =
88*ce2e198bSAlex Zinenko       tryApply<DownscaleDepthwiseConv2DNhwcHwcOp>(target);
89*ce2e198bSAlex Zinenko   if (succeeded(depthwise))
90*ce2e198bSAlex Zinenko     return depthwise;
91*ce2e198bSAlex Zinenko 
92*ce2e198bSAlex Zinenko   InFlightDiagnostic diag = emitError() << "failed to apply";
93*ce2e198bSAlex Zinenko   diag.attachNote(target.getLoc()) << "attempted to apply to this op";
94*ce2e198bSAlex Zinenko   return diag;
95*ce2e198bSAlex Zinenko }
96*ce2e198bSAlex Zinenko 
97*ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
98*ce2e198bSAlex Zinenko // GeneralizeOp
99*ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
100*ce2e198bSAlex Zinenko 
101*ce2e198bSAlex Zinenko FailureOr<LinalgOp> transform::GeneralizeOp::applyToOne(LinalgOp target) {
102*ce2e198bSAlex Zinenko   // Exit early if no transformation is needed.
103*ce2e198bSAlex Zinenko   if (isa<GenericOp>(target))
104*ce2e198bSAlex Zinenko     return target;
105*ce2e198bSAlex Zinenko 
106*ce2e198bSAlex Zinenko   FailureOr<LinalgOp> generic = tryApply<LinalgGeneralizationPattern>(target);
107*ce2e198bSAlex Zinenko   if (succeeded(generic))
108*ce2e198bSAlex Zinenko     return generic;
109*ce2e198bSAlex Zinenko 
110*ce2e198bSAlex Zinenko   InFlightDiagnostic diag = emitError() << "failed to apply";
111*ce2e198bSAlex Zinenko   diag.attachNote(target.getLoc()) << "attempted to apply to this op";
112*ce2e198bSAlex Zinenko   return diag;
113*ce2e198bSAlex Zinenko }
114*ce2e198bSAlex Zinenko 
1153c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
1165cde5a57SAlex Zinenko // InterchangeOp
1175cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
1185cde5a57SAlex Zinenko 
1195cde5a57SAlex Zinenko FailureOr<LinalgOp> transform::InterchangeOp::applyToOne(LinalgOp target) {
1205cde5a57SAlex Zinenko   SmallVector<unsigned> interchangeVector =
1215cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
1225cde5a57SAlex Zinenko   // Exit early if no transformation is needed.
1235cde5a57SAlex Zinenko   if (interchangeVector.empty())
1245cde5a57SAlex Zinenko     return target;
1255cde5a57SAlex Zinenko 
1265cde5a57SAlex Zinenko   auto genericTarget = dyn_cast<GenericOp>(target.getOperation());
1275cde5a57SAlex Zinenko   if (!genericTarget) {
1285cde5a57SAlex Zinenko     InFlightDiagnostic diag = emitOpError()
1295cde5a57SAlex Zinenko                               << "applies to " << GenericOp::getOperationName()
1305cde5a57SAlex Zinenko                               << " ops";
1315cde5a57SAlex Zinenko     diag.attachNote(target.getLoc()) << "attempted to apply to this op";
1325cde5a57SAlex Zinenko     return diag;
1335cde5a57SAlex Zinenko   }
1345cde5a57SAlex Zinenko 
135*ce2e198bSAlex Zinenko   return tryApply<GenericOpInterchangePattern>(target, interchangeVector);
1365cde5a57SAlex Zinenko }
1375cde5a57SAlex Zinenko 
1385cde5a57SAlex Zinenko LogicalResult transform::InterchangeOp::verify() {
1395cde5a57SAlex Zinenko   SmallVector<unsigned> permutation =
1405cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
1415cde5a57SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<unsigned>(0, permutation.size()));
1425cde5a57SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
1435cde5a57SAlex Zinenko                            permutation.begin(), permutation.end())) {
1445cde5a57SAlex Zinenko     return emitOpError()
1455cde5a57SAlex Zinenko            << "expects iterator_interchange to be a permutation, found "
1465cde5a57SAlex Zinenko            << getIteratorInterchange();
1475cde5a57SAlex Zinenko   }
1485cde5a57SAlex Zinenko   return success();
1495cde5a57SAlex Zinenko }
1505cde5a57SAlex Zinenko 
1515cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
1525cde5a57SAlex Zinenko // PadOp
1535cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
1545cde5a57SAlex Zinenko 
1555cde5a57SAlex Zinenko FailureOr<LinalgOp> transform::PadOp::applyToOne(LinalgOp target) {
1565cde5a57SAlex Zinenko   // Convert the integer packing flags to booleans.
1575cde5a57SAlex Zinenko   SmallVector<bool> packPaddings;
1585cde5a57SAlex Zinenko   for (int64_t packPadding : extractI64Array(getPackPaddings()))
1595cde5a57SAlex Zinenko     packPaddings.push_back(static_cast<bool>(packPadding));
1605cde5a57SAlex Zinenko 
1615cde5a57SAlex Zinenko   // Convert the padding values to attributes.
1625cde5a57SAlex Zinenko   SmallVector<Attribute> paddingValues;
1635cde5a57SAlex Zinenko   for (auto const &it :
1645cde5a57SAlex Zinenko        llvm::zip(getPaddingValues(), target->getOperandTypes())) {
1655cde5a57SAlex Zinenko     Attribute attr = std::get<0>(it);
1665cde5a57SAlex Zinenko     Type elementType = getElementTypeOrSelf(std::get<1>(it));
1675cde5a57SAlex Zinenko     // Try to parse string attributes to obtain an attribute of element type.
1685cde5a57SAlex Zinenko     if (auto stringAttr = attr.dyn_cast<StringAttr>()) {
1695cde5a57SAlex Zinenko       paddingValues.push_back(
1705cde5a57SAlex Zinenko           parseAttribute(attr.cast<StringAttr>(), elementType));
1715cde5a57SAlex Zinenko       if (!paddingValues.back()) {
1725cde5a57SAlex Zinenko         InFlightDiagnostic diag = emitOpError()
1735cde5a57SAlex Zinenko                                   << "expects a padding value that parses to "
1745cde5a57SAlex Zinenko                                   << elementType << ", got " << std::get<0>(it);
1755cde5a57SAlex Zinenko         diag.attachNote(target.getLoc()) << "when applied to this op";
1765cde5a57SAlex Zinenko         return diag;
1775cde5a57SAlex Zinenko       }
1785cde5a57SAlex Zinenko       continue;
1795cde5a57SAlex Zinenko     }
1805cde5a57SAlex Zinenko     // Otherwise, add the attribute directly.
1815cde5a57SAlex Zinenko     if (attr.getType() != elementType) {
1825cde5a57SAlex Zinenko       InFlightDiagnostic diag = emitOpError()
1835cde5a57SAlex Zinenko                                 << "expects a padding value of type "
1845cde5a57SAlex Zinenko                                 << elementType << ", got " << attr;
1855cde5a57SAlex Zinenko       diag.attachNote(target.getLoc()) << "when applied to this op";
1865cde5a57SAlex Zinenko       return diag;
1875cde5a57SAlex Zinenko     }
1885cde5a57SAlex Zinenko     paddingValues.push_back(attr);
1895cde5a57SAlex Zinenko   }
1905cde5a57SAlex Zinenko 
1915cde5a57SAlex Zinenko   // Extract the transpose vectors.
1925cde5a57SAlex Zinenko   SmallVector<SmallVector<int64_t>> transposePaddings;
1935cde5a57SAlex Zinenko   for (Attribute transposeVector : getTransposePaddings().cast<ArrayAttr>())
1945cde5a57SAlex Zinenko     transposePaddings.push_back(
1955cde5a57SAlex Zinenko         extractI64Array(transposeVector.cast<ArrayAttr>()));
1965cde5a57SAlex Zinenko 
1975cde5a57SAlex Zinenko   LinalgPaddingOptions paddingOptions;
1985cde5a57SAlex Zinenko   paddingOptions.setPaddingValues(paddingValues);
1995cde5a57SAlex Zinenko   paddingOptions.setPaddingDimensions(extractI64Array(getPaddingDimensions()));
2005cde5a57SAlex Zinenko   paddingOptions.setPackPaddings(packPaddings);
2015cde5a57SAlex Zinenko   paddingOptions.setHoistPaddings(extractI64Array(getHoistPaddings()));
2025cde5a57SAlex Zinenko   paddingOptions.setTransposePaddings(transposePaddings);
2035cde5a57SAlex Zinenko 
204*ce2e198bSAlex Zinenko   FailureOr<LinalgOp> result =
205*ce2e198bSAlex Zinenko       tryApply<LinalgPaddingPattern>(target, paddingOptions);
206*ce2e198bSAlex Zinenko   if (succeeded(result))
207*ce2e198bSAlex Zinenko     return result;
208*ce2e198bSAlex Zinenko 
2095cde5a57SAlex Zinenko   InFlightDiagnostic diag = emitError()
2105cde5a57SAlex Zinenko                             << "failed to apply pattern to target op";
2115cde5a57SAlex Zinenko   diag.attachNote(target.getLoc()) << "target op";
2125cde5a57SAlex Zinenko   return diag;
2135cde5a57SAlex Zinenko }
2145cde5a57SAlex Zinenko 
2155cde5a57SAlex Zinenko LogicalResult transform::PadOp::verify() {
2165cde5a57SAlex Zinenko   SmallVector<int64_t> packPaddings = extractI64Array(getPackPaddings());
2175cde5a57SAlex Zinenko   if (any_of(packPaddings, [](int64_t packPadding) {
2185cde5a57SAlex Zinenko         return packPadding != 0 && packPadding != 1;
2195cde5a57SAlex Zinenko       })) {
2205cde5a57SAlex Zinenko     return emitOpError()
2215cde5a57SAlex Zinenko            << "expects pack_paddings to contain booleans (0/1), found "
2225cde5a57SAlex Zinenko            << getPackPaddings();
2235cde5a57SAlex Zinenko   }
2245cde5a57SAlex Zinenko 
2255cde5a57SAlex Zinenko   SmallVector<int64_t> paddingDimensions =
2265cde5a57SAlex Zinenko       extractI64Array(getPaddingDimensions());
2275cde5a57SAlex Zinenko   if (any_of(paddingDimensions,
2285cde5a57SAlex Zinenko              [](int64_t paddingDimension) { return paddingDimension < 0; })) {
2295cde5a57SAlex Zinenko     return emitOpError()
2305cde5a57SAlex Zinenko            << "expects padding_dimensions to contain positive integers, found "
2315cde5a57SAlex Zinenko            << getPaddingDimensions();
2325cde5a57SAlex Zinenko   }
2335cde5a57SAlex Zinenko 
2345cde5a57SAlex Zinenko   SmallVector<int64_t> hoistPaddings = extractI64Array(getHoistPaddings());
2355cde5a57SAlex Zinenko   if (any_of(hoistPaddings,
2365cde5a57SAlex Zinenko              [](int64_t hoistPadding) { return hoistPadding < 0; })) {
2375cde5a57SAlex Zinenko     return emitOpError()
2385cde5a57SAlex Zinenko            << "expects hoist_paddings to contain positive integers, found "
2395cde5a57SAlex Zinenko            << getHoistPaddings();
2405cde5a57SAlex Zinenko   }
2415cde5a57SAlex Zinenko 
2425cde5a57SAlex Zinenko   ArrayAttr transposes = getTransposePaddings();
2435cde5a57SAlex Zinenko   for (Attribute attr : transposes) {
2445cde5a57SAlex Zinenko     SmallVector<int64_t> transpose = extractFromI64ArrayAttr(attr);
2455cde5a57SAlex Zinenko     auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, transpose.size()));
2465cde5a57SAlex Zinenko     if (!std::is_permutation(sequence.begin(), sequence.end(),
2475cde5a57SAlex Zinenko                              transpose.begin(), transpose.end())) {
2485cde5a57SAlex Zinenko       return emitOpError()
2495cde5a57SAlex Zinenko              << "expects transpose_paddings to be a permutation, found "
2505cde5a57SAlex Zinenko              << attr;
2515cde5a57SAlex Zinenko     }
2525cde5a57SAlex Zinenko   }
2535cde5a57SAlex Zinenko   return success();
2545cde5a57SAlex Zinenko }
2555cde5a57SAlex Zinenko 
2565cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
2575cde5a57SAlex Zinenko // ScalarizeOp
2585cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
2595cde5a57SAlex Zinenko 
2605cde5a57SAlex Zinenko FailureOr<LinalgOp> transform::ScalarizeOp::applyToOne(LinalgOp target) {
2615cde5a57SAlex Zinenko   LinalgTilingOptions tilingOptions;
2625cde5a57SAlex Zinenko   tilingOptions.scalarizeDynamicDims();
2635cde5a57SAlex Zinenko   // Tiling with "scalarize_dyn_dims" actually sets the same lambda as the tile
2645cde5a57SAlex Zinenko   // sizes and asserts that it is not already set.
2655cde5a57SAlex Zinenko   SmallVector<int64_t> emptyTileSizes;
2665cde5a57SAlex Zinenko   LinalgTilingPattern pattern(getContext(), tilingOptions);
2675cde5a57SAlex Zinenko   SimpleRewriter rewriter(getContext());
2685cde5a57SAlex Zinenko   rewriter.setInsertionPoint(target);
2695cde5a57SAlex Zinenko   FailureOr<TiledLinalgOp> result =
2705cde5a57SAlex Zinenko       pattern.returningMatchAndRewrite(target, rewriter);
2715cde5a57SAlex Zinenko   if (failed(result))
2725cde5a57SAlex Zinenko     return failure();
2735cde5a57SAlex Zinenko 
2745cde5a57SAlex Zinenko   return result->op;
2755cde5a57SAlex Zinenko }
2765cde5a57SAlex Zinenko 
2775cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
2783c2a74a3SMatthias Springer // TileOp
2793c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
2803c2a74a3SMatthias Springer 
2813c2a74a3SMatthias Springer /// Apply a tiling transformation to all payload ops and store both the
2823c2a74a3SMatthias Springer /// tiled operation as well as the created tile loops.
2833c2a74a3SMatthias Springer static LogicalResult
2843c2a74a3SMatthias Springer applyTilingToAll(Operation *transformOp, Value target,
2853c2a74a3SMatthias Springer                  ArrayRef<int64_t> tileSizes,
2863c2a74a3SMatthias Springer                  transform::TransformResults &transformResults,
2873c2a74a3SMatthias Springer                  transform::TransformState &state,
2883c2a74a3SMatthias Springer                  function_ref<FailureOr<TiledLinalgOp>(LinalgOp)> applyFn) {
2893c2a74a3SMatthias Springer   // Number of loops: Number of tiles sizes that are not zero.
2903c2a74a3SMatthias Springer   size_t numLoops = tileSizes.size() - llvm::count(tileSizes, 0);
2913c2a74a3SMatthias Springer   // All payload ops. These should all be LinalgOps for now.
2923c2a74a3SMatthias Springer   ArrayRef<Operation *> payloadOps = state.getPayloadOps(target);
2933c2a74a3SMatthias Springer 
2943c2a74a3SMatthias Springer   SmallVector<Operation *> tiledLinalgOps;
2953c2a74a3SMatthias Springer   SmallVector<SmallVector<Operation *>> loopOps(numLoops);
2963c2a74a3SMatthias Springer   for (unsigned int i = 0; i < numLoops; ++i)
2973c2a74a3SMatthias Springer     loopOps[i].reserve(payloadOps.size());
2983c2a74a3SMatthias Springer 
2993c2a74a3SMatthias Springer   for (Operation *target : payloadOps) {
3003c2a74a3SMatthias Springer     auto linalgOp = dyn_cast<linalg::LinalgOp>(target);
3013c2a74a3SMatthias Springer     if (!linalgOp)
3023c2a74a3SMatthias Springer       return transformOp->emitError("only LinalgOps are supported");
3033c2a74a3SMatthias Springer 
3043c2a74a3SMatthias Springer     FailureOr<TiledLinalgOp> tiled = applyFn(linalgOp);
3053c2a74a3SMatthias Springer     if (failed(tiled))
3063c2a74a3SMatthias Springer       return failure();
3073c2a74a3SMatthias Springer 
3083c2a74a3SMatthias Springer     tiledLinalgOps.push_back(tiled->op);
3093c2a74a3SMatthias Springer     if (tiled->loops.size() != numLoops)
3103c2a74a3SMatthias Springer       // Not enough loops were generated. This usually means that the input size
3113c2a74a3SMatthias Springer       // was smaller than the tiling size.
3123c2a74a3SMatthias Springer       // TODO: LinalgTilingPattern should return failure().
3133c2a74a3SMatthias Springer       return failure();
3143c2a74a3SMatthias Springer     for (unsigned int i = 0; i < numLoops; ++i)
3153c2a74a3SMatthias Springer       loopOps[i].push_back(tiled->loops[i]);
3163c2a74a3SMatthias Springer   }
3173c2a74a3SMatthias Springer 
3183c2a74a3SMatthias Springer   transformResults.set(transformOp->getOpResult(0), tiledLinalgOps);
3193c2a74a3SMatthias Springer   for (unsigned int i = 0; i < numLoops; ++i)
3203c2a74a3SMatthias Springer     transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]);
3213c2a74a3SMatthias Springer   return success();
3223c2a74a3SMatthias Springer }
3233c2a74a3SMatthias Springer 
3243c2a74a3SMatthias Springer LogicalResult transform::TileOp::apply(TransformResults &transformResults,
3253c2a74a3SMatthias Springer                                        TransformState &state) {
3263c2a74a3SMatthias Springer   LinalgTilingOptions tilingOptions;
3273c2a74a3SMatthias Springer   SmallVector<int64_t> tileSizes = extractI64Array(getSizes());
3283c2a74a3SMatthias Springer 
3293c2a74a3SMatthias Springer   if (!tileSizes.empty())
3303c2a74a3SMatthias Springer     tilingOptions.setTileSizes(tileSizes);
3313c2a74a3SMatthias Springer   tilingOptions.setInterchange(extractUIntArray(getInterchange()));
3323c2a74a3SMatthias Springer   LinalgTilingPattern pattern(getContext(), tilingOptions);
3333c2a74a3SMatthias Springer 
3343c2a74a3SMatthias Springer   return applyTilingToAll(getOperation(), getTarget(), tileSizes,
3353c2a74a3SMatthias Springer                           transformResults, state, [&](LinalgOp linalgOp) {
3363c2a74a3SMatthias Springer                             SimpleRewriter rewriter(linalgOp.getContext());
3373c2a74a3SMatthias Springer                             return pattern.returningMatchAndRewrite(linalgOp,
3383c2a74a3SMatthias Springer                                                                     rewriter);
3393c2a74a3SMatthias Springer                           });
3403c2a74a3SMatthias Springer }
3413c2a74a3SMatthias Springer 
3423c2a74a3SMatthias Springer ParseResult transform::TileOp::parse(OpAsmParser &parser,
3433c2a74a3SMatthias Springer                                      OperationState &result) {
3443c2a74a3SMatthias Springer   StringRef sizesAttrName = TileOp::getSizesAttrName(result.name).getValue();
3453c2a74a3SMatthias Springer   OpAsmParser::UnresolvedOperand targetOperand;
3461d7b5cd5SChris Lattner   SMLoc opLoc = parser.getCurrentLocation();
3471d7b5cd5SChris Lattner   if (parser.parseOperand(targetOperand) ||
3481d7b5cd5SChris Lattner       parser.parseOptionalAttrDict(result.attributes))
3493c2a74a3SMatthias Springer     return failure();
3503c2a74a3SMatthias Springer   Attribute sizesAttr = result.attributes.get(sizesAttrName);
3513c2a74a3SMatthias Springer   if (!sizesAttr)
3523c2a74a3SMatthias Springer     return parser.emitError(opLoc)
3533c2a74a3SMatthias Springer            << "expected '" << sizesAttrName << "' attribute";
3543c2a74a3SMatthias Springer   auto sizesArrayAttr = sizesAttr.dyn_cast<ArrayAttr>();
3553c2a74a3SMatthias Springer   if (!sizesArrayAttr)
3563c2a74a3SMatthias Springer     return parser.emitError(opLoc)
3573c2a74a3SMatthias Springer            << "'" << sizesAttrName << "' attribute must be an array";
3583c2a74a3SMatthias Springer   Type pdlOpType = parser.getBuilder().getType<pdl::OperationType>();
3593c2a74a3SMatthias Springer   size_t numExpectedLoops =
3603c2a74a3SMatthias Springer       sizesArrayAttr.size() - llvm::count(extractI64Array(sizesArrayAttr), 0);
3613c2a74a3SMatthias Springer   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOpType));
3623c2a74a3SMatthias Springer   if (parser.resolveOperand(targetOperand, pdlOpType, result.operands))
3633c2a74a3SMatthias Springer     return failure();
3643c2a74a3SMatthias Springer   return success();
3653c2a74a3SMatthias Springer }
3663c2a74a3SMatthias Springer 
3673c2a74a3SMatthias Springer void TileOp::print(OpAsmPrinter &p) {
3683c2a74a3SMatthias Springer   p << ' ';
3693c2a74a3SMatthias Springer   p << getTarget();
3703c2a74a3SMatthias Springer   p.printOptionalAttrDict((*this)->getAttrs());
3713c2a74a3SMatthias Springer }
3723c2a74a3SMatthias Springer 
3733c2a74a3SMatthias Springer void TileOp::getEffects(
3743c2a74a3SMatthias Springer     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
3753c2a74a3SMatthias Springer         &effects) {
3763c2a74a3SMatthias Springer   // `target` arg is consumed and can no longer be used.
3773c2a74a3SMatthias Springer   effects.emplace_back(MemoryEffects::Read::get(), getTarget(),
3783c2a74a3SMatthias Springer                        TransformMappingResource::get());
3793c2a74a3SMatthias Springer   effects.emplace_back(MemoryEffects::Free::get(), getTarget(),
3803c2a74a3SMatthias Springer                        TransformMappingResource::get());
3813c2a74a3SMatthias Springer 
3823c2a74a3SMatthias Springer   for (Value r : getResults()) {
3833c2a74a3SMatthias Springer     effects.emplace_back(MemoryEffects::Write::get(), r,
3843c2a74a3SMatthias Springer                          TransformMappingResource::get());
3853c2a74a3SMatthias Springer     effects.emplace_back(MemoryEffects::Allocate::get(), r,
3863c2a74a3SMatthias Springer                          TransformMappingResource::get());
3873c2a74a3SMatthias Springer   }
3883c2a74a3SMatthias Springer 
3893c2a74a3SMatthias Springer   effects.emplace_back(MemoryEffects::Read::get(), PayloadIRResource::get());
3903c2a74a3SMatthias Springer   effects.emplace_back(MemoryEffects::Write::get(), PayloadIRResource::get());
3913c2a74a3SMatthias Springer }
3923c2a74a3SMatthias Springer 
3933c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
394cc6c1592SAlex Zinenko // VectorizeOp
395cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
396cc6c1592SAlex Zinenko 
397cc6c1592SAlex Zinenko FailureOr<Operation *> VectorizeOp::applyToOne(Operation *target) {
398cc6c1592SAlex Zinenko   if (!target->hasTrait<OpTrait::IsIsolatedFromAbove>()) {
399cc6c1592SAlex Zinenko     InFlightDiagnostic diag = emitOpError()
400cc6c1592SAlex Zinenko                               << "applies only to isolated-from-above targets";
401cc6c1592SAlex Zinenko     diag.attachNote(target->getLoc()) << "non-isolated target";
402cc6c1592SAlex Zinenko     return diag;
403cc6c1592SAlex Zinenko   }
404cc6c1592SAlex Zinenko 
405cc6c1592SAlex Zinenko   MLIRContext *ctx = getContext();
406cc6c1592SAlex Zinenko   RewritePatternSet patterns(ctx);
407cc6c1592SAlex Zinenko   patterns.add<LinalgVectorizationPattern>(ctx);
408cc6c1592SAlex Zinenko 
409cc6c1592SAlex Zinenko   vector::populateVectorTransferPermutationMapLoweringPatterns(patterns);
410cc6c1592SAlex Zinenko   vector::populateVectorReductionToContractPatterns(patterns);
411cc6c1592SAlex Zinenko   patterns.add<linalg::LinalgCopyVTRForwardingPattern,
412cc6c1592SAlex Zinenko                linalg::LinalgCopyVTWForwardingPattern>(ctx,
413cc6c1592SAlex Zinenko                                                        /*benefit=*/2);
414cc6c1592SAlex Zinenko   vector::TransferReadOp::getCanonicalizationPatterns(patterns, ctx);
415cc6c1592SAlex Zinenko   vector::TransferWriteOp::getCanonicalizationPatterns(patterns, ctx);
416cc6c1592SAlex Zinenko   if (getVectorizePadding())
417cc6c1592SAlex Zinenko     linalg::populatePadOpVectorizationPatterns(patterns);
418cc6c1592SAlex Zinenko 
419cc6c1592SAlex Zinenko   if (failed(applyPatternsAndFoldGreedily(target, std::move(patterns)))) {
420cc6c1592SAlex Zinenko     InFlightDiagnostic diag = emitError() << "failed to apply";
421cc6c1592SAlex Zinenko     diag.attachNote(target->getLoc()) << "target op";
422cc6c1592SAlex Zinenko     return diag;
423cc6c1592SAlex Zinenko   }
424cc6c1592SAlex Zinenko   return target;
425cc6c1592SAlex Zinenko }
426cc6c1592SAlex Zinenko 
427cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
4283c2a74a3SMatthias Springer // Transform op registration
4293c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
4303c2a74a3SMatthias Springer 
4313c2a74a3SMatthias Springer namespace {
4323c2a74a3SMatthias Springer /// Registers new ops and declares PDL as dependent dialect since the additional
4333c2a74a3SMatthias Springer /// ops are using PDL types for operands and results.
4343c2a74a3SMatthias Springer class LinalgTransformDialectExtension
4353c2a74a3SMatthias Springer     : public transform::TransformDialectExtension<
4363c2a74a3SMatthias Springer           LinalgTransformDialectExtension> {
4373c2a74a3SMatthias Springer public:
4383c2a74a3SMatthias Springer   LinalgTransformDialectExtension() {
4393c2a74a3SMatthias Springer     declareDependentDialect<pdl::PDLDialect>();
4403c2a74a3SMatthias Springer     declareDependentDialect<scf::SCFDialect>();
441cc6c1592SAlex Zinenko     declareDependentDialect<vector::VectorDialect>();
4423c2a74a3SMatthias Springer     registerTransformOps<
4433c2a74a3SMatthias Springer #define GET_OP_LIST
4443c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
4453c2a74a3SMatthias Springer         >();
4463c2a74a3SMatthias Springer   }
4473c2a74a3SMatthias Springer };
4483c2a74a3SMatthias Springer } // namespace
4493c2a74a3SMatthias Springer 
4503c2a74a3SMatthias Springer #define GET_OP_CLASSES
4513c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
4523c2a74a3SMatthias Springer 
4533c2a74a3SMatthias Springer void mlir::linalg::registerTransformDialectExtension(
4543c2a74a3SMatthias Springer     DialectRegistry &registry) {
4553c2a74a3SMatthias Springer   registry.addExtensions<LinalgTransformDialectExtension>();
4563c2a74a3SMatthias Springer }
457