Skip to content

Commit 1c03915

Browse files
committed
bugpoint: Return Errors instead of passing around strings
This replaces the threading of `std::string &Error` through all of these APIs with checked Error returns instead. There are very few places here that actually emit any errors right now, but threading the APIs through will allow us to replace a bunch of exit(1)'s that are scattered through this code with proper error handling. This is more or less NFC, but does move around where a couple of error messages are printed out. llvm-svn: 280720
1 parent 18ea094 commit 1c03915

10 files changed

+558
-543
lines changed

llvm/tools/bugpoint/BugDriver.cpp

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,11 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
146146
/// run - The top level method that is invoked after all of the instance
147147
/// variables are set up from command line arguments.
148148
///
149-
bool BugDriver::run(std::string &ErrMsg) {
149+
Error BugDriver::run() {
150150
if (run_find_bugs) {
151151
// Rearrange the passes and apply them to the program. Repeat this process
152152
// until the user kills the program or we find a bug.
153-
return runManyPasses(PassesToRun, ErrMsg);
153+
return runManyPasses(PassesToRun);
154154
}
155155

156156
// If we're not running as a child, the first thing that we must do is
@@ -167,16 +167,14 @@ bool BugDriver::run(std::string &ErrMsg) {
167167
}
168168

169169
// Set up the execution environment, selecting a method to run LLVM bitcode.
170-
if (initializeExecutionEnvironment())
171-
return true;
170+
if (Error E = initializeExecutionEnvironment())
171+
return E;
172172

173173
// Test to see if we have a code generator crash.
174174
outs() << "Running the code generator to test for a crash: ";
175-
std::string Error;
176-
compileProgram(Program, &Error);
177-
if (!Error.empty()) {
178-
outs() << Error;
179-
return debugCodeGeneratorCrash(ErrMsg);
175+
if (Error E = compileProgram(Program)) {
176+
outs() << toString(std::move(E));
177+
return debugCodeGeneratorCrash();
180178
}
181179
outs() << '\n';
182180

@@ -187,8 +185,9 @@ bool BugDriver::run(std::string &ErrMsg) {
187185
bool CreatedOutput = false;
188186
if (ReferenceOutputFile.empty()) {
189187
outs() << "Generating reference output from raw program: ";
190-
if (!createReferenceFile(Program)) {
191-
return debugCodeGeneratorCrash(ErrMsg);
188+
if (Error E = createReferenceFile(Program)) {
189+
errs() << toString(std::move(E));
190+
return debugCodeGeneratorCrash();
192191
}
193192
CreatedOutput = true;
194193
}
@@ -202,29 +201,27 @@ bool BugDriver::run(std::string &ErrMsg) {
202201
// matches, then we assume there is a miscompilation bug and try to
203202
// diagnose it.
204203
outs() << "*** Checking the code generator...\n";
205-
bool Diff = diffProgram(Program, "", "", false, &Error);
206-
if (!Error.empty()) {
207-
errs() << Error;
208-
return debugCodeGeneratorCrash(ErrMsg);
204+
Expected<bool> Diff = diffProgram(Program, "", "", false);
205+
if (Error E = Diff.takeError()) {
206+
errs() << toString(std::move(E));
207+
return debugCodeGeneratorCrash();
209208
}
210-
if (!Diff) {
209+
if (!*Diff) {
211210
outs() << "\n*** Output matches: Debugging miscompilation!\n";
212-
debugMiscompilation(&Error);
213-
if (!Error.empty()) {
214-
errs() << Error;
215-
return debugCodeGeneratorCrash(ErrMsg);
211+
if (Error E = debugMiscompilation()) {
212+
errs() << toString(std::move(E));
213+
return debugCodeGeneratorCrash();
216214
}
217-
return false;
215+
return Error::success();
218216
}
219217

220218
outs() << "\n*** Input program does not match reference diff!\n";
221219
outs() << "Debugging code generator problem!\n";
222-
bool Failure = debugCodeGenerator(&Error);
223-
if (!Error.empty()) {
224-
errs() << Error;
225-
return debugCodeGeneratorCrash(ErrMsg);
220+
if (Error E = debugCodeGenerator()) {
221+
errs() << toString(std::move(E));
222+
return debugCodeGeneratorCrash();
226223
}
227-
return Failure;
224+
return Error::success();
228225
}
229226

230227
void llvm::PrintFunctionList(const std::vector<Function *> &Funcs) {

llvm/tools/bugpoint/BugDriver.h

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define LLVM_TOOLS_BUGPOINT_BUGDRIVER_H
1818

1919
#include "llvm/IR/ValueMap.h"
20+
#include "llvm/Support/Error.h"
2021
#include "llvm/Transforms/Utils/ValueMapper.h"
2122
#include <memory>
2223
#include <string>
@@ -85,23 +86,23 @@ class BugDriver {
8586
/// variables are set up from command line arguments. The \p as_child argument
8687
/// indicates whether the driver is to run in parent mode or child mode.
8788
///
88-
bool run(std::string &ErrMsg);
89+
Error run();
8990

9091
/// debugOptimizerCrash - This method is called when some optimizer pass
9192
/// crashes on input. It attempts to prune down the testcase to something
9293
/// reasonable, and figure out exactly which pass is crashing.
9394
///
94-
bool debugOptimizerCrash(const std::string &ID = "passes");
95+
Error debugOptimizerCrash(const std::string &ID = "passes");
9596

9697
/// debugCodeGeneratorCrash - This method is called when the code generator
9798
/// crashes on an input. It attempts to reduce the input as much as possible
9899
/// while still causing the code generator to crash.
99-
bool debugCodeGeneratorCrash(std::string &Error);
100+
Error debugCodeGeneratorCrash();
100101

101102
/// debugMiscompilation - This method is used when the passes selected are not
102103
/// crashing, but the generated output is semantically different from the
103104
/// input.
104-
void debugMiscompilation(std::string *Error);
105+
Error debugMiscompilation();
105106

106107
/// debugPassMiscompilation - This method is called when the specified pass
107108
/// miscompiles Program as input. It tries to reduce the testcase to
@@ -115,13 +116,12 @@ class BugDriver {
115116
/// compileSharedObject - This method creates a SharedObject from a given
116117
/// BitcodeFile for debugging a code generator.
117118
///
118-
std::string compileSharedObject(const std::string &BitcodeFile,
119-
std::string &Error);
119+
Expected<std::string> compileSharedObject(const std::string &BitcodeFile);
120120

121121
/// debugCodeGenerator - This method narrows down a module to a function or
122122
/// set of functions, using the CBE as a ``safe'' code generator for other
123123
/// functions that are not under consideration.
124-
bool debugCodeGenerator(std::string *Error);
124+
Error debugCodeGenerator();
125125

126126
/// isExecutingJIT - Returns true if bugpoint is currently testing the JIT
127127
///
@@ -150,46 +150,45 @@ class BugDriver {
150150
/// the specified one as the current program.
151151
void setNewProgram(Module *M);
152152

153-
/// compileProgram - Try to compile the specified module, returning false and
154-
/// setting Error if an error occurs. This is used for code generation
153+
/// Try to compile the specified module. This is used for code generation
155154
/// crash testing.
156-
///
157-
void compileProgram(Module *M, std::string *Error) const;
155+
Error compileProgram(Module *M) const;
158156

159157
/// executeProgram - This method runs "Program", capturing the output of the
160158
/// program to a file. A recommended filename may be optionally specified.
161159
///
162-
std::string executeProgram(const Module *Program, std::string OutputFilename,
163-
std::string Bitcode,
164-
const std::string &SharedObjects,
165-
AbstractInterpreter *AI, std::string *Error) const;
160+
Expected<std::string> executeProgram(const Module *Program,
161+
std::string OutputFilename,
162+
std::string Bitcode,
163+
const std::string &SharedObjects,
164+
AbstractInterpreter *AI) const;
166165

167166
/// executeProgramSafely - Used to create reference output with the "safe"
168167
/// backend, if reference output is not provided. If there is a problem with
169168
/// the code generator (e.g., llc crashes), this will return false and set
170169
/// Error.
171170
///
172-
std::string executeProgramSafely(const Module *Program,
173-
const std::string &OutputFile,
174-
std::string *Error) const;
171+
Expected<std::string>
172+
executeProgramSafely(const Module *Program,
173+
const std::string &OutputFile) const;
175174

176175
/// createReferenceFile - calls compileProgram and then records the output
177176
/// into ReferenceOutputFile. Returns true if reference file created, false
178177
/// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
179178
/// this function.
180179
///
181-
bool createReferenceFile(Module *M, const std::string &Filename =
182-
"bugpoint.reference.out-%%%%%%%");
180+
Error createReferenceFile(Module *M, const std::string &Filename =
181+
"bugpoint.reference.out-%%%%%%%");
183182

184183
/// diffProgram - This method executes the specified module and diffs the
185184
/// output against the file specified by ReferenceOutputFile. If the output
186185
/// is different, 1 is returned. If there is a problem with the code
187186
/// generator (e.g., llc crashes), this will return -1 and set Error.
188187
///
189-
bool diffProgram(const Module *Program, const std::string &BitcodeFile = "",
190-
const std::string &SharedObj = "",
191-
bool RemoveBitcode = false,
192-
std::string *Error = nullptr) const;
188+
Expected<bool> diffProgram(const Module *Program,
189+
const std::string &BitcodeFile = "",
190+
const std::string &SharedObj = "",
191+
bool RemoveBitcode = false) const;
193192

194193
/// EmitProgressBitcode - This function is used to output M to a file named
195194
/// "bugpoint-ID.bc".
@@ -257,17 +256,13 @@ class BugDriver {
257256
return runPasses(M, PassesToRun, Filename, true);
258257
}
259258

260-
/// runManyPasses - Take the specified pass list and create different
261-
/// combinations of passes to compile the program with. Compile the program
262-
/// with
263-
/// each set and mark test to see if it compiled correctly. If the passes
264-
/// compiled correctly output nothing and rearrange the passes into a new
265-
/// order.
266-
/// If the passes did not compile correctly, output the command required to
267-
/// recreate the failure. This returns true if a compiler error is found.
268-
///
269-
bool runManyPasses(const std::vector<std::string> &AllPasses,
270-
std::string &ErrMsg);
259+
/// Take the specified pass list and create different combinations of passes
260+
/// to compile the program with. Compile the program with each set and mark
261+
/// test to see if it compiled correctly. If the passes compiled correctly
262+
/// output nothing and rearrange the passes into a new order. If the passes
263+
/// did not compile correctly, output the command required to recreate the
264+
/// failure.
265+
Error runManyPasses(const std::vector<std::string> &AllPasses);
271266

272267
/// writeProgramToFile - This writes the current "Program" to the named
273268
/// bitcode file. If an error occurs, true is returned.
@@ -280,7 +275,7 @@ class BugDriver {
280275
/// initializeExecutionEnvironment - This method is used to set up the
281276
/// environment for executing LLVM programs.
282277
///
283-
bool initializeExecutionEnvironment();
278+
Error initializeExecutionEnvironment();
284279
};
285280

286281
/// Given a bitcode or assembly input filename, parse and return it, or return

0 commit comments

Comments
 (0)