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