You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
257
external/llvm/tools/bugpoint/BugDriver.cpp
vendored
257
external/llvm/tools/bugpoint/BugDriver.cpp
vendored
@ -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();
|
||||
}
|
325
external/llvm/tools/bugpoint/BugDriver.h
vendored
325
external/llvm/tools/bugpoint/BugDriver.h
vendored
@ -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
|
43
external/llvm/tools/bugpoint/CMakeLists.txt
vendored
43
external/llvm/tools/bugpoint/CMakeLists.txt
vendored
@ -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)
|
1247
external/llvm/tools/bugpoint/CrashDebugger.cpp
vendored
1247
external/llvm/tools/bugpoint/CrashDebugger.cpp
vendored
File diff suppressed because it is too large
Load Diff
470
external/llvm/tools/bugpoint/ExecutionDriver.cpp
vendored
470
external/llvm/tools/bugpoint/ExecutionDriver.cpp
vendored
@ -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; }
|
417
external/llvm/tools/bugpoint/ExtractFunction.cpp
vendored
417
external/llvm/tools/bugpoint/ExtractFunction.cpp
vendored
@ -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;
|
||||
}
|
100
external/llvm/tools/bugpoint/FindBugs.cpp
vendored
100
external/llvm/tools/bugpoint/FindBugs.cpp
vendored
@ -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.
|
||||
}
|
33
external/llvm/tools/bugpoint/LLVMBuild.txt
vendored
33
external/llvm/tools/bugpoint/LLVMBuild.txt
vendored
@ -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
|
209
external/llvm/tools/bugpoint/ListReducer.h
vendored
209
external/llvm/tools/bugpoint/ListReducer.h
vendored
@ -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
|
1105
external/llvm/tools/bugpoint/Miscompilation.cpp
vendored
1105
external/llvm/tools/bugpoint/Miscompilation.cpp
vendored
File diff suppressed because it is too large
Load Diff
287
external/llvm/tools/bugpoint/OptimizerDriver.cpp
vendored
287
external/llvm/tools/bugpoint/OptimizerDriver.cpp
vendored
@ -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;
|
||||
}
|
891
external/llvm/tools/bugpoint/ToolRunner.cpp
vendored
891
external/llvm/tools/bugpoint/ToolRunner.cpp
vendored
File diff suppressed because it is too large
Load Diff
183
external/llvm/tools/bugpoint/ToolRunner.h
vendored
183
external/llvm/tools/bugpoint/ToolRunner.h
vendored
@ -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
|
220
external/llvm/tools/bugpoint/bugpoint.cpp
vendored
220
external/llvm/tools/bugpoint/bugpoint.cpp
vendored
@ -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;
|
||||
}
|
Reference in New Issue
Block a user