github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/lib/Pass/Pass.cpp (about)

     1  //===- Pass.cpp - Pass infrastructure implementation ----------------------===//
     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 common pass infrastructure.
    19  //
    20  //===----------------------------------------------------------------------===//
    21  
    22  #include "mlir/Pass/Pass.h"
    23  #include "PassDetail.h"
    24  #include "mlir/Analysis/Verifier.h"
    25  #include "mlir/IR/Diagnostics.h"
    26  #include "mlir/IR/Module.h"
    27  #include "mlir/Pass/PassManager.h"
    28  #include "llvm/Support/CommandLine.h"
    29  #include "llvm/Support/Mutex.h"
    30  #include "llvm/Support/Parallel.h"
    31  #include "llvm/Support/Threading.h"
    32  
    33  using namespace mlir;
    34  using namespace mlir::detail;
    35  
    36  //===----------------------------------------------------------------------===//
    37  // Pass
    38  //===----------------------------------------------------------------------===//
    39  
    40  /// Out of line virtual method to ensure vtables and metadata are emitted to a
    41  /// single .o file.
    42  void Pass::anchor() {}
    43  
    44  /// Forwarding function to execute this pass.
    45  LogicalResult Pass::run(Operation *op, AnalysisManager am) {
    46    passState.emplace(op, am);
    47  
    48    // Instrument before the pass has run.
    49    auto pi = am.getPassInstrumentor();
    50    if (pi)
    51      pi->runBeforePass(this, op);
    52  
    53    // Invoke the virtual runOnOperation method.
    54    runOnOperation();
    55  
    56    // Invalidate any non preserved analyses.
    57    am.invalidate(passState->preservedAnalyses);
    58  
    59    // Instrument after the pass has run.
    60    bool passFailed = passState->irAndPassFailed.getInt();
    61    if (pi) {
    62      if (passFailed)
    63        pi->runAfterPassFailed(this, op);
    64      else
    65        pi->runAfterPass(this, op);
    66    }
    67  
    68    // Return if the pass signaled a failure.
    69    return failure(passFailed);
    70  }
    71  
    72  //===----------------------------------------------------------------------===//
    73  // PassExecutor
    74  //===----------------------------------------------------------------------===//
    75  
    76  FunctionPassExecutor::FunctionPassExecutor(const FunctionPassExecutor &rhs)
    77      : PassExecutor(Kind::FunctionExecutor) {
    78    for (auto &pass : rhs.passes)
    79      addPass(cast<FunctionPassBase>(pass->clone()));
    80  }
    81  
    82  /// Run all of the passes in this manager over the current function.
    83  LogicalResult detail::FunctionPassExecutor::run(FuncOp function,
    84                                                  AnalysisManager am) {
    85    // Run each of the held passes.
    86    for (auto &pass : passes)
    87      if (failed(pass->run(function, am)))
    88        return failure();
    89    return success();
    90  }
    91  
    92  /// Run all of the passes in this manager over the current module.
    93  LogicalResult detail::ModulePassExecutor::run(ModuleOp module,
    94                                                AnalysisManager am) {
    95    // Run each of the held passes.
    96    for (auto &pass : passes)
    97      if (failed(pass->run(module, am)))
    98        return failure();
    99    return success();
   100  }
   101  
   102  //===----------------------------------------------------------------------===//
   103  // ModuleToFunctionPassAdaptor
   104  //===----------------------------------------------------------------------===//
   105  
   106  /// Utility to run the given function and analysis manager on a provided
   107  /// function pass executor.
   108  static LogicalResult runFunctionPipeline(FunctionPassExecutor &fpe, FuncOp func,
   109                                           AnalysisManager am) {
   110    // Run the function pipeline over the provided function.
   111    auto result = fpe.run(func, am);
   112  
   113    // Clear out any computed function analyses. These analyses won't be used
   114    // any more in this pipeline, and this helps reduce the current working set
   115    // of memory. If preserving these analyses becomes important in the future
   116    // we can re-evalutate this.
   117    am.clear();
   118    return result;
   119  }
   120  
   121  /// Run the held function pipeline over all non-external functions within the
   122  /// module.
   123  void ModuleToFunctionPassAdaptor::runOnModule() {
   124    AnalysisManager am = getAnalysisManager();
   125    for (auto func : getModule().getOps<FuncOp>()) {
   126      // Skip external functions.
   127      if (func.isExternal())
   128        continue;
   129  
   130      // Run the held function pipeline over the current function.
   131      auto childAM = am.slice(func);
   132      if (failed(runFunctionPipeline(fpe, func, childAM)))
   133        return signalPassFailure();
   134  
   135      // Clear out any computed child analyses. These analyses won't be used
   136      // any more in this pipeline, and this helps reduce the current working set
   137      // of memory. If preserving these analyses becomes important in the future
   138      // we can re-evalutate this.
   139      am.clear();
   140    }
   141  }
   142  
   143  // Run the held function pipeline synchronously across the functions within
   144  // the module.
   145  void ModuleToFunctionPassAdaptorParallel::runOnModule() {
   146    AnalysisManager am = getAnalysisManager();
   147  
   148    // Create the async executors if they haven't been created, or if the main
   149    // function pipeline has changed.
   150    if (asyncExecutors.empty() || asyncExecutors.front().size() != fpe.size())
   151      asyncExecutors = {llvm::hardware_concurrency(), fpe};
   152  
   153    // Run a prepass over the module to collect the functions to execute a over.
   154    // This ensures that an analysis manager exists for each function, as well as
   155    // providing a queue of functions to execute over.
   156    std::vector<std::pair<FuncOp, AnalysisManager>> funcAMPairs;
   157    for (auto func : getModule().getOps<FuncOp>())
   158      if (!func.isExternal())
   159        funcAMPairs.emplace_back(func, am.slice(func));
   160  
   161    // A parallel diagnostic handler that provides deterministic diagnostic
   162    // ordering.
   163    ParallelDiagnosticHandler diagHandler(&getContext());
   164  
   165    // An index for the current function/analysis manager pair.
   166    std::atomic<unsigned> funcIt(0);
   167  
   168    // An atomic failure variable for the async executors.
   169    std::atomic<bool> passFailed(false);
   170    llvm::parallel::for_each(
   171        llvm::parallel::par, asyncExecutors.begin(),
   172        std::next(asyncExecutors.begin(),
   173                  std::min(asyncExecutors.size(), funcAMPairs.size())),
   174        [&](FunctionPassExecutor &executor) {
   175          for (auto e = funcAMPairs.size(); !passFailed && funcIt < e;) {
   176            // Get the next available function index.
   177            unsigned nextID = funcIt++;
   178            if (nextID >= e)
   179              break;
   180  
   181            // Set the function id for this thread in the diagnostic handler.
   182            diagHandler.setOrderIDForThread(nextID);
   183  
   184            // Run the executor over the current function.
   185            auto &it = funcAMPairs[nextID];
   186            if (failed(runFunctionPipeline(executor, it.first, it.second))) {
   187              passFailed = true;
   188              break;
   189            }
   190          }
   191        });
   192  
   193    // Signal a failure if any of the executors failed.
   194    if (passFailed)
   195      signalPassFailure();
   196  }
   197  
   198  //===----------------------------------------------------------------------===//
   199  // Verifier Passes
   200  //===----------------------------------------------------------------------===//
   201  
   202  void FunctionVerifierPass::runOnFunction() {
   203    if (failed(verify(getFunction())))
   204      signalPassFailure();
   205    markAllAnalysesPreserved();
   206  }
   207  
   208  void ModuleVerifierPass::runOnModule() {
   209    if (failed(verify(getModule())))
   210      signalPassFailure();
   211    markAllAnalysesPreserved();
   212  }
   213  
   214  //===----------------------------------------------------------------------===//
   215  // PassManager
   216  //===----------------------------------------------------------------------===//
   217  
   218  PassManager::PassManager(bool verifyPasses)
   219      : mpe(new ModulePassExecutor()), verifyPasses(verifyPasses),
   220        passTiming(false), disableThreads(false) {}
   221  
   222  PassManager::~PassManager() {}
   223  
   224  /// Run the passes within this manager on the provided module.
   225  LogicalResult PassManager::run(ModuleOp module) {
   226    ModuleAnalysisManager am(module, instrumentor.get());
   227    return mpe->run(module, am);
   228  }
   229  
   230  /// Disable support for multi-threading within the pass manager.
   231  void PassManager::disableMultithreading(bool disable) {
   232    disableThreads = disable;
   233  }
   234  
   235  /// Add an opaque pass pointer to the current manager. This takes ownership
   236  /// over the provided pass pointer.
   237  void PassManager::addPass(std::unique_ptr<Pass> pass) {
   238    if (isa<FunctionPassBase>(pass.get()))
   239      return addPass(cast<FunctionPassBase>(std::move(pass)));
   240    addPass(cast<ModulePassBase>(std::move(pass)));
   241  }
   242  
   243  /// Add a module pass to the current manager. This takes ownership over the
   244  /// provided pass pointer.
   245  void PassManager::addPass(std::unique_ptr<ModulePassBase> pass) {
   246    nestedExecutorStack.clear();
   247    mpe->addPass(std::move(pass));
   248  
   249    // Add a verifier run if requested.
   250    if (verifyPasses)
   251      mpe->addPass(std::make_unique<ModuleVerifierPass>());
   252  }
   253  
   254  /// Add a function pass to the current manager. This takes ownership over the
   255  /// provided pass pointer. This will automatically create a function pass
   256  /// executor if necessary.
   257  void PassManager::addPass(std::unique_ptr<FunctionPassBase> pass) {
   258    detail::FunctionPassExecutor *fpe;
   259    if (nestedExecutorStack.empty()) {
   260      /// Create an executor adaptor for this pass.
   261      if (disableThreads || !llvm::llvm_is_multithreaded()) {
   262        // If multi-threading is disabled, then create a synchronous adaptor.
   263        auto adaptor = std::make_unique<ModuleToFunctionPassAdaptor>();
   264        fpe = &adaptor->getFunctionExecutor();
   265        addPass(std::unique_ptr<ModulePassBase>{adaptor.release()});
   266      } else {
   267        auto adaptor = std::make_unique<ModuleToFunctionPassAdaptorParallel>();
   268        fpe = &adaptor->getFunctionExecutor();
   269        addPass(std::unique_ptr<ModulePassBase>{adaptor.release()});
   270      }
   271  
   272      /// Add the executor to the stack.
   273      nestedExecutorStack.push_back(fpe);
   274    } else {
   275      fpe = cast<detail::FunctionPassExecutor>(nestedExecutorStack.back());
   276    }
   277    fpe->addPass(std::move(pass));
   278  
   279    // Add a verifier run if requested.
   280    if (verifyPasses)
   281      fpe->addPass(std::make_unique<FunctionVerifierPass>());
   282  }
   283  
   284  /// Add the provided instrumentation to the pass manager. This takes ownership
   285  /// over the given pointer.
   286  void PassManager::addInstrumentation(PassInstrumentation *pi) {
   287    if (!instrumentor)
   288      instrumentor.reset(new PassInstrumentor());
   289  
   290    instrumentor->addInstrumentation(pi);
   291  }
   292  
   293  //===----------------------------------------------------------------------===//
   294  // AnalysisManager
   295  //===----------------------------------------------------------------------===//
   296  
   297  /// Returns a pass instrumentation object for the current operation.
   298  PassInstrumentor *AnalysisManager::getPassInstrumentor() const {
   299    ParentPointerT curParent = parent;
   300    while (auto *parentAM = curParent.dyn_cast<const AnalysisManager *>())
   301      curParent = parentAM->parent;
   302    return curParent.get<const ModuleAnalysisManager *>()->getPassInstrumentor();
   303  }
   304  
   305  /// Get an analysis manager for the given child operation.
   306  AnalysisManager AnalysisManager::slice(Operation *op) {
   307    assert(op->getParentOp() == impl->getOperation() &&
   308           "'op' has a different parent operation");
   309    auto it = impl->childAnalyses.find(op);
   310    if (it == impl->childAnalyses.end())
   311      it = impl->childAnalyses
   312               .try_emplace(op, std::make_unique<NestedAnalysisMap>(op))
   313               .first;
   314    return {this, it->second.get()};
   315  }
   316  
   317  /// Invalidate any non preserved analyses.
   318  void detail::NestedAnalysisMap::invalidate(
   319      const detail::PreservedAnalyses &pa) {
   320    // If all analyses were preserved, then there is nothing to do here.
   321    if (pa.isAll())
   322      return;
   323  
   324    // Invalidate the analyses for the current operation directly.
   325    analyses.invalidate(pa);
   326  
   327    // If no analyses were preserved, then just simply clear out the child
   328    // analysis results.
   329    if (pa.isNone()) {
   330      childAnalyses.clear();
   331      return;
   332    }
   333  
   334    // Otherwise, invalidate each child analysis map.
   335    SmallVector<NestedAnalysisMap *, 8> mapsToInvalidate(1, this);
   336    while (!mapsToInvalidate.empty()) {
   337      auto *map = mapsToInvalidate.pop_back_val();
   338      for (auto &analysisPair : map->childAnalyses) {
   339        analysisPair.second->invalidate(pa);
   340        if (!analysisPair.second->childAnalyses.empty())
   341          mapsToInvalidate.push_back(analysisPair.second.get());
   342      }
   343    }
   344  }
   345  
   346  //===----------------------------------------------------------------------===//
   347  // PassInstrumentation
   348  //===----------------------------------------------------------------------===//
   349  
   350  PassInstrumentation::~PassInstrumentation() {}
   351  
   352  //===----------------------------------------------------------------------===//
   353  // PassInstrumentor
   354  //===----------------------------------------------------------------------===//
   355  
   356  namespace mlir {
   357  namespace detail {
   358  struct PassInstrumentorImpl {
   359    /// Mutex to keep instrumentation access thread-safe.
   360    llvm::sys::SmartMutex<true> mutex;
   361  
   362    /// Set of registered instrumentations.
   363    std::vector<std::unique_ptr<PassInstrumentation>> instrumentations;
   364  };
   365  } // end namespace detail
   366  } // end namespace mlir
   367  
   368  PassInstrumentor::PassInstrumentor() : impl(new PassInstrumentorImpl()) {}
   369  PassInstrumentor::~PassInstrumentor() {}
   370  
   371  /// See PassInstrumentation::runBeforePass for details.
   372  void PassInstrumentor::runBeforePass(Pass *pass, Operation *op) {
   373    llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
   374    for (auto &instr : impl->instrumentations)
   375      instr->runBeforePass(pass, op);
   376  }
   377  
   378  /// See PassInstrumentation::runAfterPass for details.
   379  void PassInstrumentor::runAfterPass(Pass *pass, Operation *op) {
   380    llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
   381    for (auto &instr : llvm::reverse(impl->instrumentations))
   382      instr->runAfterPass(pass, op);
   383  }
   384  
   385  /// See PassInstrumentation::runAfterPassFailed for details.
   386  void PassInstrumentor::runAfterPassFailed(Pass *pass, Operation *op) {
   387    llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
   388    for (auto &instr : llvm::reverse(impl->instrumentations))
   389      instr->runAfterPassFailed(pass, op);
   390  }
   391  
   392  /// See PassInstrumentation::runBeforeAnalysis for details.
   393  void PassInstrumentor::runBeforeAnalysis(llvm::StringRef name, AnalysisID *id,
   394                                           Operation *op) {
   395    llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
   396    for (auto &instr : impl->instrumentations)
   397      instr->runBeforeAnalysis(name, id, op);
   398  }
   399  
   400  /// See PassInstrumentation::runAfterAnalysis for details.
   401  void PassInstrumentor::runAfterAnalysis(llvm::StringRef name, AnalysisID *id,
   402                                          Operation *op) {
   403    llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
   404    for (auto &instr : llvm::reverse(impl->instrumentations))
   405      instr->runAfterAnalysis(name, id, op);
   406  }
   407  
   408  /// Add the given instrumentation to the collection. This takes ownership over
   409  /// the given pointer.
   410  void PassInstrumentor::addInstrumentation(PassInstrumentation *pi) {
   411    llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex);
   412    impl->instrumentations.emplace_back(pi);
   413  }
   414  
   415  constexpr AnalysisID mlir::detail::PreservedAnalyses::allAnalysesID;