github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/test/lib/Transforms/TestLoopFusion.cpp (about) 1 //===- TestLoopFusion.cpp - Test loop fusion ------------------------------===// 2 // 3 // Copyright 2019 The MLIR Authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // ============================================================================= 17 // 18 // This file implements a pass to test various loop fusion utility functions. 19 // 20 //===----------------------------------------------------------------------===// 21 22 #include "mlir/Analysis/AffineAnalysis.h" 23 #include "mlir/Analysis/AffineStructures.h" 24 #include "mlir/Analysis/Passes.h" 25 #include "mlir/Analysis/Utils.h" 26 #include "mlir/Dialect/AffineOps/AffineOps.h" 27 #include "mlir/Dialect/StandardOps/Ops.h" 28 #include "mlir/IR/Builders.h" 29 #include "mlir/Pass/Pass.h" 30 #include "mlir/Transforms/LoopFusionUtils.h" 31 #include "mlir/Transforms/Passes.h" 32 33 #include "llvm/ADT/STLExtras.h" 34 #include "llvm/Support/CommandLine.h" 35 #include "llvm/Support/Debug.h" 36 37 #define DEBUG_TYPE "test-loop-fusion" 38 39 using namespace mlir; 40 41 static llvm::cl::OptionCategory clOptionsCategory(DEBUG_TYPE " options"); 42 43 static llvm::cl::opt<bool> clTestDependenceCheck( 44 "test-loop-fusion-dependence-check", 45 llvm::cl::desc("Enable testing of loop fusion dependence check"), 46 llvm::cl::cat(clOptionsCategory)); 47 48 static llvm::cl::opt<bool> clTestSliceComputation( 49 "test-loop-fusion-slice-computation", 50 llvm::cl::desc("Enable testing of loop fusion slice computation"), 51 llvm::cl::cat(clOptionsCategory)); 52 53 namespace { 54 55 struct TestLoopFusion : public FunctionPass<TestLoopFusion> { 56 void runOnFunction() override; 57 }; 58 59 } // end anonymous namespace 60 61 std::unique_ptr<FunctionPassBase> mlir::createTestLoopFusionPass() { 62 return std::make_unique<TestLoopFusion>(); 63 } 64 65 // Gathers all AffineForOps in 'block' at 'currLoopDepth' in 'depthToLoops'. 66 static void 67 gatherLoops(Block *block, unsigned currLoopDepth, 68 DenseMap<unsigned, SmallVector<AffineForOp, 2>> &depthToLoops) { 69 auto &loopsAtDepth = depthToLoops[currLoopDepth]; 70 for (auto &op : *block) { 71 if (auto forOp = dyn_cast<AffineForOp>(op)) { 72 loopsAtDepth.push_back(forOp); 73 gatherLoops(forOp.getBody(), currLoopDepth + 1, depthToLoops); 74 } 75 } 76 } 77 78 // Run fusion dependence check on 'loops[i]' and 'loops[j]' at loop depths 79 // in range ['loopDepth' + 1, 'maxLoopDepth']. 80 // Emits a remark on 'loops[i]' if a fusion-preventing dependence exists. 81 static void testDependenceCheck(SmallVector<AffineForOp, 2> &loops, unsigned i, 82 unsigned j, unsigned loopDepth, 83 unsigned maxLoopDepth) { 84 AffineForOp srcForOp = loops[i]; 85 AffineForOp dstForOp = loops[j]; 86 mlir::ComputationSliceState sliceUnion; 87 for (unsigned d = loopDepth + 1; d <= maxLoopDepth; ++d) { 88 FusionResult result = 89 mlir::canFuseLoops(srcForOp, dstForOp, d, &sliceUnion); 90 if (result.value == FusionResult::FailBlockDependence) { 91 srcForOp.getOperation()->emitRemark("block-level dependence preventing" 92 " fusion of loop nest ") 93 << i << " into loop nest " << j << " at depth " << loopDepth; 94 } 95 } 96 } 97 98 // Returns the index of 'op' in its block. 99 static unsigned getBlockIndex(Operation &op) { 100 unsigned index = 0; 101 for (auto &opX : *op.getBlock()) { 102 if (&op == &opX) 103 break; 104 ++index; 105 } 106 return index; 107 } 108 109 // Returns a string representation of 'sliceUnion'. 110 static std::string getSliceStr(const mlir::ComputationSliceState &sliceUnion) { 111 std::string result; 112 llvm::raw_string_ostream os(result); 113 // Slice insertion point format [loop-depth, operation-block-index] 114 unsigned ipd = getNestingDepth(*sliceUnion.insertPoint); 115 unsigned ipb = getBlockIndex(*sliceUnion.insertPoint); 116 os << "insert point: (" << std::to_string(ipd) << ", " << std::to_string(ipb) 117 << ")"; 118 assert(sliceUnion.lbs.size() == sliceUnion.ubs.size()); 119 os << " loop bounds: "; 120 for (unsigned k = 0, e = sliceUnion.lbs.size(); k < e; ++k) { 121 os << '['; 122 sliceUnion.lbs[k].print(os); 123 os << ", "; 124 sliceUnion.ubs[k].print(os); 125 os << "] "; 126 } 127 return os.str(); 128 } 129 130 // Computes fusion slice union on 'loops[i]' and 'loops[j]' at loop depths 131 // in range ['loopDepth' + 1, 'maxLoopDepth']. 132 // Emits a string represention of the slice union as a remark on 'loops[j]'. 133 static void testSliceComputation(SmallVector<AffineForOp, 2> &loops, unsigned i, 134 unsigned j, unsigned loopDepth, 135 unsigned maxLoopDepth) { 136 AffineForOp forOpA = loops[i]; 137 AffineForOp forOpB = loops[j]; 138 for (unsigned d = loopDepth + 1; d <= maxLoopDepth; ++d) { 139 mlir::ComputationSliceState sliceUnion; 140 FusionResult result = mlir::canFuseLoops(forOpA, forOpB, d, &sliceUnion); 141 if (result.value == FusionResult::Success) { 142 forOpB.getOperation()->emitRemark("slice (") 143 << " src loop: " << i << ", dst loop: " << j << ", depth: " << d 144 << " : " << getSliceStr(sliceUnion) << ")"; 145 } 146 } 147 } 148 149 void TestLoopFusion::runOnFunction() { 150 // Gather all AffineForOps by loop depth. 151 DenseMap<unsigned, SmallVector<AffineForOp, 2>> depthToLoops; 152 for (auto &block : getFunction()) { 153 gatherLoops(&block, /*currLoopDepth=*/0, depthToLoops); 154 } 155 156 // Run tests on all combinations of src/dst loop nests in 'depthToLoops'. 157 for (auto &depthAndLoops : depthToLoops) { 158 unsigned loopDepth = depthAndLoops.first; 159 auto &loops = depthAndLoops.second; 160 unsigned numLoops = loops.size(); 161 for (unsigned j = 0; j < numLoops; ++j) { 162 for (unsigned k = 0; k < numLoops; ++k) { 163 if (j == k) 164 continue; 165 if (clTestDependenceCheck) 166 testDependenceCheck(loops, j, k, loopDepth, depthToLoops.size()); 167 if (clTestSliceComputation) 168 testSliceComputation(loops, j, k, loopDepth, depthToLoops.size()); 169 } 170 } 171 } 172 } 173 174 static PassRegistration<TestLoopFusion> 175 pass("test-loop-fusion", "Tests loop fusion utility functions.");