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