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 
53ce2e198bSAlex Zinenko /// Attempts to apply the pattern specified as template argument to the given
54ce2e198bSAlex Zinenko /// operation. The pattern is expected to have a `returningMatchAndRewrite`
55ce2e198bSAlex Zinenko /// function that returns the "main" result or failure. Returns failure if the
56ce2e198bSAlex Zinenko /// pattern failed to apply. Extra arguments are forwarded to the pattern
57ce2e198bSAlex Zinenko /// constructor.
58ce2e198bSAlex Zinenko template <typename PatternTy, typename... Args>
59ce2e198bSAlex Zinenko static FailureOr<LinalgOp> tryApply(Operation *operation, Args &&...args) {
60ce2e198bSAlex Zinenko   // Check if the given operation has the type expected by the pattern.
61ce2e198bSAlex Zinenko   using OpTy = typename llvm::function_traits<
62ce2e198bSAlex Zinenko       decltype(&PatternTy::returningMatchAndRewrite)>::template arg_t<0>;
63ce2e198bSAlex Zinenko   auto op = dyn_cast<OpTy>(operation);
64ce2e198bSAlex Zinenko   if (!op)
65ce2e198bSAlex Zinenko     return failure();
66ce2e198bSAlex Zinenko 
67ce2e198bSAlex Zinenko   // Apply the pattern directly to the op.
68ce2e198bSAlex Zinenko   PatternTy pattern(operation->getContext(), std::forward<Args>(args)...);
69ce2e198bSAlex Zinenko   SimpleRewriter rewriter(operation->getContext());
70ce2e198bSAlex Zinenko   rewriter.setInsertionPoint(operation);
71ce2e198bSAlex Zinenko   auto result = pattern.returningMatchAndRewrite(op, rewriter);
72ce2e198bSAlex Zinenko   if (failed(result))
73ce2e198bSAlex Zinenko     return failure();
74ce2e198bSAlex Zinenko   return cast<LinalgOp>(result->getOperation());
75ce2e198bSAlex Zinenko }
76ce2e198bSAlex Zinenko 
77ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
78ce2e198bSAlex Zinenko // DecomposeOp
79ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
80ce2e198bSAlex Zinenko 
81ce2e198bSAlex Zinenko FailureOr<LinalgOp> transform::DecomposeOp::applyToOne(LinalgOp target) {
82ce2e198bSAlex Zinenko   FailureOr<LinalgOp> windowed =
83ce2e198bSAlex Zinenko       tryApply<DownscaleSizeOneWindowed2DConvolution>(target);
84ce2e198bSAlex Zinenko   if (succeeded(windowed))
85ce2e198bSAlex Zinenko     return windowed;
86ce2e198bSAlex Zinenko 
87ce2e198bSAlex Zinenko   FailureOr<LinalgOp> depthwise =
88ce2e198bSAlex Zinenko       tryApply<DownscaleDepthwiseConv2DNhwcHwcOp>(target);
89ce2e198bSAlex Zinenko   if (succeeded(depthwise))
90ce2e198bSAlex Zinenko     return depthwise;
91ce2e198bSAlex Zinenko 
925f0d4f20SAlex Zinenko   return reportUnknownTransformError(target);
93ce2e198bSAlex Zinenko }
94ce2e198bSAlex Zinenko 
95ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
96*b6c58ec4SAlex Zinenko // FuseOp
97*b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
98*b6c58ec4SAlex Zinenko 
99*b6c58ec4SAlex Zinenko /// Apply a tiling transformation to all payload ops and store both the
100*b6c58ec4SAlex Zinenko /// tiled operation as well as the created tile loops.
101*b6c58ec4SAlex Zinenko static LogicalResult
102*b6c58ec4SAlex Zinenko applyTilingToAll(Operation *transformOp, Value target,
103*b6c58ec4SAlex Zinenko                  ArrayRef<int64_t> tileSizes,
104*b6c58ec4SAlex Zinenko                  transform::TransformResults &transformResults,
105*b6c58ec4SAlex Zinenko                  transform::TransformState &state,
106*b6c58ec4SAlex Zinenko                  function_ref<FailureOr<TiledLinalgOp>(LinalgOp)> applyFn) {
107*b6c58ec4SAlex Zinenko   // Number of loops: Number of tiles sizes that are not zero.
108*b6c58ec4SAlex Zinenko   size_t numLoops = tileSizes.size() - llvm::count(tileSizes, 0);
109*b6c58ec4SAlex Zinenko   // All payload ops. These should all be LinalgOps for now.
110*b6c58ec4SAlex Zinenko   ArrayRef<Operation *> payloadOps = state.getPayloadOps(target);
111*b6c58ec4SAlex Zinenko 
112*b6c58ec4SAlex Zinenko   SmallVector<Operation *> tiledLinalgOps;
113*b6c58ec4SAlex Zinenko   SmallVector<SmallVector<Operation *>> loopOps(numLoops);
114*b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
115*b6c58ec4SAlex Zinenko     loopOps[i].reserve(payloadOps.size());
116*b6c58ec4SAlex Zinenko 
117*b6c58ec4SAlex Zinenko   for (Operation *target : payloadOps) {
118*b6c58ec4SAlex Zinenko     auto linalgOp = dyn_cast<linalg::LinalgOp>(target);
119*b6c58ec4SAlex Zinenko     if (!linalgOp)
120*b6c58ec4SAlex Zinenko       return transformOp->emitError("only LinalgOps are supported");
121*b6c58ec4SAlex Zinenko 
122*b6c58ec4SAlex Zinenko     FailureOr<TiledLinalgOp> tiled = applyFn(linalgOp);
123*b6c58ec4SAlex Zinenko     if (failed(tiled))
124*b6c58ec4SAlex Zinenko       return failure();
125*b6c58ec4SAlex Zinenko 
126*b6c58ec4SAlex Zinenko     tiledLinalgOps.push_back(tiled->op);
127*b6c58ec4SAlex Zinenko     if (tiled->loops.size() != numLoops)
128*b6c58ec4SAlex Zinenko       // Not enough loops were generated. This usually means that the input size
129*b6c58ec4SAlex Zinenko       // was smaller than the tiling size.
130*b6c58ec4SAlex Zinenko       // TODO: LinalgTilingPattern should return failure().
131*b6c58ec4SAlex Zinenko       return failure();
132*b6c58ec4SAlex Zinenko     for (unsigned int i = 0; i < numLoops; ++i)
133*b6c58ec4SAlex Zinenko       loopOps[i].push_back(tiled->loops[i]);
134*b6c58ec4SAlex Zinenko   }
135*b6c58ec4SAlex Zinenko 
136*b6c58ec4SAlex Zinenko   transformResults.set(transformOp->getOpResult(0), tiledLinalgOps);
137*b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
138*b6c58ec4SAlex Zinenko     transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]);
139*b6c58ec4SAlex Zinenko   return success();
140*b6c58ec4SAlex Zinenko }
141*b6c58ec4SAlex Zinenko 
142*b6c58ec4SAlex Zinenko /// Parse a tiling-like operation that returns the tiled op as well as the
143*b6c58ec4SAlex Zinenko /// created tile loops. The function counts the non-zero tile sizes to compute
144*b6c58ec4SAlex Zinenko /// the number of results.
145*b6c58ec4SAlex Zinenko static ParseResult parseTileLikeOp(OpAsmParser &parser, OperationState &result,
146*b6c58ec4SAlex Zinenko                                    StringRef sizesAttrName) {
147*b6c58ec4SAlex Zinenko   OpAsmParser::UnresolvedOperand targetOperand;
148*b6c58ec4SAlex Zinenko   SMLoc opLoc = parser.getCurrentLocation();
149*b6c58ec4SAlex Zinenko   if (parser.parseOperand(targetOperand) ||
150*b6c58ec4SAlex Zinenko       parser.parseOptionalAttrDict(result.attributes))
151*b6c58ec4SAlex Zinenko     return failure();
152*b6c58ec4SAlex Zinenko   Attribute sizesAttr = result.attributes.get(sizesAttrName);
153*b6c58ec4SAlex Zinenko   if (!sizesAttr)
154*b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
155*b6c58ec4SAlex Zinenko            << "expected '" << sizesAttrName << "' attribute";
156*b6c58ec4SAlex Zinenko   auto sizesArrayAttr = sizesAttr.dyn_cast<ArrayAttr>();
157*b6c58ec4SAlex Zinenko   if (!sizesArrayAttr)
158*b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
159*b6c58ec4SAlex Zinenko            << "'" << sizesAttrName << "' attribute must be an array";
160*b6c58ec4SAlex Zinenko   Type pdlOpType = parser.getBuilder().getType<pdl::OperationType>();
161*b6c58ec4SAlex Zinenko   size_t numExpectedLoops =
162*b6c58ec4SAlex Zinenko       sizesArrayAttr.size() - llvm::count(extractI64Array(sizesArrayAttr), 0);
163*b6c58ec4SAlex Zinenko   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOpType));
164*b6c58ec4SAlex Zinenko   if (parser.resolveOperand(targetOperand, pdlOpType, result.operands))
165*b6c58ec4SAlex Zinenko     return failure();
166*b6c58ec4SAlex Zinenko   return success();
167*b6c58ec4SAlex Zinenko }
168*b6c58ec4SAlex Zinenko 
169*b6c58ec4SAlex Zinenko LogicalResult
170*b6c58ec4SAlex Zinenko transform::FuseOp::apply(mlir::transform::TransformResults &transformResults,
171*b6c58ec4SAlex Zinenko                          mlir::transform::TransformState &state) {
172*b6c58ec4SAlex Zinenko   LinalgTilingAndFusionOptions fusionOptions;
173*b6c58ec4SAlex Zinenko   fusionOptions.tileSizes = extractI64Array(getTileSizes());
174*b6c58ec4SAlex Zinenko   fusionOptions.tileInterchange = extractI64Array(getTileInterchange());
175*b6c58ec4SAlex Zinenko 
176*b6c58ec4SAlex Zinenko   return applyTilingToAll(
177*b6c58ec4SAlex Zinenko       getOperation(), getTarget(), fusionOptions.tileSizes, transformResults,
178*b6c58ec4SAlex Zinenko       state, [&](LinalgOp linalgOp) -> FailureOr<TiledLinalgOp> {
179*b6c58ec4SAlex Zinenko         LinalgTileAndFuseTensorOpsPattern pattern(getContext(), fusionOptions);
180*b6c58ec4SAlex Zinenko         SimpleRewriter rewriter(getContext());
181*b6c58ec4SAlex Zinenko         rewriter.setInsertionPoint(linalgOp);
182*b6c58ec4SAlex Zinenko         FailureOr<TileLoopNest> tileLoopNest =
183*b6c58ec4SAlex Zinenko             pattern.returningMatchAndRewrite(linalgOp, rewriter);
184*b6c58ec4SAlex Zinenko         if (failed(tileLoopNest))
185*b6c58ec4SAlex Zinenko           return failure();
186*b6c58ec4SAlex Zinenko 
187*b6c58ec4SAlex Zinenko         TiledLinalgOp tiledLinalgOp;
188*b6c58ec4SAlex Zinenko         tiledLinalgOp.op = tileLoopNest->getRootOp();
189*b6c58ec4SAlex Zinenko         tiledLinalgOp.loops = {tileLoopNest->getLoopOps().begin(),
190*b6c58ec4SAlex Zinenko                                tileLoopNest->getLoopOps().end()};
191*b6c58ec4SAlex Zinenko         return tiledLinalgOp;
192*b6c58ec4SAlex Zinenko       });
193*b6c58ec4SAlex Zinenko }
194*b6c58ec4SAlex Zinenko 
195*b6c58ec4SAlex Zinenko ParseResult transform::FuseOp::parse(OpAsmParser &parser,
196*b6c58ec4SAlex Zinenko                                      OperationState &result) {
197*b6c58ec4SAlex Zinenko   return parseTileLikeOp(
198*b6c58ec4SAlex Zinenko       parser, result,
199*b6c58ec4SAlex Zinenko       transform::FuseOp::getTileSizesAttrName(result.name).getValue());
200*b6c58ec4SAlex Zinenko }
201*b6c58ec4SAlex Zinenko 
202*b6c58ec4SAlex Zinenko void transform::FuseOp::print(OpAsmPrinter &p) {
203*b6c58ec4SAlex Zinenko   p << ' ';
204*b6c58ec4SAlex Zinenko   p << getTarget();
205*b6c58ec4SAlex Zinenko   p.printOptionalAttrDict((*this)->getAttrs());
206*b6c58ec4SAlex Zinenko }
207*b6c58ec4SAlex Zinenko 
208*b6c58ec4SAlex Zinenko LogicalResult transform::FuseOp::verify() {
209*b6c58ec4SAlex Zinenko   SmallVector<int64_t> permutation = extractI64Array(getTileInterchange());
210*b6c58ec4SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, permutation.size()));
211*b6c58ec4SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
212*b6c58ec4SAlex Zinenko                            permutation.begin(), permutation.end())) {
213*b6c58ec4SAlex Zinenko     return emitOpError() << "expects interchange to be a permutation, found "
214*b6c58ec4SAlex Zinenko                          << getTileInterchange();
215*b6c58ec4SAlex Zinenko   }
216*b6c58ec4SAlex Zinenko   return success();
217*b6c58ec4SAlex Zinenko }
218*b6c58ec4SAlex Zinenko 
219*b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
220ce2e198bSAlex Zinenko // GeneralizeOp
221ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
222ce2e198bSAlex Zinenko 
223ce2e198bSAlex Zinenko FailureOr<LinalgOp> transform::GeneralizeOp::applyToOne(LinalgOp target) {
224ce2e198bSAlex Zinenko   // Exit early if no transformation is needed.
225ce2e198bSAlex Zinenko   if (isa<GenericOp>(target))
226ce2e198bSAlex Zinenko     return target;
227ce2e198bSAlex Zinenko 
228ce2e198bSAlex Zinenko   FailureOr<LinalgOp> generic = tryApply<LinalgGeneralizationPattern>(target);
229ce2e198bSAlex Zinenko   if (succeeded(generic))
230ce2e198bSAlex Zinenko     return generic;
231ce2e198bSAlex Zinenko 
2325f0d4f20SAlex Zinenko   return reportUnknownTransformError(target);
233ce2e198bSAlex Zinenko }
234ce2e198bSAlex Zinenko 
2353c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
2365cde5a57SAlex Zinenko // InterchangeOp
2375cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
2385cde5a57SAlex Zinenko 
2395cde5a57SAlex Zinenko FailureOr<LinalgOp> transform::InterchangeOp::applyToOne(LinalgOp target) {
2405cde5a57SAlex Zinenko   SmallVector<unsigned> interchangeVector =
2415cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2425cde5a57SAlex Zinenko   // Exit early if no transformation is needed.
2435cde5a57SAlex Zinenko   if (interchangeVector.empty())
2445cde5a57SAlex Zinenko     return target;
2455cde5a57SAlex Zinenko 
2465cde5a57SAlex Zinenko   auto genericTarget = dyn_cast<GenericOp>(target.getOperation());
2475cde5a57SAlex Zinenko   if (!genericTarget) {
2485cde5a57SAlex Zinenko     InFlightDiagnostic diag = emitOpError()
2495cde5a57SAlex Zinenko                               << "applies to " << GenericOp::getOperationName()
2505cde5a57SAlex Zinenko                               << " ops";
2515cde5a57SAlex Zinenko     diag.attachNote(target.getLoc()) << "attempted to apply to this op";
2525cde5a57SAlex Zinenko     return diag;
2535cde5a57SAlex Zinenko   }
2545cde5a57SAlex Zinenko 
255ce2e198bSAlex Zinenko   return tryApply<GenericOpInterchangePattern>(target, interchangeVector);
2565cde5a57SAlex Zinenko }
2575cde5a57SAlex Zinenko 
2585cde5a57SAlex Zinenko LogicalResult transform::InterchangeOp::verify() {
2595cde5a57SAlex Zinenko   SmallVector<unsigned> permutation =
2605cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
2615cde5a57SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<unsigned>(0, permutation.size()));
2625cde5a57SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
2635cde5a57SAlex Zinenko                            permutation.begin(), permutation.end())) {
2645cde5a57SAlex Zinenko     return emitOpError()
2655cde5a57SAlex Zinenko            << "expects iterator_interchange to be a permutation, found "
2665cde5a57SAlex Zinenko            << getIteratorInterchange();
2675cde5a57SAlex Zinenko   }
2685cde5a57SAlex Zinenko   return success();
2695cde5a57SAlex Zinenko }
2705cde5a57SAlex Zinenko 
2715cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2725cde5a57SAlex Zinenko // PadOp
2735cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
2745cde5a57SAlex Zinenko 
2755cde5a57SAlex Zinenko FailureOr<LinalgOp> transform::PadOp::applyToOne(LinalgOp target) {
2765cde5a57SAlex Zinenko   // Convert the integer packing flags to booleans.
2775cde5a57SAlex Zinenko   SmallVector<bool> packPaddings;
2785cde5a57SAlex Zinenko   for (int64_t packPadding : extractI64Array(getPackPaddings()))
2795cde5a57SAlex Zinenko     packPaddings.push_back(static_cast<bool>(packPadding));
2805cde5a57SAlex Zinenko 
2815cde5a57SAlex Zinenko   // Convert the padding values to attributes.
2825cde5a57SAlex Zinenko   SmallVector<Attribute> paddingValues;
2835cde5a57SAlex Zinenko   for (auto const &it :
2845cde5a57SAlex Zinenko        llvm::zip(getPaddingValues(), target->getOperandTypes())) {
2855cde5a57SAlex Zinenko     Attribute attr = std::get<0>(it);
2865cde5a57SAlex Zinenko     Type elementType = getElementTypeOrSelf(std::get<1>(it));
2875cde5a57SAlex Zinenko     // Try to parse string attributes to obtain an attribute of element type.
2885cde5a57SAlex Zinenko     if (auto stringAttr = attr.dyn_cast<StringAttr>()) {
2895cde5a57SAlex Zinenko       paddingValues.push_back(
2905cde5a57SAlex Zinenko           parseAttribute(attr.cast<StringAttr>(), elementType));
2915cde5a57SAlex Zinenko       if (!paddingValues.back()) {
2925cde5a57SAlex Zinenko         InFlightDiagnostic diag = emitOpError()
2935cde5a57SAlex Zinenko                                   << "expects a padding value that parses to "
2945cde5a57SAlex Zinenko                                   << elementType << ", got " << std::get<0>(it);
2955cde5a57SAlex Zinenko         diag.attachNote(target.getLoc()) << "when applied to this op";
2965cde5a57SAlex Zinenko         return diag;
2975cde5a57SAlex Zinenko       }
2985cde5a57SAlex Zinenko       continue;
2995cde5a57SAlex Zinenko     }
3005cde5a57SAlex Zinenko     // Otherwise, add the attribute directly.
3015cde5a57SAlex Zinenko     if (attr.getType() != elementType) {
3025cde5a57SAlex Zinenko       InFlightDiagnostic diag = emitOpError()
3035cde5a57SAlex Zinenko                                 << "expects a padding value of type "
3045cde5a57SAlex Zinenko                                 << elementType << ", got " << attr;
3055cde5a57SAlex Zinenko       diag.attachNote(target.getLoc()) << "when applied to this op";
3065cde5a57SAlex Zinenko       return diag;
3075cde5a57SAlex Zinenko     }
3085cde5a57SAlex Zinenko     paddingValues.push_back(attr);
3095cde5a57SAlex Zinenko   }
3105cde5a57SAlex Zinenko 
3115cde5a57SAlex Zinenko   // Extract the transpose vectors.
3125cde5a57SAlex Zinenko   SmallVector<SmallVector<int64_t>> transposePaddings;
3135cde5a57SAlex Zinenko   for (Attribute transposeVector : getTransposePaddings().cast<ArrayAttr>())
3145cde5a57SAlex Zinenko     transposePaddings.push_back(
3155cde5a57SAlex Zinenko         extractI64Array(transposeVector.cast<ArrayAttr>()));
3165cde5a57SAlex Zinenko 
3175cde5a57SAlex Zinenko   LinalgPaddingOptions paddingOptions;
3185cde5a57SAlex Zinenko   paddingOptions.setPaddingValues(paddingValues);
3195cde5a57SAlex Zinenko   paddingOptions.setPaddingDimensions(extractI64Array(getPaddingDimensions()));
3205cde5a57SAlex Zinenko   paddingOptions.setPackPaddings(packPaddings);
3215cde5a57SAlex Zinenko   paddingOptions.setHoistPaddings(extractI64Array(getHoistPaddings()));
3225cde5a57SAlex Zinenko   paddingOptions.setTransposePaddings(transposePaddings);
3235cde5a57SAlex Zinenko 
324ce2e198bSAlex Zinenko   FailureOr<LinalgOp> result =
325ce2e198bSAlex Zinenko       tryApply<LinalgPaddingPattern>(target, paddingOptions);
326ce2e198bSAlex Zinenko   if (succeeded(result))
327ce2e198bSAlex Zinenko     return result;
328ce2e198bSAlex Zinenko 
3295cde5a57SAlex Zinenko   InFlightDiagnostic diag = emitError()
3305cde5a57SAlex Zinenko                             << "failed to apply pattern to target op";
3315cde5a57SAlex Zinenko   diag.attachNote(target.getLoc()) << "target op";
3325cde5a57SAlex Zinenko   return diag;
3335cde5a57SAlex Zinenko }
3345cde5a57SAlex Zinenko 
3355cde5a57SAlex Zinenko LogicalResult transform::PadOp::verify() {
3365cde5a57SAlex Zinenko   SmallVector<int64_t> packPaddings = extractI64Array(getPackPaddings());
3375cde5a57SAlex Zinenko   if (any_of(packPaddings, [](int64_t packPadding) {
3385cde5a57SAlex Zinenko         return packPadding != 0 && packPadding != 1;
3395cde5a57SAlex Zinenko       })) {
3405cde5a57SAlex Zinenko     return emitOpError()
3415cde5a57SAlex Zinenko            << "expects pack_paddings to contain booleans (0/1), found "
3425cde5a57SAlex Zinenko            << getPackPaddings();
3435cde5a57SAlex Zinenko   }
3445cde5a57SAlex Zinenko 
3455cde5a57SAlex Zinenko   SmallVector<int64_t> paddingDimensions =
3465cde5a57SAlex Zinenko       extractI64Array(getPaddingDimensions());
3475cde5a57SAlex Zinenko   if (any_of(paddingDimensions,
3485cde5a57SAlex Zinenko              [](int64_t paddingDimension) { return paddingDimension < 0; })) {
3495cde5a57SAlex Zinenko     return emitOpError()
3505cde5a57SAlex Zinenko            << "expects padding_dimensions to contain positive integers, found "
3515cde5a57SAlex Zinenko            << getPaddingDimensions();
3525cde5a57SAlex Zinenko   }
3535cde5a57SAlex Zinenko 
3545cde5a57SAlex Zinenko   SmallVector<int64_t> hoistPaddings = extractI64Array(getHoistPaddings());
3555cde5a57SAlex Zinenko   if (any_of(hoistPaddings,
3565cde5a57SAlex Zinenko              [](int64_t hoistPadding) { return hoistPadding < 0; })) {
3575cde5a57SAlex Zinenko     return emitOpError()
3585cde5a57SAlex Zinenko            << "expects hoist_paddings to contain positive integers, found "
3595cde5a57SAlex Zinenko            << getHoistPaddings();
3605cde5a57SAlex Zinenko   }
3615cde5a57SAlex Zinenko 
3625cde5a57SAlex Zinenko   ArrayAttr transposes = getTransposePaddings();
3635cde5a57SAlex Zinenko   for (Attribute attr : transposes) {
3645cde5a57SAlex Zinenko     SmallVector<int64_t> transpose = extractFromI64ArrayAttr(attr);
3655cde5a57SAlex Zinenko     auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, transpose.size()));
3665cde5a57SAlex Zinenko     if (!std::is_permutation(sequence.begin(), sequence.end(),
3675cde5a57SAlex Zinenko                              transpose.begin(), transpose.end())) {
3685cde5a57SAlex Zinenko       return emitOpError()
3695cde5a57SAlex Zinenko              << "expects transpose_paddings to be a permutation, found "
3705cde5a57SAlex Zinenko              << attr;
3715cde5a57SAlex Zinenko     }
3725cde5a57SAlex Zinenko   }
3735cde5a57SAlex Zinenko   return success();
3745cde5a57SAlex Zinenko }
3755cde5a57SAlex Zinenko 
3765cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3775cde5a57SAlex Zinenko // ScalarizeOp
3785cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3795cde5a57SAlex Zinenko 
3805cde5a57SAlex Zinenko FailureOr<LinalgOp> transform::ScalarizeOp::applyToOne(LinalgOp target) {
3815cde5a57SAlex Zinenko   LinalgTilingOptions tilingOptions;
3825cde5a57SAlex Zinenko   tilingOptions.scalarizeDynamicDims();
3835cde5a57SAlex Zinenko   // Tiling with "scalarize_dyn_dims" actually sets the same lambda as the tile
3845cde5a57SAlex Zinenko   // sizes and asserts that it is not already set.
3855cde5a57SAlex Zinenko   SmallVector<int64_t> emptyTileSizes;
3865cde5a57SAlex Zinenko   LinalgTilingPattern pattern(getContext(), tilingOptions);
3875cde5a57SAlex Zinenko   SimpleRewriter rewriter(getContext());
3885cde5a57SAlex Zinenko   rewriter.setInsertionPoint(target);
3895cde5a57SAlex Zinenko   FailureOr<TiledLinalgOp> result =
3905cde5a57SAlex Zinenko       pattern.returningMatchAndRewrite(target, rewriter);
3915cde5a57SAlex Zinenko   if (failed(result))
3925cde5a57SAlex Zinenko     return failure();
3935cde5a57SAlex Zinenko 
3945cde5a57SAlex Zinenko   return result->op;
3955cde5a57SAlex Zinenko }
3965cde5a57SAlex Zinenko 
3975cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3983c2a74a3SMatthias Springer // TileOp
3993c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
4003c2a74a3SMatthias Springer 
4013c2a74a3SMatthias Springer LogicalResult transform::TileOp::apply(TransformResults &transformResults,
4023c2a74a3SMatthias Springer                                        TransformState &state) {
4033c2a74a3SMatthias Springer   LinalgTilingOptions tilingOptions;
4043c2a74a3SMatthias Springer   SmallVector<int64_t> tileSizes = extractI64Array(getSizes());
4053c2a74a3SMatthias Springer 
4063c2a74a3SMatthias Springer   if (!tileSizes.empty())
4073c2a74a3SMatthias Springer     tilingOptions.setTileSizes(tileSizes);
4083c2a74a3SMatthias Springer   tilingOptions.setInterchange(extractUIntArray(getInterchange()));
4093c2a74a3SMatthias Springer   LinalgTilingPattern pattern(getContext(), tilingOptions);
4103c2a74a3SMatthias Springer 
4113c2a74a3SMatthias Springer   return applyTilingToAll(getOperation(), getTarget(), tileSizes,
4123c2a74a3SMatthias Springer                           transformResults, state, [&](LinalgOp linalgOp) {
4133c2a74a3SMatthias Springer                             SimpleRewriter rewriter(linalgOp.getContext());
4143c2a74a3SMatthias Springer                             return pattern.returningMatchAndRewrite(linalgOp,
4153c2a74a3SMatthias Springer                                                                     rewriter);
4163c2a74a3SMatthias Springer                           });
4173c2a74a3SMatthias Springer }
4183c2a74a3SMatthias Springer 
4193c2a74a3SMatthias Springer ParseResult transform::TileOp::parse(OpAsmParser &parser,
4203c2a74a3SMatthias Springer                                      OperationState &result) {
421*b6c58ec4SAlex Zinenko   return parseTileLikeOp(parser, result,
422*b6c58ec4SAlex Zinenko                          TileOp::getSizesAttrName(result.name).getValue());
4233c2a74a3SMatthias Springer }
4243c2a74a3SMatthias Springer 
4253c2a74a3SMatthias Springer void TileOp::print(OpAsmPrinter &p) {
4263c2a74a3SMatthias Springer   p << ' ';
4273c2a74a3SMatthias Springer   p << getTarget();
4283c2a74a3SMatthias Springer   p.printOptionalAttrDict((*this)->getAttrs());
4293c2a74a3SMatthias Springer }
4303c2a74a3SMatthias Springer 
4313c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
432cc6c1592SAlex Zinenko // VectorizeOp
433cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
434cc6c1592SAlex Zinenko 
435cc6c1592SAlex Zinenko FailureOr<Operation *> VectorizeOp::applyToOne(Operation *target) {
436cc6c1592SAlex Zinenko   if (!target->hasTrait<OpTrait::IsIsolatedFromAbove>()) {
437cc6c1592SAlex Zinenko     InFlightDiagnostic diag = emitOpError()
438cc6c1592SAlex Zinenko                               << "applies only to isolated-from-above targets";
439cc6c1592SAlex Zinenko     diag.attachNote(target->getLoc()) << "non-isolated target";
440cc6c1592SAlex Zinenko     return diag;
441cc6c1592SAlex Zinenko   }
442cc6c1592SAlex Zinenko 
443cc6c1592SAlex Zinenko   MLIRContext *ctx = getContext();
444cc6c1592SAlex Zinenko   RewritePatternSet patterns(ctx);
445cc6c1592SAlex Zinenko   patterns.add<LinalgVectorizationPattern>(ctx);
446cc6c1592SAlex Zinenko 
447cc6c1592SAlex Zinenko   vector::populateVectorTransferPermutationMapLoweringPatterns(patterns);
448cc6c1592SAlex Zinenko   vector::populateVectorReductionToContractPatterns(patterns);
449cc6c1592SAlex Zinenko   patterns.add<linalg::LinalgCopyVTRForwardingPattern,
450cc6c1592SAlex Zinenko                linalg::LinalgCopyVTWForwardingPattern>(ctx,
451cc6c1592SAlex Zinenko                                                        /*benefit=*/2);
452cc6c1592SAlex Zinenko   vector::TransferReadOp::getCanonicalizationPatterns(patterns, ctx);
453cc6c1592SAlex Zinenko   vector::TransferWriteOp::getCanonicalizationPatterns(patterns, ctx);
454cc6c1592SAlex Zinenko   if (getVectorizePadding())
455cc6c1592SAlex Zinenko     linalg::populatePadOpVectorizationPatterns(patterns);
456cc6c1592SAlex Zinenko 
4575f0d4f20SAlex Zinenko   if (failed(applyPatternsAndFoldGreedily(target, std::move(patterns))))
4585f0d4f20SAlex Zinenko     return reportUnknownTransformError(target);
459cc6c1592SAlex Zinenko   return target;
460cc6c1592SAlex Zinenko }
461cc6c1592SAlex Zinenko 
462cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
4633c2a74a3SMatthias Springer // Transform op registration
4643c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
4653c2a74a3SMatthias Springer 
4663c2a74a3SMatthias Springer namespace {
4673c2a74a3SMatthias Springer /// Registers new ops and declares PDL as dependent dialect since the additional
4683c2a74a3SMatthias Springer /// ops are using PDL types for operands and results.
4693c2a74a3SMatthias Springer class LinalgTransformDialectExtension
4703c2a74a3SMatthias Springer     : public transform::TransformDialectExtension<
4713c2a74a3SMatthias Springer           LinalgTransformDialectExtension> {
4723c2a74a3SMatthias Springer public:
4733c2a74a3SMatthias Springer   LinalgTransformDialectExtension() {
4743c2a74a3SMatthias Springer     declareDependentDialect<pdl::PDLDialect>();
4753c2a74a3SMatthias Springer     declareDependentDialect<scf::SCFDialect>();
476cc6c1592SAlex Zinenko     declareDependentDialect<vector::VectorDialect>();
4773c2a74a3SMatthias Springer     registerTransformOps<
4783c2a74a3SMatthias Springer #define GET_OP_LIST
4793c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
4803c2a74a3SMatthias Springer         >();
4813c2a74a3SMatthias Springer   }
4823c2a74a3SMatthias Springer };
4833c2a74a3SMatthias Springer } // namespace
4843c2a74a3SMatthias Springer 
4853c2a74a3SMatthias Springer #define GET_OP_CLASSES
4863c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
4873c2a74a3SMatthias Springer 
4883c2a74a3SMatthias Springer void mlir::linalg::registerTransformDialectExtension(
4893c2a74a3SMatthias Springer     DialectRegistry &registry) {
4903c2a74a3SMatthias Springer   registry.addExtensions<LinalgTransformDialectExtension>();
4913c2a74a3SMatthias Springer }
492