diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -41,6 +41,7 @@ mlir-sdbm-api-test mlir-tblgen mlir-translate + mlir-reduce mlir_test_cblas mlir_test_cblas_interface mlir_runner_utils diff --git a/mlir/test/mlir-reduce/test.sh b/mlir/test/mlir-reduce/test.sh new file mode 100755 --- /dev/null +++ b/mlir/test/mlir-reduce/test.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +mlir-opt $1 | grep 'NO BUG' &> /dev/null + +if [ $? == 0 ]; then + exit 0 +else + exit 1 + #Interesting behavior +fi diff --git a/mlir/test/mlir-reduce/testcase.mlir b/mlir/test/mlir-reduce/testcase.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/mlir-reduce/testcase.mlir @@ -0,0 +1,14 @@ +// RUN: mlir-reduce %p/testcase.mlir -test %p/test.sh + +func @simple1(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) { + cond_br %arg0, ^bb1, ^bb2 +^bb1: + br ^bb3(%arg1 : memref<2xf32>) +^bb2: + %0 = alloc() : memref<2xf32> + br ^bb3(%0 : memref<2xf32>) +^bb3(%1: memref<2xf32>): + return +} + +// ----- diff --git a/mlir/tools/CMakeLists.txt b/mlir/tools/CMakeLists.txt --- a/mlir/tools/CMakeLists.txt +++ b/mlir/tools/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(mlir-translate) add_subdirectory(mlir-vulkan-runner) add_subdirectory(mlir-shlib) +add_subdirectory(mlir-reduce) \ No newline at end of file diff --git a/mlir/tools/mlir-reduce/CMakeLists.txt b/mlir/tools/mlir-reduce/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/mlir/tools/mlir-reduce/CMakeLists.txt @@ -0,0 +1,48 @@ +set(LLVM_OPTIONAL_SOURCES + null.cpp +) + +get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) +get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) +set(LLVM_LINK_COMPONENTS + Core + Support + AsmParser + AllTargetsAsmParsers + AllTargetsCodeGens + AllTargetsDescs + AllTargetsInfos + IRReader + Target + TransformUtils + ) + +set(LIBS + ${dialect_libs} + ${conversion_libs} + ${test_libs} + MLIRLoopAnalysis + MLIRAnalysis + MLIRDialect + MLIREDSC + MLIROptLib + MLIRParser + MLIRPass + MLIRTransforms + MLIRTransformUtils + MLIRSupport + MLIRIR + ) + +add_llvm_tool(mlir-reduce + mlir-reduce.cpp + Tester.cpp + + DEPENDS + ${LIBS} + ) + +target_link_libraries(mlir-reduce PRIVATE ${LIBS}) +llvm_update_compile_flags(mlir-reduce) + +mlir_check_all_link_libraries(mlir-reduce) diff --git a/mlir/tools/mlir-reduce/Tester.h b/mlir/tools/mlir-reduce/Tester.h new file mode 100644 --- /dev/null +++ b/mlir/tools/mlir-reduce/Tester.h @@ -0,0 +1,51 @@ + +//===- Tester.h -------------------------------------------------*- 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 testing environment. It provides functionality to run +// the interestingness scripts on the MLIR test cases and keep track of the most +// reduced test case variant. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_MLIRREDUCE_TESTER_H +#define LLVM_TOOLS_MLIRREDUCE_TESTER_H + +#include + +#include "mlir/IR/Module.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" + +using namespace llvm; +using namespace mlir; + +class Tester { + +public: + Tester(StringRef testScript, const std::vector &testScriptArgs); + + /// Runs the interestingness testing script on a MLIR test case file + int run(StringRef testCase); + + /// Returns the most reduced MLIR test case module + ModuleOp getTestCase() const { return testCase; } + + /// Updates the most reduced MLIR test case module + void setTestCase(ModuleOp t) { testCase = std::move(t); } + +private: + StringRef testScript; + const std::vector &testScriptArgs; + ModuleOp testCase; +}; + +#endif diff --git a/mlir/tools/mlir-reduce/Tester.cpp b/mlir/tools/mlir-reduce/Tester.cpp new file mode 100644 --- /dev/null +++ b/mlir/tools/mlir-reduce/Tester.cpp @@ -0,0 +1,47 @@ +//===- Tester.cpp ---------------------------------------------------------===// +// +// 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 testing environment. It provides functionality to run +// the interestingness scripts on the MLIR test cases and keep track of the most +// reduced test case variant. +// +//===----------------------------------------------------------------------===// + +#include "Tester.h" + +using namespace llvm; + +Tester::Tester(StringRef scriptName, const std::vector &scriptArgs) + : testScript(scriptName), testScriptArgs(scriptArgs) {} + +/// Runs the interestingness testing script on a MLIR test case file +int Tester::run(StringRef testCase) { + + std::vector testerArgs; + testerArgs.push_back(testCase); + + for (const auto &arg : testScriptArgs) + testerArgs.push_back(arg); + + testerArgs.push_back(testCase); + + std::string errMsg; + int result = sys::ExecuteAndWait( + testScript, testerArgs, /*Env=*/None, /*Redirects=*/None, + /*SecondsToWait=*/0, /*MemoryLimit=*/0, &errMsg); + + if (result < 0) { + Error ec = make_error("Error running interesting-ness test: " + + errMsg, + inconvertibleErrorCode()); + errs() << toString(std::move(ec)); + exit(1); + } + + return result; +} diff --git a/mlir/tools/mlir-reduce/mlir-reduce.cpp b/mlir/tools/mlir-reduce/mlir-reduce.cpp new file mode 100644 --- /dev/null +++ b/mlir/tools/mlir-reduce/mlir-reduce.cpp @@ -0,0 +1,132 @@ +//===- mlir-reduce.cpp - The MLIR reducer ---------------------------------===// +// +// 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 implements the general framework of the MLIR reducer tool. It +// parses the command line arguments, parses the initial MLIR test case and sets +// up the testing environment. It outputs the most reduced test case variant +// after executing the reduction passes. +// +//===----------------------------------------------------------------------===// + +#include + +#include "mlir/IR/AsmState.h" +#include "mlir/IR/Diagnostics.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/IR/Module.h" +#include "mlir/InitAllDialects.h" +#include "mlir/InitAllTranslations.h" +#include "mlir/Parser.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassManager.h" +#include "mlir/Support/FileUtilities.h" +#include "mlir/Support/LogicalResult.h" +#include "mlir/Support/ToolUtilities.h" +#include "mlir/Transforms/Passes.h" +#include "mlir/Translation.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/ToolOutputFile.h" + +#include "Tester.h" + +using namespace llvm; +using namespace mlir; + +static cl::opt inputFilename(cl::Positional, cl::Required, + cl::desc("Input MLIR test case")); + +static cl::opt testFilename("test", cl::Required, + cl::desc("Oracle testing script")); + +static cl::list + testArguments("test-args", cl::ZeroOrMore, + cl::desc("Arguments passed to the oracle testing script")); + +static cl::opt outputFilename("o", cl::desc("Reduced test case"), + cl::init("-")); + +// Parses the input MLIR file +int loadMLIR(MLIRContext &context, OwningModuleRef &module, + StringRef inputFilename) { + + if (inputFilename.endswith(".mlir")) { + module = parseSourceFile(inputFilename, &context); + } else { + return -1; + } + + return 0; +} + +// Parse th input MLIR file and apply pre-processing optimization passes +int loadAndProcessMLIR(MLIRContext &context, OwningModuleRef &module, + StringRef inputFilename) { + + int error = loadMLIR(context, module, inputFilename); + + if (error != 0) + return error; + + mlir::PassManager pm(&context); + mlir::OpPassManager &optPM = pm.nest(); + optPM.addPass(mlir::createCanonicalizerPass()); + + return 0; +} + +int main(int argc, char **argv) { + + InitLLVM y(argc, argv); + + registerAllDialects(); + registerMLIRContextCLOptions(); + registerPassManagerCLOptions(); + + cl::ParseCommandLineOptions(argc, argv, "MLIR test case reduction tool.\n"); + + std::string errorMessage; + + auto testscript = openInputFile(testFilename, &errorMessage); + if (!testscript) { + errs() << errorMessage << "\n"; + exit(1); + } + + auto output = openOutputFile(outputFilename, &errorMessage); + if (!output) { + errs() << errorMessage << "\n"; + exit(1); + } + + mlir::MLIRContext context; + mlir::OwningModuleRef moduleRef; + context.allowUnregisteredDialects(true); + + if (int error = loadAndProcessMLIR(context, moduleRef, inputFilename)) + return error; + + ModuleOp module = moduleRef.get(); + + // Initialize test environment + Tester test(testFilename, testArguments); + test.setTestCase(std::move(module)); + + if (!Test.run(inputFilename)) { + errs() << "Initial test case does not exhibit the interesting behavior\n " + "No reduction to be performed\n"; + exit(1); + } + + module.print(output->os()); + output->keep(); + + return 0; +}