Loading [MathJax]/extensions/tex2jax.js
CIRCT 21.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Tester.cpp
Go to the documentation of this file.
1//===- Tester.cpp ---------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the Tester class used in the CIRCT reduce tool.
10//
11//===----------------------------------------------------------------------===//
12
13#include "circt/Reduce/Tester.h"
15#include "mlir/Bytecode/BytecodeWriter.h"
16#include "mlir/IR/Verifier.h"
17#include "llvm/Support/ToolOutputFile.h"
18
19using namespace llvm;
20using namespace mlir;
21using namespace circt;
22
23//===----------------------------------------------------------------------===//
24// Tester
25//===----------------------------------------------------------------------===//
26
27Tester::Tester(StringRef testScript, ArrayRef<std::string> testScriptArgs,
28 bool testMustFail, bool emitBytecode)
29 : emitBytecode(emitBytecode), testScript(testScript),
30 testScriptArgs(testScriptArgs), testMustFail(testMustFail) {}
31
32std::pair<bool, size_t> Tester::isInteresting(ModuleOp module) const {
33 auto test = get(module);
34 return std::make_pair(test.isInteresting(), test.getSize());
35}
36
37/// Runs the interestingness testing script on a MLIR test case file. Returns
38/// true if the interesting behavior is present in the test case or false
39/// otherwise.
40bool Tester::isInteresting(StringRef testCase) const {
41 // Assemble the arguments to the tester. Note that the first one has to be the
42 // name of the program.
43 SmallVector<StringRef> testerArgs;
44 testerArgs.push_back(testScript);
45 testerArgs.append(testScriptArgs.begin(), testScriptArgs.end());
46 testerArgs.push_back(testCase);
47
48 // Run the tester.
49 std::string errMsg;
50 int result = llvm::sys::ExecuteAndWait(
51 testScript, testerArgs, /*Env=*/std::nullopt, /*Redirects=*/std::nullopt,
52 /*SecondsToWait=*/0, /*MemoryLimit=*/0, &errMsg);
53 if (result < 0)
54 llvm::report_fatal_error(
55 Twine("Error running interestingness test: ") + errMsg, false);
56
57 if (testMustFail)
58 return result > 0;
59
60 return result == 0;
61}
62
63/// Create a new test case for the given `module`.
64TestCase Tester::get(mlir::ModuleOp module) const {
65 return TestCase(*this, module);
66}
67
68/// Create a new test case for the given file already on disk.
69TestCase Tester::get(llvm::Twine filepath) const {
70 return TestCase(*this, filepath);
71}
72
73//===----------------------------------------------------------------------===//
74// Test Case
75//===----------------------------------------------------------------------===//
76
77/// Check whether the MLIR module is valid. Actual validation is only
78/// performed on the first call; subsequent calls return the cached result.
80 // Assume already-provided test cases on disk are valid.
81 if (!module)
82 return true;
83 if (!valid)
84 valid = succeeded(verify(module));
85 return *valid;
86}
87
88/// Determine the path to the MLIR module on disk. Actual writing to disk is
89/// only performed on the first call; subsequent calls return the cached result.
91 if (!isValid())
92 return "";
94 return filepath;
95}
96
97/// Determine the size of the MLIR module on disk. Actual writing to disk is
98/// only performed on the first call; subsequent calls return the cached result.
100 if (!isValid())
101 return 0;
103 return *size;
104}
105
106/// Run the tester on the MLIR module and return whether it is deemed
107/// interesting. Actual testing is only performed on the first call; subsequent
108/// calls return the cached result.
110 if (!isValid())
111 return false;
113 if (!interesting)
115 return *interesting;
116}
117
118/// Ensure `filepath` and `size` are populated, and that the test case is in a
119/// file on disk.
121 // Write the module to a temporary file if no already-prepared file path has
122 // been provided to the test.
123 if (filepath.empty()) {
124 assert(module);
125
126 // Pick a temporary output file path.
127 int fd;
128 std::error_code ec = llvm::sys::fs::createTemporaryFile(
129 "circt-reduce", "mlir", fd, filepath);
130 if (ec)
131 llvm::report_fatal_error(
132 Twine("Error making unique filename: ") + ec.message(), false);
133
134 // Write to the output.
135 file = std::make_unique<llvm::ToolOutputFile>(filepath, fd);
136 if (tester.emitBytecode) {
137 if (failed(writeBytecodeToFile(
138 module, file->os(),
139 mlir::BytecodeWriterConfig(getCirctVersion())))) {
140 file->os().close();
141 llvm::report_fatal_error(
142 llvm::Twine("Error emitting the IR to file `") + filepath + "`",
143 false);
144 }
145 } else {
146 module.print(file->os());
147 }
148
149 file->os().close();
150 if (file->os().has_error())
151 llvm::report_fatal_error(llvm::Twine("Error emitting the IR to file `") +
152 filepath + "`",
153 false);
154
155 // Update the file size.
156 size = file->os().tell();
157 return;
158 }
159
160 // Otherwise just determine the size of the already-prepared file on disk.
161 if (!size) {
162 uint64_t fileSize;
163 std::error_code ec = llvm::sys::fs::file_size(filepath, fileSize);
164 if (ec)
165 llvm::report_fatal_error(Twine("Error determining size of file `") +
166 filepath + "`: " + ec.message(),
167 false);
168 size = fileSize;
169 }
170}
assert(baseType &&"element must be base type")
A single test case to be run by a tester.
Definition Tester.h:77
std::optional< bool > interesting
Whether the tester has run on this test case, and its result.
Definition Tester.h:135
mlir::ModuleOp llvm::SmallString< 32 > filepath
The module to be tested.
Definition Tester.h:121
size_t getSize()
Determine the size of the MLIR module on disk.
Definition Tester.cpp:99
bool isValid()
Check whether the MLIR module is valid.
Definition Tester.cpp:79
std::optional< size_t > size
Whether the size of the test case on disk has already been determined, and if yes,...
Definition Tester.h:133
void ensureFileOnDisk()
Ensure filepath and size are populated, and that the test case is in a file on disk.
Definition Tester.cpp:120
std::optional< bool > valid
Whether the MLIR module validation has run, and its result.
Definition Tester.h:130
bool isInteresting()
Run the tester on the MLIR module and return whether it is deemed interesting.
Definition Tester.cpp:109
const Tester & tester
The tester that is used to run this test case.
Definition Tester.h:117
llvm::StringRef getFilepath()
Determine the path to the MLIR module on disk.
Definition Tester.cpp:90
std::unique_ptr< llvm::ToolOutputFile > file
In case this test case has created a temporary file on disk, this is the ToolOutputFile that did the ...
Definition Tester.h:127
llvm::StringRef testScript
The binary to execute in order to check a reduction attempt for interestingness.
Definition Tester.h:62
const bool emitBytecode
If true, use MLIR bytecode on-disk. Otherwise, use MLIR text.
Definition Tester.h:57
Tester(llvm::StringRef testScript, llvm::ArrayRef< std::string > testScriptArgs, bool testMustFail, bool emitBytecode)
Definition Tester.cpp:27
std::pair< bool, size_t > isInteresting(mlir::ModuleOp module) const
Runs the interestingness testing script on a MLIR test case file.
bool testMustFail
Consider the testcase to be interesting if it fails rather than on exit code 0.
Definition Tester.h:69
TestCase get(mlir::ModuleOp module) const
Create a new test case for the given module.
Definition Tester.cpp:64
llvm::ArrayRef< std::string > testScriptArgs
Additional arguments to pass to testScript.
Definition Tester.h:65
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
const char * getCirctVersion()