Imported Upstream version 5.18.0.167

Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-10-20 08:25:10 +00:00
parent e19d552987
commit b084638f15
28489 changed files with 184 additions and 3866856 deletions

View File

@ -1,257 +0,0 @@
//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class contains all of the shared state and information that is used by
// the BugPoint tool to track down errors in optimizations. This class is the
// main driver class that invokes all sub-functionality.
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
using namespace llvm;
namespace llvm {
Triple TargetTriple;
}
DiscardTemp::~DiscardTemp() {
if (SaveTemps) {
if (Error E = File.keep())
errs() << "Failed to keep temp file " << toString(std::move(E)) << '\n';
return;
}
if (Error E = File.discard())
errs() << "Failed to delete temp file " << toString(std::move(E)) << '\n';
}
// Anonymous namespace to define command line options for debugging.
//
namespace {
// Output - The user can specify a file containing the expected output of the
// program. If this filename is set, it is used as the reference diff source,
// otherwise the raw input run through an interpreter is used as the reference
// source.
//
cl::opt<std::string> OutputFile("output",
cl::desc("Specify a reference program output "
"(for miscompilation detection)"));
}
/// setNewProgram - If we reduce or update the program somehow, call this method
/// to update bugdriver with it. This deletes the old module and sets the
/// specified one as the current program.
void BugDriver::setNewProgram(Module *M) {
delete Program;
Program = M;
}
/// getPassesString - Turn a list of passes into a string which indicates the
/// command line options that must be passed to add the passes.
///
std::string llvm::getPassesString(const std::vector<std::string> &Passes) {
std::string Result;
for (unsigned i = 0, e = Passes.size(); i != e; ++i) {
if (i)
Result += " ";
Result += "-";
Result += Passes[i];
}
return Result;
}
BugDriver::BugDriver(const char *toolname, bool find_bugs, unsigned timeout,
unsigned memlimit, bool use_valgrind, LLVMContext &ctxt)
: Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile),
Program(nullptr), Interpreter(nullptr), SafeInterpreter(nullptr),
cc(nullptr), run_find_bugs(find_bugs), Timeout(timeout),
MemoryLimit(memlimit), UseValgrind(use_valgrind) {}
BugDriver::~BugDriver() {
delete Program;
if (Interpreter != SafeInterpreter)
delete Interpreter;
delete SafeInterpreter;
delete cc;
}
std::unique_ptr<Module> llvm::parseInputFile(StringRef Filename,
LLVMContext &Ctxt) {
SMDiagnostic Err;
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
if (!Result) {
Err.print("bugpoint", errs());
return Result;
}
if (verifyModule(*Result, &errs())) {
errs() << "bugpoint: " << Filename << ": error: input module is broken!\n";
return std::unique_ptr<Module>();
}
// If we don't have an override triple, use the first one to configure
// bugpoint, or use the host triple if none provided.
if (TargetTriple.getTriple().empty()) {
Triple TheTriple(Result->getTargetTriple());
if (TheTriple.getTriple().empty())
TheTriple.setTriple(sys::getDefaultTargetTriple());
TargetTriple.setTriple(TheTriple.getTriple());
}
Result->setTargetTriple(TargetTriple.getTriple()); // override the triple
return Result;
}
// This method takes the specified list of LLVM input files, attempts to load
// them, either as assembly or bitcode, then link them together. It returns
// true on failure (if, for example, an input bitcode file could not be
// parsed), and false on success.
//
bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
assert(!Program && "Cannot call addSources multiple times!");
assert(!Filenames.empty() && "Must specify at least on input filename!");
// Load the first input file.
Program = parseInputFile(Filenames[0], Context).release();
if (!Program)
return true;
outs() << "Read input file : '" << Filenames[0] << "'\n";
for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
std::unique_ptr<Module> M = parseInputFile(Filenames[i], Context);
if (!M.get())
return true;
outs() << "Linking in input file: '" << Filenames[i] << "'\n";
if (Linker::linkModules(*Program, std::move(M)))
return true;
}
outs() << "*** All input ok\n";
// All input files read successfully!
return false;
}
/// run - The top level method that is invoked after all of the instance
/// variables are set up from command line arguments.
///
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);
}
// If we're not running as a child, the first thing that we must do is
// determine what the problem is. Does the optimization series crash the
// compiler, or does it produce illegal code? We make the top-level
// decision by trying to run all of the passes on the input program,
// which should generate a bitcode file. If it does generate a bitcode
// file, then we know the compiler didn't crash, so try to diagnose a
// miscompilation.
if (!PassesToRun.empty()) {
outs() << "Running selected passes on program to test for crash: ";
if (runPasses(Program, PassesToRun))
return debugOptimizerCrash();
}
// Set up the execution environment, selecting a method to run LLVM bitcode.
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: ";
if (Error E = compileProgram(Program)) {
outs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
outs() << '\n';
// Run the raw input to see where we are coming from. If a reference output
// was specified, make sure that the raw output matches it. If not, it's a
// problem in the front-end or the code generator.
//
bool CreatedOutput = false;
if (ReferenceOutputFile.empty()) {
outs() << "Generating reference output from raw program: ";
if (Error E = createReferenceFile(Program)) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
CreatedOutput = true;
}
// Make sure the reference output file gets deleted on exit from this
// function, if appropriate.
std::string ROF(ReferenceOutputFile);
FileRemover RemoverInstance(ROF, CreatedOutput && !SaveTemps);
// Diff the output of the raw program against the reference output. If it
// matches, then we assume there is a miscompilation bug and try to
// diagnose it.
outs() << "*** Checking the code generator...\n";
Expected<bool> Diff = diffProgram(Program, "", "", false);
if (Error E = Diff.takeError()) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
if (!*Diff) {
outs() << "\n*** Output matches: Debugging miscompilation!\n";
if (Error E = debugMiscompilation()) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
return Error::success();
}
outs() << "\n*** Input program does not match reference diff!\n";
outs() << "Debugging code generator problem!\n";
if (Error E = debugCodeGenerator()) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
return Error::success();
}
void llvm::PrintFunctionList(const std::vector<Function *> &Funcs) {
unsigned NumPrint = Funcs.size();
if (NumPrint > 10)
NumPrint = 10;
for (unsigned i = 0; i != NumPrint; ++i)
outs() << " " << Funcs[i]->getName();
if (NumPrint < Funcs.size())
outs() << "... <" << Funcs.size() << " total>";
outs().flush();
}
void llvm::PrintGlobalVariableList(const std::vector<GlobalVariable *> &GVs) {
unsigned NumPrint = GVs.size();
if (NumPrint > 10)
NumPrint = 10;
for (unsigned i = 0; i != NumPrint; ++i)
outs() << " " << GVs[i]->getName();
if (NumPrint < GVs.size())
outs() << "... <" << GVs.size() << " total>";
outs().flush();
}

View File

@ -1,325 +0,0 @@
//===- BugDriver.h - Top-Level BugPoint class -------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class contains all of the shared state and information that is used by
// the BugPoint tool to track down errors in optimizations. This class is the
// main driver class that invokes all sub-functionality.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_BUGPOINT_BUGDRIVER_H
#define LLVM_TOOLS_BUGPOINT_BUGDRIVER_H
#include "llvm/IR/ValueMap.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include <memory>
#include <string>
#include <vector>
namespace llvm {
class Value;
class PassInfo;
class Module;
class GlobalVariable;
class Function;
class BasicBlock;
class AbstractInterpreter;
class Instruction;
class LLVMContext;
class DebugCrashes;
class CC;
extern bool DisableSimplifyCFG;
/// BugpointIsInterrupted - Set to true when the user presses ctrl-c.
///
extern bool BugpointIsInterrupted;
class BugDriver {
LLVMContext &Context;
const char *ToolName; // argv[0] of bugpoint
std::string ReferenceOutputFile; // Name of `good' output file
Module *Program; // The raw program, linked together
std::vector<std::string> PassesToRun;
AbstractInterpreter *Interpreter; // How to run the program
AbstractInterpreter *SafeInterpreter; // To generate reference output, etc.
CC *cc;
bool run_find_bugs;
unsigned Timeout;
unsigned MemoryLimit;
bool UseValgrind;
// FIXME: sort out public/private distinctions...
friend class ReducePassList;
friend class ReduceMisCodegenFunctions;
public:
BugDriver(const char *toolname, bool find_bugs, unsigned timeout,
unsigned memlimit, bool use_valgrind, LLVMContext &ctxt);
~BugDriver();
const char *getToolName() const { return ToolName; }
LLVMContext &getContext() const { return Context; }
// Set up methods... these methods are used to copy information about the
// command line arguments into instance variables of BugDriver.
//
bool addSources(const std::vector<std::string> &FileNames);
void addPass(std::string p) { PassesToRun.push_back(std::move(p)); }
void setPassesToRun(const std::vector<std::string> &PTR) {
PassesToRun = PTR;
}
const std::vector<std::string> &getPassesToRun() const { return PassesToRun; }
/// run - The top level method that is invoked after all of the instance
/// 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.
///
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.
///
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.
Error debugCodeGeneratorCrash();
/// debugMiscompilation - This method is used when the passes selected are not
/// crashing, but the generated output is semantically different from the
/// input.
Error debugMiscompilation();
/// debugPassMiscompilation - This method is called when the specified pass
/// miscompiles Program as input. It tries to reduce the testcase to
/// something that smaller that still miscompiles the program.
/// ReferenceOutput contains the filename of the file containing the output we
/// are to match.
///
bool debugPassMiscompilation(const PassInfo *ThePass,
const std::string &ReferenceOutput);
/// compileSharedObject - This method creates a SharedObject from a given
/// BitcodeFile for debugging a code generator.
///
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.
Error debugCodeGenerator();
/// isExecutingJIT - Returns true if bugpoint is currently testing the JIT
///
bool isExecutingJIT();
Module *getProgram() const { return Program; }
/// swapProgramIn - Set the current module to the specified module, returning
/// the old one.
Module *swapProgramIn(Module *M) {
Module *OldProgram = Program;
Program = M;
return OldProgram;
}
AbstractInterpreter *switchToSafeInterpreter() {
AbstractInterpreter *Old = Interpreter;
Interpreter = (AbstractInterpreter *)SafeInterpreter;
return Old;
}
void switchToInterpreter(AbstractInterpreter *AI) { Interpreter = AI; }
/// setNewProgram - If we reduce or update the program somehow, call this
/// method to update bugdriver with it. This deletes the old module and sets
/// the specified one as the current program.
void setNewProgram(Module *M);
/// Try to compile the specified module. This is used for code generation
/// crash testing.
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.
///
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.
///
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.
///
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.
///
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".
///
void EmitProgressBitcode(const Module *M, const std::string &ID,
bool NoFlyer = false) const;
/// This method clones the current Program and deletes the specified
/// instruction from the cloned module. It then runs a series of cleanup
/// passes (ADCE and SimplifyCFG) to eliminate any code which depends on the
/// value. The modified module is then returned.
///
std::unique_ptr<Module> deleteInstructionFromProgram(const Instruction *I,
unsigned Simp);
/// This method clones the current Program and performs a series of cleanups
/// intended to get rid of extra cruft on the module. If the
/// MayModifySemantics argument is true, then the cleanups is allowed to
/// modify how the code behaves.
///
std::unique_ptr<Module> performFinalCleanups(Module *M,
bool MayModifySemantics = false);
/// Given a module, extract up to one loop from it into a new function. This
/// returns null if there are no extractable loops in the program or if the
/// loop extractor crashes.
std::unique_ptr<Module> extractLoop(Module *M);
/// Extract all but the specified basic blocks into their own functions. The
/// only detail is that M is actually a module cloned from the one the BBs are
/// in, so some mapping needs to be performed. If this operation fails for
/// some reason (ie the implementation is buggy), this function should return
/// null, otherwise it returns a new Module.
std::unique_ptr<Module>
extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs,
Module *M);
/// Carefully run the specified set of pass on the specified/ module,
/// returning the transformed module on success, or a null pointer on failure.
std::unique_ptr<Module> runPassesOn(Module *M,
const std::vector<std::string> &Passes,
unsigned NumExtraArgs = 0,
const char *const *ExtraArgs = nullptr);
/// runPasses - Run the specified passes on Program, outputting a bitcode
/// file and writting the filename into OutputFile if successful. If the
/// optimizations fail for some reason (optimizer crashes), return true,
/// otherwise return false. If DeleteOutput is set to true, the bitcode is
/// deleted on success, and the filename string is undefined. This prints to
/// outs() a single line message indicating whether compilation was successful
/// or failed, unless Quiet is set. ExtraArgs specifies additional arguments
/// to pass to the child bugpoint instance.
///
bool runPasses(Module *Program, const std::vector<std::string> &PassesToRun,
std::string &OutputFilename, bool DeleteOutput = false,
bool Quiet = false, unsigned NumExtraArgs = 0,
const char *const *ExtraArgs = nullptr) const;
/// runPasses - Just like the method above, but this just returns true or
/// false indicating whether or not the optimizer crashed on the specified
/// input (true = crashed). Does not produce any output.
///
bool runPasses(Module *M, const std::vector<std::string> &PassesToRun) const {
std::string Filename;
return runPasses(M, PassesToRun, Filename, true);
}
/// 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.
///
bool writeProgramToFile(const std::string &Filename, const Module *M) const;
bool writeProgramToFile(const std::string &Filename, int FD,
const Module *M) const;
bool writeProgramToFile(int FD, const Module *M) const;
private:
/// initializeExecutionEnvironment - This method is used to set up the
/// environment for executing LLVM programs.
///
Error initializeExecutionEnvironment();
};
struct DiscardTemp {
sys::fs::TempFile &File;
~DiscardTemp();
};
/// Given a bitcode or assembly input filename, parse and return it, or return
/// null if not possible.
///
std::unique_ptr<Module> parseInputFile(StringRef InputFilename,
LLVMContext &ctxt);
/// getPassesString - Turn a list of passes into a string which indicates the
/// command line options that must be passed to add the passes.
///
std::string getPassesString(const std::vector<std::string> &Passes);
/// PrintFunctionList - prints out list of problematic functions
///
void PrintFunctionList(const std::vector<Function *> &Funcs);
/// PrintGlobalVariableList - prints out list of problematic global variables
///
void PrintGlobalVariableList(const std::vector<GlobalVariable *> &GVs);
// DeleteGlobalInitializer - "Remove" the global variable by deleting its
// initializer, making it external.
//
void DeleteGlobalInitializer(GlobalVariable *GV);
// DeleteFunctionBody - "Remove" the function by deleting all of it's basic
// blocks, making it external.
//
void DeleteFunctionBody(Function *F);
/// Given a module and a list of functions in the module, split the functions
/// OUT of the specified module, and place them in the new module.
std::unique_ptr<Module>
SplitFunctionsOutOfModule(Module *M, const std::vector<Function *> &F,
ValueToValueMapTy &VMap);
} // End llvm namespace
#endif

View File

@ -1,43 +0,0 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
Analysis
BitWriter
CodeGen
Core
IPO
IRReader
InstCombine
Instrumentation
Linker
ObjCARCOpts
ScalarOpts
Support
Target
TransformUtils
Vectorize
)
# Support plugins.
set(LLVM_NO_DEAD_STRIP 1)
add_llvm_tool(bugpoint
BugDriver.cpp
CrashDebugger.cpp
ExecutionDriver.cpp
ExtractFunction.cpp
FindBugs.cpp
Miscompilation.cpp
OptimizerDriver.cpp
ToolRunner.cpp
bugpoint.cpp
DEPENDS
intrinsics_gen
)
export_executable_symbols(bugpoint)
if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)
target_link_libraries(bugpoint PRIVATE Polly)
# Ensure LLVMTarget can resolve dependences in Polly.
target_link_libraries(bugpoint PRIVATE LLVMTarget)
endif(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)

File diff suppressed because it is too large Load Diff

View File

@ -1,470 +0,0 @@
//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains code used to execute the program utilizing one of the
// various ways of running LLVM bitcode.
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/raw_ostream.h"
#include <fstream>
using namespace llvm;
namespace {
// OutputType - Allow the user to specify the way code should be run, to test
// for miscompilation.
//
enum OutputType {
AutoPick,
RunLLI,
RunJIT,
RunLLC,
RunLLCIA,
LLC_Safe,
CompileCustom,
Custom
};
cl::opt<double> AbsTolerance("abs-tolerance",
cl::desc("Absolute error tolerated"),
cl::init(0.0));
cl::opt<double> RelTolerance("rel-tolerance",
cl::desc("Relative error tolerated"),
cl::init(0.0));
cl::opt<OutputType> InterpreterSel(
cl::desc("Specify the \"test\" i.e. suspect back-end:"),
cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
clEnumValN(RunLLI, "run-int", "Execute with the interpreter"),
clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
clEnumValN(RunLLCIA, "run-llc-ia",
"Compile with LLC with integrated assembler"),
clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"),
clEnumValN(CompileCustom, "compile-custom",
"Use -compile-command to define a command to "
"compile the bitcode. Useful to avoid linking."),
clEnumValN(Custom, "run-custom",
"Use -exec-command to define a command to execute "
"the bitcode. Useful for cross-compilation.")),
cl::init(AutoPick));
cl::opt<OutputType> SafeInterpreterSel(
cl::desc("Specify \"safe\" i.e. known-good backend:"),
cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"),
clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"),
clEnumValN(Custom, "safe-run-custom",
"Use -exec-command to define a command to execute "
"the bitcode. Useful for cross-compilation.")),
cl::init(AutoPick));
cl::opt<std::string> SafeInterpreterPath(
"safe-path", cl::desc("Specify the path to the \"safe\" backend program"),
cl::init(""));
cl::opt<bool> AppendProgramExitCode(
"append-exit-code",
cl::desc("Append the exit code to the output so it gets diff'd too"),
cl::init(false));
cl::opt<std::string>
InputFile("input", cl::init("/dev/null"),
cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
cl::list<std::string>
AdditionalSOs("additional-so", cl::desc("Additional shared objects to load "
"into executing programs"));
cl::list<std::string> AdditionalLinkerArgs(
"Xlinker", cl::desc("Additional arguments to pass to the linker"));
cl::opt<std::string> CustomCompileCommand(
"compile-command", cl::init("llc"),
cl::desc("Command to compile the bitcode (use with -compile-custom) "
"(default: llc)"));
cl::opt<std::string> CustomExecCommand(
"exec-command", cl::init("simulate"),
cl::desc("Command to execute the bitcode (use with -run-custom) "
"(default: simulate)"));
}
namespace llvm {
// Anything specified after the --args option are taken as arguments to the
// program being debugged.
cl::list<std::string> InputArgv("args", cl::Positional,
cl::desc("<program arguments>..."),
cl::ZeroOrMore, cl::PositionalEatsArgs);
cl::opt<std::string>
OutputPrefix("output-prefix", cl::init("bugpoint"),
cl::desc("Prefix to use for outputs (default: 'bugpoint')"));
}
namespace {
cl::list<std::string> ToolArgv("tool-args", cl::Positional,
cl::desc("<tool arguments>..."), cl::ZeroOrMore,
cl::PositionalEatsArgs);
cl::list<std::string> SafeToolArgv("safe-tool-args", cl::Positional,
cl::desc("<safe-tool arguments>..."),
cl::ZeroOrMore, cl::PositionalEatsArgs);
cl::opt<std::string> CCBinary("gcc", cl::init(""),
cl::desc("The gcc binary to use."));
cl::list<std::string> CCToolArgv("gcc-tool-args", cl::Positional,
cl::desc("<gcc-tool arguments>..."),
cl::ZeroOrMore, cl::PositionalEatsArgs);
}
//===----------------------------------------------------------------------===//
// BugDriver method implementation
//
/// initializeExecutionEnvironment - This method is used to set up the
/// environment for executing LLVM programs.
///
Error BugDriver::initializeExecutionEnvironment() {
outs() << "Initializing execution environment: ";
// Create an instance of the AbstractInterpreter interface as specified on
// the command line
SafeInterpreter = nullptr;
std::string Message;
if (CCBinary.empty()) {
if (sys::findProgramByName("clang"))
CCBinary = "clang";
else
CCBinary = "gcc";
}
switch (InterpreterSel) {
case AutoPick:
if (!Interpreter) {
InterpreterSel = RunJIT;
Interpreter =
AbstractInterpreter::createJIT(getToolName(), Message, &ToolArgv);
}
if (!Interpreter) {
InterpreterSel = RunLLC;
Interpreter = AbstractInterpreter::createLLC(
getToolName(), Message, CCBinary, &ToolArgv, &CCToolArgv);
}
if (!Interpreter) {
InterpreterSel = RunLLI;
Interpreter =
AbstractInterpreter::createLLI(getToolName(), Message, &ToolArgv);
}
if (!Interpreter) {
InterpreterSel = AutoPick;
Message = "Sorry, I can't automatically select an interpreter!\n";
}
break;
case RunLLI:
Interpreter =
AbstractInterpreter::createLLI(getToolName(), Message, &ToolArgv);
break;
case RunLLC:
case RunLLCIA:
case LLC_Safe:
Interpreter = AbstractInterpreter::createLLC(
getToolName(), Message, CCBinary, &ToolArgv, &CCToolArgv,
InterpreterSel == RunLLCIA);
break;
case RunJIT:
Interpreter =
AbstractInterpreter::createJIT(getToolName(), Message, &ToolArgv);
break;
case CompileCustom:
Interpreter = AbstractInterpreter::createCustomCompiler(
Message, CustomCompileCommand);
break;
case Custom:
Interpreter =
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
break;
}
if (!Interpreter)
errs() << Message;
else // Display informational messages on stdout instead of stderr
outs() << Message;
std::string Path = SafeInterpreterPath;
if (Path.empty())
Path = getToolName();
std::vector<std::string> SafeToolArgs = SafeToolArgv;
switch (SafeInterpreterSel) {
case AutoPick:
// In "llc-safe" mode, default to using LLC as the "safe" backend.
if (!SafeInterpreter && InterpreterSel == LLC_Safe) {
SafeInterpreterSel = RunLLC;
SafeToolArgs.push_back("--relocation-model=pic");
SafeInterpreter = AbstractInterpreter::createLLC(
Path.c_str(), Message, CCBinary, &SafeToolArgs, &CCToolArgv);
}
if (!SafeInterpreter && InterpreterSel != RunLLC &&
InterpreterSel != RunJIT) {
SafeInterpreterSel = RunLLC;
SafeToolArgs.push_back("--relocation-model=pic");
SafeInterpreter = AbstractInterpreter::createLLC(
Path.c_str(), Message, CCBinary, &SafeToolArgs, &CCToolArgv);
}
if (!SafeInterpreter) {
SafeInterpreterSel = AutoPick;
Message = "Sorry, I can't automatically select a safe interpreter!\n";
}
break;
case RunLLC:
case RunLLCIA:
SafeToolArgs.push_back("--relocation-model=pic");
SafeInterpreter = AbstractInterpreter::createLLC(
Path.c_str(), Message, CCBinary, &SafeToolArgs, &CCToolArgv,
SafeInterpreterSel == RunLLCIA);
break;
case Custom:
SafeInterpreter =
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
break;
default:
Message = "Sorry, this back-end is not supported by bugpoint as the "
"\"safe\" backend right now!\n";
break;
}
if (!SafeInterpreter) {
outs() << Message << "\nExiting.\n";
exit(1);
}
cc = CC::create(Message, CCBinary, &CCToolArgv);
if (!cc) {
outs() << Message << "\nExiting.\n";
exit(1);
}
// If there was an error creating the selected interpreter, quit with error.
if (Interpreter == nullptr)
return make_error<StringError>("Failed to init execution environment",
inconvertibleErrorCode());
return Error::success();
}
/// compileProgram - Try to compile the specified module, returning false and
/// setting Error if an error occurs. This is used for code generation
/// crash testing.
///
Error BugDriver::compileProgram(Module *M) const {
// Emit the program to a bitcode file...
auto Temp =
sys::fs::TempFile::create(OutputPrefix + "-test-program-%%%%%%%.bc");
if (!Temp) {
errs() << ToolName
<< ": Error making unique filename: " << toString(Temp.takeError())
<< "\n";
exit(1);
}
DiscardTemp Discard{*Temp};
if (writeProgramToFile(Temp->FD, M)) {
errs() << ToolName << ": Error emitting bitcode to file '" << Temp->TmpName
<< "'!\n";
exit(1);
}
// Actually compile the program!
return Interpreter->compileProgram(Temp->TmpName, Timeout, MemoryLimit);
}
/// executeProgram - This method runs "Program", capturing the output of the
/// program to a file, returning the filename of the file. A recommended
/// filename may be optionally specified.
///
Expected<std::string> BugDriver::executeProgram(const Module *Program,
std::string OutputFile,
std::string BitcodeFile,
const std::string &SharedObj,
AbstractInterpreter *AI) const {
if (!AI)
AI = Interpreter;
assert(AI && "Interpreter should have been created already!");
if (BitcodeFile.empty()) {
// Emit the program to a bitcode file...
auto File =
sys::fs::TempFile::create(OutputPrefix + "-test-program-%%%%%%%.bc");
if (!File) {
errs() << ToolName
<< ": Error making unique filename: " << toString(File.takeError())
<< "!\n";
exit(1);
}
DiscardTemp Discard{*File};
BitcodeFile = File->TmpName;
if (writeProgramToFile(File->FD, Program)) {
errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile
<< "'!\n";
exit(1);
}
}
if (OutputFile.empty())
OutputFile = OutputPrefix + "-execution-output-%%%%%%%";
// Check to see if this is a valid output filename...
SmallString<128> UniqueFile;
std::error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile);
if (EC) {
errs() << ToolName << ": Error making unique filename: " << EC.message()
<< "\n";
exit(1);
}
OutputFile = UniqueFile.str();
// Figure out which shared objects to run, if any.
std::vector<std::string> SharedObjs(AdditionalSOs);
if (!SharedObj.empty())
SharedObjs.push_back(SharedObj);
Expected<int> RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile,
OutputFile, AdditionalLinkerArgs,
SharedObjs, Timeout, MemoryLimit);
if (Error E = RetVal.takeError())
return std::move(E);
if (*RetVal == -1) {
errs() << "<timeout>";
static bool FirstTimeout = true;
if (FirstTimeout) {
outs()
<< "\n"
"*** Program execution timed out! This mechanism is designed to "
"handle\n"
" programs stuck in infinite loops gracefully. The -timeout "
"option\n"
" can be used to change the timeout threshold or disable it "
"completely\n"
" (with -timeout=0). This message is only displayed once.\n";
FirstTimeout = false;
}
}
if (AppendProgramExitCode) {
std::ofstream outFile(OutputFile.c_str(), std::ios_base::app);
outFile << "exit " << *RetVal << '\n';
outFile.close();
}
// Return the filename we captured the output to.
return OutputFile;
}
/// executeProgramSafely - Used to create reference output with the "safe"
/// backend, if reference output is not provided.
///
Expected<std::string>
BugDriver::executeProgramSafely(const Module *Program,
const std::string &OutputFile) const {
return executeProgram(Program, OutputFile, "", "", SafeInterpreter);
}
Expected<std::string>
BugDriver::compileSharedObject(const std::string &BitcodeFile) {
assert(Interpreter && "Interpreter should have been created already!");
std::string OutputFile;
// Using the known-good backend.
Expected<CC::FileType> FT =
SafeInterpreter->OutputCode(BitcodeFile, OutputFile);
if (Error E = FT.takeError())
return std::move(E);
std::string SharedObjectFile;
if (Error E = cc->MakeSharedObject(OutputFile, *FT, SharedObjectFile,
AdditionalLinkerArgs))
return std::move(E);
// Remove the intermediate C file
sys::fs::remove(OutputFile);
return SharedObjectFile;
}
/// 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.
///
Error BugDriver::createReferenceFile(Module *M, const std::string &Filename) {
if (Error E = compileProgram(Program))
return E;
Expected<std::string> Result = executeProgramSafely(Program, Filename);
if (Error E = Result.takeError()) {
if (Interpreter != SafeInterpreter) {
E = joinErrors(
std::move(E),
make_error<StringError>(
"*** There is a bug running the \"safe\" backend. Either"
" debug it (for example with the -run-jit bugpoint option,"
" if JIT is being used as the \"safe\" backend), or fix the"
" error some other way.\n",
inconvertibleErrorCode()));
}
return E;
}
ReferenceOutputFile = *Result;
outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n";
return Error::success();
}
/// 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 set ErrMsg.
///
Expected<bool> BugDriver::diffProgram(const Module *Program,
const std::string &BitcodeFile,
const std::string &SharedObject,
bool RemoveBitcode) const {
// Execute the program, generating an output file...
Expected<std::string> Output =
executeProgram(Program, "", BitcodeFile, SharedObject, nullptr);
if (Error E = Output.takeError())
return std::move(E);
std::string Error;
bool FilesDifferent = false;
if (int Diff = DiffFilesWithTolerance(ReferenceOutputFile, *Output,
AbsTolerance, RelTolerance, &Error)) {
if (Diff == 2) {
errs() << "While diffing output: " << Error << '\n';
exit(1);
}
FilesDifferent = true;
} else {
// Remove the generated output if there are no differences.
sys::fs::remove(*Output);
}
// Remove the bitcode file if we are supposed to.
if (RemoveBitcode)
sys::fs::remove(BitcodeFile);
return FilesDifferent;
}
bool BugDriver::isExecutingJIT() { return InterpreterSel == RunJIT; }

View File

@ -1,417 +0,0 @@
//===- ExtractFunction.cpp - Extract a function from Program --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements several methods that are used to extract functions,
// loops, or portions of a module from the rest of the module.
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/CodeExtractor.h"
#include <set>
using namespace llvm;
#define DEBUG_TYPE "bugpoint"
namespace llvm {
bool DisableSimplifyCFG = false;
extern cl::opt<std::string> OutputPrefix;
} // End llvm namespace
namespace {
cl::opt<bool> NoDCE("disable-dce",
cl::desc("Do not use the -dce pass to reduce testcases"));
cl::opt<bool, true>
NoSCFG("disable-simplifycfg", cl::location(DisableSimplifyCFG),
cl::desc("Do not use the -simplifycfg pass to reduce testcases"));
Function *globalInitUsesExternalBA(GlobalVariable *GV) {
if (!GV->hasInitializer())
return nullptr;
Constant *I = GV->getInitializer();
// walk the values used by the initializer
// (and recurse into things like ConstantExpr)
std::vector<Constant *> Todo;
std::set<Constant *> Done;
Todo.push_back(I);
while (!Todo.empty()) {
Constant *V = Todo.back();
Todo.pop_back();
Done.insert(V);
if (BlockAddress *BA = dyn_cast<BlockAddress>(V)) {
Function *F = BA->getFunction();
if (F->isDeclaration())
return F;
}
for (User::op_iterator i = V->op_begin(), e = V->op_end(); i != e; ++i) {
Constant *C = dyn_cast<Constant>(*i);
if (C && !isa<GlobalValue>(C) && !Done.count(C))
Todo.push_back(C);
}
}
return nullptr;
}
} // end anonymous namespace
std::unique_ptr<Module>
BugDriver::deleteInstructionFromProgram(const Instruction *I,
unsigned Simplification) {
// FIXME, use vmap?
Module *Clone = CloneModule(Program).release();
const BasicBlock *PBB = I->getParent();
const Function *PF = PBB->getParent();
Module::iterator RFI = Clone->begin(); // Get iterator to corresponding fn
std::advance(
RFI, std::distance(PF->getParent()->begin(), Module::const_iterator(PF)));
Function::iterator RBI = RFI->begin(); // Get iterator to corresponding BB
std::advance(RBI, std::distance(PF->begin(), Function::const_iterator(PBB)));
BasicBlock::iterator RI = RBI->begin(); // Get iterator to corresponding inst
std::advance(RI, std::distance(PBB->begin(), BasicBlock::const_iterator(I)));
Instruction *TheInst = &*RI; // Got the corresponding instruction!
// If this instruction produces a value, replace any users with null values
if (!TheInst->getType()->isVoidTy())
TheInst->replaceAllUsesWith(Constant::getNullValue(TheInst->getType()));
// Remove the instruction from the program.
TheInst->getParent()->getInstList().erase(TheInst);
// Spiff up the output a little bit.
std::vector<std::string> Passes;
/// Can we get rid of the -disable-* options?
if (Simplification > 1 && !NoDCE)
Passes.push_back("dce");
if (Simplification && !DisableSimplifyCFG)
Passes.push_back("simplifycfg"); // Delete dead control flow
Passes.push_back("verify");
std::unique_ptr<Module> New = runPassesOn(Clone, Passes);
delete Clone;
if (!New) {
errs() << "Instruction removal failed. Sorry. :( Please report a bug!\n";
exit(1);
}
return New;
}
std::unique_ptr<Module>
BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) {
// Make all functions external, so GlobalDCE doesn't delete them...
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
I->setLinkage(GlobalValue::ExternalLinkage);
std::vector<std::string> CleanupPasses;
CleanupPasses.push_back("globaldce");
if (MayModifySemantics)
CleanupPasses.push_back("deadarghaX0r");
else
CleanupPasses.push_back("deadargelim");
std::unique_ptr<Module> New = runPassesOn(M, CleanupPasses);
if (!New) {
errs() << "Final cleanups failed. Sorry. :( Please report a bug!\n";
return nullptr;
}
delete M;
return New;
}
std::unique_ptr<Module> BugDriver::extractLoop(Module *M) {
std::vector<std::string> LoopExtractPasses;
LoopExtractPasses.push_back("loop-extract-single");
std::unique_ptr<Module> NewM = runPassesOn(M, LoopExtractPasses);
if (!NewM) {
outs() << "*** Loop extraction failed: ";
EmitProgressBitcode(M, "loopextraction", true);
outs() << "*** Sorry. :( Please report a bug!\n";
return nullptr;
}
// Check to see if we created any new functions. If not, no loops were
// extracted and we should return null. Limit the number of loops we extract
// to avoid taking forever.
static unsigned NumExtracted = 32;
if (M->size() == NewM->size() || --NumExtracted == 0) {
return nullptr;
} else {
assert(M->size() < NewM->size() && "Loop extract removed functions?");
Module::iterator MI = NewM->begin();
for (unsigned i = 0, e = M->size(); i != e; ++i)
++MI;
}
return NewM;
}
static void eliminateAliases(GlobalValue *GV) {
// First, check whether a GlobalAlias references this definition.
// GlobalAlias MAY NOT reference declarations.
for (;;) {
// 1. Find aliases
SmallVector<GlobalAlias *, 1> aliases;
Module *M = GV->getParent();
for (Module::alias_iterator I = M->alias_begin(), E = M->alias_end();
I != E; ++I)
if (I->getAliasee()->stripPointerCasts() == GV)
aliases.push_back(&*I);
if (aliases.empty())
break;
// 2. Resolve aliases
for (unsigned i = 0, e = aliases.size(); i < e; ++i) {
aliases[i]->replaceAllUsesWith(aliases[i]->getAliasee());
aliases[i]->eraseFromParent();
}
// 3. Repeat until no more aliases found; there might
// be an alias to an alias...
}
}
//
// DeleteGlobalInitializer - "Remove" the global variable by deleting its
// initializer,
// making it external.
//
void llvm::DeleteGlobalInitializer(GlobalVariable *GV) {
eliminateAliases(GV);
GV->setInitializer(nullptr);
GV->setComdat(nullptr);
}
// DeleteFunctionBody - "Remove" the function by deleting all of its basic
// blocks, making it external.
//
void llvm::DeleteFunctionBody(Function *F) {
eliminateAliases(F);
// Function declarations can't have comdats.
F->setComdat(nullptr);
// delete the body of the function...
F->deleteBody();
assert(F->isDeclaration() && "This didn't make the function external!");
}
/// GetTorInit - Given a list of entries for static ctors/dtors, return them
/// as a constant array.
static Constant *GetTorInit(std::vector<std::pair<Function *, int>> &TorList) {
assert(!TorList.empty() && "Don't create empty tor list!");
std::vector<Constant *> ArrayElts;
Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext());
StructType *STy = StructType::get(Int32Ty, TorList[0].first->getType());
for (unsigned i = 0, e = TorList.size(); i != e; ++i) {
Constant *Elts[] = {ConstantInt::get(Int32Ty, TorList[i].second),
TorList[i].first};
ArrayElts.push_back(ConstantStruct::get(STy, Elts));
}
return ConstantArray::get(
ArrayType::get(ArrayElts[0]->getType(), ArrayElts.size()), ArrayElts);
}
/// SplitStaticCtorDtor - A module was recently split into two parts, M1/M2, and
/// M1 has all of the global variables. If M2 contains any functions that are
/// static ctors/dtors, we need to add an llvm.global_[cd]tors global to M2, and
/// prune appropriate entries out of M1s list.
static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2,
ValueToValueMapTy &VMap) {
GlobalVariable *GV = M1->getNamedGlobal(GlobalName);
if (!GV || GV->isDeclaration() || GV->hasLocalLinkage() || !GV->use_empty())
return;
std::vector<std::pair<Function *, int>> M1Tors, M2Tors;
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
if (!InitList)
return;
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
if (ConstantStruct *CS =
dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
if (CS->getNumOperands() != 2)
return; // Not array of 2-element structs.
if (CS->getOperand(1)->isNullValue())
break; // Found a null terminator, stop here.
ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
int Priority = CI ? CI->getSExtValue() : 0;
Constant *FP = CS->getOperand(1);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
if (CE->isCast())
FP = CE->getOperand(0);
if (Function *F = dyn_cast<Function>(FP)) {
if (!F->isDeclaration())
M1Tors.push_back(std::make_pair(F, Priority));
else {
// Map to M2's version of the function.
F = cast<Function>(VMap[F]);
M2Tors.push_back(std::make_pair(F, Priority));
}
}
}
}
GV->eraseFromParent();
if (!M1Tors.empty()) {
Constant *M1Init = GetTorInit(M1Tors);
new GlobalVariable(*M1, M1Init->getType(), false,
GlobalValue::AppendingLinkage, M1Init, GlobalName);
}
GV = M2->getNamedGlobal(GlobalName);
assert(GV && "Not a clone of M1?");
assert(GV->use_empty() && "llvm.ctors shouldn't have uses!");
GV->eraseFromParent();
if (!M2Tors.empty()) {
Constant *M2Init = GetTorInit(M2Tors);
new GlobalVariable(*M2, M2Init->getType(), false,
GlobalValue::AppendingLinkage, M2Init, GlobalName);
}
}
std::unique_ptr<Module>
llvm::SplitFunctionsOutOfModule(Module *M, const std::vector<Function *> &F,
ValueToValueMapTy &VMap) {
// Make sure functions & globals are all external so that linkage
// between the two modules will work.
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
I->setLinkage(GlobalValue::ExternalLinkage);
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
I != E; ++I) {
if (I->hasName() && I->getName()[0] == '\01')
I->setName(I->getName().substr(1));
I->setLinkage(GlobalValue::ExternalLinkage);
}
ValueToValueMapTy NewVMap;
std::unique_ptr<Module> New = CloneModule(M, NewVMap);
// Remove the Test functions from the Safe module
std::set<Function *> TestFunctions;
for (unsigned i = 0, e = F.size(); i != e; ++i) {
Function *TNOF = cast<Function>(VMap[F[i]]);
DEBUG(errs() << "Removing function ");
DEBUG(TNOF->printAsOperand(errs(), false));
DEBUG(errs() << "\n");
TestFunctions.insert(cast<Function>(NewVMap[TNOF]));
DeleteFunctionBody(TNOF); // Function is now external in this module!
}
// Remove the Safe functions from the Test module
for (Function &I : *New)
if (!TestFunctions.count(&I))
DeleteFunctionBody(&I);
// Try to split the global initializers evenly
for (GlobalVariable &I : M->globals()) {
GlobalVariable *GV = cast<GlobalVariable>(NewVMap[&I]);
if (Function *TestFn = globalInitUsesExternalBA(&I)) {
if (Function *SafeFn = globalInitUsesExternalBA(GV)) {
errs() << "*** Error: when reducing functions, encountered "
"the global '";
GV->printAsOperand(errs(), false);
errs() << "' with an initializer that references blockaddresses "
"from safe function '"
<< SafeFn->getName() << "' and from test function '"
<< TestFn->getName() << "'.\n";
exit(1);
}
DeleteGlobalInitializer(&I); // Delete the initializer to make it external
} else {
// If we keep it in the safe module, then delete it in the test module
DeleteGlobalInitializer(GV);
}
}
// Make sure that there is a global ctor/dtor array in both halves of the
// module if they both have static ctor/dtor functions.
SplitStaticCtorDtor("llvm.global_ctors", M, New.get(), NewVMap);
SplitStaticCtorDtor("llvm.global_dtors", M, New.get(), NewVMap);
return New;
}
//===----------------------------------------------------------------------===//
// Basic Block Extraction Code
//===----------------------------------------------------------------------===//
std::unique_ptr<Module>
BugDriver::extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs,
Module *M) {
auto Temp = sys::fs::TempFile::create(OutputPrefix + "-extractblocks%%%%%%%");
if (!Temp) {
outs() << "*** Basic Block extraction failed!\n";
errs() << "Error creating temporary file: " << toString(Temp.takeError())
<< "\n";
EmitProgressBitcode(M, "basicblockextractfail", true);
return nullptr;
}
DiscardTemp Discard{*Temp};
raw_fd_ostream OS(Temp->FD, /*shouldClose*/ false);
for (std::vector<BasicBlock *>::const_iterator I = BBs.begin(), E = BBs.end();
I != E; ++I) {
BasicBlock *BB = *I;
// If the BB doesn't have a name, give it one so we have something to key
// off of.
if (!BB->hasName())
BB->setName("tmpbb");
OS << BB->getParent()->getName() << " " << BB->getName() << "\n";
}
OS.flush();
if (OS.has_error()) {
errs() << "Error writing list of blocks to not extract\n";
EmitProgressBitcode(M, "basicblockextractfail", true);
OS.clear_error();
return nullptr;
}
std::string uniqueFN = "--extract-blocks-file=";
uniqueFN += Temp->TmpName;
const char *ExtraArg = uniqueFN.c_str();
std::vector<std::string> PI;
PI.push_back("extract-blocks");
std::unique_ptr<Module> Ret = runPassesOn(M, PI, 1, &ExtraArg);
if (!Ret) {
outs() << "*** Basic Block extraction failed, please report a bug!\n";
EmitProgressBitcode(M, "basicblockextractfail", true);
}
return Ret;
}

View File

@ -1,100 +0,0 @@
//===-- FindBugs.cpp - Run Many Different Optimizations -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an interface that allows bugpoint to choose different
// combinations of optimizations to run on the selected input. Bugpoint will
// run these optimizations and record the success/failure of each. This way
// we can hopefully spot bugs in the optimizations.
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <random>
using namespace llvm;
Error
BugDriver::runManyPasses(const std::vector<std::string> &AllPasses) {
setPassesToRun(AllPasses);
outs() << "Starting bug finding procedure...\n\n";
// Creating a reference output if necessary
if (Error E = initializeExecutionEnvironment())
return E;
outs() << "\n";
if (ReferenceOutputFile.empty()) {
outs() << "Generating reference output from raw program: \n";
if (Error E = createReferenceFile(Program))
return E;
}
std::mt19937 randomness(std::random_device{}());
unsigned num = 1;
while (1) {
//
// Step 1: Randomize the order of the optimizer passes.
//
std::shuffle(PassesToRun.begin(), PassesToRun.end(), randomness);
//
// Step 2: Run optimizer passes on the program and check for success.
//
outs() << "Running selected passes on program to test for crash: ";
for (int i = 0, e = PassesToRun.size(); i != e; i++) {
outs() << "-" << PassesToRun[i] << " ";
}
std::string Filename;
if (runPasses(Program, PassesToRun, Filename, false)) {
outs() << "\n";
outs() << "Optimizer passes caused failure!\n\n";
return debugOptimizerCrash();
} else {
outs() << "Combination " << num << " optimized successfully!\n";
}
//
// Step 3: Compile the optimized code.
//
outs() << "Running the code generator to test for a crash: ";
if (Error E = compileProgram(Program)) {
outs() << "\n*** compileProgram threw an exception: ";
outs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
outs() << '\n';
//
// Step 4: Run the program and compare its output to the reference
// output (created above).
//
outs() << "*** Checking if passes caused miscompliation:\n";
Expected<bool> Diff = diffProgram(Program, Filename, "", false);
if (Error E = Diff.takeError()) {
errs() << toString(std::move(E));
return debugCodeGeneratorCrash();
}
if (*Diff) {
outs() << "\n*** diffProgram returned true!\n";
Error E = debugMiscompilation();
if (!E)
return Error::success();
}
outs() << "\n*** diff'd output matches!\n";
sys::fs::remove(Filename);
outs() << "\n\n";
num++;
} // end while
// Unreachable.
}

View File

@ -1,33 +0,0 @@
;===- ./tools/bugpoint/LLVMBuild.txt ---------------------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Tool
name = bugpoint
parent = Tools
required_libraries =
AsmParser
BitReader
BitWriter
CodeGen
IRReader
IPO
Instrumentation
Linker
ObjCARC
Scalar
all-targets

View File

@ -1,209 +0,0 @@
//===- ListReducer.h - Trim down list while retaining property --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class is to be used as a base class for operations that want to zero in
// on a subset of the input which still causes the bug we are tracking.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_BUGPOINT_LISTREDUCER_H
#define LLVM_TOOLS_BUGPOINT_LISTREDUCER_H
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdlib>
#include <random>
#include <vector>
namespace llvm {
extern bool BugpointIsInterrupted;
template <typename ElTy> struct ListReducer {
enum TestResult {
NoFailure, // No failure of the predicate was detected
KeepSuffix, // The suffix alone satisfies the predicate
KeepPrefix // The prefix alone satisfies the predicate
};
virtual ~ListReducer() {}
/// This virtual function should be overriden by subclasses to implement the
/// test desired. The testcase is only required to test to see if the Kept
/// list still satisfies the property, but if it is going to check the prefix
/// anyway, it can.
virtual Expected<TestResult> doTest(std::vector<ElTy> &Prefix,
std::vector<ElTy> &Kept) = 0;
/// This function attempts to reduce the length of the specified list while
/// still maintaining the "test" property. This is the core of the "work"
/// that bugpoint does.
Expected<bool> reduceList(std::vector<ElTy> &TheList) {
std::vector<ElTy> empty;
std::mt19937 randomness(0x6e5ea738); // Seed the random number generator
Expected<TestResult> Result = doTest(TheList, empty);
if (Error E = Result.takeError())
return std::move(E);
switch (*Result) {
case KeepPrefix:
if (TheList.size() == 1) // we are done, it's the base case and it fails
return true;
else
break; // there's definitely an error, but we need to narrow it down
case KeepSuffix:
// cannot be reached!
llvm_unreachable("bugpoint ListReducer internal error: "
"selected empty set.");
case NoFailure:
return false; // there is no failure with the full set of passes/funcs!
}
// Maximal number of allowed splitting iterations,
// before the elements are randomly shuffled.
const unsigned MaxIterationsWithoutProgress = 3;
// Maximal number of allowed single-element trim iterations. We add a
// threshold here as single-element reductions may otherwise take a
// very long time to complete.
const unsigned MaxTrimIterationsWithoutBackJump = 3;
bool ShufflingEnabled = true;
Backjump:
unsigned MidTop = TheList.size();
unsigned MaxIterations = MaxIterationsWithoutProgress;
unsigned NumOfIterationsWithoutProgress = 0;
while (MidTop > 1) { // Binary split reduction loop
// Halt if the user presses ctrl-c.
if (BugpointIsInterrupted) {
errs() << "\n\n*** Reduction Interrupted, cleaning up...\n\n";
return true;
}
// If the loop doesn't make satisfying progress, try shuffling.
// The purpose of shuffling is to avoid the heavy tails of the
// distribution (improving the speed of convergence).
if (ShufflingEnabled && NumOfIterationsWithoutProgress > MaxIterations) {
std::vector<ElTy> ShuffledList(TheList);
std::shuffle(ShuffledList.begin(), ShuffledList.end(), randomness);
errs() << "\n\n*** Testing shuffled set...\n\n";
// Check that random shuffle doesn't lose the bug
Expected<TestResult> Result = doTest(ShuffledList, empty);
// TODO: Previously, this error was ignored and we treated it as if
// shuffling hid the bug. This should really either be consumeError if
// that behaviour was sensible, or we should propagate the error.
assert(!Result.takeError() && "Shuffling caused internal error?");
if (*Result == KeepPrefix) {
// If the bug is still here, use the shuffled list.
TheList.swap(ShuffledList);
MidTop = TheList.size();
// Must increase the shuffling treshold to avoid the small
// probability of infinite looping without making progress.
MaxIterations += 2;
errs() << "\n\n*** Shuffling does not hide the bug...\n\n";
} else {
ShufflingEnabled = false; // Disable shuffling further on
errs() << "\n\n*** Shuffling hides the bug...\n\n";
}
NumOfIterationsWithoutProgress = 0;
}
unsigned Mid = MidTop / 2;
std::vector<ElTy> Prefix(TheList.begin(), TheList.begin() + Mid);
std::vector<ElTy> Suffix(TheList.begin() + Mid, TheList.end());
Expected<TestResult> Result = doTest(Prefix, Suffix);
if (Error E = Result.takeError())
return std::move(E);
switch (*Result) {
case KeepSuffix:
// The property still holds. We can just drop the prefix elements, and
// shorten the list to the "kept" elements.
TheList.swap(Suffix);
MidTop = TheList.size();
// Reset progress treshold and progress counter
MaxIterations = MaxIterationsWithoutProgress;
NumOfIterationsWithoutProgress = 0;
break;
case KeepPrefix:
// The predicate still holds, shorten the list to the prefix elements.
TheList.swap(Prefix);
MidTop = TheList.size();
// Reset progress treshold and progress counter
MaxIterations = MaxIterationsWithoutProgress;
NumOfIterationsWithoutProgress = 0;
break;
case NoFailure:
// Otherwise the property doesn't hold. Some of the elements we removed
// must be necessary to maintain the property.
MidTop = Mid;
NumOfIterationsWithoutProgress++;
break;
}
}
// Probability of backjumping from the trimming loop back to the binary
// split reduction loop.
const int BackjumpProbability = 10;
// Okay, we trimmed as much off the top and the bottom of the list as we
// could. If there is more than two elements in the list, try deleting
// interior elements and testing that.
//
if (TheList.size() > 2) {
bool Changed = true;
std::vector<ElTy> EmptyList;
unsigned TrimIterations = 0;
while (Changed) { // Trimming loop.
Changed = false;
// If the binary split reduction loop made an unfortunate sequence of
// splits, the trimming loop might be left off with a huge number of
// remaining elements (large search space). Backjumping out of that
// search space and attempting a different split can significantly
// improve the convergence speed.
if (std::rand() % 100 < BackjumpProbability)
goto Backjump;
for (unsigned i = 1; i < TheList.size() - 1; ++i) {
// Check interior elts
if (BugpointIsInterrupted) {
errs() << "\n\n*** Reduction Interrupted, cleaning up...\n\n";
return true;
}
std::vector<ElTy> TestList(TheList);
TestList.erase(TestList.begin() + i);
Expected<TestResult> Result = doTest(EmptyList, TestList);
if (Error E = Result.takeError())
return std::move(E);
if (*Result == KeepSuffix) {
// We can trim down the list!
TheList.swap(TestList);
--i; // Don't skip an element of the list
Changed = true;
}
}
if (TrimIterations >= MaxTrimIterationsWithoutBackJump)
break;
TrimIterations++;
}
}
return true; // there are some failure and we've narrowed them down
}
};
} // End llvm namespace
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,287 +0,0 @@
//===- OptimizerDriver.cpp - Allow BugPoint to run passes safely ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an interface that allows bugpoint to run various passes
// without the threat of a buggy pass corrupting bugpoint (of course, bugpoint
// may have its own bugs, but that's another story...). It achieves this by
// forking a copy of itself and having the child process do the optimizations.
// If this client dies, we can always fork a new one. :)
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/ToolOutputFile.h"
#define DONT_GET_PLUGIN_LOADER_OPTION
#include "llvm/Support/PluginLoader.h"
using namespace llvm;
#define DEBUG_TYPE "bugpoint"
namespace llvm {
extern cl::opt<std::string> OutputPrefix;
}
static cl::opt<bool> PreserveBitcodeUseListOrder(
"preserve-bc-uselistorder",
cl::desc("Preserve use-list order when writing LLVM bitcode."),
cl::init(true), cl::Hidden);
// ChildOutput - This option captures the name of the child output file that
// is set up by the parent bugpoint process
static cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden);
static cl::opt<std::string>
OptCmd("opt-command", cl::init(""),
cl::desc("Path to opt. (default: search path "
"for 'opt'.)"));
/// writeProgramToFile - This writes the current "Program" to the named bitcode
/// file. If an error occurs, true is returned.
///
static bool writeProgramToFileAux(ToolOutputFile &Out, const Module *M) {
WriteBitcodeToFile(M, Out.os(), PreserveBitcodeUseListOrder);
Out.os().close();
if (!Out.os().has_error()) {
Out.keep();
return false;
}
return true;
}
bool BugDriver::writeProgramToFile(const std::string &Filename, int FD,
const Module *M) const {
ToolOutputFile Out(Filename, FD);
return writeProgramToFileAux(Out, M);
}
bool BugDriver::writeProgramToFile(int FD, const Module *M) const {
raw_fd_ostream OS(FD, /*shouldClose*/ false);
WriteBitcodeToFile(M, OS, PreserveBitcodeUseListOrder);
OS.flush();
if (!OS.has_error())
return false;
OS.clear_error();
return true;
}
bool BugDriver::writeProgramToFile(const std::string &Filename,
const Module *M) const {
std::error_code EC;
ToolOutputFile Out(Filename, EC, sys::fs::F_None);
if (!EC)
return writeProgramToFileAux(Out, M);
return true;
}
/// EmitProgressBitcode - This function is used to output the current Program
/// to a file named "bugpoint-ID.bc".
///
void BugDriver::EmitProgressBitcode(const Module *M, const std::string &ID,
bool NoFlyer) const {
// Output the input to the current pass to a bitcode file, emit a message
// telling the user how to reproduce it: opt -foo blah.bc
//
std::string Filename = OutputPrefix + "-" + ID + ".bc";
if (writeProgramToFile(Filename, M)) {
errs() << "Error opening file '" << Filename << "' for writing!\n";
return;
}
outs() << "Emitted bitcode to '" << Filename << "'\n";
if (NoFlyer || PassesToRun.empty())
return;
outs() << "\n*** You can reproduce the problem with: ";
if (UseValgrind)
outs() << "valgrind ";
outs() << "opt " << Filename;
for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
outs() << " -load " << PluginLoader::getPlugin(i);
}
outs() << " " << getPassesString(PassesToRun) << "\n";
}
cl::opt<bool> SilencePasses(
"silence-passes",
cl::desc("Suppress output of running passes (both stdout and stderr)"));
static cl::list<std::string> OptArgs("opt-args", cl::Positional,
cl::desc("<opt arguments>..."),
cl::ZeroOrMore, cl::PositionalEatsArgs);
/// runPasses - Run the specified passes on Program, outputting a bitcode file
/// and writing the filename into OutputFile if successful. If the
/// optimizations fail for some reason (optimizer crashes), return true,
/// otherwise return false. If DeleteOutput is set to true, the bitcode is
/// deleted on success, and the filename string is undefined. This prints to
/// outs() a single line message indicating whether compilation was successful
/// or failed.
///
bool BugDriver::runPasses(Module *Program,
const std::vector<std::string> &Passes,
std::string &OutputFilename, bool DeleteOutput,
bool Quiet, unsigned NumExtraArgs,
const char *const *ExtraArgs) const {
// setup the output file name
outs().flush();
SmallString<128> UniqueFilename;
std::error_code EC = sys::fs::createUniqueFile(
OutputPrefix + "-output-%%%%%%%.bc", UniqueFilename);
if (EC) {
errs() << getToolName()
<< ": Error making unique filename: " << EC.message() << "\n";
return 1;
}
OutputFilename = UniqueFilename.str();
// set up the input file name
Expected<sys::fs::TempFile> Temp =
sys::fs::TempFile::create(OutputPrefix + "-input-%%%%%%%.bc");
if (!Temp) {
errs() << getToolName()
<< ": Error making unique filename: " << toString(Temp.takeError())
<< "\n";
return 1;
}
DiscardTemp Discard{*Temp};
raw_fd_ostream OS(Temp->FD, /*shouldClose*/ false);
WriteBitcodeToFile(Program, OS, PreserveBitcodeUseListOrder);
OS.flush();
if (OS.has_error()) {
errs() << "Error writing bitcode file: " << Temp->TmpName << "\n";
OS.clear_error();
return 1;
}
std::string tool = OptCmd;
if (OptCmd.empty()) {
if (ErrorOr<std::string> Path = sys::findProgramByName("opt"))
tool = *Path;
else
errs() << Path.getError().message() << "\n";
}
if (tool.empty()) {
errs() << "Cannot find `opt' in PATH!\n";
return 1;
}
std::string Prog;
if (UseValgrind) {
if (ErrorOr<std::string> Path = sys::findProgramByName("valgrind"))
Prog = *Path;
else
errs() << Path.getError().message() << "\n";
} else
Prog = tool;
if (Prog.empty()) {
errs() << "Cannot find `valgrind' in PATH!\n";
return 1;
}
// setup the child process' arguments
SmallVector<const char *, 8> Args;
if (UseValgrind) {
Args.push_back("valgrind");
Args.push_back("--error-exitcode=1");
Args.push_back("-q");
Args.push_back(tool.c_str());
} else
Args.push_back(tool.c_str());
for (unsigned i = 0, e = OptArgs.size(); i != e; ++i)
Args.push_back(OptArgs[i].c_str());
Args.push_back("-disable-symbolication");
Args.push_back("-o");
Args.push_back(OutputFilename.c_str());
std::vector<std::string> pass_args;
for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
pass_args.push_back(std::string("-load"));
pass_args.push_back(PluginLoader::getPlugin(i));
}
for (std::vector<std::string>::const_iterator I = Passes.begin(),
E = Passes.end();
I != E; ++I)
pass_args.push_back(std::string("-") + (*I));
for (std::vector<std::string>::const_iterator I = pass_args.begin(),
E = pass_args.end();
I != E; ++I)
Args.push_back(I->c_str());
Args.push_back(Temp->TmpName.c_str());
for (unsigned i = 0; i < NumExtraArgs; ++i)
Args.push_back(*ExtraArgs);
Args.push_back(nullptr);
DEBUG(errs() << "\nAbout to run:\t";
for (unsigned i = 0, e = Args.size() - 1; i != e; ++i) errs()
<< " " << Args[i];
errs() << "\n";);
Optional<StringRef> Redirects[3] = {None, None, None};
// Redirect stdout and stderr to nowhere if SilencePasses is given.
if (SilencePasses) {
Redirects[1] = "";
Redirects[2] = "";
}
std::string ErrMsg;
int result = sys::ExecuteAndWait(Prog, Args.data(), nullptr, Redirects,
Timeout, MemoryLimit, &ErrMsg);
// If we are supposed to delete the bitcode file or if the passes crashed,
// remove it now. This may fail if the file was never created, but that's ok.
if (DeleteOutput || result != 0)
sys::fs::remove(OutputFilename);
if (!Quiet) {
if (result == 0)
outs() << "Success!\n";
else if (result > 0)
outs() << "Exited with error code '" << result << "'\n";
else if (result < 0) {
if (result == -1)
outs() << "Execute failed: " << ErrMsg << "\n";
else
outs() << "Crashed: " << ErrMsg << "\n";
}
if (result & 0x01000000)
outs() << "Dumped core\n";
}
// Was the child successful?
return result != 0;
}
std::unique_ptr<Module>
BugDriver::runPassesOn(Module *M, const std::vector<std::string> &Passes,
unsigned NumExtraArgs, const char *const *ExtraArgs) {
std::string BitcodeResult;
if (runPasses(M, Passes, BitcodeResult, false /*delete*/, true /*quiet*/,
NumExtraArgs, ExtraArgs)) {
return nullptr;
}
std::unique_ptr<Module> Ret = parseInputFile(BitcodeResult, Context);
if (!Ret) {
errs() << getToolName() << ": Error reading bitcode file '" << BitcodeResult
<< "'!\n";
exit(1);
}
sys::fs::remove(BitcodeResult);
return Ret;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,183 +0,0 @@
//===-- tools/bugpoint/ToolRunner.h -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file exposes an abstraction around a platform C compiler, used to
// compile C and assembly code. It also exposes an "AbstractIntepreter"
// interface, which is used to execute code using one of the LLVM execution
// engines.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_BUGPOINT_TOOLRUNNER_H
#define LLVM_TOOLS_BUGPOINT_TOOLRUNNER_H
#include "llvm/ADT/Triple.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SystemUtils.h"
#include <exception>
#include <vector>
namespace llvm {
extern cl::opt<bool> SaveTemps;
extern Triple TargetTriple;
class LLC;
//===---------------------------------------------------------------------===//
// CC abstraction
//
class CC {
std::string CCPath; // The path to the cc executable.
std::string RemoteClientPath; // The path to the rsh / ssh executable.
std::vector<std::string> ccArgs; // CC-specific arguments.
CC(StringRef ccPath, StringRef RemotePath,
const std::vector<std::string> *CCArgs)
: CCPath(ccPath), RemoteClientPath(RemotePath) {
if (CCArgs)
ccArgs = *CCArgs;
}
public:
enum FileType { AsmFile, ObjectFile, CFile };
static CC *create(std::string &Message, const std::string &CCBinary,
const std::vector<std::string> *Args);
/// ExecuteProgram - Execute the program specified by "ProgramFile" (which is
/// either a .s file, or a .c file, specified by FileType), with the specified
/// arguments. Standard input is specified with InputFile, and standard
/// Output is captured to the specified OutputFile location. The SharedLibs
/// option specifies optional native shared objects that can be loaded into
/// the program for execution.
///
Expected<int> ExecuteProgram(
const std::string &ProgramFile, const std::vector<std::string> &Args,
FileType fileType, const std::string &InputFile,
const std::string &OutputFile,
const std::vector<std::string> &CCArgs = std::vector<std::string>(),
unsigned Timeout = 0, unsigned MemoryLimit = 0);
/// MakeSharedObject - This compiles the specified file (which is either a .c
/// file or a .s file) into a shared object.
///
Error MakeSharedObject(const std::string &InputFile, FileType fileType,
std::string &OutputFile,
const std::vector<std::string> &ArgsForCC);
};
//===---------------------------------------------------------------------===//
/// AbstractInterpreter Class - Subclasses of this class are used to execute
/// LLVM bitcode in a variety of ways. This abstract interface hides this
/// complexity behind a simple interface.
///
class AbstractInterpreter {
virtual void anchor();
public:
static LLC *createLLC(const char *Argv0, std::string &Message,
const std::string &CCBinary,
const std::vector<std::string> *Args = nullptr,
const std::vector<std::string> *CCArgs = nullptr,
bool UseIntegratedAssembler = false);
static AbstractInterpreter *
createLLI(const char *Argv0, std::string &Message,
const std::vector<std::string> *Args = nullptr);
static AbstractInterpreter *
createJIT(const char *Argv0, std::string &Message,
const std::vector<std::string> *Args = nullptr);
static AbstractInterpreter *
createCustomCompiler(std::string &Message,
const std::string &CompileCommandLine);
static AbstractInterpreter *
createCustomExecutor(std::string &Message,
const std::string &ExecCommandLine);
virtual ~AbstractInterpreter() {}
/// compileProgram - Compile the specified program from bitcode to executable
/// code. This does not produce any output, it is only used when debugging
/// the code generator. It returns false if the code generator fails.
virtual Error compileProgram(const std::string &Bitcode, unsigned Timeout = 0,
unsigned MemoryLimit = 0) {
return Error::success();
}
/// Compile the specified program from bitcode to code understood by the CC
/// driver (either C or asm). Returns an error if the code generator fails,,
/// otherwise, the type of code emitted.
virtual Expected<CC::FileType> OutputCode(const std::string &Bitcode,
std::string &OutFile,
unsigned Timeout = 0,
unsigned MemoryLimit = 0) {
return make_error<StringError>(
"OutputCode not supported by this AbstractInterpreter!",
inconvertibleErrorCode());
}
/// ExecuteProgram - Run the specified bitcode file, emitting output to the
/// specified filename. This sets RetVal to the exit code of the program or
/// returns an Error if a problem was encountered that prevented execution of
/// the program.
///
virtual Expected<int> ExecuteProgram(
const std::string &Bitcode, const std::vector<std::string> &Args,
const std::string &InputFile, const std::string &OutputFile,
const std::vector<std::string> &CCArgs = std::vector<std::string>(),
const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
unsigned Timeout = 0, unsigned MemoryLimit = 0) = 0;
};
//===---------------------------------------------------------------------===//
// LLC Implementation of AbstractIntepreter interface
//
class LLC : public AbstractInterpreter {
std::string LLCPath; // The path to the LLC executable.
std::vector<std::string> ToolArgs; // Extra args to pass to LLC.
CC *cc;
bool UseIntegratedAssembler;
public:
LLC(const std::string &llcPath, CC *cc, const std::vector<std::string> *Args,
bool useIntegratedAssembler)
: LLCPath(llcPath), cc(cc),
UseIntegratedAssembler(useIntegratedAssembler) {
ToolArgs.clear();
if (Args)
ToolArgs = *Args;
}
~LLC() override { delete cc; }
/// compileProgram - Compile the specified program from bitcode to executable
/// code. This does not produce any output, it is only used when debugging
/// the code generator. Returns false if the code generator fails.
Error compileProgram(const std::string &Bitcode, unsigned Timeout = 0,
unsigned MemoryLimit = 0) override;
Expected<int> ExecuteProgram(
const std::string &Bitcode, const std::vector<std::string> &Args,
const std::string &InputFile, const std::string &OutputFile,
const std::vector<std::string> &CCArgs = std::vector<std::string>(),
const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
Expected<CC::FileType> OutputCode(const std::string &Bitcode,
std::string &OutFile, unsigned Timeout = 0,
unsigned MemoryLimit = 0) override;
};
} // End llvm namespace
#endif

View File

@ -1,220 +0,0 @@
//===- bugpoint.cpp - The LLVM Bugpoint utility ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is an automated compiler debugger tool. It is used to narrow
// down miscompilations and crash problems to a specific pass in the compiler,
// and the specific Module or Function input that is causing the problem.
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/LinkAllIR.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Valgrind.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
// Enable this macro to debug bugpoint itself.
//#define DEBUG_BUGPOINT 1
using namespace llvm;
static cl::opt<bool>
FindBugs("find-bugs", cl::desc("Run many different optimization sequences "
"on program to find bugs"),
cl::init(false));
static cl::list<std::string>
InputFilenames(cl::Positional, cl::OneOrMore,
cl::desc("<input llvm ll/bc files>"));
static cl::opt<unsigned> TimeoutValue(
"timeout", cl::init(300), cl::value_desc("seconds"),
cl::desc("Number of seconds program is allowed to run before it "
"is killed (default is 300s), 0 disables timeout"));
static cl::opt<int> MemoryLimit(
"mlimit", cl::init(-1), cl::value_desc("MBytes"),
cl::desc("Maximum amount of memory to use. 0 disables check. Defaults to "
"400MB (800MB under valgrind, 0 with sanitizers)."));
static cl::opt<bool>
UseValgrind("enable-valgrind",
cl::desc("Run optimizations through valgrind"));
// The AnalysesList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo *, bool, PassNameParser>
PassList(cl::desc("Passes available:"), cl::ZeroOrMore);
static cl::opt<bool>
StandardLinkOpts("std-link-opts",
cl::desc("Include the standard link time optimizations"));
static cl::opt<bool>
OptLevelO1("O1", cl::desc("Optimization level 1. Identical to 'opt -O1'"));
static cl::opt<bool>
OptLevelO2("O2", cl::desc("Optimization level 2. Identical to 'opt -O2'"));
static cl::opt<bool> OptLevelOs(
"Os",
cl::desc(
"Like -O2 with extra optimizations for size. Similar to clang -Os"));
static cl::opt<bool>
OptLevelO3("O3", cl::desc("Optimization level 3. Identical to 'opt -O3'"));
static cl::opt<std::string>
OverrideTriple("mtriple", cl::desc("Override target triple for module"));
/// BugpointIsInterrupted - Set to true when the user presses ctrl-c.
bool llvm::BugpointIsInterrupted = false;
#ifndef DEBUG_BUGPOINT
static void BugpointInterruptFunction() { BugpointIsInterrupted = true; }
#endif
// Hack to capture a pass list.
namespace {
class AddToDriver : public legacy::FunctionPassManager {
BugDriver &D;
public:
AddToDriver(BugDriver &_D) : FunctionPassManager(nullptr), D(_D) {}
void add(Pass *P) override {
const void *ID = P->getPassID();
const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID);
D.addPass(PI->getPassArgument());
}
};
}
#ifdef LINK_POLLY_INTO_TOOLS
namespace polly {
void initializePollyPasses(llvm::PassRegistry &Registry);
}
#endif
int main(int argc, char **argv) {
#ifndef DEBUG_BUGPOINT
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
llvm::PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
#endif
// Initialize passes
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeScalarOpts(Registry);
initializeObjCARCOpts(Registry);
initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
initializeInstrumentation(Registry);
initializeTarget(Registry);
#ifdef LINK_POLLY_INTO_TOOLS
polly::initializePollyPasses(Registry);
#endif
if (std::getenv("bar") == (char*) -1) {
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmPrinters();
InitializeAllAsmParsers();
}
cl::ParseCommandLineOptions(argc, argv,
"LLVM automatic testcase reducer. See\nhttp://"
"llvm.org/cmds/bugpoint.html"
" for more information.\n");
#ifndef DEBUG_BUGPOINT
sys::SetInterruptFunction(BugpointInterruptFunction);
#endif
LLVMContext Context;
// If we have an override, set it and then track the triple we want Modules
// to use.
if (!OverrideTriple.empty()) {
TargetTriple.setTriple(Triple::normalize(OverrideTriple));
outs() << "Override triple set to '" << TargetTriple.getTriple() << "'\n";
}
if (MemoryLimit < 0) {
// Set the default MemoryLimit. Be sure to update the flag's description if
// you change this.
if (sys::RunningOnValgrind() || UseValgrind)
MemoryLimit = 800;
else
MemoryLimit = 400;
#if (LLVM_ADDRESS_SANITIZER_BUILD || LLVM_MEMORY_SANITIZER_BUILD || \
LLVM_THREAD_SANITIZER_BUILD)
// Starting from kernel 4.9 memory allocated with mmap is counted against
// RLIMIT_DATA. Sanitizers need to allocate tens of terabytes for shadow.
MemoryLimit = 0;
#endif
}
BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit, UseValgrind,
Context);
if (D.addSources(InputFilenames))
return 1;
AddToDriver PM(D);
if (StandardLinkOpts) {
PassManagerBuilder Builder;
Builder.Inliner = createFunctionInliningPass();
Builder.populateLTOPassManager(PM);
}
if (OptLevelO1 || OptLevelO2 || OptLevelO3) {
PassManagerBuilder Builder;
if (OptLevelO1)
Builder.Inliner = createAlwaysInlinerLegacyPass();
else if (OptLevelOs || OptLevelO2)
Builder.Inliner = createFunctionInliningPass(
2, OptLevelOs ? 1 : 0, false);
else
Builder.Inliner = createFunctionInliningPass(275);
Builder.populateFunctionPassManager(PM);
Builder.populateModulePassManager(PM);
}
for (const PassInfo *PI : PassList)
D.addPass(PI->getPassArgument());
// Bugpoint has the ability of generating a plethora of core files, so to
// avoid filling up the disk, we prevent it
#ifndef DEBUG_BUGPOINT
sys::Process::PreventCoreFiles();
#endif
if (Error E = D.run()) {
errs() << toString(std::move(E));
return 1;
}
return 0;
}