Use PassPipelineCLParser in mlir-reduce
authorChia-hung Duan <chiahungduan@google.com>
Wed, 14 Apr 2021 21:34:17 +0000 (14:34 -0700)
committerJacques Pienaar <jpienaar@google.com>
Wed, 14 Apr 2021 21:35:55 +0000 (14:35 -0700)
We are able to config the reducer pass pipeline through command-line.

Reviewed By: jpienaar, rriddle

Differential Revision: https://reviews.llvm.org/D100155

mlir/include/mlir/Reducer/CMakeLists.txt
mlir/include/mlir/Reducer/OptReductionPass.h
mlir/include/mlir/Reducer/Passes.h [new file with mode: 0644]
mlir/include/mlir/Reducer/Passes.td
mlir/include/mlir/Reducer/ReductionTreePass.h
mlir/test/mlir-reduce/dce-test.mlir
mlir/test/mlir-reduce/multiple-function.mlir
mlir/test/mlir-reduce/simple-test.mlir
mlir/tools/mlir-reduce/OptReductionPass.cpp
mlir/tools/mlir-reduce/ReductionTreePass.cpp
mlir/tools/mlir-reduce/mlir-reduce.cpp

index 5cfaa09..85dfaab 100644 (file)
@@ -1,5 +1,5 @@
 set(LLVM_TARGET_DEFINITIONS Passes.td)
-mlir_tablegen(Passes.h.inc -gen-pass-decls)
+mlir_tablegen(Passes.h.inc -gen-pass-decls -name Reducer)
 add_public_tablegen_target(MLIRReducerIncGen)
 
 add_mlir_doc(Passes -gen-pass-doc ReducerPasses ./)
index 3549c28..f273539 100644 (file)
@@ -28,23 +28,12 @@ namespace mlir {
 
 class OptReductionPass : public OptReductionBase<OptReductionPass> {
 public:
-  OptReductionPass(const Tester &test, MLIRContext *context,
-                   std::unique_ptr<Pass> optPass);
+  OptReductionPass() = default;
 
-  OptReductionPass(const OptReductionPass &srcPass);
+  OptReductionPass(const OptReductionPass &srcPass) = default;
 
   /// Runs the pass instance in the pass pipeline.
   void runOnOperation() override;
-
-private:
-  // Points to the context to be used in the pass manager.
-  MLIRContext *context;
-
-  // This is used to test the interesting behavior of the transformed module.
-  const Tester &test;
-
-  // Points to the mlir-opt pass to be called.
-  std::unique_ptr<Pass> optPass;
 };
 
 } // end namespace mlir
diff --git a/mlir/include/mlir/Reducer/Passes.h b/mlir/include/mlir/Reducer/Passes.h
new file mode 100644 (file)
index 0000000..8eb1d59
--- /dev/null
@@ -0,0 +1,27 @@
+//===- Passes.h - Reducer Pass Construction and Registration ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef MLIR_REDUCER_PASSES_H
+#define MLIR_REDUCER_PASSES_H
+
+#include "mlir/Pass/Pass.h"
+#include "mlir/Reducer/OptReductionPass.h"
+#include "mlir/Reducer/ReductionTreePass.h"
+
+namespace mlir {
+
+std::unique_ptr<Pass> createReductionTreePass();
+
+std::unique_ptr<Pass> createOptReductionPass();
+
+/// Generate the code for registering reducer passes.
+#define GEN_PASS_REGISTRATION
+#include "mlir/Reducer/Passes.h.inc"
+
+} // end namespace mlir
+
+#endif // MLIR_REDUCER_PASSES_H
index d3a934e..ce99507 100644 (file)
 
 include "mlir/Pass/PassBase.td"
 
+def CommonReductionPassOptions {
+  list<Option> options = [
+    Option<"testerName", "test", "std::string", /* default */"",
+           "The filename of the tester">,
+    ListOption<"testerArgs", "test-arg", "std::string",
+               "llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated">,
+  ];
+}
+
 def ReductionTree : Pass<"reduction-tree", "ModuleOp"> {
   let summary = "A general reduction tree pass for the MLIR Reduce Tool";
+
+  let constructor = "mlir::createReductionTreePass()";
+
+  let options = [
+    Option<"opReducerName", "op-reducer", "std::string", /* default */"",
+           "The OpReducer to reduce the module">,
+    Option<"traversalModeId", "traversal-mode", "unsigned",
+           /* default */"0", "The graph traversal mode">,
+  ] # CommonReductionPassOptions.options;
 }
 
 def OptReduction : Pass<"opt-reduction-pass", "ModuleOp"> {
   let summary = "A reduction pass wrapper for optimization passes";
+
+  let constructor = "mlir::createOptReductionPass()";
+
+  let options = [
+    Option<"optPass", "opt-pass", "std::string", /* default */"",
+           "The optimization pass will be run dynamically in OptReductionPass">,
+  ] # CommonReductionPassOptions.options;
 }
 
 #endif // MLIR_REDUCER_PASSES
index 8f1269e..a657d61 100644 (file)
@@ -33,12 +33,8 @@ namespace mlir {
 /// generated reduced variants.
 class ReductionTreePass : public ReductionTreeBase<ReductionTreePass> {
 public:
-  ReductionTreePass(const ReductionTreePass &pass)
-      : ReductionTreeBase<ReductionTreePass>(pass), opType(pass.opType),
-        mode(pass.mode), test(pass.test) {}
-
-  ReductionTreePass(StringRef opType, TraversalMode mode, const Tester &test)
-      : opType(opType), mode(mode), test(test) {}
+  ReductionTreePass() = default;
+  ReductionTreePass(const ReductionTreePass &pass) = default;
 
   /// Runs the pass instance in the pass pipeline.
   void runOnOperation() override;
@@ -47,15 +43,6 @@ private:
   template <typename IteratorType>
   ModuleOp findOptimal(ModuleOp module, std::unique_ptr<OpReducer> reducer,
                        ReductionNode *node);
-
-  /// The name of operation that we will try to remove.
-  StringRef opType;
-
-  TraversalMode mode;
-
-  /// This is used to test the interesting behavior of the reduction nodes in
-  /// the tree.
-  const Tester &test;
 };
 
 } // end namespace mlir
index 2160568..7faa150 100644 (file)
@@ -1,5 +1,5 @@
 // UNSUPPORTED: system-windows
-// RUN: mlir-reduce %s -test %S/failure-test.sh -pass-test DCE | FileCheck %s
+// RUN: mlir-reduce %s -opt-reduction-pass='opt-pass=symbol-dce test=%S/failure-test.sh' | FileCheck %s
 // This input should be reduced by the pass pipeline so that only
 // the @simple1 function remains as the other functions should be
 // removed by the dead code elimination pass.
index 64609c1..06e51a1 100644 (file)
@@ -1,5 +1,5 @@
 // UNSUPPORTED: system-windows
-// RUN: mlir-reduce %s -test %S/failure-test.sh -pass-test function-reducer | FileCheck %s
+// RUN: mlir-reduce %s -reduction-tree='op-reducer=func traversal-mode=0 test=%S/failure-test.sh' | FileCheck %s
 // This input should be reduced by the pass pipeline so that only
 // the @simple5 function remains as this is the shortest function
 // containing the interesting behavior.
index 2f5a2c0..6630030 100644 (file)
@@ -1,5 +1,5 @@
 // UNSUPPORTED: system-windows
-// RUN: mlir-reduce %s -test %S/test.sh -pass-test function
+// RUN: mlir-reduce %s -reduction-tree='op-reducer=func traversal-mode=0 test=%S/test.sh'
 
 func @simple1(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {
   cond_br %arg0, ^bb1, ^bb2
index 97b9b3e..533afc0 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Reducer/OptReductionPass.h"
+#include "mlir/Pass/PassRegistry.h"
+#include "mlir/Reducer/Passes.h"
+#include "mlir/Reducer/Tester.h"
 
 #define DEBUG_TYPE "mlir-reduce"
 
 using namespace mlir;
 
-OptReductionPass::OptReductionPass(const Tester &test, MLIRContext *context,
-                                   std::unique_ptr<Pass> optPass)
-    : context(context), test(test), optPass(std::move(optPass)) {}
-
-OptReductionPass::OptReductionPass(const OptReductionPass &srcPass)
-    : OptReductionBase<OptReductionPass>(srcPass), test(srcPass.test),
-      optPass(srcPass.optPass.get()) {}
-
 /// Runs the pass instance in the pass pipeline.
 void OptReductionPass::runOnOperation() {
   LLVM_DEBUG(llvm::dbgs() << "\nOptimization Reduction pass: ");
-  LLVM_DEBUG(llvm::dbgs() << optPass.get()->getName() << "\nTesting:\n");
+
+  Tester test(testerName, testerArgs);
 
   ModuleOp module = this->getOperation();
   ModuleOp moduleVariant = module.clone();
-  PassManager pmTransform(context);
-  pmTransform.addPass(std::move(optPass));
+
+  PassManager passManager(module.getContext());
+  if (failed(parsePassPipeline(optPass, passManager))) {
+    LLVM_DEBUG(llvm::dbgs() << "\nFailed to parse pass pipeline");
+    return;
+  }
 
   std::pair<Tester::Interestingness, int> original = test.isInteresting(module);
+  if (original.first != Tester::Interestingness::True) {
+    LLVM_DEBUG(llvm::dbgs() << "\nThe original input is not interested");
+    return;
+  }
 
-  if (failed(pmTransform.run(moduleVariant)))
+  if (failed(passManager.run(moduleVariant))) {
+    LLVM_DEBUG(llvm::dbgs() << "\nFailed to run pass pipeline");
     return;
+  }
 
   std::pair<Tester::Interestingness, int> reduced =
       test.isInteresting(moduleVariant);
@@ -58,3 +64,7 @@ void OptReductionPass::runOnOperation() {
 
   LLVM_DEBUG(llvm::dbgs() << "Pass Complete\n\n");
 }
+
+std::unique_ptr<Pass> mlir::createOptReductionPass() {
+  return std::make_unique<OptReductionPass>();
+}
index 6dbf783..e3a7565 100644 (file)
@@ -15,6 +15,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Reducer/ReductionTreePass.h"
+#include "mlir/Reducer/Passes.h"
 
 #include "llvm/Support/Allocator.h"
 
@@ -30,7 +31,7 @@ static std::unique_ptr<OpReducer> getOpReducer(llvm::StringRef opType) {
 
 void ReductionTreePass::runOnOperation() {
   ModuleOp module = this->getOperation();
-  std::unique_ptr<OpReducer> reducer = getOpReducer(opType);
+  std::unique_ptr<OpReducer> reducer = getOpReducer(opReducerName);
   std::vector<std::pair<int, int>> ranges = {
       {0, reducer->getNumTargetOps(module)}};
 
@@ -40,7 +41,7 @@ void ReductionTreePass::runOnOperation() {
   new (root) ReductionNode(nullptr, ranges, allocator);
 
   ModuleOp golden = module;
-  switch (mode) {
+  switch (traversalModeId) {
   case TraversalMode::SinglePath:
     golden = findOptimal<ReductionNode::iterator<TraversalMode::SinglePath>>(
         module, std::move(reducer), root);
@@ -61,8 +62,15 @@ template <typename IteratorType>
 ModuleOp ReductionTreePass::findOptimal(ModuleOp module,
                                         std::unique_ptr<OpReducer> reducer,
                                         ReductionNode *root) {
+  Tester test(testerName, testerArgs);
   std::pair<Tester::Interestingness, size_t> initStatus =
       test.isInteresting(module);
+
+  if (initStatus.first != Tester::Interestingness::True) {
+    LLVM_DEBUG(llvm::dbgs() << "\nThe original input is not interested");
+    return module;
+  }
+
   root->update(initStatus);
 
   ReductionNode *smallestNode = root;
@@ -93,3 +101,7 @@ ModuleOp ReductionTreePass::findOptimal(ModuleOp module,
 
   return golden;
 }
+
+std::unique_ptr<Pass> mlir::createReductionTreePass() {
+  return std::make_unique<ReductionTreePass>();
+}
index 7df1dc1..b23177d 100644 (file)
 #include <vector>
 
 #include "mlir/InitAllDialects.h"
+#include "mlir/InitAllPasses.h"
 #include "mlir/Parser.h"
 #include "mlir/Pass/Pass.h"
 #include "mlir/Pass/PassManager.h"
 #include "mlir/Reducer/OptReductionPass.h"
+#include "mlir/Reducer/Passes.h"
 #include "mlir/Reducer/Passes/OpReducer.h"
 #include "mlir/Reducer/ReductionNode.h"
 #include "mlir/Reducer/ReductionTreePass.h"
@@ -43,22 +45,10 @@ static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional,
                                                 llvm::cl::desc("<input file>"));
 
 static llvm::cl::opt<std::string>
-    testFilename("test", llvm::cl::Required, llvm::cl::desc("Testing script"));
-
-static llvm::cl::list<std::string>
-    testArguments("test-args", llvm::cl::ZeroOrMore,
-                  llvm::cl::desc("Testing script arguments"));
-
-static llvm::cl::opt<std::string>
     outputFilename("o",
                    llvm::cl::desc("Output filename for the reduced test case"),
                    llvm::cl::init("-"));
 
-// TODO: Use PassPipelineCLParser to define pass pieplines in the command line.
-static llvm::cl::opt<std::string>
-    passTestSpecifier("pass-test",
-                      llvm::cl::desc("Indicate a specific pass to be tested"));
-
 // Parse and verify the input MLIR file.
 static LogicalResult loadModule(MLIRContext &context, OwningModuleRef &module,
                                 StringRef inputFilename) {
@@ -75,16 +65,15 @@ int main(int argc, char **argv) {
 
   registerMLIRContextCLOptions();
   registerPassManagerCLOptions();
+  registerAllPasses();
+  registerReducerPasses();
+  PassPipelineCLParser parser("", "Reduction Passes to Run");
 
   llvm::cl::ParseCommandLineOptions(argc, argv,
                                     "MLIR test case reduction tool.\n");
 
   std::string errorMessage;
 
-  auto testscript = openInputFile(testFilename, &errorMessage);
-  if (!testscript)
-    llvm::report_fatal_error(errorMessage);
-
   auto output = openOutputFile(outputFilename, &errorMessage);
   if (!output)
     llvm::report_fatal_error(errorMessage);
@@ -100,29 +89,14 @@ int main(int argc, char **argv) {
   if (failed(loadModule(context, moduleRef, inputFilename)))
     llvm::report_fatal_error("Input test case can't be parsed");
 
-  // Initialize test environment.
-  const Tester test(testFilename, testArguments);
-
-  if (test.isInteresting(inputFilename) != Tester::Interestingness::True)
-    llvm::report_fatal_error(
-        "Input test case does not exhibit interesting behavior");
+  auto errorHandler = [&](const Twine &msg) {
+    return emitError(UnknownLoc::get(&context)) << msg;
+  };
 
   // Reduction pass pipeline.
   PassManager pm(&context);
-
-  if (passTestSpecifier == "DCE") {
-
-    // Opt Reduction Pass with SymbolDCEPass as opt pass.
-    pm.addPass(std::make_unique<OptReductionPass>(test, &context,
-                                                  createSymbolDCEPass()));
-
-  } else if (passTestSpecifier == "function-reducer") {
-
-    // Reduction tree pass with Reducer variant generation and single path
-    // traversal.
-    pm.addPass(std::make_unique<ReductionTreePass>(
-        FuncOp::getOperationName(), TraversalMode::SinglePath, test));
-  }
+  if (failed(parser.addToPipeline(pm, errorHandler)))
+    llvm::report_fatal_error("Failed to add pipeline");
 
   ModuleOp m = moduleRef.get().clone();