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.");