diff --git a/mlir/include/mlir/Reducer/OptReductionPass.h b/mlir/include/mlir/Reducer/OptReductionPass.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/Reducer/OptReductionPass.h @@ -0,0 +1,52 @@ +//===- OptReductionPass.h - Optimization Reduction Pass Wrapper -*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the Opt Reduction Pass Wrapper. It creates a pass to run +// any optimization pass within it and only replaces the output module with the +// transformed version if it is smaller and interesting. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_REDUCER_OPTREDUCTIONPASS_H +#define MLIR_REDUCER_OPTREDUCTIONPASS_H + +#include "PassDetail.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassManager.h" +#include "mlir/Reducer/ReductionNode.h" +#include "mlir/Reducer/ReductionTreePass.h" +#include "mlir/Reducer/Tester.h" +#include "mlir/Transforms/Passes.h" +#include "llvm/Support/Debug.h" + +namespace mlir { + +class OptReductionPass : public OptReductionBase { +public: + OptReductionPass(const Tester *test, MLIRContext *context, + std::unique_ptr optPass); + + OptReductionPass(const OptReductionPass &srcPass); + + /// 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 optPass; +}; + +} // end namespace mlir + +#endif diff --git a/mlir/include/mlir/Reducer/Passes.td b/mlir/include/mlir/Reducer/Passes.td --- a/mlir/include/mlir/Reducer/Passes.td +++ b/mlir/include/mlir/Reducer/Passes.td @@ -17,7 +17,10 @@ def ReductionTree : Pass<"reduction-tree", "ModuleOp"> { let summary = "A general reduction tree pass for the MLIR Reduce Tool"; - let constructor = "mlir::createReductionTreePass()"; } -#endif // MLIR_REDUCE_PASSES +def OptReduction : Pass<"opt-reduction-pass", "ModuleOp"> { + let summary = "A reduction pass wrapper for optimization passes"; +} + +#endif // MLIR_REDUCER_PASSES diff --git a/mlir/include/mlir/Reducer/ReductionTreePass.h b/mlir/include/mlir/Reducer/ReductionTreePass.h --- a/mlir/include/mlir/Reducer/ReductionTreePass.h +++ b/mlir/include/mlir/Reducer/ReductionTreePass.h @@ -34,7 +34,7 @@ // class. class ReductionTreeUtils { public: - void updateGoldenModule(ModuleOp &golden, ModuleOp reduced); + static void updateGoldenModule(ModuleOp &golden, ModuleOp reduced); }; /// This class defines the Reduction Tree Pass. It provides a framework to diff --git a/mlir/test/mlir-reduce/dce-test.mlir b/mlir/test/mlir-reduce/dce-test.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/mlir-reduce/dce-test.mlir @@ -0,0 +1,17 @@ +// UNSUPPORTED: -windows- +// RUN: mlir-reduce %s -test %S/failure-test.sh -pass-test DCE | FileCheck %s +// This input should be reduced by the pass pipeline so that only +// the @simple1 function remains as the other fucntions should be +// removed by the dead code elimination pass. +// CHECK-LABEL: func @simple1(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) { + +// CHECK-NOT: func @dead_nested_function +func @dead_private_function() attributes { sym_visibility = "private" } + +// CHECK-NOT: func @dead_nested_function +func @dead_nested_function() attributes { sym_visibility = "nested" } + +func @simple1(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) { + "test.crashOp" () : () -> () + return +} diff --git a/mlir/test/mlir-reduce/reduction-tree-pass.mlir b/mlir/test/mlir-reduce/multiple-function.mlir rename from mlir/test/mlir-reduce/reduction-tree-pass.mlir rename to mlir/test/mlir-reduce/multiple-function.mlir --- a/mlir/test/mlir-reduce/reduction-tree-pass.mlir +++ b/mlir/test/mlir-reduce/multiple-function.mlir @@ -1,5 +1,5 @@ // UNSUPPORTED: -windows- -// RUN: mlir-reduce %s -test %S/failure-test.sh | FileCheck %s +// RUN: mlir-reduce %s -test %S/failure-test.sh -pass-test function-reducer | 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. diff --git a/mlir/test/mlir-reduce/testcase-linux.mlir b/mlir/test/mlir-reduce/simple-test.mlir rename from mlir/test/mlir-reduce/testcase-linux.mlir rename to mlir/test/mlir-reduce/simple-test.mlir --- a/mlir/test/mlir-reduce/testcase-linux.mlir +++ b/mlir/test/mlir-reduce/simple-test.mlir @@ -1,5 +1,5 @@ // UNSUPPORTED: -windows- -// RUN: mlir-reduce %s -test %S/test.sh +// RUN: mlir-reduce %s -test %S/test.sh -pass-test function func @simple1(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) { cond_br %arg0, ^bb1, ^bb2 @@ -10,4 +10,4 @@ br ^bb3(%0 : memref<2xf32>) ^bb3(%1: memref<2xf32>): return -} \ No newline at end of file +} diff --git a/mlir/test/mlir-reduce/test-reducer-pass.mlir b/mlir/test/mlir-reduce/single-function.mlir rename from mlir/test/mlir-reduce/test-reducer-pass.mlir rename to mlir/test/mlir-reduce/single-function.mlir --- a/mlir/test/mlir-reduce/test-reducer-pass.mlir +++ b/mlir/test/mlir-reduce/single-function.mlir @@ -1,5 +1,5 @@ // RUN: mlir-opt %s -// RUN: not mlir-opt %s -test-mlir-reducer +// RUN: not mlir-opt %s -test-mlir-reducer -pass-test function-reducer func @test() { "test.crashOp"() : () -> () diff --git a/mlir/tools/mlir-reduce/CMakeLists.txt b/mlir/tools/mlir-reduce/CMakeLists.txt --- a/mlir/tools/mlir-reduce/CMakeLists.txt +++ b/mlir/tools/mlir-reduce/CMakeLists.txt @@ -32,6 +32,7 @@ ) add_llvm_tool(mlir-reduce + OptReductionPass.cpp Passes/FunctionReducer.cpp ReductionNode.cpp ReductionTreePass.cpp diff --git a/mlir/tools/mlir-reduce/OptReductionPass.cpp b/mlir/tools/mlir-reduce/OptReductionPass.cpp new file mode 100644 --- /dev/null +++ b/mlir/tools/mlir-reduce/OptReductionPass.cpp @@ -0,0 +1,55 @@ +//===- OptReductionPass.cpp - Optimization Reduction Pass Wrapper ---------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the Opt Reduction Pass class. It creates a pass to run +// any optimization pass within it and only replaces the output module with the +// transformed version if it is smaller and interesting. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Reducer/OptReductionPass.h" + +#define DEBUG_TYPE "mlir-reduce" + +using namespace mlir; + +OptReductionPass::OptReductionPass(const Tester *test, MLIRContext *context, + std::unique_ptr optPass) + : context(context), test(test), optPass(std::move(optPass)) {} + +OptReductionPass::OptReductionPass(const 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"); + + ModuleOp module = this->getOperation(); + ModuleOp moduleVariant = module.clone(); + PassManager pmTransform(context); + pmTransform.addPass(std::move(optPass)); + + if (failed(pmTransform.run(moduleVariant))) + return; + + ReductionNode original(module, nullptr); + original.measureAndTest(test); + + ReductionNode reduced(moduleVariant, nullptr); + reduced.measureAndTest(test); + + if (reduced.isInteresting() && reduced.getSize() < original.getSize()) { + ReductionTreeUtils::updateGoldenModule(module, reduced.getModule().clone()); + LLVM_DEBUG(llvm::dbgs() << "\nSuccessful Transformed version\n\n"); + } else { + LLVM_DEBUG(llvm::dbgs() << "\nUnsuccessful Transformed version\n\n"); + } + + LLVM_DEBUG(llvm::dbgs() << "Pass Complete\n\n"); +} diff --git a/mlir/tools/mlir-reduce/mlir-reduce.cpp b/mlir/tools/mlir-reduce/mlir-reduce.cpp --- a/mlir/tools/mlir-reduce/mlir-reduce.cpp +++ b/mlir/tools/mlir-reduce/mlir-reduce.cpp @@ -19,6 +19,7 @@ #include "mlir/Parser.h" #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassManager.h" +#include "mlir/Reducer/OptReductionPass.h" #include "mlir/Reducer/ReductionNode.h" #include "mlir/Reducer/ReductionTreePass.h" #include "mlir/Reducer/Tester.h" @@ -46,6 +47,11 @@ 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 + 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) { @@ -94,10 +100,19 @@ // Reduction pass pipeline. PassManager pm(&context); - // Reduction tree pass with OpReducer variant generation and single path - // traversal. - pm.addPass( - std::make_unique>(&test)); + if (passTestSpecifier == "DCE") { + + // Opt Reduction Pass with SymbolDCEPass as opt pass. + pm.addPass(std::make_unique(&test, &context, + createSymbolDCEPass())); + + } else if (passTestSpecifier == "function-reducer") { + + // Reduction tree pass with OpReducer variant generation and single path + // traversal. + pm.addPass(std::make_unique>( + &test)); + } ModuleOp m = moduleRef.get().clone();