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