Skip to content

Commit

Permalink
bugpoint: Return Errors instead of passing around strings
Browse files Browse the repository at this point in the history
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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280720 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
bogner committed Sep 6, 2016
1 parent a68463e commit d8090ae
Show file tree
Hide file tree
Showing 10 changed files with 558 additions and 543 deletions.
49 changes: 23 additions & 26 deletions tools/bugpoint/BugDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
/// run - The top level method that is invoked after all of the instance
/// variables are set up from command line arguments.
///
bool BugDriver::run(std::string &ErrMsg) {
Error BugDriver::run() {
if (run_find_bugs) {
// Rearrange the passes and apply them to the program. Repeat this process
// until the user kills the program or we find a bug.
return runManyPasses(PassesToRun, ErrMsg);
return runManyPasses(PassesToRun);
}

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

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

// Test to see if we have a code generator crash.
outs() << "Running the code generator to test for a crash: ";
std::string Error;
compileProgram(Program, &Error);
if (!Error.empty()) {
outs() << Error;
return debugCodeGeneratorCrash(ErrMsg);
if (Error E = compileProgram(Program)) {
outs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
outs() << '\n';

Expand All @@ -187,8 +185,9 @@ bool BugDriver::run(std::string &ErrMsg) {
bool CreatedOutput = false;
if (ReferenceOutputFile.empty()) {
outs() << "Generating reference output from raw program: ";
if (!createReferenceFile(Program)) {
return debugCodeGeneratorCrash(ErrMsg);
if (Error E = createReferenceFile(Program)) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
CreatedOutput = true;
}
Expand All @@ -202,29 +201,27 @@ bool BugDriver::run(std::string &ErrMsg) {
// matches, then we assume there is a miscompilation bug and try to
// diagnose it.
outs() << "*** Checking the code generator...\n";
bool Diff = diffProgram(Program, "", "", false, &Error);
if (!Error.empty()) {
errs() << Error;
return debugCodeGeneratorCrash(ErrMsg);
Expected<bool> Diff = diffProgram(Program, "", "", false);
if (Error E = Diff.takeError()) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
if (!Diff) {
if (!*Diff) {
outs() << "\n*** Output matches: Debugging miscompilation!\n";
debugMiscompilation(&Error);
if (!Error.empty()) {
errs() << Error;
return debugCodeGeneratorCrash(ErrMsg);
if (Error E = debugMiscompilation()) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
return false;
return Error::success();
}

outs() << "\n*** Input program does not match reference diff!\n";
outs() << "Debugging code generator problem!\n";
bool Failure = debugCodeGenerator(&Error);
if (!Error.empty()) {
errs() << Error;
return debugCodeGeneratorCrash(ErrMsg);
if (Error E = debugCodeGenerator()) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
return Failure;
return Error::success();
}

void llvm::PrintFunctionList(const std::vector<Function *> &Funcs) {
Expand Down
67 changes: 31 additions & 36 deletions tools/bugpoint/BugDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define LLVM_TOOLS_BUGPOINT_BUGDRIVER_H

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/// Given a bitcode or assembly input filename, parse and return it, or return
Expand Down
Loading

0 comments on commit d8090ae

Please sign in to comment.