1 //===- TestLinalgElementwiseFusion.cpp - Test Linalg elementwise fusion ---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements a pass for testing fusion of elementwise operations in 10 // Linalg, mainly linalg options. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "mlir/Dialect/Linalg/Transforms/Transforms.h" 15 #include "mlir/Pass/Pass.h" 16 #include "mlir/Pass/PassManager.h" 17 #include "mlir/Transforms/GreedyPatternRewriteDriver.h" 18 #include "llvm/ADT/TypeSwitch.h" 19 20 namespace mlir { 21 22 static void addOperands(Operation *op, SetVector<Value> &operandSet) { 23 if (!op) 24 return; 25 TypeSwitch<Operation *, void>(op) 26 .Case<linalg::LinalgOp>([&](linalg::LinalgOp linalgOp) { 27 SmallVector<Value> inputOperands = linalgOp.getInputOperands(); 28 operandSet.insert(inputOperands.begin(), inputOperands.end()); 29 }) 30 .Default([&](Operation *operation) { 31 operandSet.insert(operation->operand_begin(), operation->operand_end()); 32 }); 33 } 34 35 template <int limit = 3> 36 static bool setFusedOpOperandLimit(const OpResult &producer, 37 const OpOperand &consumer) { 38 SetVector<Value> fusedOpOperands; 39 if (producer.getOwner()->getNumResults() != 1) 40 return false; 41 addOperands(consumer.getOwner(), fusedOpOperands); 42 fusedOpOperands.remove(producer); 43 addOperands(producer.getOwner(), fusedOpOperands); 44 return fusedOpOperands.size() <= limit; 45 } 46 47 namespace { 48 struct TestLinalgElementwiseFusion 49 : public PassWrapper<TestLinalgElementwiseFusion, FunctionPass> { 50 void getDependentDialects(DialectRegistry ®istry) const override { 51 registry.insert<AffineDialect, linalg::LinalgDialect, memref::MemRefDialect, 52 tensor::TensorDialect>(); 53 } 54 StringRef getArgument() const final { 55 return "test-linalg-elementwise-fusion-patterns"; 56 } 57 StringRef getDescription() const final { 58 return "Test Linalg element wise operation fusion patterns"; 59 } 60 61 void runOnFunction() override { 62 MLIRContext *context = &this->getContext(); 63 FuncOp funcOp = this->getFunction(); 64 RewritePatternSet fusionPatterns(context); 65 66 linalg::populateElementwiseOpsFusionPatterns( 67 fusionPatterns, 68 linalg::LinalgElementwiseFusionOptions() 69 .setControlElementwiseOpsFusionFn(setFusedOpOperandLimit<4>)); 70 71 (void)applyPatternsAndFoldGreedily(funcOp.getBody(), 72 std::move(fusionPatterns)); 73 } 74 }; 75 76 struct TestPushExpandingReshape 77 : public PassWrapper<TestPushExpandingReshape, FunctionPass> { 78 void getDependentDialects(DialectRegistry ®istry) const override { 79 registry 80 .insert<AffineDialect, linalg::LinalgDialect, tensor::TensorDialect>(); 81 } 82 StringRef getArgument() const final { return "test-linalg-push-reshape"; } 83 StringRef getDescription() const final { 84 return "Test Linalg reshape push patterns"; 85 } 86 87 void runOnFunction() override { 88 MLIRContext *context = &this->getContext(); 89 FuncOp funcOp = this->getFunction(); 90 RewritePatternSet patterns(context); 91 linalg::populatePushReshapeOpsPatterns(patterns); 92 (void)applyPatternsAndFoldGreedily(funcOp.getBody(), std::move(patterns)); 93 } 94 }; 95 } // namespace 96 97 namespace test { 98 void registerTestLinalgElementwiseFusion() { 99 PassRegistration<TestLinalgElementwiseFusion>(); 100 } 101 102 void registerTestPushExpandingReshape() { 103 PassRegistration<TestPushExpandingReshape>(); 104 } 105 } // namespace test 106 107 } // namespace mlir 108