1*3fef2d26SRiver Riddle //===- TestLinalgTransforms.cpp - Test Linalg transformation patterns -----===// 2*3fef2d26SRiver Riddle // 3*3fef2d26SRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*3fef2d26SRiver Riddle // See https://llvm.org/LICENSE.txt for license information. 5*3fef2d26SRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*3fef2d26SRiver Riddle // 7*3fef2d26SRiver Riddle //===----------------------------------------------------------------------===// 8*3fef2d26SRiver Riddle // 9*3fef2d26SRiver Riddle // This file implements logic for testing Linalg transformations. 10*3fef2d26SRiver Riddle // 11*3fef2d26SRiver Riddle //===----------------------------------------------------------------------===// 12*3fef2d26SRiver Riddle 13*3fef2d26SRiver Riddle #include "mlir/Dialect/Affine/IR/AffineOps.h" 14*3fef2d26SRiver Riddle #include "mlir/Dialect/GPU/GPUDialect.h" 15*3fef2d26SRiver Riddle #include "mlir/Dialect/Linalg/IR/LinalgOps.h" 16*3fef2d26SRiver Riddle #include "mlir/Dialect/Linalg/Transforms/Hoisting.h" 17*3fef2d26SRiver Riddle #include "mlir/Dialect/Linalg/Transforms/Transforms.h" 18*3fef2d26SRiver Riddle #include "mlir/Dialect/Linalg/Utils/Utils.h" 19*3fef2d26SRiver Riddle #include "mlir/Dialect/StandardOps/IR/Ops.h" 20*3fef2d26SRiver Riddle #include "mlir/Dialect/Vector/VectorOps.h" 21*3fef2d26SRiver Riddle #include "mlir/Pass/Pass.h" 22*3fef2d26SRiver Riddle #include "mlir/Transforms/GreedyPatternRewriteDriver.h" 23*3fef2d26SRiver Riddle 24*3fef2d26SRiver Riddle #include "llvm/ADT/SetVector.h" 25*3fef2d26SRiver Riddle 26*3fef2d26SRiver Riddle using namespace mlir; 27*3fef2d26SRiver Riddle using namespace mlir::linalg; 28*3fef2d26SRiver Riddle 29*3fef2d26SRiver Riddle namespace { 30*3fef2d26SRiver Riddle struct TestLinalgTransforms 31*3fef2d26SRiver Riddle : public PassWrapper<TestLinalgTransforms, FunctionPass> { 32*3fef2d26SRiver Riddle TestLinalgTransforms() = default; 33*3fef2d26SRiver Riddle TestLinalgTransforms(const TestLinalgTransforms &pass) {} 34*3fef2d26SRiver Riddle 35*3fef2d26SRiver Riddle void getDependentDialects(DialectRegistry ®istry) const override { 36*3fef2d26SRiver Riddle // clang-format off 37*3fef2d26SRiver Riddle registry.insert<AffineDialect, 38*3fef2d26SRiver Riddle memref::MemRefDialect, 39*3fef2d26SRiver Riddle scf::SCFDialect, 40*3fef2d26SRiver Riddle StandardOpsDialect, 41*3fef2d26SRiver Riddle vector::VectorDialect, 42*3fef2d26SRiver Riddle gpu::GPUDialect>(); 43*3fef2d26SRiver Riddle // clang-format on 44*3fef2d26SRiver Riddle } 45*3fef2d26SRiver Riddle 46*3fef2d26SRiver Riddle void runOnFunction() override; 47*3fef2d26SRiver Riddle 48*3fef2d26SRiver Riddle Option<bool> testPatterns{*this, "test-patterns", 49*3fef2d26SRiver Riddle llvm::cl::desc("Test a mixed set of patterns"), 50*3fef2d26SRiver Riddle llvm::cl::init(false)}; 51*3fef2d26SRiver Riddle Option<bool> testMatmulToVectorPatterns1dTiling{ 52*3fef2d26SRiver Riddle *this, "test-matmul-to-vector-patterns-tile-1d", 53*3fef2d26SRiver Riddle llvm::cl::desc( 54*3fef2d26SRiver Riddle "Test a fused pass that applies patterns from matmul to vectors via " 55*3fef2d26SRiver Riddle "1-d tiling"), 56*3fef2d26SRiver Riddle llvm::cl::init(false)}; 57*3fef2d26SRiver Riddle Option<bool> testMatmulToVectorPatterns2dTiling{ 58*3fef2d26SRiver Riddle *this, "test-matmul-to-vector-patterns-tile-2d", 59*3fef2d26SRiver Riddle llvm::cl::desc( 60*3fef2d26SRiver Riddle "Test a fused pass that applies patterns from matmul to vectors via " 61*3fef2d26SRiver Riddle "2-d tiling"), 62*3fef2d26SRiver Riddle llvm::cl::init(false)}; 63*3fef2d26SRiver Riddle Option<bool> testPromotionOptions{*this, "test-linalg-promotion-options", 64*3fef2d26SRiver Riddle llvm::cl::desc("Test promotion options"), 65*3fef2d26SRiver Riddle llvm::cl::init(false)}; 66*3fef2d26SRiver Riddle Option<bool> testTileAndDistributionOptions{ 67*3fef2d26SRiver Riddle *this, "test-tile-and-distribute-options", 68*3fef2d26SRiver Riddle llvm::cl::desc("Test tile and distribute options"), 69*3fef2d26SRiver Riddle llvm::cl::init(false)}; 70*3fef2d26SRiver Riddle Option<bool> testVectorTransferForwardingPatterns{ 71*3fef2d26SRiver Riddle *this, "test-vector-transfer-forwarding-patterns", 72*3fef2d26SRiver Riddle llvm::cl::desc( 73*3fef2d26SRiver Riddle "Test a fused pass that forwards linalg.copy to vector.transfer"), 74*3fef2d26SRiver Riddle llvm::cl::init(false)}; 75*3fef2d26SRiver Riddle Option<bool> testGenericToVectorPattern{ 76*3fef2d26SRiver Riddle *this, "test-linalg-to-vector-patterns", 77*3fef2d26SRiver Riddle llvm::cl::desc("Test a set of patterns that rewrite a linalg contraction " 78*3fef2d26SRiver Riddle "in vector.contract form"), 79*3fef2d26SRiver Riddle llvm::cl::init(false)}; 80*3fef2d26SRiver Riddle Option<bool> testAffineMinSCFCanonicalizationPatterns{ 81*3fef2d26SRiver Riddle *this, "test-affine-min-scf-canonicalization-patterns", 82*3fef2d26SRiver Riddle llvm::cl::desc("Test affine-min + scf canonicalization patterns."), 83*3fef2d26SRiver Riddle llvm::cl::init(false)}; 84*3fef2d26SRiver Riddle Option<bool> testTileAndPadPattern{ 85*3fef2d26SRiver Riddle *this, "test-tile-and-pad-pattern", 86*3fef2d26SRiver Riddle llvm::cl::desc("Test tile and pad pattern"), llvm::cl::init(false)}; 87*3fef2d26SRiver Riddle Option<int> testHoistPadding{*this, "test-hoist-padding", 88*3fef2d26SRiver Riddle llvm::cl::desc("Test hoist padding"), 89*3fef2d26SRiver Riddle llvm::cl::init(0)}; 90*3fef2d26SRiver Riddle ListOption<int64_t> tileSizesForPadding{ 91*3fef2d26SRiver Riddle *this, "tile-sizes-for-padding", 92*3fef2d26SRiver Riddle llvm::cl::desc("Linalg tile sizes when tile+pad"), llvm::cl::ZeroOrMore, 93*3fef2d26SRiver Riddle llvm::cl::MiscFlags::CommaSeparated}; 94*3fef2d26SRiver Riddle ListOption<unsigned> testInterchangePattern{ 95*3fef2d26SRiver Riddle *this, "test-interchange-pattern", llvm::cl::MiscFlags::CommaSeparated, 96*3fef2d26SRiver Riddle llvm::cl::desc("Test the interchange pattern.")}; 97*3fef2d26SRiver Riddle }; 98*3fef2d26SRiver Riddle } // end anonymous namespace 99*3fef2d26SRiver Riddle 100*3fef2d26SRiver Riddle static void applyPatterns(FuncOp funcOp) { 101*3fef2d26SRiver Riddle MLIRContext *ctx = funcOp.getContext(); 102*3fef2d26SRiver Riddle RewritePatternSet patterns(ctx); 103*3fef2d26SRiver Riddle 104*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 105*3fef2d26SRiver Riddle // Linalg tiling patterns. 106*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 107*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 108*3fef2d26SRiver Riddle ctx, LinalgTilingOptions().setTileSizes({2000, 3000, 4000}), 109*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("MEM", ctx), 110*3fef2d26SRiver Riddle Identifier::get("L3", ctx))); 111*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 112*3fef2d26SRiver Riddle ctx, LinalgTilingOptions().setTileSizes({200, 300, 400}), 113*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("L3", ctx), 114*3fef2d26SRiver Riddle Identifier::get("L2", ctx))); 115*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 116*3fef2d26SRiver Riddle ctx, LinalgTilingOptions().setTileSizes({20, 30, 40}), 117*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("L2", ctx), 118*3fef2d26SRiver Riddle Identifier::get("L1", ctx))); 119*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 120*3fef2d26SRiver Riddle ctx, LinalgTilingOptions().setTileSizes({2, 3, 4}), 121*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("L1", ctx), 122*3fef2d26SRiver Riddle Identifier::get("REG", ctx))); 123*3fef2d26SRiver Riddle 124*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatvecOp>>( 125*3fef2d26SRiver Riddle ctx, 126*3fef2d26SRiver Riddle LinalgTilingOptions().setTileSizes({5, 6}).setLoopType( 127*3fef2d26SRiver Riddle LinalgTilingLoopType::ParallelLoops), 128*3fef2d26SRiver Riddle LinalgTransformationFilter(ArrayRef<Identifier>{}, 129*3fef2d26SRiver Riddle Identifier::get("L1", ctx))); 130*3fef2d26SRiver Riddle 131*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<DotOp>>( 132*3fef2d26SRiver Riddle ctx, LinalgTilingOptions().setTileSizes(8000), 133*3fef2d26SRiver Riddle LinalgTransformationFilter( 134*3fef2d26SRiver Riddle ArrayRef<Identifier>{Identifier::get("MEM", ctx), 135*3fef2d26SRiver Riddle Identifier::get("L3", ctx), 136*3fef2d26SRiver Riddle Identifier::get("L2", ctx)}, 137*3fef2d26SRiver Riddle Identifier::get("REG", ctx))); 138*3fef2d26SRiver Riddle 139*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 140*3fef2d26SRiver Riddle // Linalg tiling and permutation patterns. 141*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 142*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 143*3fef2d26SRiver Riddle ctx, 144*3fef2d26SRiver Riddle LinalgTilingOptions() 145*3fef2d26SRiver Riddle .setTileSizes({2000, 3000, 4000}) 146*3fef2d26SRiver Riddle .setInterchange({1, 2, 0}), 147*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("__with_perm__", ctx), 148*3fef2d26SRiver Riddle Identifier::get("L2__with_perm__", ctx))); 149*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 150*3fef2d26SRiver Riddle ctx, 151*3fef2d26SRiver Riddle LinalgTilingOptions() 152*3fef2d26SRiver Riddle .setTileSizes({200, 300, 400}) 153*3fef2d26SRiver Riddle .setInterchange({1, 0, 2}), 154*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("L2__with_perm__", ctx), 155*3fef2d26SRiver Riddle Identifier::get("L1__with_perm__", ctx))); 156*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 157*3fef2d26SRiver Riddle ctx, LinalgTilingOptions().setTileSizes({20, 30, 40}), 158*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("L1__with_perm__", ctx), 159*3fef2d26SRiver Riddle Identifier::get("REG__with_perm__", ctx))); 160*3fef2d26SRiver Riddle 161*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatvecOp>>( 162*3fef2d26SRiver Riddle ctx, LinalgTilingOptions().setTileSizes({5, 6}).setInterchange({1, 0}), 163*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("__with_perm__", ctx), 164*3fef2d26SRiver Riddle Identifier::get("L1__with_perm__", ctx))); 165*3fef2d26SRiver Riddle 166*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 167*3fef2d26SRiver Riddle ctx, 168*3fef2d26SRiver Riddle LinalgTilingOptions() 169*3fef2d26SRiver Riddle .setTileSizes({16, 8, 4}) 170*3fef2d26SRiver Riddle .setInterchange({1, 2, 0}) 171*3fef2d26SRiver Riddle .setLoopType(LinalgTilingLoopType::ParallelLoops), 172*3fef2d26SRiver Riddle LinalgTransformationFilter( 173*3fef2d26SRiver Riddle Identifier::get("par__with_perm__", ctx), 174*3fef2d26SRiver Riddle Identifier::get("after_par__with_perm__", ctx))); 175*3fef2d26SRiver Riddle 176*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 177*3fef2d26SRiver Riddle // Linalg to loops patterns. 178*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 179*3fef2d26SRiver Riddle patterns.add<LinalgLoweringPattern<DotOp>>( 180*3fef2d26SRiver Riddle ctx, 181*3fef2d26SRiver Riddle /*loweringType=*/LinalgLoweringType::Loops, 182*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("REG", ctx))); 183*3fef2d26SRiver Riddle 184*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 185*3fef2d26SRiver Riddle // Linalg distribution patterns. 186*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 187*3fef2d26SRiver Riddle LinalgLoopDistributionOptions distributionOptions; 188*3fef2d26SRiver Riddle 189*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 190*3fef2d26SRiver Riddle // Linalg to vector contraction patterns. 191*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 192*3fef2d26SRiver Riddle patterns.add<LinalgVectorizationPattern>( 193*3fef2d26SRiver Riddle ctx, LinalgTransformationFilter(Identifier::get("VECTORIZE", ctx)) 194*3fef2d26SRiver Riddle .addOpFilter<MatmulOp, FillOp, CopyOp, GenericOp>()); 195*3fef2d26SRiver Riddle 196*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 197*3fef2d26SRiver Riddle // Linalg generic interchange pattern. 198*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 199*3fef2d26SRiver Riddle patterns.add<GenericOpInterchangePattern>( 200*3fef2d26SRiver Riddle ctx, 201*3fef2d26SRiver Riddle /*interchangeVector=*/ArrayRef<unsigned>{1, 2, 0}, 202*3fef2d26SRiver Riddle LinalgTransformationFilter(ArrayRef<Identifier>{}, 203*3fef2d26SRiver Riddle Identifier::get("PERMUTED", ctx))); 204*3fef2d26SRiver Riddle 205*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 206*3fef2d26SRiver Riddle // Linalg subview operands promotion. 207*3fef2d26SRiver Riddle //===--------------------------------------------------------------------===// 208*3fef2d26SRiver Riddle patterns.add<LinalgPromotionPattern<MatmulOp>>( 209*3fef2d26SRiver Riddle ctx, LinalgPromotionOptions().setUseFullTileBuffersByDefault(true), 210*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("_promote_views_", ctx), 211*3fef2d26SRiver Riddle Identifier::get("_views_promoted_", ctx))); 212*3fef2d26SRiver Riddle patterns.add<LinalgPromotionPattern<MatmulOp>>( 213*3fef2d26SRiver Riddle ctx, 214*3fef2d26SRiver Riddle LinalgPromotionOptions() 215*3fef2d26SRiver Riddle .setOperandsToPromote({0}) 216*3fef2d26SRiver Riddle .setUseFullTileBuffersByDefault(true), 217*3fef2d26SRiver Riddle LinalgTransformationFilter( 218*3fef2d26SRiver Riddle Identifier::get("_promote_first_view_", ctx), 219*3fef2d26SRiver Riddle Identifier::get("_first_view_promoted_", ctx))); 220*3fef2d26SRiver Riddle patterns.add<LinalgPromotionPattern<FillOp>>( 221*3fef2d26SRiver Riddle ctx, 222*3fef2d26SRiver Riddle LinalgPromotionOptions() 223*3fef2d26SRiver Riddle .setOperandsToPromote({0}) 224*3fef2d26SRiver Riddle .setUseFullTileBuffers({true}) 225*3fef2d26SRiver Riddle .setAlignment(32), 226*3fef2d26SRiver Riddle LinalgTransformationFilter( 227*3fef2d26SRiver Riddle Identifier::get("_promote_views_aligned_", ctx), 228*3fef2d26SRiver Riddle Identifier::get("_views_aligned_promoted_", ctx))); 229*3fef2d26SRiver Riddle 230*3fef2d26SRiver Riddle (void)applyPatternsAndFoldGreedily(funcOp, std::move(patterns)); 231*3fef2d26SRiver Riddle 232*3fef2d26SRiver Riddle // Drop the marker. 233*3fef2d26SRiver Riddle funcOp.walk([](LinalgOp op) { 234*3fef2d26SRiver Riddle op->removeAttr(LinalgTransforms::kLinalgTransformMarker); 235*3fef2d26SRiver Riddle }); 236*3fef2d26SRiver Riddle } 237*3fef2d26SRiver Riddle 238*3fef2d26SRiver Riddle static void fillL1TilingAndMatmulToVectorPatterns( 239*3fef2d26SRiver Riddle FuncOp funcOp, StringRef startMarker, 240*3fef2d26SRiver Riddle SmallVectorImpl<RewritePatternSet> &patternsVector) { 241*3fef2d26SRiver Riddle MLIRContext *ctx = funcOp.getContext(); 242*3fef2d26SRiver Riddle patternsVector.emplace_back( 243*3fef2d26SRiver Riddle ctx, std::make_unique<LinalgTilingPattern<MatmulOp>>( 244*3fef2d26SRiver Riddle ctx, 245*3fef2d26SRiver Riddle LinalgTilingOptions() 246*3fef2d26SRiver Riddle .setTileSizes({8, 12, 16}) 247*3fef2d26SRiver Riddle .setInterchange({1, 0, 2}), 248*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get(startMarker, ctx), 249*3fef2d26SRiver Riddle Identifier::get("L1", ctx)))); 250*3fef2d26SRiver Riddle 251*3fef2d26SRiver Riddle patternsVector.emplace_back( 252*3fef2d26SRiver Riddle ctx, 253*3fef2d26SRiver Riddle std::make_unique<LinalgPromotionPattern<MatmulOp>>( 254*3fef2d26SRiver Riddle ctx, LinalgPromotionOptions().setUseFullTileBuffersByDefault(true), 255*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("L1", ctx), 256*3fef2d26SRiver Riddle Identifier::get("VEC", ctx)))); 257*3fef2d26SRiver Riddle 258*3fef2d26SRiver Riddle patternsVector.emplace_back( 259*3fef2d26SRiver Riddle ctx, std::make_unique<LinalgVectorizationPattern>( 260*3fef2d26SRiver Riddle MatmulOp::getOperationName(), ctx, LinalgVectorizationOptions(), 261*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("VEC", ctx)))); 262*3fef2d26SRiver Riddle patternsVector.back().add<LinalgVectorizationPattern>( 263*3fef2d26SRiver Riddle ctx, LinalgTransformationFilter().addFilter( 264*3fef2d26SRiver Riddle [](Operation *op) { return success(isa<FillOp, CopyOp>(op)); })); 265*3fef2d26SRiver Riddle } 266*3fef2d26SRiver Riddle 267*3fef2d26SRiver Riddle //===----------------------------------------------------------------------===// 268*3fef2d26SRiver Riddle // Test promotion callbacks 269*3fef2d26SRiver Riddle //===----------------------------------------------------------------------===// 270*3fef2d26SRiver Riddle 271*3fef2d26SRiver Riddle // Allocation call back 272*3fef2d26SRiver Riddle static Optional<Value> allocCallBackFn(OpBuilder &b, memref::SubViewOp subView, 273*3fef2d26SRiver Riddle ArrayRef<Value> boundingSubViewSize, 274*3fef2d26SRiver Riddle DataLayout &layout, 275*3fef2d26SRiver Riddle OperationFolder *folder) { 276*3fef2d26SRiver Riddle SmallVector<int64_t, 4> shape(boundingSubViewSize.size(), -1); 277*3fef2d26SRiver Riddle return b 278*3fef2d26SRiver Riddle .create<memref::AllocOp>( 279*3fef2d26SRiver Riddle subView.getLoc(), 280*3fef2d26SRiver Riddle MemRefType::get(shape, subView.getType().getElementType(), 281*3fef2d26SRiver Riddle /*affineMapComposition =*/{}, 3), 282*3fef2d26SRiver Riddle boundingSubViewSize) 283*3fef2d26SRiver Riddle .getResult(); 284*3fef2d26SRiver Riddle } 285*3fef2d26SRiver Riddle 286*3fef2d26SRiver Riddle // Deallocation callback 287*3fef2d26SRiver Riddle static LogicalResult deallocCallBackFn(OpBuilder &b, Value buffer) { 288*3fef2d26SRiver Riddle b.create<memref::DeallocOp>(buffer.getLoc(), buffer); 289*3fef2d26SRiver Riddle return success(); 290*3fef2d26SRiver Riddle } 291*3fef2d26SRiver Riddle 292*3fef2d26SRiver Riddle // Copy in call back 293*3fef2d26SRiver Riddle static LogicalResult copyCallBackFn(OpBuilder &b, Value src, Value dst, 294*3fef2d26SRiver Riddle bool isOutput) { 295*3fef2d26SRiver Riddle auto floatType = src.getType().cast<MemRefType>().getElementType(); 296*3fef2d26SRiver Riddle if (!floatType.isa<FloatType>()) 297*3fef2d26SRiver Riddle return failure(); 298*3fef2d26SRiver Riddle if (!isOutput) 299*3fef2d26SRiver Riddle b.create<FillOp>( 300*3fef2d26SRiver Riddle src.getLoc(), dst, 301*3fef2d26SRiver Riddle b.create<ConstantOp>(src.getLoc(), FloatAttr::get(floatType, 42.0))); 302*3fef2d26SRiver Riddle b.create<CopyOp>(src.getLoc(), src, dst); 303*3fef2d26SRiver Riddle return success(); 304*3fef2d26SRiver Riddle } 305*3fef2d26SRiver Riddle 306*3fef2d26SRiver Riddle static void fillPromotionCallBackPatterns(MLIRContext *ctx, 307*3fef2d26SRiver Riddle RewritePatternSet &patterns) { 308*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 309*3fef2d26SRiver Riddle ctx, LinalgTilingOptions().setTileSizes({16, 16, 16}), 310*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("START", ctx), 311*3fef2d26SRiver Riddle Identifier::get("PROMOTE", ctx))); 312*3fef2d26SRiver Riddle patterns.add<LinalgPromotionPattern<MatmulOp>>( 313*3fef2d26SRiver Riddle ctx, 314*3fef2d26SRiver Riddle LinalgPromotionOptions() 315*3fef2d26SRiver Riddle .setOperandsToPromote({0, 2}) 316*3fef2d26SRiver Riddle .setUseFullTileBuffers({false, false}) 317*3fef2d26SRiver Riddle .setAllocationDeallocationFns(allocCallBackFn, deallocCallBackFn) 318*3fef2d26SRiver Riddle .setCopyInOutFns( 319*3fef2d26SRiver Riddle [](OpBuilder &b, Value src, Value dst) -> LogicalResult { 320*3fef2d26SRiver Riddle return copyCallBackFn(b, src, dst, false); 321*3fef2d26SRiver Riddle }, 322*3fef2d26SRiver Riddle [](OpBuilder &b, Value src, Value dst) -> LogicalResult { 323*3fef2d26SRiver Riddle return copyCallBackFn(b, src, dst, true); 324*3fef2d26SRiver Riddle }), 325*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("PROMOTE", ctx))); 326*3fef2d26SRiver Riddle } 327*3fef2d26SRiver Riddle 328*3fef2d26SRiver Riddle template <typename IdOp, typename NProcsOp> 329*3fef2d26SRiver Riddle static SmallVector<ProcInfo, 2> 330*3fef2d26SRiver Riddle getGpuProcIds(OpBuilder &b, Location loc, ArrayRef<Range> parallelLoopRanges) { 331*3fef2d26SRiver Riddle size_t count = std::min<size_t>(3, parallelLoopRanges.size()); 332*3fef2d26SRiver Riddle SmallVector<ProcInfo, 2> procInfo(count); 333*3fef2d26SRiver Riddle const char *xyz[] = {"x", "y", "z"}; 334*3fef2d26SRiver Riddle Type indexType = b.getIndexType(); 335*3fef2d26SRiver Riddle for (unsigned i = 0; i < count; ++i) { 336*3fef2d26SRiver Riddle procInfo[count - 1 - i] = { 337*3fef2d26SRiver Riddle b.create<IdOp>(loc, indexType, b.getStringAttr(xyz[i])), 338*3fef2d26SRiver Riddle b.create<NProcsOp>(loc, indexType, b.getStringAttr(xyz[i]))}; 339*3fef2d26SRiver Riddle } 340*3fef2d26SRiver Riddle return procInfo; 341*3fef2d26SRiver Riddle } 342*3fef2d26SRiver Riddle 343*3fef2d26SRiver Riddle static void fillTileAndDistributePatterns(MLIRContext *context, 344*3fef2d26SRiver Riddle RewritePatternSet &patterns) { 345*3fef2d26SRiver Riddle { 346*3fef2d26SRiver Riddle LinalgLoopDistributionOptions cyclicNprocsEqNiters; 347*3fef2d26SRiver Riddle cyclicNprocsEqNiters.distributionMethod.resize( 348*3fef2d26SRiver Riddle 2, DistributionMethod::CyclicNumProcsEqNumIters); 349*3fef2d26SRiver Riddle cyclicNprocsEqNiters.procInfo = 350*3fef2d26SRiver Riddle getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>; 351*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 352*3fef2d26SRiver Riddle context, 353*3fef2d26SRiver Riddle LinalgTilingOptions() 354*3fef2d26SRiver Riddle .setTileSizes({8, 8, 4}) 355*3fef2d26SRiver Riddle .setLoopType(LinalgTilingLoopType::ParallelLoops) 356*3fef2d26SRiver Riddle .setDistributionOptions(cyclicNprocsEqNiters), 357*3fef2d26SRiver Riddle LinalgTransformationFilter( 358*3fef2d26SRiver Riddle Identifier::get("distribute1", context), 359*3fef2d26SRiver Riddle Identifier::get("after_distribute1", context))); 360*3fef2d26SRiver Riddle } 361*3fef2d26SRiver Riddle 362*3fef2d26SRiver Riddle { 363*3fef2d26SRiver Riddle LinalgLoopDistributionOptions cyclicNprocsGeNiters; 364*3fef2d26SRiver Riddle cyclicNprocsGeNiters.distributionMethod.resize( 365*3fef2d26SRiver Riddle 2, DistributionMethod::CyclicNumProcsGeNumIters); 366*3fef2d26SRiver Riddle cyclicNprocsGeNiters.procInfo = 367*3fef2d26SRiver Riddle getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>; 368*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 369*3fef2d26SRiver Riddle context, 370*3fef2d26SRiver Riddle LinalgTilingOptions() 371*3fef2d26SRiver Riddle .setTileSizes({8, 8, 4}) 372*3fef2d26SRiver Riddle .setLoopType(LinalgTilingLoopType::ParallelLoops) 373*3fef2d26SRiver Riddle .setDistributionOptions(cyclicNprocsGeNiters), 374*3fef2d26SRiver Riddle LinalgTransformationFilter( 375*3fef2d26SRiver Riddle Identifier::get("distribute2", context), 376*3fef2d26SRiver Riddle Identifier::get("after_distribute2", context))); 377*3fef2d26SRiver Riddle } 378*3fef2d26SRiver Riddle 379*3fef2d26SRiver Riddle { 380*3fef2d26SRiver Riddle LinalgLoopDistributionOptions cyclicNprocsDefault; 381*3fef2d26SRiver Riddle cyclicNprocsDefault.distributionMethod.resize(2, 382*3fef2d26SRiver Riddle DistributionMethod::Cyclic); 383*3fef2d26SRiver Riddle cyclicNprocsDefault.procInfo = 384*3fef2d26SRiver Riddle getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>; 385*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 386*3fef2d26SRiver Riddle context, 387*3fef2d26SRiver Riddle LinalgTilingOptions() 388*3fef2d26SRiver Riddle .setTileSizes({8, 8, 4}) 389*3fef2d26SRiver Riddle .setLoopType(LinalgTilingLoopType::ParallelLoops) 390*3fef2d26SRiver Riddle .setDistributionOptions(cyclicNprocsDefault), 391*3fef2d26SRiver Riddle LinalgTransformationFilter( 392*3fef2d26SRiver Riddle Identifier::get("distribute3", context), 393*3fef2d26SRiver Riddle Identifier::get("after_distribute3", context))); 394*3fef2d26SRiver Riddle } 395*3fef2d26SRiver Riddle 396*3fef2d26SRiver Riddle { 397*3fef2d26SRiver Riddle LinalgLoopDistributionOptions cyclicNprocsMixed1; 398*3fef2d26SRiver Riddle cyclicNprocsMixed1.distributionMethod = { 399*3fef2d26SRiver Riddle DistributionMethod::CyclicNumProcsEqNumIters, 400*3fef2d26SRiver Riddle DistributionMethod::CyclicNumProcsGeNumIters}; 401*3fef2d26SRiver Riddle cyclicNprocsMixed1.procInfo = getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>; 402*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 403*3fef2d26SRiver Riddle context, 404*3fef2d26SRiver Riddle LinalgTilingOptions() 405*3fef2d26SRiver Riddle .setTileSizes({8, 8, 4}) 406*3fef2d26SRiver Riddle .setLoopType(LinalgTilingLoopType::ParallelLoops) 407*3fef2d26SRiver Riddle .setDistributionOptions(cyclicNprocsMixed1), 408*3fef2d26SRiver Riddle LinalgTransformationFilter( 409*3fef2d26SRiver Riddle Identifier::get("distribute4", context), 410*3fef2d26SRiver Riddle Identifier::get("after_distribute4", context))); 411*3fef2d26SRiver Riddle } 412*3fef2d26SRiver Riddle 413*3fef2d26SRiver Riddle { 414*3fef2d26SRiver Riddle LinalgLoopDistributionOptions cyclicNprocsMixed2; 415*3fef2d26SRiver Riddle cyclicNprocsMixed2.distributionMethod = { 416*3fef2d26SRiver Riddle DistributionMethod::CyclicNumProcsGeNumIters, 417*3fef2d26SRiver Riddle DistributionMethod::Cyclic}; 418*3fef2d26SRiver Riddle cyclicNprocsMixed2.procInfo = getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>; 419*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 420*3fef2d26SRiver Riddle context, 421*3fef2d26SRiver Riddle LinalgTilingOptions() 422*3fef2d26SRiver Riddle .setTileSizes({8, 8, 4}) 423*3fef2d26SRiver Riddle .setLoopType(LinalgTilingLoopType::ParallelLoops) 424*3fef2d26SRiver Riddle .setDistributionOptions(cyclicNprocsMixed2), 425*3fef2d26SRiver Riddle LinalgTransformationFilter( 426*3fef2d26SRiver Riddle Identifier::get("distribute5", context), 427*3fef2d26SRiver Riddle Identifier::get("after_distribute5", context))); 428*3fef2d26SRiver Riddle } 429*3fef2d26SRiver Riddle 430*3fef2d26SRiver Riddle { 431*3fef2d26SRiver Riddle LinalgLoopDistributionOptions cyclicNprocsMixed3; 432*3fef2d26SRiver Riddle cyclicNprocsMixed3.distributionMethod = { 433*3fef2d26SRiver Riddle DistributionMethod::Cyclic, 434*3fef2d26SRiver Riddle DistributionMethod::CyclicNumProcsEqNumIters}; 435*3fef2d26SRiver Riddle cyclicNprocsMixed3.procInfo = getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>; 436*3fef2d26SRiver Riddle 437*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 438*3fef2d26SRiver Riddle context, 439*3fef2d26SRiver Riddle LinalgTilingOptions() 440*3fef2d26SRiver Riddle .setTileSizes({8, 8, 4}) 441*3fef2d26SRiver Riddle .setLoopType(LinalgTilingLoopType::ParallelLoops) 442*3fef2d26SRiver Riddle .setDistributionOptions(cyclicNprocsMixed3), 443*3fef2d26SRiver Riddle LinalgTransformationFilter( 444*3fef2d26SRiver Riddle Identifier::get("distribute6", context), 445*3fef2d26SRiver Riddle Identifier::get("after_distribute6", context))); 446*3fef2d26SRiver Riddle } 447*3fef2d26SRiver Riddle 448*3fef2d26SRiver Riddle { 449*3fef2d26SRiver Riddle LinalgLoopDistributionOptions cyclicNprocsEqNiters; 450*3fef2d26SRiver Riddle cyclicNprocsEqNiters.distributionMethod.resize(2, 451*3fef2d26SRiver Riddle DistributionMethod::Cyclic); 452*3fef2d26SRiver Riddle cyclicNprocsEqNiters.procInfo = 453*3fef2d26SRiver Riddle getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>; 454*3fef2d26SRiver Riddle patterns.add<LinalgTilingPattern<MatmulOp>>( 455*3fef2d26SRiver Riddle context, 456*3fef2d26SRiver Riddle LinalgTilingOptions() 457*3fef2d26SRiver Riddle .setTileSizes({8, 8, 4}) 458*3fef2d26SRiver Riddle .setLoopType(LinalgTilingLoopType::Loops) 459*3fef2d26SRiver Riddle .setDistributionOptions(cyclicNprocsEqNiters), 460*3fef2d26SRiver Riddle LinalgTransformationFilter( 461*3fef2d26SRiver Riddle Identifier::get("tensors_distribute1", context), 462*3fef2d26SRiver Riddle Identifier::get("tensors_after_distribute1", context))); 463*3fef2d26SRiver Riddle } 464*3fef2d26SRiver Riddle } 465*3fef2d26SRiver Riddle 466*3fef2d26SRiver Riddle static void 467*3fef2d26SRiver Riddle applyMatmulToVectorPatterns(FuncOp funcOp, 468*3fef2d26SRiver Riddle bool testMatmulToVectorPatterns1dTiling, 469*3fef2d26SRiver Riddle bool testMatmulToVectorPatterns2dTiling) { 470*3fef2d26SRiver Riddle MLIRContext *ctx = funcOp.getContext(); 471*3fef2d26SRiver Riddle SmallVector<RewritePatternSet, 4> stage1Patterns; 472*3fef2d26SRiver Riddle if (testMatmulToVectorPatterns1dTiling) { 473*3fef2d26SRiver Riddle fillL1TilingAndMatmulToVectorPatterns(funcOp, Identifier::get("START", ctx), 474*3fef2d26SRiver Riddle stage1Patterns); 475*3fef2d26SRiver Riddle } else if (testMatmulToVectorPatterns2dTiling) { 476*3fef2d26SRiver Riddle stage1Patterns.emplace_back( 477*3fef2d26SRiver Riddle ctx, std::make_unique<LinalgTilingPattern<MatmulOp>>( 478*3fef2d26SRiver Riddle ctx, 479*3fef2d26SRiver Riddle LinalgTilingOptions() 480*3fef2d26SRiver Riddle .setTileSizes({768, 264, 768}) 481*3fef2d26SRiver Riddle .setInterchange({1, 2, 0}), 482*3fef2d26SRiver Riddle LinalgTransformationFilter(Identifier::get("START", ctx), 483*3fef2d26SRiver Riddle Identifier::get("L2", ctx)))); 484*3fef2d26SRiver Riddle fillL1TilingAndMatmulToVectorPatterns(funcOp, Identifier::get("L2", ctx), 485*3fef2d26SRiver Riddle stage1Patterns); 486*3fef2d26SRiver Riddle } 487*3fef2d26SRiver Riddle SmallVector<FrozenRewritePatternSet, 4> frozenStage1Patterns; 488*3fef2d26SRiver Riddle llvm::move(stage1Patterns, std::back_inserter(frozenStage1Patterns)); 489*3fef2d26SRiver Riddle FrozenRewritePatternSet stage2Patterns = 490*3fef2d26SRiver Riddle getLinalgTilingCanonicalizationPatterns(ctx); 491*3fef2d26SRiver Riddle (void)applyStagedPatterns(funcOp, frozenStage1Patterns, 492*3fef2d26SRiver Riddle std::move(stage2Patterns)); 493*3fef2d26SRiver Riddle } 494*3fef2d26SRiver Riddle 495*3fef2d26SRiver Riddle static void applyVectorTransferForwardingPatterns(FuncOp funcOp) { 496*3fef2d26SRiver Riddle RewritePatternSet forwardPattern(funcOp.getContext()); 497*3fef2d26SRiver Riddle forwardPattern.add<LinalgCopyVTRForwardingPattern>(funcOp.getContext()); 498*3fef2d26SRiver Riddle forwardPattern.add<LinalgCopyVTWForwardingPattern>(funcOp.getContext()); 499*3fef2d26SRiver Riddle (void)applyPatternsAndFoldGreedily(funcOp, std::move(forwardPattern)); 500*3fef2d26SRiver Riddle } 501*3fef2d26SRiver Riddle 502*3fef2d26SRiver Riddle static void applyLinalgToVectorPatterns(FuncOp funcOp) { 503*3fef2d26SRiver Riddle RewritePatternSet patterns(funcOp.getContext()); 504*3fef2d26SRiver Riddle patterns.add<LinalgVectorizationPattern>( 505*3fef2d26SRiver Riddle funcOp.getContext(), 506*3fef2d26SRiver Riddle LinalgTransformationFilter() 507*3fef2d26SRiver Riddle .addOpFilter<ContractionOpInterface, FillOp, CopyOp, GenericOp>()); 508*3fef2d26SRiver Riddle patterns.add<PadTensorOpVectorizationPattern>(funcOp.getContext()); 509*3fef2d26SRiver Riddle (void)applyPatternsAndFoldGreedily(funcOp, std::move(patterns)); 510*3fef2d26SRiver Riddle } 511*3fef2d26SRiver Riddle 512*3fef2d26SRiver Riddle static void applyAffineMinSCFCanonicalizationPatterns(FuncOp funcOp) { 513*3fef2d26SRiver Riddle RewritePatternSet foldPattern(funcOp.getContext()); 514*3fef2d26SRiver Riddle foldPattern.add<AffineMinSCFCanonicalizationPattern>(funcOp.getContext()); 515*3fef2d26SRiver Riddle FrozenRewritePatternSet frozenPatterns(std::move(foldPattern)); 516*3fef2d26SRiver Riddle 517*3fef2d26SRiver Riddle // Explicitly walk and apply the pattern locally to avoid more general folding 518*3fef2d26SRiver Riddle // on the rest of the IR. 519*3fef2d26SRiver Riddle funcOp.walk([&frozenPatterns](AffineMinOp minOp) { 520*3fef2d26SRiver Riddle (void)applyOpPatternsAndFold(minOp, frozenPatterns); 521*3fef2d26SRiver Riddle }); 522*3fef2d26SRiver Riddle } 523*3fef2d26SRiver Riddle 524*3fef2d26SRiver Riddle // For now, just assume it is the zero of type. 525*3fef2d26SRiver Riddle // In the future, it should be the zero of type + op. 526*3fef2d26SRiver Riddle static Value getNeutralOfLinalgOp(OpBuilder &b, OpOperand &op) { 527*3fef2d26SRiver Riddle auto t = getElementTypeOrSelf(op.get().getType()); 528*3fef2d26SRiver Riddle return b.create<ConstantOp>(op.getOwner()->getLoc(), t, b.getZeroAttr(t)); 529*3fef2d26SRiver Riddle } 530*3fef2d26SRiver Riddle 531*3fef2d26SRiver Riddle static void applyTileAndPadPattern(FuncOp funcOp, ArrayRef<int64_t> tileSizes) { 532*3fef2d26SRiver Riddle MLIRContext *context = funcOp.getContext(); 533*3fef2d26SRiver Riddle RewritePatternSet tilingPattern(context); 534*3fef2d26SRiver Riddle auto linalgTilingOptions = 535*3fef2d26SRiver Riddle linalg::LinalgTilingOptions() 536*3fef2d26SRiver Riddle .setTileSizes(tileSizes) 537*3fef2d26SRiver Riddle .setPaddingValueComputationFunction(getNeutralOfLinalgOp); 538*3fef2d26SRiver Riddle tilingPattern.add<linalg::LinalgTilingPattern<linalg::MatmulI8I8I32Op>>( 539*3fef2d26SRiver Riddle context, linalgTilingOptions, 540*3fef2d26SRiver Riddle linalg::LinalgTransformationFilter( 541*3fef2d26SRiver Riddle Identifier::get("tile-and-pad", context))); 542*3fef2d26SRiver Riddle (void)applyPatternsAndFoldGreedily(funcOp, std::move(tilingPattern)); 543*3fef2d26SRiver Riddle } 544*3fef2d26SRiver Riddle 545*3fef2d26SRiver Riddle static void applyInterchangePattern(FuncOp funcOp, 546*3fef2d26SRiver Riddle ArrayRef<unsigned> interchangeVector) { 547*3fef2d26SRiver Riddle MLIRContext *context = funcOp.getContext(); 548*3fef2d26SRiver Riddle RewritePatternSet interchangePattern(context); 549*3fef2d26SRiver Riddle interchangePattern.add<GenericOpInterchangePattern>( 550*3fef2d26SRiver Riddle context, interchangeVector, 551*3fef2d26SRiver Riddle LinalgTransformationFilter(ArrayRef<Identifier>{}, 552*3fef2d26SRiver Riddle Identifier::get("interchange", context))); 553*3fef2d26SRiver Riddle (void)applyPatternsAndFoldGreedily(funcOp, std::move(interchangePattern)); 554*3fef2d26SRiver Riddle } 555*3fef2d26SRiver Riddle 556*3fef2d26SRiver Riddle /// Apply transformations specified as patterns. 557*3fef2d26SRiver Riddle void TestLinalgTransforms::runOnFunction() { 558*3fef2d26SRiver Riddle auto lambda = [&](void *) { 559*3fef2d26SRiver Riddle getFunction().walk([](LinalgOp op) { 560*3fef2d26SRiver Riddle op->removeAttr(LinalgTransforms::kLinalgTransformMarker); 561*3fef2d26SRiver Riddle }); 562*3fef2d26SRiver Riddle }; 563*3fef2d26SRiver Riddle std::unique_ptr<void, decltype(lambda)> cleanupGuard{(void *)1, lambda}; 564*3fef2d26SRiver Riddle 565*3fef2d26SRiver Riddle if (testPromotionOptions) { 566*3fef2d26SRiver Riddle RewritePatternSet patterns(&getContext()); 567*3fef2d26SRiver Riddle fillPromotionCallBackPatterns(&getContext(), patterns); 568*3fef2d26SRiver Riddle (void)applyPatternsAndFoldGreedily(getFunction(), std::move(patterns)); 569*3fef2d26SRiver Riddle return; 570*3fef2d26SRiver Riddle } 571*3fef2d26SRiver Riddle if (testTileAndDistributionOptions) { 572*3fef2d26SRiver Riddle RewritePatternSet patterns(&getContext()); 573*3fef2d26SRiver Riddle fillTileAndDistributePatterns(&getContext(), patterns); 574*3fef2d26SRiver Riddle (void)applyPatternsAndFoldGreedily(getFunction(), std::move(patterns)); 575*3fef2d26SRiver Riddle return; 576*3fef2d26SRiver Riddle } 577*3fef2d26SRiver Riddle if (testPatterns) 578*3fef2d26SRiver Riddle return applyPatterns(getFunction()); 579*3fef2d26SRiver Riddle if (testMatmulToVectorPatterns1dTiling || testMatmulToVectorPatterns2dTiling) 580*3fef2d26SRiver Riddle return applyMatmulToVectorPatterns(getFunction(), 581*3fef2d26SRiver Riddle testMatmulToVectorPatterns1dTiling, 582*3fef2d26SRiver Riddle testMatmulToVectorPatterns2dTiling); 583*3fef2d26SRiver Riddle if (testVectorTransferForwardingPatterns) 584*3fef2d26SRiver Riddle return applyVectorTransferForwardingPatterns(getFunction()); 585*3fef2d26SRiver Riddle if (testGenericToVectorPattern) 586*3fef2d26SRiver Riddle return applyLinalgToVectorPatterns(getFunction()); 587*3fef2d26SRiver Riddle if (testAffineMinSCFCanonicalizationPatterns) 588*3fef2d26SRiver Riddle return applyAffineMinSCFCanonicalizationPatterns(getFunction()); 589*3fef2d26SRiver Riddle if (testTileAndPadPattern) 590*3fef2d26SRiver Riddle return applyTileAndPadPattern(getFunction(), tileSizesForPadding); 591*3fef2d26SRiver Riddle if (testHoistPadding) { 592*3fef2d26SRiver Riddle getFunction().walk([&](linalg::PadTensorOp padTensorOp) { 593*3fef2d26SRiver Riddle (void)linalg::hoistPaddingOnTensors(padTensorOp, testHoistPadding); 594*3fef2d26SRiver Riddle }); 595*3fef2d26SRiver Riddle } 596*3fef2d26SRiver Riddle if (testInterchangePattern.hasValue()) 597*3fef2d26SRiver Riddle return applyInterchangePattern(getFunction(), testInterchangePattern); 598*3fef2d26SRiver Riddle } 599*3fef2d26SRiver Riddle 600*3fef2d26SRiver Riddle namespace mlir { 601*3fef2d26SRiver Riddle namespace test { 602*3fef2d26SRiver Riddle void registerTestLinalgTransforms() { 603*3fef2d26SRiver Riddle PassRegistration<TestLinalgTransforms> testTransformPatternsPass( 604*3fef2d26SRiver Riddle "test-linalg-transform-patterns", 605*3fef2d26SRiver Riddle "Test Linalg transformation patterns by applying them greedily."); 606*3fef2d26SRiver Riddle } 607*3fef2d26SRiver Riddle } // namespace test 608*3fef2d26SRiver Riddle } // namespace mlir 609