CIRCT 24.0.0git
Loading...
Searching...
No Matches
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 mlir;
20using namespace circt;
21
22//===----------------------------------------------------------------------===//
23// Tester
24//===----------------------------------------------------------------------===//
25
30
31std::pair<bool, size_t> Tester::isInteresting(ModuleOp module) const {
32 auto test = get(module);
33 return std::make_pair(test.isInteresting(), test.getSize());
34}
35
36/// Runs the interestingness testing script on a MLIR test case file. Returns
37/// true if the interesting behavior is present in the test case or false
38/// otherwise.
39bool Tester::isInteresting(StringRef testCase) const {
40 // Assemble the arguments to the tester. Note that the first one has to be the
41 // name of the program.
42 SmallVector<StringRef> testerArgs;
43 testerArgs.push_back(testScript);
44 testerArgs.append(testScriptArgs.begin(), testScriptArgs.end());
45 testerArgs.push_back(testCase);
46
47 // Run the tester.
48 std::string errMsg;
49 int result = llvm::sys::ExecuteAndWait(
50 testScript, testerArgs, /*Env=*/std::nullopt, /*Redirects=*/{},
51 /*SecondsToWait=*/0, /*MemoryLimit=*/0, &errMsg);
52 if (result < 0)
53 llvm::report_fatal_error(
54 Twine("Error running interestingness test: ") + errMsg, false);
55
56 if (testMustFail)
57 return result > 0;
58
59 return result == 0;
60}
61
62/// Create a new test case for the given `module`.
63TestCase Tester::get(mlir::ModuleOp module) const {
64 return TestCase(*this, module);
65}
66
67/// Create a new test case for the given file already on disk.
68TestCase Tester::get(llvm::Twine filepath) const {
69 return TestCase(*this, filepath);
70}
71
72//===----------------------------------------------------------------------===//
73// Test Case
74//===----------------------------------------------------------------------===//
75
76/// Check whether the MLIR module is valid. Actual validation is only
77/// performed on the first call; subsequent calls return the cached result.
79 // Assume already-provided test cases on disk are valid.
80 if (!module)
81 return true;
82 if (!valid)
83 valid = succeeded(verify(module));
84 return *valid;
85}
86
87/// Determine the path to the MLIR module on disk. Actual writing to disk is
88/// only performed on the first call; subsequent calls return the cached result.
90 if (!isValid())
91 return "";
93 return filepath;
94}
95
96/// Determine the size of the MLIR module on disk. Actual writing to disk is
97/// only performed on the first call; subsequent calls return the cached result.
99 if (!isValid())
100 return 0;
102 return *size;
103}
104
105/// Run the tester on the MLIR module and return whether it is deemed
106/// interesting. Actual testing is only performed on the first call; subsequent
107/// calls return the cached result.
109 if (!isValid())
110 return false;
112 if (!interesting)
113 interesting = tester.isInteresting(filepath);
114 return *interesting;
115}
116
117/// Ensure `filepath` and `size` are populated, and that the test case is in a
118/// file on disk.
120 // Write the module to a temporary file if no already-prepared file path has
121 // been provided to the test.
122 if (filepath.empty()) {
123 assert(module);
124
125 // Pick a temporary output file path.
126 int fd;
127 std::error_code ec = llvm::sys::fs::createTemporaryFile(
128 "circt-reduce", "mlir", fd, filepath);
129 if (ec)
130 llvm::report_fatal_error(
131 Twine("Error making unique filename: ") + ec.message(), false);
132
133 // Write to the output.
134 file = std::make_unique<llvm::ToolOutputFile>(filepath, fd);
135 if (tester.emitBytecode) {
136 if (failed(writeBytecodeToFile(
137 module, file->os(),
138 mlir::BytecodeWriterConfig(getCirctVersion())))) {
139 file->os().close();
140 llvm::report_fatal_error(
141 llvm::Twine("Error emitting the IR to file `") + filepath + "`",
142 false);
143 }
144 } else {
145 module.print(file->os());
146 }
147
148 file->os().close();
149 if (file->os().has_error())
150 llvm::report_fatal_error(llvm::Twine("Error emitting the IR to file `") +
151 filepath + "`",
152 false);
153
154 // Update the file size.
155 size = file->os().tell();
156 return;
157 }
158
159 // Otherwise just determine the size of the already-prepared file on disk.
160 if (!size) {
161 uint64_t fileSize;
162 std::error_code ec = llvm::sys::fs::file_size(filepath, fileSize);
163 if (ec)
164 llvm::report_fatal_error(Twine("Error determining size of file `") +
165 filepath + "`: " + ec.message(),
166 false);
167 size = fileSize;
168 }
169}
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
llvm::SmallString< 32 > filepath
The path on disk where the test case is located.
Definition Tester.h:121
mlir::ModuleOp module
The module to be tested.
Definition Tester.h:119
size_t getSize()
Determine the size of the MLIR module on disk.
Definition Tester.cpp:98
bool isValid()
Check whether the MLIR module is valid.
Definition Tester.cpp:78
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:119
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:108
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:89
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:26
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:63
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()