diff --git a/mlir/include/mlir/Reducer/Tester.h b/mlir/include/mlir/Reducer/Tester.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/Reducer/Tester.h @@ -0,0 +1,53 @@ +//===- 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 MLIR_REDUCER_TESTER_H +#define MLIR_REDUCER_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/Program.h" + +namespace mlir { + +// This class defines the testing environment. It contains a method to run the +// interestingness testing script on MLIR test case files and provides +// functionality to track the most reduced test case. +class Tester { +public: + Tester(StringRef testScript, + const llvm::ArrayRef &testScriptArgs); + + /// Runs the interestingness testing script on a MLIR test case file + LogicalResult run(StringRef testCase); + + /// Returns the most reduced MLIR test case module + ModuleOp getMostReduced() const { return mostReduced; } + + /// Updates the most reduced MLIR test case module + void setMostReduced(ModuleOp t) { mostReduced = std::move(t); } + +private: + StringRef testScript; + const llvm::ArrayRef &testScriptArgs; + ModuleOp mostReduced; +}; + +} // end namespace mlir + +#endif \ No newline at end of file diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -38,6 +38,7 @@ mlir-edsc-builder-api-test mlir-linalg-ods-gen mlir-opt + mlir-reduce mlir-sdbm-api-test mlir-tblgen mlir-translate 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,7 @@ +#!/bin/bash + +#Replicate bug +mlir-opt $1 + +#Interesting behavior +exit 1 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 %s -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 @@ -2,7 +2,8 @@ add_subdirectory(mlir-cpu-runner) add_subdirectory(mlir-linalg-ods-gen) add_subdirectory(mlir-opt) +add_subdirectory(mlir-reduce) add_subdirectory(mlir-rocm-runner) -add_subdirectory(mlir-translate) -add_subdirectory(mlir-vulkan-runner) add_subdirectory(mlir-shlib) +add_subdirectory(mlir-translate) +add_subdirectory(mlir-vulkan-runner) \ 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,41 @@ +get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) +get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) +set(LLVM_LINK_COMPONENTS + AllTargetsAsmParsers + AllTargetsCodeGens + AllTargetsDescs + AllTargetsInfos + AsmParser + Core + IRReader + Support + Target + TransformUtils + ) + +set(LIBS + ${dialect_libs} + ${conversion_libs} + ${test_libs} + MLIRAnalysis + MLIRDialect + MLIREDSC + MLIRIR + MLIRLoopAnalysis + MLIROptLib + MLIRParser + MLIRPass + MLIRSupport + MLIRTransforms + MLIRTransformUtils + ) + +add_llvm_tool(mlir-reduce + mlir-reduce.cpp + Tester.cpp + ) + +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.cpp b/mlir/tools/mlir-reduce/Tester.cpp new file mode 100644 --- /dev/null +++ b/mlir/tools/mlir-reduce/Tester.cpp @@ -0,0 +1,48 @@ +//===- 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 "mlir/Reducer/Tester.h" + +using namespace mlir; + +Tester::Tester(StringRef scriptName, + const llvm::ArrayRef &scriptArgs) + : testScript(scriptName), testScriptArgs(scriptArgs) {} + +/// Runs the interestingness testing script on a MLIR test case file +/// Returns success() if the interesting behavior is present in the test case or +/// failure() otherwise +LogicalResult Tester::run(StringRef testCase) { + + std::vector testerArgs; + testerArgs.push_back(testCase); + + for (const std::string &arg : testScriptArgs) + testerArgs.push_back(arg); + + testerArgs.push_back(testCase); + + std::string errMsg; + int result = llvm::sys::ExecuteAndWait( + testScript, testerArgs, /*Env=*/None, /*Redirects=*/None, + /*SecondsToWait=*/0, /*MemoryLimit=*/0, &errMsg); + + if (result < 0) + llvm::report_fatal_error("Error running interestingness test: " + errMsg); + + if (!result) + return failure(); + + return success(); +} 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,98 @@ +//===- 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/Verifier.h" +#include "mlir/InitAllDialects.h" +#include "mlir/Parser.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassManager.h" +#include "mlir/Reducer/Tester.h" +#include "mlir/Support/FileUtilities.h" +#include "mlir/Support/LogicalResult.h" +#include "mlir/Transforms/Passes.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/ToolOutputFile.h" + +using namespace mlir; + +static llvm::cl::opt inputFilename(llvm::cl::Positional, + llvm::cl::Required, + llvm::cl::desc("")); + +static llvm::cl::opt + testFilename("test", llvm::cl::Required, llvm::cl::desc("Testing script")); + +static llvm::cl::list + testArguments("test-args", llvm::cl::ZeroOrMore, + llvm::cl::desc("Testing script arguments")); + +static llvm::cl::opt + outputFilename("o", + llvm::cl::desc("Output filename for the reduced test case"), + llvm::cl::init("-")); + +// Parse and verify the input MLIR file +static LogicalResult loadModule(MLIRContext &context, OwningModuleRef &module, + StringRef inputFilename) { + module = parseSourceFile(inputFilename, &context); + if (!module || failed(verify(*module))) + return failure(); + + return success(); +} + +int main(int argc, char **argv) { + + llvm::InitLLVM y(argc, argv); + + registerAllDialects(); + registerMLIRContextCLOptions(); + registerPassManagerCLOptions(); + + 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); + + mlir::MLIRContext context; + mlir::OwningModuleRef moduleRef; + context.allowUnregisteredDialects(true); + + if (failed(loadModule(context, moduleRef, inputFilename))) + llvm::report_fatal_error("Input test case can't be parsed"); + + // Initialize test environment + Tester test(testFilename, testArguments); + test.setMostReduced(moduleRef.get()); + + if (failed(test.run(inputFilename))) + llvm::report_fatal_error( + "Input test case does not exhibit interesting behavior"); + + moduleRef.get().print(output->os()); + output->keep(); + + return 0; +} \ No newline at end of file