13c2a74a3SMatthias Springer //===- LinalgTransformOps.cpp - Implementation of Linalg transform ops ----===//
23c2a74a3SMatthias Springer //
33c2a74a3SMatthias Springer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43c2a74a3SMatthias Springer // See https://llvm.org/LICENSE.txt for license information.
53c2a74a3SMatthias Springer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63c2a74a3SMatthias Springer //
73c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
83c2a74a3SMatthias Springer 
93c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h"
103c2a74a3SMatthias Springer 
11*c60b897dSRiver Riddle #include "mlir/AsmParser/AsmParser.h"
123963b4d0SAlex Zinenko #include "mlir/Dialect/Affine/IR/AffineOps.h"
134e4a4c05SAlex Zinenko #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h"
143c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/IR/Linalg.h"
153c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/Transforms/Transforms.h"
163c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDL.h"
173c2a74a3SMatthias Springer #include "mlir/Dialect/PDL/IR/PDLTypes.h"
183c2a74a3SMatthias Springer #include "mlir/Dialect/Transform/IR/TransformDialect.h"
193963b4d0SAlex Zinenko #include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
2018b92c66SNicolas Vasilache #include "mlir/Interfaces/TilingInterface.h"
213c2a74a3SMatthias Springer #include "mlir/Parser/Parser.h"
22cc6c1592SAlex Zinenko #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
231f77f01cSNicolas Vasilache #include "llvm/ADT/StringSet.h"
243c2a74a3SMatthias Springer 
253c2a74a3SMatthias Springer using namespace mlir;
263c2a74a3SMatthias Springer using namespace mlir::linalg;
273c2a74a3SMatthias Springer using namespace mlir::transform;
283c2a74a3SMatthias Springer 
293c2a74a3SMatthias Springer /// Extracts a vector of unsigned from an array attribute. Asserts if the
303c2a74a3SMatthias Springer /// attribute contains values other than intergers. May truncate.
extractUIntArray(ArrayAttr attr)313c2a74a3SMatthias Springer static SmallVector<unsigned> extractUIntArray(ArrayAttr attr) {
323c2a74a3SMatthias Springer   SmallVector<unsigned> result;
333c2a74a3SMatthias Springer   result.reserve(attr.size());
343c2a74a3SMatthias Springer   for (APInt value : attr.getAsValueRange<IntegerAttr>())
353c2a74a3SMatthias Springer     result.push_back(value.getZExtValue());
363c2a74a3SMatthias Springer   return result;
373c2a74a3SMatthias Springer }
383c2a74a3SMatthias Springer 
393c2a74a3SMatthias Springer namespace {
403c2a74a3SMatthias Springer /// A simple pattern rewriter that implements no special logic.
413c2a74a3SMatthias Springer class SimpleRewriter : public PatternRewriter {
423c2a74a3SMatthias Springer public:
SimpleRewriter(MLIRContext * context)433c2a74a3SMatthias Springer   SimpleRewriter(MLIRContext *context) : PatternRewriter(context) {}
443c2a74a3SMatthias Springer };
453c2a74a3SMatthias Springer } // namespace
463c2a74a3SMatthias Springer 
47ce2e198bSAlex Zinenko /// Attempts to apply the pattern specified as template argument to the given
48ce2e198bSAlex Zinenko /// operation. The pattern is expected to have a `returningMatchAndRewrite`
49ce2e198bSAlex Zinenko /// function that returns the "main" result or failure. Returns failure if the
50ce2e198bSAlex Zinenko /// pattern failed to apply. Extra arguments are forwarded to the pattern
51ce2e198bSAlex Zinenko /// constructor.
52ce2e198bSAlex Zinenko template <typename PatternTy, typename... Args>
tryApply(Operation * operation,Args &&...args)53ce2e198bSAlex Zinenko static FailureOr<LinalgOp> tryApply(Operation *operation, Args &&...args) {
54ce2e198bSAlex Zinenko   // Check if the given operation has the type expected by the pattern.
55ce2e198bSAlex Zinenko   using OpTy = typename llvm::function_traits<
56ce2e198bSAlex Zinenko       decltype(&PatternTy::returningMatchAndRewrite)>::template arg_t<0>;
57ce2e198bSAlex Zinenko   auto op = dyn_cast<OpTy>(operation);
58ce2e198bSAlex Zinenko   if (!op)
59ce2e198bSAlex Zinenko     return failure();
60ce2e198bSAlex Zinenko 
61ce2e198bSAlex Zinenko   // Apply the pattern directly to the op.
62ce2e198bSAlex Zinenko   PatternTy pattern(operation->getContext(), std::forward<Args>(args)...);
63ce2e198bSAlex Zinenko   SimpleRewriter rewriter(operation->getContext());
64ce2e198bSAlex Zinenko   rewriter.setInsertionPoint(operation);
65ce2e198bSAlex Zinenko   auto result = pattern.returningMatchAndRewrite(op, rewriter);
66ce2e198bSAlex Zinenko   if (failed(result))
67ce2e198bSAlex Zinenko     return failure();
68ce2e198bSAlex Zinenko   return cast<LinalgOp>(result->getOperation());
69ce2e198bSAlex Zinenko }
70ce2e198bSAlex Zinenko 
71ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
72ce2e198bSAlex Zinenko // DecomposeOp
73ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
74ce2e198bSAlex Zinenko 
7552307109SNicolas Vasilache DiagnosedSilenceableFailure
applyToOne(linalg::LinalgOp target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)7652307109SNicolas Vasilache transform::DecomposeOp::applyToOne(linalg::LinalgOp target,
7752307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
7852307109SNicolas Vasilache                                    transform::TransformState &state) {
79ce2e198bSAlex Zinenko   FailureOr<LinalgOp> windowed =
80ce2e198bSAlex Zinenko       tryApply<DownscaleSizeOneWindowed2DConvolution>(target);
8152307109SNicolas Vasilache   if (succeeded(windowed)) {
8252307109SNicolas Vasilache     results.push_back(*windowed);
8352307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
8452307109SNicolas Vasilache   }
85ce2e198bSAlex Zinenko   FailureOr<LinalgOp> depthwise =
86ce2e198bSAlex Zinenko       tryApply<DownscaleDepthwiseConv2DNhwcHwcOp>(target);
8752307109SNicolas Vasilache   if (succeeded(depthwise)) {
8852307109SNicolas Vasilache     results.push_back(*depthwise);
8952307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
9052307109SNicolas Vasilache   }
9152307109SNicolas Vasilache   results.assign(1, nullptr);
9252307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
93ce2e198bSAlex Zinenko }
94ce2e198bSAlex Zinenko 
95ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
96b6c58ec4SAlex Zinenko // FuseOp
97b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
98b6c58ec4SAlex Zinenko 
99b6c58ec4SAlex Zinenko /// Apply a tiling transformation to all payload ops and store both the
100b6c58ec4SAlex Zinenko /// tiled operation as well as the created tile loops.
101b6c58ec4SAlex Zinenko static LogicalResult
applyTilingToAll(Operation * transformOp,ArrayRef<Operation * > payloadOps,unsigned numLoops,transform::TransformResults & transformResults,function_ref<FailureOr<TiledLinalgOp> (LinalgOp)> applyFn)1024e4a4c05SAlex Zinenko applyTilingToAll(Operation *transformOp, ArrayRef<Operation *> payloadOps,
1034e4a4c05SAlex Zinenko                  unsigned numLoops,
104b6c58ec4SAlex Zinenko                  transform::TransformResults &transformResults,
105b6c58ec4SAlex Zinenko                  function_ref<FailureOr<TiledLinalgOp>(LinalgOp)> applyFn) {
106b6c58ec4SAlex Zinenko   SmallVector<Operation *> tiledLinalgOps;
107b6c58ec4SAlex Zinenko   SmallVector<SmallVector<Operation *>> loopOps(numLoops);
108b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
109b6c58ec4SAlex Zinenko     loopOps[i].reserve(payloadOps.size());
110b6c58ec4SAlex Zinenko 
111b6c58ec4SAlex Zinenko   for (Operation *target : payloadOps) {
112b6c58ec4SAlex Zinenko     auto linalgOp = dyn_cast<linalg::LinalgOp>(target);
113b6c58ec4SAlex Zinenko     if (!linalgOp)
114b6c58ec4SAlex Zinenko       return transformOp->emitError("only LinalgOps are supported");
115b6c58ec4SAlex Zinenko 
116b6c58ec4SAlex Zinenko     FailureOr<TiledLinalgOp> tiled = applyFn(linalgOp);
117b6c58ec4SAlex Zinenko     if (failed(tiled))
118b6c58ec4SAlex Zinenko       return failure();
119b6c58ec4SAlex Zinenko 
120b6c58ec4SAlex Zinenko     tiledLinalgOps.push_back(tiled->op);
121b6c58ec4SAlex Zinenko     if (tiled->loops.size() != numLoops)
122b6c58ec4SAlex Zinenko       // Not enough loops were generated. This usually means that the input size
123b6c58ec4SAlex Zinenko       // was smaller than the tiling size.
124b6c58ec4SAlex Zinenko       // TODO: LinalgTilingPattern should return failure().
125b6c58ec4SAlex Zinenko       return failure();
126b6c58ec4SAlex Zinenko     for (unsigned int i = 0; i < numLoops; ++i)
127b6c58ec4SAlex Zinenko       loopOps[i].push_back(tiled->loops[i]);
128b6c58ec4SAlex Zinenko   }
129b6c58ec4SAlex Zinenko 
130b6c58ec4SAlex Zinenko   transformResults.set(transformOp->getOpResult(0), tiledLinalgOps);
131b6c58ec4SAlex Zinenko   for (unsigned int i = 0; i < numLoops; ++i)
132b6c58ec4SAlex Zinenko     transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]);
133b6c58ec4SAlex Zinenko   return success();
134b6c58ec4SAlex Zinenko }
135b6c58ec4SAlex Zinenko 
136b6c58ec4SAlex Zinenko /// Parse a tiling-like operation that returns the tiled op as well as the
137b6c58ec4SAlex Zinenko /// created tile loops. The function counts the non-zero tile sizes to compute
138b6c58ec4SAlex Zinenko /// the number of results.
parseTileLikeOp(OpAsmParser & parser,OperationState & result,StringRef sizesAttrName)139b6c58ec4SAlex Zinenko static ParseResult parseTileLikeOp(OpAsmParser &parser, OperationState &result,
140b6c58ec4SAlex Zinenko                                    StringRef sizesAttrName) {
141b6c58ec4SAlex Zinenko   OpAsmParser::UnresolvedOperand targetOperand;
142b6c58ec4SAlex Zinenko   SMLoc opLoc = parser.getCurrentLocation();
143b6c58ec4SAlex Zinenko   if (parser.parseOperand(targetOperand) ||
144b6c58ec4SAlex Zinenko       parser.parseOptionalAttrDict(result.attributes))
145b6c58ec4SAlex Zinenko     return failure();
146b6c58ec4SAlex Zinenko   Attribute sizesAttr = result.attributes.get(sizesAttrName);
147b6c58ec4SAlex Zinenko   if (!sizesAttr)
148b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
149b6c58ec4SAlex Zinenko            << "expected '" << sizesAttrName << "' attribute";
150b6c58ec4SAlex Zinenko   auto sizesArrayAttr = sizesAttr.dyn_cast<ArrayAttr>();
151b6c58ec4SAlex Zinenko   if (!sizesArrayAttr)
152b6c58ec4SAlex Zinenko     return parser.emitError(opLoc)
153b6c58ec4SAlex Zinenko            << "'" << sizesAttrName << "' attribute must be an array";
154b6c58ec4SAlex Zinenko   Type pdlOpType = parser.getBuilder().getType<pdl::OperationType>();
155b6c58ec4SAlex Zinenko   size_t numExpectedLoops =
15618b92c66SNicolas Vasilache       sizesArrayAttr.size() -
15718b92c66SNicolas Vasilache       llvm::count(extractFromI64ArrayAttr(sizesArrayAttr), 0);
158b6c58ec4SAlex Zinenko   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOpType));
159b6c58ec4SAlex Zinenko   if (parser.resolveOperand(targetOperand, pdlOpType, result.operands))
160b6c58ec4SAlex Zinenko     return failure();
161b6c58ec4SAlex Zinenko   return success();
162b6c58ec4SAlex Zinenko }
163b6c58ec4SAlex Zinenko 
1641d45282aSAlex Zinenko DiagnosedSilenceableFailure
apply(mlir::transform::TransformResults & transformResults,mlir::transform::TransformState & state)165b6c58ec4SAlex Zinenko transform::FuseOp::apply(mlir::transform::TransformResults &transformResults,
166b6c58ec4SAlex Zinenko                          mlir::transform::TransformState &state) {
167b6c58ec4SAlex Zinenko   LinalgTilingAndFusionOptions fusionOptions;
16818b92c66SNicolas Vasilache   fusionOptions.tileSizes = extractFromI64ArrayAttr(getTileSizes());
16918b92c66SNicolas Vasilache   fusionOptions.tileInterchange = extractFromI64ArrayAttr(getTileInterchange());
170b6c58ec4SAlex Zinenko 
171e3890b7fSAlex Zinenko   LogicalResult result = applyTilingToAll(
1724e4a4c05SAlex Zinenko       getOperation(), state.getPayloadOps(getTarget()),
1734e4a4c05SAlex Zinenko       fusionOptions.tileSizes.size() - llvm::count(fusionOptions.tileSizes, 0),
1744e4a4c05SAlex Zinenko       transformResults, [&](LinalgOp linalgOp) -> FailureOr<TiledLinalgOp> {
175b6c58ec4SAlex Zinenko         LinalgTileAndFuseTensorOpsPattern pattern(getContext(), fusionOptions);
176b6c58ec4SAlex Zinenko         SimpleRewriter rewriter(getContext());
177b6c58ec4SAlex Zinenko         rewriter.setInsertionPoint(linalgOp);
178b6c58ec4SAlex Zinenko         FailureOr<TileLoopNest> tileLoopNest =
179b6c58ec4SAlex Zinenko             pattern.returningMatchAndRewrite(linalgOp, rewriter);
180b6c58ec4SAlex Zinenko         if (failed(tileLoopNest))
181b6c58ec4SAlex Zinenko           return failure();
182b6c58ec4SAlex Zinenko 
183b6c58ec4SAlex Zinenko         TiledLinalgOp tiledLinalgOp;
184b6c58ec4SAlex Zinenko         tiledLinalgOp.op = tileLoopNest->getRootOp();
185b6c58ec4SAlex Zinenko         tiledLinalgOp.loops = {tileLoopNest->getLoopOps().begin(),
186b6c58ec4SAlex Zinenko                                tileLoopNest->getLoopOps().end()};
187b6c58ec4SAlex Zinenko         return tiledLinalgOp;
188b6c58ec4SAlex Zinenko       });
1894e4a4c05SAlex Zinenko   return DiagnosedSilenceableFailure(result);
190b6c58ec4SAlex Zinenko }
191b6c58ec4SAlex Zinenko 
parse(OpAsmParser & parser,OperationState & result)192b6c58ec4SAlex Zinenko ParseResult transform::FuseOp::parse(OpAsmParser &parser,
193b6c58ec4SAlex Zinenko                                      OperationState &result) {
194b6c58ec4SAlex Zinenko   return parseTileLikeOp(
195b6c58ec4SAlex Zinenko       parser, result,
196b6c58ec4SAlex Zinenko       transform::FuseOp::getTileSizesAttrName(result.name).getValue());
197b6c58ec4SAlex Zinenko }
198b6c58ec4SAlex Zinenko 
print(OpAsmPrinter & p)199b6c58ec4SAlex Zinenko void transform::FuseOp::print(OpAsmPrinter &p) {
200b6c58ec4SAlex Zinenko   p << ' ';
201b6c58ec4SAlex Zinenko   p << getTarget();
202b6c58ec4SAlex Zinenko   p.printOptionalAttrDict((*this)->getAttrs());
203b6c58ec4SAlex Zinenko }
204b6c58ec4SAlex Zinenko 
verify()205b6c58ec4SAlex Zinenko LogicalResult transform::FuseOp::verify() {
20618b92c66SNicolas Vasilache   SmallVector<int64_t> permutation =
20718b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getTileInterchange());
208b6c58ec4SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, permutation.size()));
209b6c58ec4SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
210b6c58ec4SAlex Zinenko                            permutation.begin(), permutation.end())) {
211b6c58ec4SAlex Zinenko     return emitOpError() << "expects interchange to be a permutation, found "
212b6c58ec4SAlex Zinenko                          << getTileInterchange();
213b6c58ec4SAlex Zinenko   }
214b6c58ec4SAlex Zinenko   return success();
215b6c58ec4SAlex Zinenko }
216b6c58ec4SAlex Zinenko 
217b6c58ec4SAlex Zinenko //===----------------------------------------------------------------------===//
218bc882ed2SMatthias Springer // FuseIntoContainingOp
219bc882ed2SMatthias Springer //===----------------------------------------------------------------------===//
220bc882ed2SMatthias Springer 
tileAndFuse(Operation * producerOp,Operation * containingOp,RewriterBase & rewriter)221bc882ed2SMatthias Springer static FailureOr<SmallVector<Operation *>> tileAndFuse(Operation *producerOp,
222bc882ed2SMatthias Springer                                                        Operation *containingOp,
223bc882ed2SMatthias Springer                                                        RewriterBase &rewriter) {
224bc882ed2SMatthias Springer   auto tileableProducer = dyn_cast<TilingInterface>(producerOp);
225bc882ed2SMatthias Springer   if (!tileableProducer)
226bc882ed2SMatthias Springer     return failure();
227bc882ed2SMatthias Springer 
228bc882ed2SMatthias Springer   // Search the producer slices accessed within the containing operation.
229bc882ed2SMatthias Springer   // TODO: Generalize to more extract/insert/parallel_insert triples. Maybe
230bc882ed2SMatthias Springer   // evolve into an interface.
231bc882ed2SMatthias Springer   SmallVector<tensor::ExtractSliceOp> sliceOps;
232bc882ed2SMatthias Springer   for (Operation *user : tileableProducer->getUsers()) {
233bc882ed2SMatthias Springer     auto sliceOp = dyn_cast<tensor::ExtractSliceOp>(user);
234bc882ed2SMatthias Springer     if (!sliceOp)
235bc882ed2SMatthias Springer       continue;
236bc882ed2SMatthias Springer     if (!containingOp->isProperAncestor(sliceOp))
237bc882ed2SMatthias Springer       continue;
238bc882ed2SMatthias Springer     sliceOps.push_back(sliceOp);
239bc882ed2SMatthias Springer   }
240bc882ed2SMatthias Springer 
241bc882ed2SMatthias Springer   // Check for a non-empty list of fusion opportunities.
242bc882ed2SMatthias Springer   if (sliceOps.empty())
243bc882ed2SMatthias Springer     return failure();
244bc882ed2SMatthias Springer 
245bc882ed2SMatthias Springer   SmallVector<Value> destinationOperands =
246bc882ed2SMatthias Springer       tileableProducer.getDestinationOperands(rewriter);
247bc882ed2SMatthias Springer 
248bc882ed2SMatthias Springer   // Try to fuse the producer in-place.
249bc882ed2SMatthias Springer   SmallVector<Operation *> fusedOps;
250bc882ed2SMatthias Springer   for (tensor::ExtractSliceOp sliceOp : sliceOps) {
251bc882ed2SMatthias Springer     OpBuilder::InsertionGuard guard(rewriter);
252bc882ed2SMatthias Springer     rewriter.setInsertionPoint(sliceOp);
253bc882ed2SMatthias Springer 
254bc882ed2SMatthias Springer     // Tile the producer.
255bc882ed2SMatthias Springer     FailureOr<Value> tiledProducer = tileableProducer.generateResultTileValue(
256bc882ed2SMatthias Springer         rewriter, /*resultNumber=*/0, destinationOperands,
257bc882ed2SMatthias Springer         sliceOp.getMixedOffsets(), sliceOp.getMixedSizes(), true);
258bc882ed2SMatthias Springer     if (failed(tiledProducer))
259bc882ed2SMatthias Springer       return failure();
260bc882ed2SMatthias Springer     fusedOps.push_back(tiledProducer->getDefiningOp());
261bc882ed2SMatthias Springer   }
262bc882ed2SMatthias Springer 
263bc882ed2SMatthias Springer   // Replace the extract op.
264bc882ed2SMatthias Springer   for (const auto &en : enumerate(sliceOps))
265bc882ed2SMatthias Springer     rewriter.replaceOp(en.value(), fusedOps[en.index()]->getResult(0));
266bc882ed2SMatthias Springer   return fusedOps;
267bc882ed2SMatthias Springer }
268bc882ed2SMatthias Springer 
269bc882ed2SMatthias Springer static FailureOr<SmallVector<Operation *>>
cloneAndFuse(Operation * producerOp,Operation * containingOp,RewriterBase & rewriter)270bc882ed2SMatthias Springer cloneAndFuse(Operation *producerOp, Operation *containingOp,
271bc882ed2SMatthias Springer              RewriterBase &rewriter) {
272bc882ed2SMatthias Springer   // Gather all uses inside the containing op.
273bc882ed2SMatthias Springer   SmallVector<OpOperand *> uses;
274bc882ed2SMatthias Springer   for (OpResult result : producerOp->getOpResults())
275bc882ed2SMatthias Springer     for (OpOperand &use : result.getUses())
276bc882ed2SMatthias Springer       if (containingOp->isProperAncestor(use.getOwner()))
277bc882ed2SMatthias Springer         uses.push_back(&use);
278bc882ed2SMatthias Springer 
279bc882ed2SMatthias Springer   // Check for a non-empty list of fusion opportunities.
280bc882ed2SMatthias Springer   if (uses.empty())
281bc882ed2SMatthias Springer     return failure();
282bc882ed2SMatthias Springer 
283bc882ed2SMatthias Springer   // Clone and fuse inside the containing op.
284bc882ed2SMatthias Springer   SmallVector<Operation *> fusedOps;
285bc882ed2SMatthias Springer   for (OpOperand *use : uses) {
286bc882ed2SMatthias Springer     unsigned resultNumber = use->get().cast<OpResult>().getResultNumber();
287bc882ed2SMatthias Springer     OpBuilder::InsertionGuard guard(rewriter);
288bc882ed2SMatthias Springer     rewriter.setInsertionPoint(use->getOwner());
289bc882ed2SMatthias Springer     Operation *cloned = rewriter.clone(*producerOp);
290bc882ed2SMatthias Springer     rewriter.updateRootInPlace(
291bc882ed2SMatthias Springer         use->getOwner(), [&] { use->set(cloned->getOpResult(resultNumber)); });
292bc882ed2SMatthias Springer     fusedOps.push_back(cloned);
293bc882ed2SMatthias Springer   }
294bc882ed2SMatthias Springer 
295bc882ed2SMatthias Springer   return fusedOps;
296bc882ed2SMatthias Springer }
297bc882ed2SMatthias Springer 
298bc882ed2SMatthias Springer DiagnosedSilenceableFailure
apply(transform::TransformResults & results,transform::TransformState & state)299bc882ed2SMatthias Springer transform::FuseIntoContainingOp::apply(transform::TransformResults &results,
300bc882ed2SMatthias Springer                                        transform::TransformState &state) {
301bc882ed2SMatthias Springer   SmallVector<Operation *> fusedOps;
302bc882ed2SMatthias Springer   ArrayRef<Operation *> producerOps = state.getPayloadOps(getProducerOp());
303bc882ed2SMatthias Springer   for (Operation *producerOp : producerOps) {
304bc882ed2SMatthias Springer     if (producerOp->getNumResults() != 1) {
305bc882ed2SMatthias Springer       Diagnostic diag(producerOp->getLoc(), DiagnosticSeverity::Note);
306bc882ed2SMatthias Springer       diag << "op with != 1 results not supported";
307bc882ed2SMatthias Springer       return DiagnosedSilenceableFailure::silenceableFailure(std::move(diag));
308bc882ed2SMatthias Springer     }
309bc882ed2SMatthias Springer   }
310bc882ed2SMatthias Springer   ArrayRef<Operation *> containingOps = state.getPayloadOps(getContainingOp());
311bc882ed2SMatthias Springer   if (containingOps.size() != 1)
312bc882ed2SMatthias Springer     return DiagnosedSilenceableFailure(
313bc882ed2SMatthias Springer         this->emitOpError("requires exactly one containing_op handle"));
314bc882ed2SMatthias Springer   Operation *containingOp = containingOps.front();
315bc882ed2SMatthias Springer 
316bc882ed2SMatthias Springer   // Helper function to find the next producer that should be fused. Take any
317bc882ed2SMatthias Springer   // producer that has a use inside the containing op.
318bc882ed2SMatthias Springer   SmallVector<Operation *> remainingProducers(producerOps.begin(),
319bc882ed2SMatthias Springer                                               producerOps.end());
320bc882ed2SMatthias Springer   auto getNextProducer = [&]() -> FailureOr<Operation *> {
321bc882ed2SMatthias Springer     for (const auto &it : enumerate(remainingProducers)) {
322bc882ed2SMatthias Springer       Operation *producerOp = it.value();
323bc882ed2SMatthias Springer       bool hasUseInContainingOp =
324bc882ed2SMatthias Springer           any_of(producerOp->getUsers(), [&](Operation *op) {
325bc882ed2SMatthias Springer             return containingOp->isProperAncestor(op);
326bc882ed2SMatthias Springer           });
327bc882ed2SMatthias Springer       // TODO: When resolving the TODO below (no duplicate ops), take an op that
328bc882ed2SMatthias Springer       // has no use among the remaining producers. This is a topological
329bc882ed2SMatthias Springer       // sorting.
330bc882ed2SMatthias Springer       if (hasUseInContainingOp) {
331bc882ed2SMatthias Springer         remainingProducers.erase(remainingProducers.begin() + it.index());
332bc882ed2SMatthias Springer         return producerOp;
333bc882ed2SMatthias Springer       }
334bc882ed2SMatthias Springer     }
335bc882ed2SMatthias Springer     return failure();
336bc882ed2SMatthias Springer   };
337bc882ed2SMatthias Springer 
338bc882ed2SMatthias Springer   IRRewriter rewriter(getContext());
339bc882ed2SMatthias Springer   while (!remainingProducers.empty()) {
340bc882ed2SMatthias Springer     auto nextProducer = getNextProducer();
341bc882ed2SMatthias Springer     if (failed(nextProducer)) {
342bc882ed2SMatthias Springer       Diagnostic diag(containingOp->getLoc(), DiagnosticSeverity::Note);
343bc882ed2SMatthias Springer       diag << "could not fuse ops into container";
344bc882ed2SMatthias Springer       return DiagnosedSilenceableFailure::silenceableFailure(std::move(diag));
345bc882ed2SMatthias Springer     }
346bc882ed2SMatthias Springer 
347bc882ed2SMatthias Springer     Operation *producerOp = *nextProducer;
348bc882ed2SMatthias Springer     // TODO: If there are multiple uses of the producer in the containing op, we
349bc882ed2SMatthias Springer     // currently tile/clone the op multiple times (once per use). In some cases,
350bc882ed2SMatthias Springer     // we can tile/clone once and reuse the value for each use. Futhermore,
351bc882ed2SMatthias Springer     // producers should then be traversed according to a topological sorting.
352bc882ed2SMatthias Springer     auto tiled = tileAndFuse(producerOp, containingOp, rewriter);
353bc882ed2SMatthias Springer     if (succeeded(tiled))
354bc882ed2SMatthias Springer       fusedOps.append(*tiled);
355bc882ed2SMatthias Springer 
356bc882ed2SMatthias Springer     auto cloned = cloneAndFuse(producerOp, containingOp, rewriter);
357bc882ed2SMatthias Springer     if (succeeded(cloned))
358bc882ed2SMatthias Springer       fusedOps.append(*cloned);
359bc882ed2SMatthias Springer 
360bc882ed2SMatthias Springer     if (failed(tiled) && failed(cloned)) {
361bc882ed2SMatthias Springer       Diagnostic diag(producerOp->getLoc(), DiagnosticSeverity::Note);
362bc882ed2SMatthias Springer       diag << "could not fuse into containing op";
363bc882ed2SMatthias Springer       return DiagnosedSilenceableFailure::silenceableFailure(std::move(diag));
364bc882ed2SMatthias Springer     }
365bc882ed2SMatthias Springer   }
366bc882ed2SMatthias Springer 
367bc882ed2SMatthias Springer   results.set(getFusedOp().cast<OpResult>(), fusedOps);
368bc882ed2SMatthias Springer   return DiagnosedSilenceableFailure::success();
369bc882ed2SMatthias Springer }
370bc882ed2SMatthias Springer 
371bc882ed2SMatthias Springer //===----------------------------------------------------------------------===//
372ce2e198bSAlex Zinenko // GeneralizeOp
373ce2e198bSAlex Zinenko //===----------------------------------------------------------------------===//
374ce2e198bSAlex Zinenko 
37552307109SNicolas Vasilache DiagnosedSilenceableFailure
applyToOne(linalg::LinalgOp target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)37652307109SNicolas Vasilache transform::GeneralizeOp::applyToOne(linalg::LinalgOp target,
37752307109SNicolas Vasilache                                     SmallVectorImpl<Operation *> &results,
37852307109SNicolas Vasilache                                     transform::TransformState &state) {
379ce2e198bSAlex Zinenko   // Exit early if no transformation is needed.
38052307109SNicolas Vasilache   if (isa<GenericOp>(target)) {
38152307109SNicolas Vasilache     results.push_back(target);
38252307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
38352307109SNicolas Vasilache   }
384ce2e198bSAlex Zinenko   FailureOr<LinalgOp> generic = tryApply<LinalgGeneralizationPattern>(target);
38552307109SNicolas Vasilache   if (succeeded(generic)) {
38652307109SNicolas Vasilache     results.push_back(generic->getOperation());
38752307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
38852307109SNicolas Vasilache   }
38952307109SNicolas Vasilache   results.assign(1, nullptr);
39052307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
391ce2e198bSAlex Zinenko }
392ce2e198bSAlex Zinenko 
3933c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
3945cde5a57SAlex Zinenko // InterchangeOp
3955cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
3965cde5a57SAlex Zinenko 
39752307109SNicolas Vasilache DiagnosedSilenceableFailure
applyToOne(linalg::GenericOp target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)39852307109SNicolas Vasilache transform::InterchangeOp::applyToOne(linalg::GenericOp target,
39952307109SNicolas Vasilache                                      SmallVectorImpl<Operation *> &results,
40052307109SNicolas Vasilache                                      transform::TransformState &state) {
4015cde5a57SAlex Zinenko   SmallVector<unsigned> interchangeVector =
4025cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
4035cde5a57SAlex Zinenko   // Exit early if no transformation is needed.
40452307109SNicolas Vasilache   if (interchangeVector.empty()) {
40552307109SNicolas Vasilache     results.push_back(target);
40652307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
4075cde5a57SAlex Zinenko   }
40852307109SNicolas Vasilache   SimpleRewriter rewriter(target->getContext());
40952307109SNicolas Vasilache   FailureOr<GenericOp> res =
41052307109SNicolas Vasilache       interchangeGenericOp(rewriter, target, interchangeVector);
41152307109SNicolas Vasilache   if (failed(res))
41252307109SNicolas Vasilache     return DiagnosedSilenceableFailure::definiteFailure();
41352307109SNicolas Vasilache   results.push_back(res->getOperation());
41452307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
4155cde5a57SAlex Zinenko }
4165cde5a57SAlex Zinenko 
verify()4175cde5a57SAlex Zinenko LogicalResult transform::InterchangeOp::verify() {
4185cde5a57SAlex Zinenko   SmallVector<unsigned> permutation =
4195cde5a57SAlex Zinenko       extractUIntArray(getIteratorInterchange());
4205cde5a57SAlex Zinenko   auto sequence = llvm::to_vector(llvm::seq<unsigned>(0, permutation.size()));
4215cde5a57SAlex Zinenko   if (!std::is_permutation(sequence.begin(), sequence.end(),
4225cde5a57SAlex Zinenko                            permutation.begin(), permutation.end())) {
4235cde5a57SAlex Zinenko     return emitOpError()
4245cde5a57SAlex Zinenko            << "expects iterator_interchange to be a permutation, found "
4255cde5a57SAlex Zinenko            << getIteratorInterchange();
4265cde5a57SAlex Zinenko   }
4275cde5a57SAlex Zinenko   return success();
4285cde5a57SAlex Zinenko }
4295cde5a57SAlex Zinenko 
4305cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
4311f77f01cSNicolas Vasilache // MatchOp
4321f77f01cSNicolas Vasilache //===---------------------------------------------------------------------===//
4331f77f01cSNicolas Vasilache 
4341f77f01cSNicolas Vasilache DiagnosedSilenceableFailure
apply(transform::TransformResults & results,transform::TransformState & state)4351f77f01cSNicolas Vasilache transform::MatchOp::apply(transform::TransformResults &results,
4361f77f01cSNicolas Vasilache                           transform::TransformState &state) {
4371f77f01cSNicolas Vasilache   llvm::StringSet<> strs;
4386fa6901bSKazu Hirata   if (getOps().has_value())
4391f77f01cSNicolas Vasilache     strs.insert(getOps()->getAsValueRange<StringAttr>().begin(),
4401f77f01cSNicolas Vasilache                 getOps()->getAsValueRange<StringAttr>().end());
4411f77f01cSNicolas Vasilache 
4421f77f01cSNicolas Vasilache   ArrayRef<Operation *> payloadOps = state.getPayloadOps(getTarget());
4431f77f01cSNicolas Vasilache   if (payloadOps.size() != 1)
4441f77f01cSNicolas Vasilache     return DiagnosedSilenceableFailure(
4451f77f01cSNicolas Vasilache         this->emitOpError("requires exactly one target handle"));
4461f77f01cSNicolas Vasilache 
4471f77f01cSNicolas Vasilache   SmallVector<Operation *> res;
4481f77f01cSNicolas Vasilache   auto matchFun = [&](Operation *op) {
4496fa6901bSKazu Hirata     if (getOps().has_value() && !strs.contains(op->getName().getStringRef()))
45032c6e081SMatthias Springer       return WalkResult::advance();
45132c6e081SMatthias Springer 
4521f77f01cSNicolas Vasilache     // Interfaces cannot be matched by name, just by ID.
4531f77f01cSNicolas Vasilache     // So we specifically encode the interfaces we care about for this op.
4546fa6901bSKazu Hirata     if (getInterface().has_value()) {
45533c18fbcSKazu Hirata       auto iface = getInterface().value();
4561f77f01cSNicolas Vasilache       if (iface == transform::MatchInterfaceEnum::LinalgOp &&
45732c6e081SMatthias Springer           !isa<linalg::LinalgOp>(op))
45832c6e081SMatthias Springer         return WalkResult::advance();
4591f77f01cSNicolas Vasilache       if (iface == transform::MatchInterfaceEnum::TilingInterface &&
4601f77f01cSNicolas Vasilache           isa<TilingInterface>(op))
46132c6e081SMatthias Springer         return WalkResult::advance();
4621f77f01cSNicolas Vasilache     }
46332c6e081SMatthias Springer 
46433c18fbcSKazu Hirata     if (getAttribute().has_value() && !op->hasAttr(getAttribute().value()))
46532c6e081SMatthias Springer       return WalkResult::advance();
46632c6e081SMatthias Springer 
46732c6e081SMatthias Springer     // All constraints are satisfied.
46832c6e081SMatthias Springer     res.push_back(op);
46932c6e081SMatthias Springer     return WalkResult::advance();
4701f77f01cSNicolas Vasilache   };
4711f77f01cSNicolas Vasilache 
4721f77f01cSNicolas Vasilache   payloadOps.front()->walk(matchFun);
4731f77f01cSNicolas Vasilache   results.set(getResult().cast<OpResult>(), res);
4741f77f01cSNicolas Vasilache   return DiagnosedSilenceableFailure(success());
4751f77f01cSNicolas Vasilache }
4761f77f01cSNicolas Vasilache 
4771f77f01cSNicolas Vasilache //===---------------------------------------------------------------------===//
4783963b4d0SAlex Zinenko // MultiTileSizesOp
4793963b4d0SAlex Zinenko //===---------------------------------------------------------------------===//
4803963b4d0SAlex Zinenko 
applyToOne(LinalgOp target,SmallVector<Operation * > & results,TransformState & state)4813963b4d0SAlex Zinenko DiagnosedSilenceableFailure transform::MultiTileSizesOp::applyToOne(
4823963b4d0SAlex Zinenko     LinalgOp target, SmallVector<Operation *> &results, TransformState &state) {
4833963b4d0SAlex Zinenko   OpBuilder builder(target.getContext());
4843963b4d0SAlex Zinenko   builder.setInsertionPoint(target);
4853963b4d0SAlex Zinenko   OpFoldResult targetSize = builder.getIndexAttr(getTargetSize());
4863963b4d0SAlex Zinenko   OpFoldResult divisor = builder.getIndexAttr(getDivisor());
4873963b4d0SAlex Zinenko   FailureOr<MultiSizeSpecification> spec = computeMultiTileSizes(
4883963b4d0SAlex Zinenko       builder, target, getDimension(), targetSize, divisor);
4893963b4d0SAlex Zinenko   if (failed(spec)) {
4903963b4d0SAlex Zinenko     return emitSilenceableError() << "could not generate tile size computation";
4913963b4d0SAlex Zinenko   }
4923963b4d0SAlex Zinenko 
493a5c802a4SAlex Zinenko   AffineExpr s0 = builder.getAffineSymbolExpr(0);
494a5c802a4SAlex Zinenko   AffineExpr s1 = builder.getAffineSymbolExpr(1);
4953963b4d0SAlex Zinenko   Operation *splitPoint =
496a5c802a4SAlex Zinenko       makeComposedAffineApply(builder, target.getLoc(), s0 * s1,
497a5c802a4SAlex Zinenko                               {spec->lowTileSize, spec->lowTripCount});
4983963b4d0SAlex Zinenko   Operation *lowTileSize = spec->lowTileSize.getDefiningOp();
4993963b4d0SAlex Zinenko   Operation *highTileSize = spec->highTileSize.getDefiningOp();
5003963b4d0SAlex Zinenko   assert(lowTileSize && highTileSize && splitPoint &&
5013963b4d0SAlex Zinenko          "tile sizes are not produced by operations");
5023963b4d0SAlex Zinenko   results.reserve(results.size() + 3);
5033963b4d0SAlex Zinenko   results.push_back(lowTileSize);
5043963b4d0SAlex Zinenko   results.push_back(highTileSize);
5053963b4d0SAlex Zinenko   results.push_back(splitPoint);
5063963b4d0SAlex Zinenko   return DiagnosedSilenceableFailure::success();
5073963b4d0SAlex Zinenko }
5083963b4d0SAlex Zinenko 
getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> & effects)5093963b4d0SAlex Zinenko void transform::MultiTileSizesOp::getEffects(
5103963b4d0SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
511e15b855eSAlex Zinenko   onlyReadsHandle(getTarget(), effects);
512e15b855eSAlex Zinenko   producesHandle(getResults(), effects);
513e15b855eSAlex Zinenko   modifiesPayload(effects);
5143963b4d0SAlex Zinenko }
5153963b4d0SAlex Zinenko 
5163963b4d0SAlex Zinenko //===---------------------------------------------------------------------===//
5175cde5a57SAlex Zinenko // PadOp
5185cde5a57SAlex Zinenko //===---------------------------------------------------------------------===//
5195cde5a57SAlex Zinenko 
52052307109SNicolas Vasilache DiagnosedSilenceableFailure
applyToOne(linalg::LinalgOp target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)52152307109SNicolas Vasilache transform::PadOp::applyToOne(linalg::LinalgOp target,
52252307109SNicolas Vasilache                              SmallVectorImpl<Operation *> &results,
52352307109SNicolas Vasilache                              transform::TransformState &state) {
5245cde5a57SAlex Zinenko   // Convert the integer packing flags to booleans.
5255cde5a57SAlex Zinenko   SmallVector<bool> packPaddings;
52618b92c66SNicolas Vasilache   for (int64_t packPadding : extractFromI64ArrayAttr(getPackPaddings()))
5275cde5a57SAlex Zinenko     packPaddings.push_back(static_cast<bool>(packPadding));
5285cde5a57SAlex Zinenko 
5295cde5a57SAlex Zinenko   // Convert the padding values to attributes.
5305cde5a57SAlex Zinenko   SmallVector<Attribute> paddingValues;
5315cde5a57SAlex Zinenko   for (auto const &it :
5325cde5a57SAlex Zinenko        llvm::zip(getPaddingValues(), target->getOperandTypes())) {
5335cde5a57SAlex Zinenko     Attribute attr = std::get<0>(it);
5345cde5a57SAlex Zinenko     Type elementType = getElementTypeOrSelf(std::get<1>(it));
5355cde5a57SAlex Zinenko     // Try to parse string attributes to obtain an attribute of element type.
5365cde5a57SAlex Zinenko     if (auto stringAttr = attr.dyn_cast<StringAttr>()) {
5375cde5a57SAlex Zinenko       paddingValues.push_back(
5385cde5a57SAlex Zinenko           parseAttribute(attr.cast<StringAttr>(), elementType));
5395cde5a57SAlex Zinenko       if (!paddingValues.back()) {
54052307109SNicolas Vasilache         auto diag = this->emitOpError("expects a padding that parses to ")
5415cde5a57SAlex Zinenko                     << elementType << ", got " << std::get<0>(it);
5425cde5a57SAlex Zinenko         diag.attachNote(target.getLoc()) << "when applied to this op";
54352307109SNicolas Vasilache         return DiagnosedSilenceableFailure::definiteFailure();
5445cde5a57SAlex Zinenko       }
5455cde5a57SAlex Zinenko       continue;
5465cde5a57SAlex Zinenko     }
5475cde5a57SAlex Zinenko     // Otherwise, add the attribute directly.
5485cde5a57SAlex Zinenko     if (attr.getType() != elementType) {
54952307109SNicolas Vasilache       auto diag = this->emitOpError("expects a padding value of type ")
5505cde5a57SAlex Zinenko                   << elementType << ", got " << attr;
5515cde5a57SAlex Zinenko       diag.attachNote(target.getLoc()) << "when applied to this op";
55252307109SNicolas Vasilache       return DiagnosedSilenceableFailure::definiteFailure();
5535cde5a57SAlex Zinenko     }
5545cde5a57SAlex Zinenko     paddingValues.push_back(attr);
5555cde5a57SAlex Zinenko   }
5565cde5a57SAlex Zinenko 
5575cde5a57SAlex Zinenko   // Extract the transpose vectors.
5585cde5a57SAlex Zinenko   SmallVector<SmallVector<int64_t>> transposePaddings;
5595cde5a57SAlex Zinenko   for (Attribute transposeVector : getTransposePaddings().cast<ArrayAttr>())
5605cde5a57SAlex Zinenko     transposePaddings.push_back(
56118b92c66SNicolas Vasilache         extractFromI64ArrayAttr(transposeVector.cast<ArrayAttr>()));
5625cde5a57SAlex Zinenko 
5635cde5a57SAlex Zinenko   LinalgPaddingOptions paddingOptions;
5645cde5a57SAlex Zinenko   paddingOptions.setPaddingValues(paddingValues);
56518b92c66SNicolas Vasilache   paddingOptions.setPaddingDimensions(
56618b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getPaddingDimensions()));
5675cde5a57SAlex Zinenko   paddingOptions.setPackPaddings(packPaddings);
56818b92c66SNicolas Vasilache   paddingOptions.setHoistPaddings(extractFromI64ArrayAttr(getHoistPaddings()));
5695cde5a57SAlex Zinenko   paddingOptions.setTransposePaddings(transposePaddings);
5705cde5a57SAlex Zinenko 
571ce2e198bSAlex Zinenko   FailureOr<LinalgOp> result =
572ce2e198bSAlex Zinenko       tryApply<LinalgPaddingPattern>(target, paddingOptions);
57352307109SNicolas Vasilache   if (succeeded(result)) {
57452307109SNicolas Vasilache     results.push_back(result->getOperation());
57552307109SNicolas Vasilache     return DiagnosedSilenceableFailure(success());
57652307109SNicolas Vasilache   }
577ce2e198bSAlex Zinenko 
57852307109SNicolas Vasilache   results.assign(1, nullptr);
57952307109SNicolas Vasilache   return emitDefaultSilenceableFailure(target);
5805cde5a57SAlex Zinenko }
5815cde5a57SAlex Zinenko 
verify()5825cde5a57SAlex Zinenko LogicalResult transform::PadOp::verify() {
58318b92c66SNicolas Vasilache   SmallVector<int64_t> packPaddings =
58418b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getPackPaddings());
5855cde5a57SAlex Zinenko   if (any_of(packPaddings, [](int64_t packPadding) {
5865cde5a57SAlex Zinenko         return packPadding != 0 && packPadding != 1;
5875cde5a57SAlex Zinenko       })) {
5885cde5a57SAlex Zinenko     return emitOpError()
5895cde5a57SAlex Zinenko            << "expects pack_paddings to contain booleans (0/1), found "
5905cde5a57SAlex Zinenko            << getPackPaddings();
5915cde5a57SAlex Zinenko   }
5925cde5a57SAlex Zinenko 
5935cde5a57SAlex Zinenko   SmallVector<int64_t> paddingDimensions =
59418b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getPaddingDimensions());
5955cde5a57SAlex Zinenko   if (any_of(paddingDimensions,
5965cde5a57SAlex Zinenko              [](int64_t paddingDimension) { return paddingDimension < 0; })) {
5975cde5a57SAlex Zinenko     return emitOpError()
5985cde5a57SAlex Zinenko            << "expects padding_dimensions to contain positive integers, found "
5995cde5a57SAlex Zinenko            << getPaddingDimensions();
6005cde5a57SAlex Zinenko   }
6015cde5a57SAlex Zinenko 
60218b92c66SNicolas Vasilache   SmallVector<int64_t> hoistPaddings =
60318b92c66SNicolas Vasilache       extractFromI64ArrayAttr(getHoistPaddings());
6045cde5a57SAlex Zinenko   if (any_of(hoistPaddings,
6055cde5a57SAlex Zinenko              [](int64_t hoistPadding) { return hoistPadding < 0; })) {
6065cde5a57SAlex Zinenko     return emitOpError()
6075cde5a57SAlex Zinenko            << "expects hoist_paddings to contain positive integers, found "
6085cde5a57SAlex Zinenko            << getHoistPaddings();
6095cde5a57SAlex Zinenko   }
6105cde5a57SAlex Zinenko 
6115cde5a57SAlex Zinenko   ArrayAttr transposes = getTransposePaddings();
6125cde5a57SAlex Zinenko   for (Attribute attr : transposes) {
6135cde5a57SAlex Zinenko     SmallVector<int64_t> transpose = extractFromI64ArrayAttr(attr);
6145cde5a57SAlex Zinenko     auto sequence = llvm::to_vector(llvm::seq<int64_t>(0, transpose.size()));
6155cde5a57SAlex Zinenko     if (!std::is_permutation(sequence.begin(), sequence.end(),
6165cde5a57SAlex Zinenko                              transpose.begin(), transpose.end())) {
6175cde5a57SAlex Zinenko       return emitOpError()
6185cde5a57SAlex Zinenko              << "expects transpose_paddings to be a permutation, found "
6195cde5a57SAlex Zinenko              << attr;
6205cde5a57SAlex Zinenko     }
6215cde5a57SAlex Zinenko   }
6225cde5a57SAlex Zinenko   return success();
6235cde5a57SAlex Zinenko }
6245cde5a57SAlex Zinenko 
6255cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
6265a001136SNicolas Vasilache // PromoteOp
6275a001136SNicolas Vasilache //===----------------------------------------------------------------------===//
6285a001136SNicolas Vasilache 
6295a001136SNicolas Vasilache DiagnosedSilenceableFailure
applyToOne(linalg::LinalgOp target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)6305a001136SNicolas Vasilache transform::PromoteOp::applyToOne(linalg::LinalgOp target,
6315a001136SNicolas Vasilache                                  SmallVectorImpl<Operation *> &results,
6325a001136SNicolas Vasilache                                  transform::TransformState &state) {
6335a001136SNicolas Vasilache   LinalgPromotionOptions promotionOptions;
6345a001136SNicolas Vasilache   if (!getOperandsToPromote().empty())
6355a001136SNicolas Vasilache     promotionOptions = promotionOptions.setOperandsToPromote(
6365a001136SNicolas Vasilache         extractFromI64ArrayAttr(getOperandsToPromote()));
6375a001136SNicolas Vasilache   if (getUseFullTilesByDefault())
6385a001136SNicolas Vasilache     promotionOptions = promotionOptions.setUseFullTileBuffersByDefault(
6395a001136SNicolas Vasilache         getUseFullTilesByDefault());
6405a001136SNicolas Vasilache   if (getUseAlloca())
6415a001136SNicolas Vasilache     promotionOptions = promotionOptions.setUseAlloca(getUseAlloca());
6425a001136SNicolas Vasilache   if (!getUseFullTileBuffers().empty())
6435a001136SNicolas Vasilache     promotionOptions = promotionOptions.setUseFullTileBuffers(
6445a001136SNicolas Vasilache         llvm::to_vector(getUseFullTileBuffers().getAsValueRange<BoolAttr>()));
6451a5d0076SKazu Hirata   if (getAlignment().has_value())
6465a001136SNicolas Vasilache     promotionOptions = promotionOptions.setAlignment(*getAlignment());
6475a001136SNicolas Vasilache 
6485a001136SNicolas Vasilache   if (failed(promoteSubviewsPrecondition(target, promotionOptions)))
6495a001136SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
6505a001136SNicolas Vasilache 
6515a001136SNicolas Vasilache   SimpleRewriter rewriter(target->getContext());
6525a001136SNicolas Vasilache   rewriter.setInsertionPoint(target);
6535a001136SNicolas Vasilache   FailureOr<LinalgOp> res = promoteSubViews(rewriter, target, promotionOptions);
6545a001136SNicolas Vasilache   if (failed(res))
6555a001136SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
6565a001136SNicolas Vasilache   results.push_back(target);
6575a001136SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
6585a001136SNicolas Vasilache }
6595a001136SNicolas Vasilache 
6605a001136SNicolas Vasilache //===----------------------------------------------------------------------===//
6615cde5a57SAlex Zinenko // ScalarizeOp
6625cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
6635cde5a57SAlex Zinenko 
66452307109SNicolas Vasilache DiagnosedSilenceableFailure
applyToOne(linalg::LinalgOp target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)66552307109SNicolas Vasilache transform::ScalarizeOp::applyToOne(linalg::LinalgOp target,
66652307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
66752307109SNicolas Vasilache                                    transform::TransformState &state) {
6685cde5a57SAlex Zinenko   LinalgTilingOptions tilingOptions;
6695cde5a57SAlex Zinenko   tilingOptions.scalarizeDynamicDims();
6705cde5a57SAlex Zinenko   // Tiling with "scalarize_dyn_dims" actually sets the same lambda as the tile
6715cde5a57SAlex Zinenko   // sizes and asserts that it is not already set.
6725cde5a57SAlex Zinenko   SmallVector<int64_t> emptyTileSizes;
6735cde5a57SAlex Zinenko   LinalgTilingPattern pattern(getContext(), tilingOptions);
6745cde5a57SAlex Zinenko   SimpleRewriter rewriter(getContext());
6755cde5a57SAlex Zinenko   rewriter.setInsertionPoint(target);
6765cde5a57SAlex Zinenko   FailureOr<TiledLinalgOp> result =
6775cde5a57SAlex Zinenko       pattern.returningMatchAndRewrite(target, rewriter);
6785cde5a57SAlex Zinenko   if (failed(result))
67952307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
6805cde5a57SAlex Zinenko 
68152307109SNicolas Vasilache   results.push_back(result->op);
68252307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
6835cde5a57SAlex Zinenko }
6845cde5a57SAlex Zinenko 
6855cde5a57SAlex Zinenko //===----------------------------------------------------------------------===//
686ff6e5508SAlex Zinenko // SplitOp
687ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
688ff6e5508SAlex Zinenko 
apply(TransformResults & results,TransformState & state)689ff6e5508SAlex Zinenko DiagnosedSilenceableFailure SplitOp::apply(TransformResults &results,
690ff6e5508SAlex Zinenko                                            TransformState &state) {
691ff6e5508SAlex Zinenko   // Collect the dynamic split points if provided.
692ff6e5508SAlex Zinenko   ArrayRef<Operation *> payload = state.getPayloadOps(getTarget());
693ff6e5508SAlex Zinenko   SimpleRewriter rewriter(getContext());
694ff6e5508SAlex Zinenko   SmallVector<OpFoldResult> splitPoints;
695ff6e5508SAlex Zinenko   splitPoints.reserve(payload.size());
696ff6e5508SAlex Zinenko   if (getDynamicSplitPoint()) {
697ff6e5508SAlex Zinenko     auto diag = DiagnosedSilenceableFailure::success();
698ff6e5508SAlex Zinenko     splitPoints = llvm::to_vector(llvm::map_range(
699ff6e5508SAlex Zinenko         state.getPayloadOps(getDynamicSplitPoint()), [&](Operation *op) {
700ff6e5508SAlex Zinenko           if (op->getNumResults() != 1 ||
701ff6e5508SAlex Zinenko               !op->getResult(0).getType().isIndex()) {
702ff6e5508SAlex Zinenko             diag = emitSilenceableError()
703ff6e5508SAlex Zinenko                    << "expected dynamic split point handle to point to a "
704ff6e5508SAlex Zinenko                       "single-result index-typed op";
705ff6e5508SAlex Zinenko             diag.attachNote(op->getLoc()) << "dynamic split point";
706ff6e5508SAlex Zinenko           }
707ff6e5508SAlex Zinenko           return OpFoldResult(op->getResult(0));
708ff6e5508SAlex Zinenko         }));
709ff6e5508SAlex Zinenko     if (!diag.succeeded())
710ff6e5508SAlex Zinenko       return diag;
711ff6e5508SAlex Zinenko 
712ff6e5508SAlex Zinenko     if (splitPoints.size() != payload.size()) {
713ff6e5508SAlex Zinenko       emitError() << "expected the dynamic split point handle to point to as "
714ff6e5508SAlex Zinenko                      "many operations ("
715ff6e5508SAlex Zinenko                   << splitPoints.size() << ") as the target handle ("
716ff6e5508SAlex Zinenko                   << payload.size() << ")";
717ff6e5508SAlex Zinenko       return DiagnosedSilenceableFailure::definiteFailure();
718ff6e5508SAlex Zinenko     }
719ff6e5508SAlex Zinenko   } else {
720ff6e5508SAlex Zinenko     splitPoints.resize(payload.size(),
721ff6e5508SAlex Zinenko                        rewriter.getIndexAttr(getStaticSplitPoint()));
722ff6e5508SAlex Zinenko   }
723ff6e5508SAlex Zinenko 
724ff6e5508SAlex Zinenko   // Split each target operation.
725ff6e5508SAlex Zinenko   SmallVector<Operation *> first, second;
726ff6e5508SAlex Zinenko   for (const auto &pair : llvm::zip(payload, splitPoints)) {
727ff6e5508SAlex Zinenko     Operation *target = std::get<0>(pair);
728ff6e5508SAlex Zinenko     auto linalgOp = dyn_cast<LinalgOp>(target);
729ff6e5508SAlex Zinenko     if (!linalgOp) {
730ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "only applies to structured ops";
731ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
732ff6e5508SAlex Zinenko       return diag;
733ff6e5508SAlex Zinenko     }
734ff6e5508SAlex Zinenko 
735ff6e5508SAlex Zinenko     if (getDimension() >= linalgOp.getNumLoops()) {
736ff6e5508SAlex Zinenko       auto diag = emitSilenceableError() << "dimension " << getDimension()
737ff6e5508SAlex Zinenko                                          << " does not exist in target op";
738ff6e5508SAlex Zinenko       diag.attachNote(target->getLoc()) << "target op";
739ff6e5508SAlex Zinenko       return diag;
740ff6e5508SAlex Zinenko     }
741ff6e5508SAlex Zinenko 
742ff6e5508SAlex Zinenko     rewriter.setInsertionPoint(linalgOp);
743ff6e5508SAlex Zinenko     std::tie(first.emplace_back(), second.emplace_back()) =
744ff6e5508SAlex Zinenko         linalg::splitOp(rewriter, linalgOp, getDimension(), std::get<1>(pair));
745ff6e5508SAlex Zinenko   }
746ff6e5508SAlex Zinenko 
747ff6e5508SAlex Zinenko   results.set(getFirst().cast<OpResult>(), first);
748ff6e5508SAlex Zinenko   results.set(getSecond().cast<OpResult>(), second);
749ff6e5508SAlex Zinenko   return DiagnosedSilenceableFailure::success();
750ff6e5508SAlex Zinenko }
751ff6e5508SAlex Zinenko 
getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> & effects)752ff6e5508SAlex Zinenko void SplitOp::getEffects(
753ff6e5508SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
754e15b855eSAlex Zinenko   consumesHandle(getTarget(), effects);
755e15b855eSAlex Zinenko   if (getDynamicSplitPoint())
756e15b855eSAlex Zinenko     onlyReadsHandle(getDynamicSplitPoint(), effects);
757e15b855eSAlex Zinenko   producesHandle(getResults(), effects);
758e15b855eSAlex Zinenko   modifiesPayload(effects);
759ff6e5508SAlex Zinenko }
760ff6e5508SAlex Zinenko 
parse(OpAsmParser & parser,OperationState & result)761ff6e5508SAlex Zinenko ParseResult SplitOp::parse(OpAsmParser &parser, OperationState &result) {
762ff6e5508SAlex Zinenko   OpAsmParser::UnresolvedOperand target, dynamicSplitPoint;
763ff6e5508SAlex Zinenko   IntegerAttr staticSplitPoint;
764ff6e5508SAlex Zinenko   auto pdlOperationType =
765ff6e5508SAlex Zinenko       pdl::OperationType::get(parser.getBuilder().getContext());
766ff6e5508SAlex Zinenko   if (parser.parseOperand(target) ||
767ff6e5508SAlex Zinenko       parser.resolveOperand(target, pdlOperationType, result.operands) ||
768ff6e5508SAlex Zinenko       parser.parseKeyword("after"))
769ff6e5508SAlex Zinenko     return failure();
770ff6e5508SAlex Zinenko 
771ff6e5508SAlex Zinenko   OptionalParseResult dynamicPointParseResult =
772ff6e5508SAlex Zinenko       parser.parseOptionalOperand(dynamicSplitPoint);
773ff6e5508SAlex Zinenko   if (!dynamicPointParseResult.hasValue()) {
774ff6e5508SAlex Zinenko     int64_t staticSplitPointValue;
775ff6e5508SAlex Zinenko     if (failed(parser.parseInteger(staticSplitPointValue)))
776ff6e5508SAlex Zinenko       return failure();
777ff6e5508SAlex Zinenko 
778ff6e5508SAlex Zinenko     staticSplitPoint =
779ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(staticSplitPointValue);
780ff6e5508SAlex Zinenko   } else {
781ff6e5508SAlex Zinenko     if (failed(*dynamicPointParseResult) ||
782ff6e5508SAlex Zinenko         parser.resolveOperand(dynamicSplitPoint, pdlOperationType,
783ff6e5508SAlex Zinenko                               result.operands)) {
784ff6e5508SAlex Zinenko       return failure();
785ff6e5508SAlex Zinenko     }
786ff6e5508SAlex Zinenko 
787ff6e5508SAlex Zinenko     staticSplitPoint =
788ff6e5508SAlex Zinenko         parser.getBuilder().getI64IntegerAttr(ShapedType::kDynamicSize);
789ff6e5508SAlex Zinenko   }
790ff6e5508SAlex Zinenko 
791ff6e5508SAlex Zinenko   result.addAttribute(
792ff6e5508SAlex Zinenko       SplitOp::getStaticSplitPointAttrName(result.name).getValue(),
793ff6e5508SAlex Zinenko       staticSplitPoint);
794ff6e5508SAlex Zinenko   if (failed(parser.parseOptionalAttrDict(result.attributes)))
795ff6e5508SAlex Zinenko     return failure();
796ff6e5508SAlex Zinenko 
797ff6e5508SAlex Zinenko   result.addTypes({pdlOperationType, pdlOperationType});
798ff6e5508SAlex Zinenko   return success();
799ff6e5508SAlex Zinenko }
800ff6e5508SAlex Zinenko 
print(OpAsmPrinter & printer)801ff6e5508SAlex Zinenko void SplitOp::print(OpAsmPrinter &printer) {
802ff6e5508SAlex Zinenko   printer << " " << getTarget() << " after ";
803ff6e5508SAlex Zinenko   int64_t staticSplitSize = static_cast<int64_t>(getStaticSplitPoint());
804ff6e5508SAlex Zinenko   if (staticSplitSize != ShapedType::kDynamicSize)
805ff6e5508SAlex Zinenko     printer << staticSplitSize;
806ff6e5508SAlex Zinenko   else
807ff6e5508SAlex Zinenko     printer << getDynamicSplitPoint();
808ff6e5508SAlex Zinenko   printer << " ";
809ff6e5508SAlex Zinenko   printer.printOptionalAttrDict(getOperation()->getAttrs(),
810ff6e5508SAlex Zinenko                                 {getStaticSplitPointAttrName()});
811ff6e5508SAlex Zinenko }
812ff6e5508SAlex Zinenko 
verify()813ff6e5508SAlex Zinenko LogicalResult SplitOp::verify() {
814ff6e5508SAlex Zinenko   if ((static_cast<int64_t>(getStaticSplitPoint()) !=
815ff6e5508SAlex Zinenko        ShapedType::kDynamicSize) ^
816ff6e5508SAlex Zinenko       (getDynamicSplitPoint() == nullptr)) {
817ff6e5508SAlex Zinenko     return emitOpError()
818ff6e5508SAlex Zinenko            << "expects either a dynamic or a static split point to be provided";
819ff6e5508SAlex Zinenko   }
820ff6e5508SAlex Zinenko   return success();
821ff6e5508SAlex Zinenko }
822ff6e5508SAlex Zinenko 
823ff6e5508SAlex Zinenko //===----------------------------------------------------------------------===//
824f439b319SNicolas Vasilache // SplitReductionOp
825f439b319SNicolas Vasilache //===----------------------------------------------------------------------===//
826f439b319SNicolas Vasilache 
82752307109SNicolas Vasilache DiagnosedSilenceableFailure
applyToOne(linalg::LinalgOp target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)82852307109SNicolas Vasilache transform::SplitReductionOp::applyToOne(linalg::LinalgOp target,
82952307109SNicolas Vasilache                                         SmallVectorImpl<Operation *> &results,
83052307109SNicolas Vasilache                                         transform::TransformState &state) {
831f439b319SNicolas Vasilache   ControlSplitReductionFn splitFn = [&](LinalgOp) {
832f439b319SNicolas Vasilache     return std::pair<int64_t, unsigned>(getSplitFactor(),
833f439b319SNicolas Vasilache                                         getInsertSplitDimension());
834f439b319SNicolas Vasilache   };
835f439b319SNicolas Vasilache   SimpleRewriter rewriter(getContext());
836f439b319SNicolas Vasilache   rewriter.setInsertionPoint(target);
837f439b319SNicolas Vasilache   FailureOr<SplitReductionResult> splitResult =
838178f9bd6SNicolas Vasilache       (getUseScalingAlgorithm())
839178f9bd6SNicolas Vasilache           ? splitReductionByScaling(rewriter, target, splitFn, getUseAlloc())
840178f9bd6SNicolas Vasilache           : splitReduction(rewriter, target, splitFn, getUseAlloc());
841d5716395SNicolas Vasilache   if (failed(splitResult))
84252307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
84352307109SNicolas Vasilache 
84452307109SNicolas Vasilache   results.push_back(splitResult->initOrAlloc);
84552307109SNicolas Vasilache   results.push_back(splitResult->fillOp);
84652307109SNicolas Vasilache   results.push_back(splitResult->splitLinalgOp);
84752307109SNicolas Vasilache   results.push_back(splitResult->resultCombiningLinalgOp);
84852307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
849d5716395SNicolas Vasilache }
850d5716395SNicolas Vasilache 
851d5716395SNicolas Vasilache //===----------------------------------------------------------------------===//
8523c2a74a3SMatthias Springer // TileOp
8533c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
8543c2a74a3SMatthias Springer 
8551d45282aSAlex Zinenko DiagnosedSilenceableFailure
apply(TransformResults & transformResults,TransformState & state)856e3890b7fSAlex Zinenko transform::TileOp::apply(TransformResults &transformResults,
8573c2a74a3SMatthias Springer                          TransformState &state) {
8583c2a74a3SMatthias Springer   LinalgTilingOptions tilingOptions;
85918b92c66SNicolas Vasilache   SmallVector<int64_t> tileSizes = extractFromI64ArrayAttr(getStaticSizes());
8603c2a74a3SMatthias Springer 
8614e4a4c05SAlex Zinenko   ArrayRef<Operation *> targets = state.getPayloadOps(getTarget());
8624e4a4c05SAlex Zinenko   SmallVector<ArrayRef<Operation *>> dynamicSizeProducers;
8634e4a4c05SAlex Zinenko   dynamicSizeProducers.reserve(getDynamicSizes().size());
8644e4a4c05SAlex Zinenko   for (Value dynamicSizeProducerHandle : getDynamicSizes()) {
8654e4a4c05SAlex Zinenko     dynamicSizeProducers.push_back(
8664e4a4c05SAlex Zinenko         state.getPayloadOps(dynamicSizeProducerHandle));
8674e4a4c05SAlex Zinenko 
8684e4a4c05SAlex Zinenko     if (dynamicSizeProducers.back().size() != targets.size()) {
8694e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag =
8704e4a4c05SAlex Zinenko           emitSilenceableError()
8714e4a4c05SAlex Zinenko           << "expected as many dynamic size-producing operations ("
8724e4a4c05SAlex Zinenko           << dynamicSizeProducers.back().size() << ") as target ops ("
8734e4a4c05SAlex Zinenko           << targets.size() << ")";
8744e4a4c05SAlex Zinenko       diag.attachNote(dynamicSizeProducerHandle.getLoc()) << "for this handle";
8754e4a4c05SAlex Zinenko       return diag;
8764e4a4c05SAlex Zinenko     }
8774e4a4c05SAlex Zinenko 
8784e4a4c05SAlex Zinenko     for (Operation *op : dynamicSizeProducers.back()) {
8794e4a4c05SAlex Zinenko       if (op->getNumResults() == 1 &&
8804e4a4c05SAlex Zinenko           op->getResult(0).getType().isa<IndexType>())
8814e4a4c05SAlex Zinenko         continue;
8824e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag =
8834e4a4c05SAlex Zinenko           emitSilenceableError() << "expected sizes to be produced by ops "
8844e4a4c05SAlex Zinenko                                     "with a single index-type result";
8854e4a4c05SAlex Zinenko       diag.attachNote(op->getLoc()) << "size producer op";
8864e4a4c05SAlex Zinenko       diag.attachNote(dynamicSizeProducerHandle.getLoc()) << "for this handle";
8874e4a4c05SAlex Zinenko       return diag;
8884e4a4c05SAlex Zinenko     }
8894e4a4c05SAlex Zinenko   }
8904e4a4c05SAlex Zinenko 
8914e4a4c05SAlex Zinenko   SmallVector<Operation *> tiled;
8924e4a4c05SAlex Zinenko   SmallVector<SmallVector<Operation *, 4>, 4> loops;
8934e4a4c05SAlex Zinenko   loops.resize(getLoops().size());
8944e4a4c05SAlex Zinenko   for (auto &en : llvm::enumerate(targets)) {
8954e4a4c05SAlex Zinenko     auto linalgOp = dyn_cast<LinalgOp>(en.value());
8964e4a4c05SAlex Zinenko     if (!linalgOp) {
8974e4a4c05SAlex Zinenko       DiagnosedSilenceableFailure diag = emitSilenceableError()
8984e4a4c05SAlex Zinenko                                          << "only linalg ops are supported";
8994e4a4c05SAlex Zinenko       diag.attachNote(en.value()->getLoc()) << "target op";
9004e4a4c05SAlex Zinenko       return diag;
9014e4a4c05SAlex Zinenko     }
9024e4a4c05SAlex Zinenko 
9034e4a4c05SAlex Zinenko     unsigned index = en.index();
9044e4a4c05SAlex Zinenko     if (!tileSizes.empty()) {
9054e4a4c05SAlex Zinenko       tilingOptions.setTileSizeComputationFunction(
9064e4a4c05SAlex Zinenko           [&, index](OpBuilder &b, Operation *) {
9074e4a4c05SAlex Zinenko             SmallVector<Value, 4> sizes;
9084e4a4c05SAlex Zinenko             sizes.reserve(tileSizes.size());
9094e4a4c05SAlex Zinenko             unsigned dynamicIdx = 0;
9104e4a4c05SAlex Zinenko             for (OpFoldResult ofr : getMixedSizes()) {
9114e4a4c05SAlex Zinenko               if (auto attr = ofr.dyn_cast<Attribute>()) {
9124e4a4c05SAlex Zinenko                 sizes.push_back(b.create<arith::ConstantIndexOp>(
9134e4a4c05SAlex Zinenko                     getLoc(), attr.cast<IntegerAttr>().getInt()));
9144e4a4c05SAlex Zinenko               } else {
9154e4a4c05SAlex Zinenko                 sizes.push_back(
9164e4a4c05SAlex Zinenko                     dynamicSizeProducers[dynamicIdx++][index]->getResult(0));
9174e4a4c05SAlex Zinenko               }
9184e4a4c05SAlex Zinenko             }
9194e4a4c05SAlex Zinenko             return sizes;
9204e4a4c05SAlex Zinenko           });
9214e4a4c05SAlex Zinenko     }
9224e4a4c05SAlex Zinenko 
9233c2a74a3SMatthias Springer     tilingOptions.setInterchange(extractUIntArray(getInterchange()));
9243c2a74a3SMatthias Springer     LinalgTilingPattern pattern(getContext(), tilingOptions);
9253c2a74a3SMatthias Springer     SimpleRewriter rewriter(linalgOp.getContext());
9264e4a4c05SAlex Zinenko     FailureOr<TiledLinalgOp> tiledOp =
9274e4a4c05SAlex Zinenko         pattern.returningMatchAndRewrite(linalgOp, rewriter);
9284e4a4c05SAlex Zinenko     if (failed(tiledOp))
9294e4a4c05SAlex Zinenko       return DiagnosedSilenceableFailure::definiteFailure();
9304e4a4c05SAlex Zinenko 
9314e4a4c05SAlex Zinenko     tiled.push_back(tiledOp->op);
9324e4a4c05SAlex Zinenko     for (const auto &en2 : llvm::enumerate(tiledOp->loops))
9334e4a4c05SAlex Zinenko       loops[en2.index()].push_back(en2.value());
9344e4a4c05SAlex Zinenko   }
9354e4a4c05SAlex Zinenko 
9364e4a4c05SAlex Zinenko   transformResults.set(getTiledLinalgOp().cast<OpResult>(), tiled);
9374e4a4c05SAlex Zinenko   for (const auto &en : llvm::enumerate(loops))
9384e4a4c05SAlex Zinenko     transformResults.set(getLoops()[en.index()].cast<OpResult>(), en.value());
9394e4a4c05SAlex Zinenko 
9404e4a4c05SAlex Zinenko   return DiagnosedSilenceableFailure::success();
9414e4a4c05SAlex Zinenko }
9424e4a4c05SAlex Zinenko 
getMixedSizes()9434e4a4c05SAlex Zinenko SmallVector<OpFoldResult> transform::TileOp::getMixedSizes() {
9444e4a4c05SAlex Zinenko   ValueRange dynamic = getDynamicSizes();
94518b92c66SNicolas Vasilache   SmallVector<int64_t> tileSizes = extractFromI64ArrayAttr(getStaticSizes());
9464e4a4c05SAlex Zinenko   SmallVector<OpFoldResult> results;
9474e4a4c05SAlex Zinenko   results.reserve(tileSizes.size());
9484e4a4c05SAlex Zinenko   unsigned dynamicPos = 0;
9494e4a4c05SAlex Zinenko   Builder builder(getContext());
9504e4a4c05SAlex Zinenko   for (int64_t size : tileSizes) {
9514e4a4c05SAlex Zinenko     if (size == ShapedType::kDynamicSize) {
9524e4a4c05SAlex Zinenko       results.push_back(dynamic[dynamicPos++]);
9534e4a4c05SAlex Zinenko     } else {
9544e4a4c05SAlex Zinenko       results.push_back(builder.getIndexAttr(size));
9554e4a4c05SAlex Zinenko     }
9564e4a4c05SAlex Zinenko   }
9574e4a4c05SAlex Zinenko   return results;
9583c2a74a3SMatthias Springer }
9593c2a74a3SMatthias Springer 
parse(OpAsmParser & parser,OperationState & result)9603c2a74a3SMatthias Springer ParseResult transform::TileOp::parse(OpAsmParser &parser,
9613c2a74a3SMatthias Springer                                      OperationState &result) {
9624e4a4c05SAlex Zinenko   OpAsmParser::UnresolvedOperand target;
9634e4a4c05SAlex Zinenko   SmallVector<OpAsmParser::UnresolvedOperand> dynamicSizes;
9644e4a4c05SAlex Zinenko   ArrayAttr staticSizes;
9654e4a4c05SAlex Zinenko   auto pdlOperationType = pdl::OperationType::get(parser.getContext());
9664e4a4c05SAlex Zinenko   if (parser.parseOperand(target) ||
9674e4a4c05SAlex Zinenko       parser.resolveOperand(target, pdlOperationType, result.operands) ||
9684e4a4c05SAlex Zinenko       parseOperandsOrIntegersSizesList(parser, dynamicSizes, staticSizes) ||
9694e4a4c05SAlex Zinenko       parser.resolveOperands(dynamicSizes, pdlOperationType, result.operands) ||
9704e4a4c05SAlex Zinenko       parser.parseOptionalAttrDict(result.attributes))
9714e4a4c05SAlex Zinenko     return ParseResult::failure();
9724e4a4c05SAlex Zinenko 
9734e4a4c05SAlex Zinenko   result.addAttribute(getStaticSizesAttrName(result.name), staticSizes);
9744e4a4c05SAlex Zinenko   size_t numExpectedLoops =
97518b92c66SNicolas Vasilache       staticSizes.size() - llvm::count(extractFromI64ArrayAttr(staticSizes), 0);
9764e4a4c05SAlex Zinenko   result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOperationType));
9774e4a4c05SAlex Zinenko   return success();
9783c2a74a3SMatthias Springer }
9793c2a74a3SMatthias Springer 
print(OpAsmPrinter & p)9803c2a74a3SMatthias Springer void TileOp::print(OpAsmPrinter &p) {
9814e4a4c05SAlex Zinenko   p << ' ' << getTarget();
9824e4a4c05SAlex Zinenko   printOperandsOrIntegersSizesList(p, getOperation(), getDynamicSizes(),
9834e4a4c05SAlex Zinenko                                    getStaticSizes());
9844e4a4c05SAlex Zinenko   p.printOptionalAttrDict((*this)->getAttrs(), {getStaticSizesAttrName()});
9854e4a4c05SAlex Zinenko }
9864e4a4c05SAlex Zinenko 
getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> & effects)9874e4a4c05SAlex Zinenko void transform::TileOp::getEffects(
9884e4a4c05SAlex Zinenko     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
9894e4a4c05SAlex Zinenko   consumesHandle(getTarget(), effects);
9904e4a4c05SAlex Zinenko   onlyReadsHandle(getDynamicSizes(), effects);
9914e4a4c05SAlex Zinenko   producesHandle(getTiledLinalgOp(), effects);
9924e4a4c05SAlex Zinenko   producesHandle(getLoops(), effects);
9934e4a4c05SAlex Zinenko   modifiesPayload(effects);
9943c2a74a3SMatthias Springer }
9953c2a74a3SMatthias Springer 
9963c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
99718b92c66SNicolas Vasilache // TileToForeachThreadOp
99818b92c66SNicolas Vasilache //===----------------------------------------------------------------------===//
99918b92c66SNicolas Vasilache 
applyToOne(TilingInterface target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)100018b92c66SNicolas Vasilache DiagnosedSilenceableFailure transform::TileToForeachThreadOp::applyToOne(
100118b92c66SNicolas Vasilache     TilingInterface target, SmallVectorImpl<Operation *> &results,
100218b92c66SNicolas Vasilache     transform::TransformState &state) {
100318b92c66SNicolas Vasilache   IRRewriter rewriter(getContext());
100418b92c66SNicolas Vasilache   rewriter.setInsertionPoint(target);
100518b92c66SNicolas Vasilache   auto maybeThreadDimMappingAttr = getThreadDimMapping();
1006297ba167SChristopher Bate   auto dimMapping =
1007297ba167SChristopher Bate       llvm::to_vector(maybeThreadDimMappingAttr
100818b92c66SNicolas Vasilache                           ? extractFromI64ArrayAttr(*maybeThreadDimMappingAttr)
100918b92c66SNicolas Vasilache                           : ArrayRef<int64_t>{});
1010297ba167SChristopher Bate 
1011297ba167SChristopher Bate   FailureOr<ForeachThreadTilingResult> tilingResult = failure();
1012297ba167SChristopher Bate   if (Optional<ArrayAttr> numThreads = getNumThreads())
1013297ba167SChristopher Bate     tilingResult = linalg::tileToForeachThreadOp(
1014297ba167SChristopher Bate         rewriter, target, getAsOpFoldResult(*numThreads), dimMapping);
1015297ba167SChristopher Bate 
1016297ba167SChristopher Bate   if (Optional<ArrayAttr> tileSizes = getTileSizes())
1017297ba167SChristopher Bate     tilingResult = linalg::tileToForeachThreadOpUsingTileSizes(
1018297ba167SChristopher Bate         rewriter, target, getAsOpFoldResult(*tileSizes), dimMapping);
1019297ba167SChristopher Bate 
102018b92c66SNicolas Vasilache   if (failed(tilingResult))
102118b92c66SNicolas Vasilache     return emitDefaultSilenceableFailure(target);
102218b92c66SNicolas Vasilache   rewriter.replaceOp(target, tilingResult->tileOp->getResults());
102318b92c66SNicolas Vasilache   results.assign({tilingResult->tileOp, tilingResult->tiledOp});
102418b92c66SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
102518b92c66SNicolas Vasilache }
102618b92c66SNicolas Vasilache 
102718b92c66SNicolas Vasilache //===----------------------------------------------------------------------===//
1028cc6c1592SAlex Zinenko // VectorizeOp
1029cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
1030cc6c1592SAlex Zinenko 
103152307109SNicolas Vasilache DiagnosedSilenceableFailure
applyToOne(Operation * target,SmallVectorImpl<Operation * > & results,transform::TransformState & state)103252307109SNicolas Vasilache transform::VectorizeOp::applyToOne(Operation *target,
103352307109SNicolas Vasilache                                    SmallVectorImpl<Operation *> &results,
103452307109SNicolas Vasilache                                    transform::TransformState &state) {
1035cc6c1592SAlex Zinenko   if (!target->hasTrait<OpTrait::IsIsolatedFromAbove>()) {
103652307109SNicolas Vasilache     auto diag = this->emitOpError("requires isolated-from-above targets");
1037cc6c1592SAlex Zinenko     diag.attachNote(target->getLoc()) << "non-isolated target";
103852307109SNicolas Vasilache     return DiagnosedSilenceableFailure::definiteFailure();
1039cc6c1592SAlex Zinenko   }
1040cc6c1592SAlex Zinenko 
1041cc6c1592SAlex Zinenko   MLIRContext *ctx = getContext();
1042cc6c1592SAlex Zinenko   RewritePatternSet patterns(ctx);
1043cc6c1592SAlex Zinenko   patterns.add<LinalgVectorizationPattern>(ctx);
1044cc6c1592SAlex Zinenko 
1045cc6c1592SAlex Zinenko   vector::populateVectorTransferPermutationMapLoweringPatterns(patterns);
1046cc6c1592SAlex Zinenko   vector::populateVectorReductionToContractPatterns(patterns);
1047cc6c1592SAlex Zinenko   patterns.add<linalg::LinalgCopyVTRForwardingPattern,
1048cc6c1592SAlex Zinenko                linalg::LinalgCopyVTWForwardingPattern>(ctx,
1049cc6c1592SAlex Zinenko                                                        /*benefit=*/2);
1050cc6c1592SAlex Zinenko   vector::TransferReadOp::getCanonicalizationPatterns(patterns, ctx);
1051cc6c1592SAlex Zinenko   vector::TransferWriteOp::getCanonicalizationPatterns(patterns, ctx);
1052cc6c1592SAlex Zinenko   if (getVectorizePadding())
1053cc6c1592SAlex Zinenko     linalg::populatePadOpVectorizationPatterns(patterns);
1054cc6c1592SAlex Zinenko 
10555f0d4f20SAlex Zinenko   if (failed(applyPatternsAndFoldGreedily(target, std::move(patterns))))
105652307109SNicolas Vasilache     return DiagnosedSilenceableFailure(reportUnknownTransformError(target));
105752307109SNicolas Vasilache 
105852307109SNicolas Vasilache   results.push_back(target);
105952307109SNicolas Vasilache   return DiagnosedSilenceableFailure(success());
1060cc6c1592SAlex Zinenko }
1061cc6c1592SAlex Zinenko 
1062cc6c1592SAlex Zinenko //===----------------------------------------------------------------------===//
10633c2a74a3SMatthias Springer // Transform op registration
10643c2a74a3SMatthias Springer //===----------------------------------------------------------------------===//
10653c2a74a3SMatthias Springer 
10663c2a74a3SMatthias Springer namespace {
10673c2a74a3SMatthias Springer /// Registers new ops and declares PDL as dependent dialect since the additional
10683c2a74a3SMatthias Springer /// ops are using PDL types for operands and results.
10693c2a74a3SMatthias Springer class LinalgTransformDialectExtension
10703c2a74a3SMatthias Springer     : public transform::TransformDialectExtension<
10713c2a74a3SMatthias Springer           LinalgTransformDialectExtension> {
10723c2a74a3SMatthias Springer public:
1073333ee218SAlex Zinenko   using Base::Base;
1074333ee218SAlex Zinenko 
init()1075333ee218SAlex Zinenko   void init() {
10763c2a74a3SMatthias Springer     declareDependentDialect<pdl::PDLDialect>();
1077333ee218SAlex Zinenko 
1078333ee218SAlex Zinenko     declareGeneratedDialect<AffineDialect>();
1079333ee218SAlex Zinenko     declareGeneratedDialect<arith::ArithmeticDialect>();
1080333ee218SAlex Zinenko     declareGeneratedDialect<scf::SCFDialect>();
1081333ee218SAlex Zinenko     declareGeneratedDialect<vector::VectorDialect>();
1082333ee218SAlex Zinenko 
10833c2a74a3SMatthias Springer     registerTransformOps<
10843c2a74a3SMatthias Springer #define GET_OP_LIST
10853c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
10863c2a74a3SMatthias Springer         >();
10873c2a74a3SMatthias Springer   }
10883c2a74a3SMatthias Springer };
10893c2a74a3SMatthias Springer } // namespace
10903c2a74a3SMatthias Springer 
10911f77f01cSNicolas Vasilache #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOpsEnums.cpp.inc"
10921f77f01cSNicolas Vasilache 
10933c2a74a3SMatthias Springer #define GET_OP_CLASSES
10943c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc"
10953c2a74a3SMatthias Springer 
registerTransformDialectExtension(DialectRegistry & registry)10963c2a74a3SMatthias Springer void mlir::linalg::registerTransformDialectExtension(
10973c2a74a3SMatthias Springer     DialectRegistry &registry) {
10983c2a74a3SMatthias Springer   registry.addExtensions<LinalgTransformDialectExtension>();
10993c2a74a3SMatthias Springer }
1100