CIRCT  19.0.0git
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"
14 #include "mlir/IR/Verifier.h"
15 #include "llvm/Support/ToolOutputFile.h"
16 
17 using namespace llvm;
18 using namespace mlir;
19 using namespace circt;
20 
21 //===----------------------------------------------------------------------===//
22 // Tester
23 //===----------------------------------------------------------------------===//
24 
25 Tester::Tester(StringRef testScript, ArrayRef<std::string> testScriptArgs,
26  bool testMustFail)
27  : testScript(testScript), testScriptArgs(testScriptArgs),
28  testMustFail(testMustFail) {}
29 
30 std::pair<bool, size_t> Tester::isInteresting(ModuleOp module) const {
31  auto test = get(module);
32  return std::make_pair(test.isInteresting(), test.getSize());
33 }
34 
35 /// Runs the interestingness testing script on a MLIR test case file. Returns
36 /// true if the interesting behavior is present in the test case or false
37 /// otherwise.
38 bool Tester::isInteresting(StringRef testCase) const {
39  // Assemble the arguments to the tester. Note that the first one has to be the
40  // name of the program.
41  SmallVector<StringRef> testerArgs;
42  testerArgs.push_back(testScript);
43  testerArgs.append(testScriptArgs.begin(), testScriptArgs.end());
44  testerArgs.push_back(testCase);
45 
46  // Run the tester.
47  std::string errMsg;
48  int result = llvm::sys::ExecuteAndWait(
49  testScript, testerArgs, /*Env=*/std::nullopt, /*Redirects=*/std::nullopt,
50  /*SecondsToWait=*/0, /*MemoryLimit=*/0, &errMsg);
51  if (result < 0)
52  llvm::report_fatal_error(
53  Twine("Error running interestingness test: ") + errMsg, false);
54 
55  if (testMustFail)
56  return result > 0;
57 
58  return result == 0;
59 }
60 
61 /// Create a new test case for the given `module`.
62 TestCase Tester::get(mlir::ModuleOp module) const {
63  return TestCase(*this, module);
64 }
65 
66 /// Create a new test case for the given file already on disk.
67 TestCase Tester::get(llvm::Twine filepath) const {
68  return TestCase(*this, filepath);
69 }
70 
71 //===----------------------------------------------------------------------===//
72 // Test Case
73 //===----------------------------------------------------------------------===//
74 
75 /// Check whether the MLIR module is valid. Actual validation is only
76 /// performed on the first call; subsequent calls return the cached result.
78  // Assume already-provided test cases on disk are valid.
79  if (!module)
80  return true;
81  if (!valid)
82  valid = succeeded(verify(module));
83  return *valid;
84 }
85 
86 /// Determine the path to the MLIR module on disk. Actual writing to disk is
87 /// only performed on the first call; subsequent calls return the cached result.
88 StringRef TestCase::getFilepath() {
89  if (!isValid())
90  return "";
92  return filepath;
93 }
94 
95 /// Determine the size of the MLIR module on disk. Actual writing to disk is
96 /// only performed on the first call; subsequent calls return the cached result.
98  if (!isValid())
99  return 0;
101  return *size;
102 }
103 
104 /// Run the tester on the MLIR module and return whether it is deemed
105 /// interesting. Actual testing is only performed on the first call; subsequent
106 /// calls return the cached result.
108  if (!isValid())
109  return false;
111  if (!interesting)
113  return *interesting;
114 }
115 
116 /// Ensure `filepath` and `size` are populated, and that the test case is in a
117 /// file on disk.
119  // Write the module to a temporary file if no already-prepared file path has
120  // been provided to the test.
121  if (filepath.empty()) {
122  assert(module);
123 
124  // Pick a temporary output file path.
125  int fd;
126  std::error_code ec = llvm::sys::fs::createTemporaryFile(
127  "circt-reduce", "mlir", fd, filepath);
128  if (ec)
129  llvm::report_fatal_error(
130  Twine("Error making unique filename: ") + ec.message(), false);
131 
132  // Write to the output.
133  file = std::make_unique<llvm::ToolOutputFile>(filepath, fd);
134  module.print(file->os());
135  file->os().close();
136  if (file->os().has_error())
137  llvm::report_fatal_error(llvm::Twine("Error emitting the IR to file `") +
138  filepath + "`",
139  false);
140 
141  // Update the file size.
142  size = file->os().tell();
143  return;
144  }
145 
146  // Otherwise just determine the size of the already-prepared file on disk.
147  if (!size) {
148  uint64_t fileSize;
149  std::error_code ec = llvm::sys::fs::file_size(filepath, fileSize);
150  if (ec)
151  llvm::report_fatal_error(Twine("Error determining size of file `") +
152  filepath + "`: " + ec.message(),
153  false);
154  size = fileSize;
155  }
156 }
assert(baseType &&"element must be base type")
A single test case to be run by a tester.
Definition: Tester.h:74
std::optional< bool > interesting
Whether the tester has run on this test case, and its result.
Definition: Tester.h:132
llvm::SmallString< 32 > filepath
The path on disk where the test case is located.
Definition: Tester.h:118
mlir::ModuleOp module
The module to be tested.
Definition: Tester.h:116
size_t getSize()
Determine the size of the MLIR module on disk.
Definition: Tester.cpp:97
bool isValid()
Check whether the MLIR module is valid.
Definition: Tester.cpp:77
std::optional< size_t > size
Whether the size of the test case on disk has already been determined, and if yes,...
Definition: Tester.h:130
void ensureFileOnDisk()
Ensure filepath and size are populated, and that the test case is in a file on disk.
Definition: Tester.cpp:118
std::optional< bool > valid
Whether the MLIR module validation has run, and its result.
Definition: Tester.h:127
bool isInteresting()
Run the tester on the MLIR module and return whether it is deemed interesting.
Definition: Tester.cpp:107
const Tester & tester
The tester that is used to run this test case.
Definition: Tester.h:114
llvm::StringRef getFilepath()
Determine the path to the MLIR module on disk.
Definition: Tester.cpp:88
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:124
llvm::StringRef testScript
The binary to execute in order to check a reduction attempt for interestingness.
Definition: Tester.h:59
bool testMustFail
Consider the testcase to be interesting if it fails rather than on exit code 0.
Definition: Tester.h:66
TestCase get(mlir::ModuleOp module) const
Create a new test case for the given module.
Definition: Tester.cpp:62
std::pair< bool, size_t > isInteresting(mlir::ModuleOp module) const
Runs the interestingness testing script on a MLIR test case file.
llvm::ArrayRef< std::string > testScriptArgs
Additional arguments to pass to testScript.
Definition: Tester.h:62
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21