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" 183c2a74a3SMatthias Springer #include "llvm/Support/FormatVariadic.h" 193c2a74a3SMatthias Springer 203c2a74a3SMatthias Springer using namespace mlir; 213c2a74a3SMatthias Springer using namespace mlir::linalg; 223c2a74a3SMatthias Springer using namespace mlir::transform; 233c2a74a3SMatthias Springer 243c2a74a3SMatthias Springer /// Extracts a vector of int64_t from an array attribute. Asserts if the 253c2a74a3SMatthias Springer /// attribute contains values other than integers. 263c2a74a3SMatthias Springer static SmallVector<int64_t> extractI64Array(ArrayAttr attr) { 273c2a74a3SMatthias Springer SmallVector<int64_t> result; 283c2a74a3SMatthias Springer result.reserve(attr.size()); 293c2a74a3SMatthias Springer for (APInt value : attr.getAsValueRange<IntegerAttr>()) 303c2a74a3SMatthias Springer result.push_back(value.getSExtValue()); 313c2a74a3SMatthias Springer return result; 323c2a74a3SMatthias Springer } 333c2a74a3SMatthias Springer 343c2a74a3SMatthias Springer /// Extracts a vector of unsigned from an array attribute. Asserts if the 353c2a74a3SMatthias Springer /// attribute contains values other than intergers. May truncate. 363c2a74a3SMatthias Springer static SmallVector<unsigned> extractUIntArray(ArrayAttr attr) { 373c2a74a3SMatthias Springer SmallVector<unsigned> result; 383c2a74a3SMatthias Springer result.reserve(attr.size()); 393c2a74a3SMatthias Springer for (APInt value : attr.getAsValueRange<IntegerAttr>()) 403c2a74a3SMatthias Springer result.push_back(value.getZExtValue()); 413c2a74a3SMatthias Springer return result; 423c2a74a3SMatthias Springer } 433c2a74a3SMatthias Springer 443c2a74a3SMatthias Springer namespace { 453c2a74a3SMatthias Springer /// A simple pattern rewriter that implements no special logic. 463c2a74a3SMatthias Springer class SimpleRewriter : public PatternRewriter { 473c2a74a3SMatthias Springer public: 483c2a74a3SMatthias Springer SimpleRewriter(MLIRContext *context) : PatternRewriter(context) {} 493c2a74a3SMatthias Springer }; 503c2a74a3SMatthias Springer } // namespace 513c2a74a3SMatthias Springer 523c2a74a3SMatthias Springer //===----------------------------------------------------------------------===// 533c2a74a3SMatthias Springer // TileOp 543c2a74a3SMatthias Springer //===----------------------------------------------------------------------===// 553c2a74a3SMatthias Springer 563c2a74a3SMatthias Springer /// Apply a tiling transformation to all payload ops and store both the 573c2a74a3SMatthias Springer /// tiled operation as well as the created tile loops. 583c2a74a3SMatthias Springer static LogicalResult 593c2a74a3SMatthias Springer applyTilingToAll(Operation *transformOp, Value target, 603c2a74a3SMatthias Springer ArrayRef<int64_t> tileSizes, 613c2a74a3SMatthias Springer transform::TransformResults &transformResults, 623c2a74a3SMatthias Springer transform::TransformState &state, 633c2a74a3SMatthias Springer function_ref<FailureOr<TiledLinalgOp>(LinalgOp)> applyFn) { 643c2a74a3SMatthias Springer // Number of loops: Number of tiles sizes that are not zero. 653c2a74a3SMatthias Springer size_t numLoops = tileSizes.size() - llvm::count(tileSizes, 0); 663c2a74a3SMatthias Springer // All payload ops. These should all be LinalgOps for now. 673c2a74a3SMatthias Springer ArrayRef<Operation *> payloadOps = state.getPayloadOps(target); 683c2a74a3SMatthias Springer 693c2a74a3SMatthias Springer SmallVector<Operation *> tiledLinalgOps; 703c2a74a3SMatthias Springer SmallVector<SmallVector<Operation *>> loopOps(numLoops); 713c2a74a3SMatthias Springer for (unsigned int i = 0; i < numLoops; ++i) 723c2a74a3SMatthias Springer loopOps[i].reserve(payloadOps.size()); 733c2a74a3SMatthias Springer 743c2a74a3SMatthias Springer for (Operation *target : payloadOps) { 753c2a74a3SMatthias Springer auto linalgOp = dyn_cast<linalg::LinalgOp>(target); 763c2a74a3SMatthias Springer if (!linalgOp) 773c2a74a3SMatthias Springer return transformOp->emitError("only LinalgOps are supported"); 783c2a74a3SMatthias Springer 793c2a74a3SMatthias Springer FailureOr<TiledLinalgOp> tiled = applyFn(linalgOp); 803c2a74a3SMatthias Springer if (failed(tiled)) 813c2a74a3SMatthias Springer return failure(); 823c2a74a3SMatthias Springer 833c2a74a3SMatthias Springer tiledLinalgOps.push_back(tiled->op); 843c2a74a3SMatthias Springer if (tiled->loops.size() != numLoops) 853c2a74a3SMatthias Springer // Not enough loops were generated. This usually means that the input size 863c2a74a3SMatthias Springer // was smaller than the tiling size. 873c2a74a3SMatthias Springer // TODO: LinalgTilingPattern should return failure(). 883c2a74a3SMatthias Springer return failure(); 893c2a74a3SMatthias Springer for (unsigned int i = 0; i < numLoops; ++i) 903c2a74a3SMatthias Springer loopOps[i].push_back(tiled->loops[i]); 913c2a74a3SMatthias Springer } 923c2a74a3SMatthias Springer 933c2a74a3SMatthias Springer transformResults.set(transformOp->getOpResult(0), tiledLinalgOps); 943c2a74a3SMatthias Springer for (unsigned int i = 0; i < numLoops; ++i) 953c2a74a3SMatthias Springer transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]); 963c2a74a3SMatthias Springer return success(); 973c2a74a3SMatthias Springer } 983c2a74a3SMatthias Springer 993c2a74a3SMatthias Springer LogicalResult transform::TileOp::apply(TransformResults &transformResults, 1003c2a74a3SMatthias Springer TransformState &state) { 1013c2a74a3SMatthias Springer LinalgTilingOptions tilingOptions; 1023c2a74a3SMatthias Springer SmallVector<int64_t> tileSizes = extractI64Array(getSizes()); 1033c2a74a3SMatthias Springer 1043c2a74a3SMatthias Springer if (!tileSizes.empty()) 1053c2a74a3SMatthias Springer tilingOptions.setTileSizes(tileSizes); 1063c2a74a3SMatthias Springer tilingOptions.setInterchange(extractUIntArray(getInterchange())); 1073c2a74a3SMatthias Springer LinalgTilingPattern pattern(getContext(), tilingOptions); 1083c2a74a3SMatthias Springer 1093c2a74a3SMatthias Springer return applyTilingToAll(getOperation(), getTarget(), tileSizes, 1103c2a74a3SMatthias Springer transformResults, state, [&](LinalgOp linalgOp) { 1113c2a74a3SMatthias Springer SimpleRewriter rewriter(linalgOp.getContext()); 1123c2a74a3SMatthias Springer return pattern.returningMatchAndRewrite(linalgOp, 1133c2a74a3SMatthias Springer rewriter); 1143c2a74a3SMatthias Springer }); 1153c2a74a3SMatthias Springer } 1163c2a74a3SMatthias Springer 1173c2a74a3SMatthias Springer ParseResult transform::TileOp::parse(OpAsmParser &parser, 1183c2a74a3SMatthias Springer OperationState &result) { 1193c2a74a3SMatthias Springer StringRef sizesAttrName = TileOp::getSizesAttrName(result.name).getValue(); 1203c2a74a3SMatthias Springer OpAsmParser::UnresolvedOperand targetOperand; 121*1d7b5cd5SChris Lattner SMLoc opLoc = parser.getCurrentLocation(); 122*1d7b5cd5SChris Lattner if (parser.parseOperand(targetOperand) || 123*1d7b5cd5SChris Lattner parser.parseOptionalAttrDict(result.attributes)) 1243c2a74a3SMatthias Springer return failure(); 1253c2a74a3SMatthias Springer Attribute sizesAttr = result.attributes.get(sizesAttrName); 1263c2a74a3SMatthias Springer if (!sizesAttr) 1273c2a74a3SMatthias Springer return parser.emitError(opLoc) 1283c2a74a3SMatthias Springer << "expected '" << sizesAttrName << "' attribute"; 1293c2a74a3SMatthias Springer auto sizesArrayAttr = sizesAttr.dyn_cast<ArrayAttr>(); 1303c2a74a3SMatthias Springer if (!sizesArrayAttr) 1313c2a74a3SMatthias Springer return parser.emitError(opLoc) 1323c2a74a3SMatthias Springer << "'" << sizesAttrName << "' attribute must be an array"; 1333c2a74a3SMatthias Springer Type pdlOpType = parser.getBuilder().getType<pdl::OperationType>(); 1343c2a74a3SMatthias Springer size_t numExpectedLoops = 1353c2a74a3SMatthias Springer sizesArrayAttr.size() - llvm::count(extractI64Array(sizesArrayAttr), 0); 1363c2a74a3SMatthias Springer result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOpType)); 1373c2a74a3SMatthias Springer if (parser.resolveOperand(targetOperand, pdlOpType, result.operands)) 1383c2a74a3SMatthias Springer return failure(); 1393c2a74a3SMatthias Springer return success(); 1403c2a74a3SMatthias Springer } 1413c2a74a3SMatthias Springer 1423c2a74a3SMatthias Springer void TileOp::print(OpAsmPrinter &p) { 1433c2a74a3SMatthias Springer p << ' '; 1443c2a74a3SMatthias Springer p << getTarget(); 1453c2a74a3SMatthias Springer p.printOptionalAttrDict((*this)->getAttrs()); 1463c2a74a3SMatthias Springer } 1473c2a74a3SMatthias Springer 1483c2a74a3SMatthias Springer void TileOp::getEffects( 1493c2a74a3SMatthias Springer SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>> 1503c2a74a3SMatthias Springer &effects) { 1513c2a74a3SMatthias Springer // `target` arg is consumed and can no longer be used. 1523c2a74a3SMatthias Springer effects.emplace_back(MemoryEffects::Read::get(), getTarget(), 1533c2a74a3SMatthias Springer TransformMappingResource::get()); 1543c2a74a3SMatthias Springer effects.emplace_back(MemoryEffects::Free::get(), getTarget(), 1553c2a74a3SMatthias Springer TransformMappingResource::get()); 1563c2a74a3SMatthias Springer 1573c2a74a3SMatthias Springer for (Value r : getResults()) { 1583c2a74a3SMatthias Springer effects.emplace_back(MemoryEffects::Write::get(), r, 1593c2a74a3SMatthias Springer TransformMappingResource::get()); 1603c2a74a3SMatthias Springer effects.emplace_back(MemoryEffects::Allocate::get(), r, 1613c2a74a3SMatthias Springer TransformMappingResource::get()); 1623c2a74a3SMatthias Springer } 1633c2a74a3SMatthias Springer 1643c2a74a3SMatthias Springer effects.emplace_back(MemoryEffects::Read::get(), PayloadIRResource::get()); 1653c2a74a3SMatthias Springer effects.emplace_back(MemoryEffects::Write::get(), PayloadIRResource::get()); 1663c2a74a3SMatthias Springer } 1673c2a74a3SMatthias Springer 1683c2a74a3SMatthias Springer //===----------------------------------------------------------------------===// 1693c2a74a3SMatthias Springer // Transform op registration 1703c2a74a3SMatthias Springer //===----------------------------------------------------------------------===// 1713c2a74a3SMatthias Springer 1723c2a74a3SMatthias Springer namespace { 1733c2a74a3SMatthias Springer /// Registers new ops and declares PDL as dependent dialect since the additional 1743c2a74a3SMatthias Springer /// ops are using PDL types for operands and results. 1753c2a74a3SMatthias Springer class LinalgTransformDialectExtension 1763c2a74a3SMatthias Springer : public transform::TransformDialectExtension< 1773c2a74a3SMatthias Springer LinalgTransformDialectExtension> { 1783c2a74a3SMatthias Springer public: 1793c2a74a3SMatthias Springer LinalgTransformDialectExtension() { 1803c2a74a3SMatthias Springer declareDependentDialect<pdl::PDLDialect>(); 1813c2a74a3SMatthias Springer declareDependentDialect<scf::SCFDialect>(); 1823c2a74a3SMatthias Springer registerTransformOps< 1833c2a74a3SMatthias Springer #define GET_OP_LIST 1843c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc" 1853c2a74a3SMatthias Springer >(); 1863c2a74a3SMatthias Springer } 1873c2a74a3SMatthias Springer }; 1883c2a74a3SMatthias Springer } // namespace 1893c2a74a3SMatthias Springer 1903c2a74a3SMatthias Springer #define GET_OP_CLASSES 1913c2a74a3SMatthias Springer #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp.inc" 1923c2a74a3SMatthias Springer 1933c2a74a3SMatthias Springer void mlir::linalg::registerTransformDialectExtension( 1943c2a74a3SMatthias Springer DialectRegistry ®istry) { 1953c2a74a3SMatthias Springer registry.addExtensions<LinalgTransformDialectExtension>(); 1963c2a74a3SMatthias Springer } 197