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

     1  //===- MlirOptMain.cpp - MLIR Optimizer Driver ----------------------------===//
     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 is a utility that runs an optimization pass and prints the result back
    19  // out. It is designed to support unit testing.
    20  //
    21  //===----------------------------------------------------------------------===//
    22  
    23  #include "mlir/Support/MlirOptMain.h"
    24  #include "mlir/Analysis/Passes.h"
    25  #include "mlir/IR/Attributes.h"
    26  #include "mlir/IR/Diagnostics.h"
    27  #include "mlir/IR/Location.h"
    28  #include "mlir/IR/MLIRContext.h"
    29  #include "mlir/IR/Module.h"
    30  #include "mlir/Parser.h"
    31  #include "mlir/Pass/Pass.h"
    32  #include "mlir/Pass/PassManager.h"
    33  #include "mlir/Transforms/Passes.h"
    34  #include "llvm/Support/FileUtilities.h"
    35  #include "llvm/Support/Regex.h"
    36  #include "llvm/Support/SourceMgr.h"
    37  
    38  using namespace mlir;
    39  using namespace llvm;
    40  using llvm::SMLoc;
    41  
    42  /// Perform the actions on the input file indicated by the command line flags
    43  /// within the specified context.
    44  ///
    45  /// This typically parses the main source file, runs zero or more optimization
    46  /// passes, then prints the output.
    47  ///
    48  static LogicalResult
    49  performActions(raw_ostream &os, bool verifyDiagnostics, bool verifyPasses,
    50                 SourceMgr &sourceMgr, MLIRContext *context,
    51                 const std::vector<const mlir::PassRegistryEntry *> &passList) {
    52    OwningModuleRef module(parseSourceFile(sourceMgr, context));
    53    if (!module)
    54      return failure();
    55  
    56    // Apply any pass manager command line options.
    57    PassManager pm(verifyPasses);
    58    applyPassManagerCLOptions(pm);
    59  
    60    // Run each of the passes that were selected.
    61    for (const auto *passEntry : passList)
    62      passEntry->addToPipeline(pm);
    63  
    64    // Run the pipeline.
    65    if (failed(pm.run(*module)))
    66      return failure();
    67  
    68    // Print the output.
    69    module->print(os);
    70    return success();
    71  }
    72  
    73  /// Parses the memory buffer.  If successfully, run a series of passes against
    74  /// it and print the result.
    75  static LogicalResult
    76  processBuffer(raw_ostream &os, std::unique_ptr<MemoryBuffer> ownedBuffer,
    77                bool verifyDiagnostics, bool verifyPasses,
    78                const std::vector<const mlir::PassRegistryEntry *> &passList) {
    79    // Tell sourceMgr about this buffer, which is what the parser will pick up.
    80    SourceMgr sourceMgr;
    81    sourceMgr.AddNewSourceBuffer(std::move(ownedBuffer), SMLoc());
    82  
    83    // Parse the input file.
    84    MLIRContext context;
    85  
    86    // If we are in verify diagnostics mode then we have a lot of work to do,
    87    // otherwise just perform the actions without worrying about it.
    88    if (!verifyDiagnostics) {
    89      SourceMgrDiagnosticHandler sourceMgrHandler(sourceMgr, &context);
    90      return performActions(os, verifyDiagnostics, verifyPasses, sourceMgr,
    91                            &context, passList);
    92    }
    93  
    94    SourceMgrDiagnosticVerifierHandler sourceMgrHandler(sourceMgr, &context);
    95  
    96    // Do any processing requested by command line flags.  We don't care whether
    97    // these actions succeed or fail, we only care what diagnostics they produce
    98    // and whether they match our expectations.
    99    performActions(os, verifyDiagnostics, verifyPasses, sourceMgr, &context,
   100                   passList);
   101  
   102    // Verify the diagnostic handler to make sure that each of the diagnostics
   103    // matched.
   104    return sourceMgrHandler.verify();
   105  }
   106  
   107  /// Split the specified file on a marker and process each chunk independently
   108  /// according to the normal processBuffer logic.  This is primarily used to
   109  /// allow a large number of small independent parser tests to be put into a
   110  /// single test, but could be used for other purposes as well.
   111  static LogicalResult splitAndProcessFile(
   112      raw_ostream &os, std::unique_ptr<MemoryBuffer> originalBuffer,
   113      bool verifyDiagnostics, bool verifyPasses,
   114      const std::vector<const mlir::PassRegistryEntry *> &passList) {
   115    const char marker[] = "// -----";
   116    auto *origMemBuffer = originalBuffer.get();
   117    SmallVector<StringRef, 8> sourceBuffers;
   118    origMemBuffer->getBuffer().split(sourceBuffers, marker);
   119  
   120    // Add the original buffer to the source manager.
   121    SourceMgr fileSourceMgr;
   122    fileSourceMgr.AddNewSourceBuffer(std::move(originalBuffer), SMLoc());
   123  
   124    bool hadUnexpectedResult = false;
   125  
   126    // Process each chunk in turn.  If any fails, then return a failure of the
   127    // tool.
   128    for (auto &subBuffer : sourceBuffers) {
   129      auto splitLoc = SMLoc::getFromPointer(subBuffer.data());
   130      unsigned splitLine = fileSourceMgr.getLineAndColumn(splitLoc).first;
   131      auto subMemBuffer = MemoryBuffer::getMemBufferCopy(
   132          subBuffer, origMemBuffer->getBufferIdentifier() +
   133                         Twine(" split at line #") + Twine(splitLine));
   134      if (failed(processBuffer(os, std::move(subMemBuffer), verifyDiagnostics,
   135                               verifyPasses, passList)))
   136        hadUnexpectedResult = true;
   137    }
   138  
   139    return failure(hadUnexpectedResult);
   140  }
   141  
   142  LogicalResult
   143  mlir::MlirOptMain(raw_ostream &os, std::unique_ptr<MemoryBuffer> buffer,
   144                    const std::vector<const mlir::PassRegistryEntry *> &passList,
   145                    bool splitInputFile, bool verifyDiagnostics,
   146                    bool verifyPasses) {
   147    // The split-input-file mode is a very specific mode that slices the file
   148    // up into small pieces and checks each independently.
   149    if (splitInputFile)
   150      return splitAndProcessFile(os, std::move(buffer), verifyDiagnostics,
   151                                 verifyPasses, passList);
   152  
   153    return processBuffer(os, std::move(buffer), verifyDiagnostics, verifyPasses,
   154                         passList);
   155  }