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