diff options
Diffstat (limited to 'contrib/llvm/tools/bugpoint')
-rw-r--r-- | contrib/llvm/tools/bugpoint/BugDriver.cpp | 257 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/BugDriver.h | 332 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/CMakeLists.txt | 15 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/CrashDebugger.cpp | 659 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/ExecutionDriver.cpp | 497 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/ExtractFunction.cpp | 378 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/FindBugs.cpp | 113 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/ListReducer.h | 201 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/Makefile | 16 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/Miscompilation.cpp | 1027 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/OptimizerDriver.cpp | 267 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/TestPasses.cpp | 75 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/ToolRunner.cpp | 879 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/ToolRunner.h | 242 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/bugpoint.cpp | 159 |
15 files changed, 5117 insertions, 0 deletions
diff --git a/contrib/llvm/tools/bugpoint/BugDriver.cpp b/contrib/llvm/tools/bugpoint/BugDriver.cpp new file mode 100644 index 0000000..45a0d4d --- /dev/null +++ b/contrib/llvm/tools/bugpoint/BugDriver.cpp @@ -0,0 +1,257 @@ +//===- 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/Linker.h" +#include "llvm/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/IRReader.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Host.h" +#include <memory> +using namespace llvm; + +namespace llvm { + Triple TargetTriple; +} + +// 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<const PassInfo*> &Passes) { + std::string Result; + for (unsigned i = 0, e = Passes.size(); i != e; ++i) { + if (i) Result += " "; + Result += "-"; + Result += Passes[i]->getPassArgument(); + } + return Result; +} + +BugDriver::BugDriver(const char *toolname, bool as_child, bool find_bugs, + unsigned timeout, unsigned memlimit, bool use_valgrind, + LLVMContext& ctxt) + : Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile), + Program(0), Interpreter(0), SafeInterpreter(0), gcc(0), + run_as_child(as_child), run_find_bugs(find_bugs), Timeout(timeout), + MemoryLimit(memlimit), UseValgrind(use_valgrind) {} + +BugDriver::~BugDriver() { + delete Program; +} + + +/// ParseInputFile - Given a bitcode or assembly input filename, parse and +/// return it, or return null if not possible. +/// +Module *llvm::ParseInputFile(const std::string &Filename, + LLVMContext& Ctxt) { + SMDiagnostic Err; + Module *Result = ParseIRFile(Filename, Err, Ctxt); + if (!Result) + Err.Print("bugpoint", errs()); + + // If we don't have an override triple, use the first one to configure + // bugpoint, or use the host triple if none provided. + if (Result) { + if (TargetTriple.getTriple().empty()) { + Triple TheTriple(Result->getTargetTriple()); + + if (TheTriple.getTriple().empty()) + TheTriple.setTriple(sys::getHostTriple()); + + 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 == 0 && "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); + if (Program == 0) return true; + + if (!run_as_child) + outs() << "Read input file : '" << Filenames[0] << "'\n"; + + for (unsigned i = 1, e = Filenames.size(); i != e; ++i) { + std::auto_ptr<Module> M(ParseInputFile(Filenames[i], Context)); + if (M.get() == 0) return true; + + if (!run_as_child) + outs() << "Linking in input file: '" << Filenames[i] << "'\n"; + std::string ErrorMessage; + if (Linker::LinkModules(Program, M.get(), &ErrorMessage)) { + errs() << ToolName << ": error linking in '" << Filenames[i] << "': " + << ErrorMessage << '\n'; + return true; + } + } + + if (!run_as_child) + 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. +/// +bool BugDriver::run(std::string &ErrMsg) { + // The first thing to do is determine if we're running as a child. If we are, + // then what to do is very narrow. This form of invocation is only called + // from the runPasses method to actually run those passes in a child process. + if (run_as_child) { + // Execute the passes + return runPassesAsChild(PassesToRun); + } + + if (run_find_bugs) { + // Rearrange the passes and apply them to the program. Repeat this process + // until the user kills the program or we find a bug. + return runManyPasses(PassesToRun, ErrMsg); + } + + // 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 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(PassesToRun)) + return debugOptimizerCrash(); + } + + // Set up the execution environment, selecting a method to run LLVM bitcode. + if (initializeExecutionEnvironment()) return true; + + // Test to see if we have a code generator crash. + outs() << "Running the code generator to test for a crash: "; + std::string Error; + compileProgram(Program, &Error); + if (!Error.empty()) { + outs() << Error; + return debugCodeGeneratorCrash(ErrMsg); + } + 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 (!createReferenceFile(Program)) { + return debugCodeGeneratorCrash(ErrMsg); + } + CreatedOutput = true; + } + + // Make sure the reference output file gets deleted on exit from this + // function, if appropriate. + sys::Path 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"; + bool Diff = diffProgram("", "", false, &Error); + if (!Error.empty()) { + errs() << Error; + return debugCodeGeneratorCrash(ErrMsg); + } + if (!Diff) { + outs() << "\n*** Output matches: Debugging miscompilation!\n"; + debugMiscompilation(&Error); + if (!Error.empty()) { + errs() << Error; + return debugCodeGeneratorCrash(ErrMsg); + } + return false; + } + + outs() << "\n*** Input program does not match reference diff!\n"; + outs() << "Debugging code generator problem!\n"; + bool Failure = debugCodeGenerator(&Error); + if (!Error.empty()) { + errs() << Error; + return debugCodeGeneratorCrash(ErrMsg); + } + return Failure; +} + +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(); +} diff --git a/contrib/llvm/tools/bugpoint/BugDriver.h b/contrib/llvm/tools/bugpoint/BugDriver.h new file mode 100644 index 0000000..e5b7373 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/BugDriver.h @@ -0,0 +1,332 @@ +//===- 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 BUGDRIVER_H +#define BUGDRIVER_H + +#include "llvm/ADT/DenseMap.h" +#include <vector> +#include <string> + +namespace llvm { + +class Value; +class PassInfo; +class Module; +class GlobalVariable; +class Function; +class BasicBlock; +class AbstractInterpreter; +class Instruction; +class LLVMContext; + +class DebugCrashes; + +class GCC; + +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<const PassInfo*> PassesToRun; + AbstractInterpreter *Interpreter; // How to run the program + AbstractInterpreter *SafeInterpreter; // To generate reference output, etc. + GCC *gcc; + bool run_as_child; + 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 as_child, bool find_bugs, + unsigned timeout, unsigned memlimit, bool use_valgrind, + LLVMContext& ctxt); + ~BugDriver(); + + const char *getToolName() const { return ToolName; } + + LLVMContext& getContext() { 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); + template<class It> + void addPasses(It I, It E) { PassesToRun.insert(PassesToRun.end(), I, E); } + void setPassesToRun(const std::vector<const PassInfo*> &PTR) { + PassesToRun = PTR; + } + const std::vector<const PassInfo*> &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. + /// + bool run(std::string &ErrMsg); + + /// debugOptimizerCrash - This method is called when some optimizer pass + /// crashes on input. It attempts to prune down the testcase to something + /// reasonable, and figure out exactly which pass is crashing. + /// + bool debugOptimizerCrash(const std::string &ID = "passes"); + + /// debugCodeGeneratorCrash - This method is called when the code generator + /// crashes on an input. It attempts to reduce the input as much as possible + /// while still causing the code generator to crash. + bool debugCodeGeneratorCrash(std::string &Error); + + /// debugMiscompilation - This method is used when the passes selected are not + /// crashing, but the generated output is semantically different from the + /// input. + void debugMiscompilation(std::string *Error); + + /// 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. + /// + std::string compileSharedObject(const std::string &BitcodeFile, + std::string &Error); + + /// debugCodeGenerator - This method narrows down a module to a function or + /// set of functions, using the CBE as a ``safe'' code generator for other + /// functions that are not under consideration. + bool debugCodeGenerator(std::string *Error); + + /// isExecutingJIT - Returns true if bugpoint is currently testing the JIT + /// + bool isExecutingJIT(); + + /// runPasses - Run all of the passes in the "PassesToRun" list, discard the + /// output, and return true if any of the passes crashed. + bool runPasses(Module *M = 0) { + if (M == 0) M = Program; + std::swap(M, Program); + bool Result = runPasses(PassesToRun); + std::swap(M, Program); + return Result; + } + + 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); + + /// compileProgram - Try to compile the specified module, returning false and + /// setting Error if an error occurs. This is used for code generation + /// crash testing. + /// + void compileProgram(Module *M, std::string *Error); + + /// executeProgram - This method runs "Program", capturing the output of the + /// program to a file. A recommended filename may be optionally specified. + /// + std::string executeProgram(std::string OutputFilename, + std::string Bitcode, + const std::string &SharedObjects, + AbstractInterpreter *AI, + std::string *Error); + + /// executeProgramSafely - Used to create reference output with the "safe" + /// backend, if reference output is not provided. If there is a problem with + /// the code generator (e.g., llc crashes), this will return false and set + /// Error. + /// + std::string executeProgramSafely(std::string OutputFile, std::string *Error); + + /// createReferenceFile - calls compileProgram and then records the output + /// into ReferenceOutputFile. Returns true if reference file created, false + /// otherwise. Note: initializeExecutionEnvironment should be called BEFORE + /// this function. + /// + bool createReferenceFile(Module *M, const std::string &Filename + = "bugpoint.reference.out"); + + /// diffProgram - This method executes the specified module and diffs the + /// output against the file specified by ReferenceOutputFile. If the output + /// is different, 1 is returned. If there is a problem with the code + /// generator (e.g., llc crashes), this will return -1 and set Error. + /// + bool diffProgram(const std::string &BitcodeFile = "", + const std::string &SharedObj = "", + bool RemoveBitcode = false, + std::string *Error = 0); + + /// EmitProgressBitcode - This function is used to output the current Program + /// to a file named "bugpoint-ID.bc". + /// + void EmitProgressBitcode(const std::string &ID, bool NoFlyer = false); + + /// deleteInstructionFromProgram - 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. + /// + Module *deleteInstructionFromProgram(const Instruction *I, unsigned Simp) + const; + + /// performFinalCleanups - 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. + /// + Module *performFinalCleanups(Module *M, bool MayModifySemantics = false); + + /// ExtractLoop - 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. + Module *ExtractLoop(Module *M); + + /// ExtractMappedBlocksFromModule - 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. + Module *ExtractMappedBlocksFromModule(const std::vector<BasicBlock*> &BBs, + Module *M); + + /// runPassesOn - Carefully run the specified set of pass on the specified + /// module, returning the transformed module on success, or a null pointer on + /// failure. If AutoDebugCrashes is set to true, then bugpoint will + /// automatically attempt to track down a crashing pass if one exists, and + /// this method will never return null. + Module *runPassesOn(Module *M, const std::vector<const PassInfo*> &Passes, + bool AutoDebugCrashes = false, unsigned NumExtraArgs = 0, + const char * const *ExtraArgs = NULL); + + /// 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(const std::vector<const PassInfo*> &PassesToRun, + std::string &OutputFilename, bool DeleteOutput = false, + bool Quiet = false, unsigned NumExtraArgs = 0, + const char * const *ExtraArgs = NULL) const; + + /// runManyPasses - Take the specified pass list and create different + /// combinations of passes to compile the program with. Compile the program with + /// each set and mark test to see if it compiled correctly. If the passes + /// compiled correctly output nothing and rearrange the passes into a new order. + /// If the passes did not compile correctly, output the command required to + /// recreate the failure. This returns true if a compiler error is found. + /// + bool runManyPasses(const std::vector<const PassInfo*> &AllPasses, + std::string &ErrMsg); + + /// writeProgramToFile - This writes the current "Program" to the named + /// bitcode file. If an error occurs, true is returned. + /// + bool writeProgramToFile(const std::string &Filename, Module *M = 0) const; + +private: + /// 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). + /// + bool runPasses(const std::vector<const PassInfo*> &PassesToRun, + bool DeleteOutput = true) const { + std::string Filename; + return runPasses(PassesToRun, Filename, DeleteOutput); + } + + /// runAsChild - The actual "runPasses" guts that runs in a child process. + int runPassesAsChild(const std::vector<const PassInfo*> &PassesToRun); + + /// initializeExecutionEnvironment - This method is used to set up the + /// environment for executing LLVM programs. + /// + bool initializeExecutionEnvironment(); +}; + +/// ParseInputFile - Given a bitcode or assembly input filename, parse and +/// return it, or return null if not possible. +/// +Module *ParseInputFile(const std::string &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<const PassInfo*> &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); + +// DeleteFunctionBody - "Remove" the function by deleting all of it's basic +// blocks, making it external. +// +void DeleteFunctionBody(Function *F); + +/// SplitFunctionsOutOfModule - 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. +Module *SplitFunctionsOutOfModule(Module *M, const std::vector<Function*> &F, + DenseMap<const Value*, Value*> &ValueMap); + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/tools/bugpoint/CMakeLists.txt b/contrib/llvm/tools/bugpoint/CMakeLists.txt new file mode 100644 index 0000000..34b759f --- /dev/null +++ b/contrib/llvm/tools/bugpoint/CMakeLists.txt @@ -0,0 +1,15 @@ +set(LLVM_LINK_COMPONENTS asmparser instrumentation scalaropts ipo + linker bitreader bitwriter) + +add_llvm_tool(bugpoint + BugDriver.cpp + CrashDebugger.cpp + ExecutionDriver.cpp + ExtractFunction.cpp + FindBugs.cpp + Miscompilation.cpp + OptimizerDriver.cpp + TestPasses.cpp + ToolRunner.cpp + bugpoint.cpp + ) diff --git a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp new file mode 100644 index 0000000..46b33d2 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp @@ -0,0 +1,659 @@ +//===- CrashDebugger.cpp - Debug compilation crashes ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the bugpoint internals that narrow down compilation crashes +// +//===----------------------------------------------------------------------===// + +#include "BugDriver.h" +#include "ToolRunner.h" +#include "ListReducer.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Instructions.h" +#include "llvm/Module.h" +#include "llvm/Pass.h" +#include "llvm/PassManager.h" +#include "llvm/ValueSymbolTable.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Support/CFG.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/CommandLine.h" +#include <set> +using namespace llvm; + +namespace { + cl::opt<bool> + KeepMain("keep-main", + cl::desc("Force function reduction to keep main"), + cl::init(false)); + cl::opt<bool> + NoGlobalRM ("disable-global-remove", + cl::desc("Do not remove global variables"), + cl::init(false)); +} + +namespace llvm { + class ReducePassList : public ListReducer<const PassInfo*> { + BugDriver &BD; + public: + ReducePassList(BugDriver &bd) : BD(bd) {} + + // doTest - Return true iff running the "removed" passes succeeds, and + // running the "Kept" passes fail when run on the output of the "removed" + // passes. If we return true, we update the current module of bugpoint. + // + virtual TestResult doTest(std::vector<const PassInfo*> &Removed, + std::vector<const PassInfo*> &Kept, + std::string &Error); + }; +} + +ReducePassList::TestResult +ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, + std::vector<const PassInfo*> &Suffix, + std::string &Error) { + sys::Path PrefixOutput; + Module *OrigProgram = 0; + if (!Prefix.empty()) { + outs() << "Checking to see if these passes crash: " + << getPassesString(Prefix) << ": "; + std::string PfxOutput; + if (BD.runPasses(Prefix, PfxOutput)) + return KeepPrefix; + + PrefixOutput.set(PfxOutput); + OrigProgram = BD.Program; + + BD.Program = ParseInputFile(PrefixOutput.str(), BD.getContext()); + if (BD.Program == 0) { + errs() << BD.getToolName() << ": Error reading bitcode file '" + << PrefixOutput.str() << "'!\n"; + exit(1); + } + PrefixOutput.eraseFromDisk(); + } + + outs() << "Checking to see if these passes crash: " + << getPassesString(Suffix) << ": "; + + if (BD.runPasses(Suffix)) { + delete OrigProgram; // The suffix crashes alone... + return KeepSuffix; + } + + // Nothing failed, restore state... + if (OrigProgram) { + delete BD.Program; + BD.Program = OrigProgram; + } + return NoFailure; +} + +namespace { + /// ReduceCrashingGlobalVariables - This works by removing the global + /// variable's initializer and seeing if the program still crashes. If it + /// does, then we keep that program and try again. + /// + class ReduceCrashingGlobalVariables : public ListReducer<GlobalVariable*> { + BugDriver &BD; + bool (*TestFn)(BugDriver &, Module *); + public: + ReduceCrashingGlobalVariables(BugDriver &bd, + bool (*testFn)(BugDriver &, Module *)) + : BD(bd), TestFn(testFn) {} + + virtual TestResult doTest(std::vector<GlobalVariable*> &Prefix, + std::vector<GlobalVariable*> &Kept, + std::string &Error) { + if (!Kept.empty() && TestGlobalVariables(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestGlobalVariables(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestGlobalVariables(std::vector<GlobalVariable*> &GVs); + }; +} + +bool +ReduceCrashingGlobalVariables::TestGlobalVariables( + std::vector<GlobalVariable*> &GVs) { + // Clone the program to try hacking it apart... + DenseMap<const Value*, Value*> ValueMap; + Module *M = CloneModule(BD.getProgram(), ValueMap); + + // Convert list to set for fast lookup... + std::set<GlobalVariable*> GVSet; + + for (unsigned i = 0, e = GVs.size(); i != e; ++i) { + GlobalVariable* CMGV = cast<GlobalVariable>(ValueMap[GVs[i]]); + assert(CMGV && "Global Variable not in module?!"); + GVSet.insert(CMGV); + } + + outs() << "Checking for crash with only these global variables: "; + PrintGlobalVariableList(GVs); + outs() << ": "; + + // Loop over and delete any global variables which we aren't supposed to be + // playing with... + for (Module::global_iterator I = M->global_begin(), E = M->global_end(); + I != E; ++I) + if (I->hasInitializer() && !GVSet.count(I)) { + I->setInitializer(0); + I->setLinkage(GlobalValue::ExternalLinkage); + } + + // Try running the hacked up program... + if (TestFn(BD, M)) { + BD.setNewProgram(M); // It crashed, keep the trimmed version... + + // Make sure to use global variable pointers that point into the now-current + // module. + GVs.assign(GVSet.begin(), GVSet.end()); + return true; + } + + delete M; + return false; +} + +namespace llvm { + /// ReduceCrashingFunctions reducer - This works by removing functions and + /// seeing if the program still crashes. If it does, then keep the newer, + /// smaller program. + /// + class ReduceCrashingFunctions : public ListReducer<Function*> { + BugDriver &BD; + bool (*TestFn)(BugDriver &, Module *); + public: + ReduceCrashingFunctions(BugDriver &bd, + bool (*testFn)(BugDriver &, Module *)) + : BD(bd), TestFn(testFn) {} + + virtual TestResult doTest(std::vector<Function*> &Prefix, + std::vector<Function*> &Kept, + std::string &Error) { + if (!Kept.empty() && TestFuncs(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestFuncs(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestFuncs(std::vector<Function*> &Prefix); + }; +} + +bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { + + //if main isn't present, claim there is no problem + if (KeepMain && find(Funcs.begin(), Funcs.end(), + BD.getProgram()->getFunction("main")) == Funcs.end()) + return false; + + // Clone the program to try hacking it apart... + DenseMap<const Value*, Value*> ValueMap; + Module *M = CloneModule(BD.getProgram(), ValueMap); + + // Convert list to set for fast lookup... + std::set<Function*> Functions; + for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { + Function *CMF = cast<Function>(ValueMap[Funcs[i]]); + assert(CMF && "Function not in module?!"); + assert(CMF->getFunctionType() == Funcs[i]->getFunctionType() && "wrong ty"); + assert(CMF->getName() == Funcs[i]->getName() && "wrong name"); + Functions.insert(CMF); + } + + outs() << "Checking for crash with only these functions: "; + PrintFunctionList(Funcs); + outs() << ": "; + + // Loop over and delete any functions which we aren't supposed to be playing + // with... + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + if (!I->isDeclaration() && !Functions.count(I)) + DeleteFunctionBody(I); + + // Try running the hacked up program... + if (TestFn(BD, M)) { + BD.setNewProgram(M); // It crashed, keep the trimmed version... + + // Make sure to use function pointers that point into the now-current + // module. + Funcs.assign(Functions.begin(), Functions.end()); + return true; + } + delete M; + return false; +} + + +namespace { + /// ReduceCrashingBlocks reducer - This works by setting the terminators of + /// all terminators except the specified basic blocks to a 'ret' instruction, + /// then running the simplify-cfg pass. This has the effect of chopping up + /// the CFG really fast which can reduce large functions quickly. + /// + class ReduceCrashingBlocks : public ListReducer<const BasicBlock*> { + BugDriver &BD; + bool (*TestFn)(BugDriver &, Module *); + public: + ReduceCrashingBlocks(BugDriver &bd, bool (*testFn)(BugDriver &, Module *)) + : BD(bd), TestFn(testFn) {} + + virtual TestResult doTest(std::vector<const BasicBlock*> &Prefix, + std::vector<const BasicBlock*> &Kept, + std::string &Error) { + if (!Kept.empty() && TestBlocks(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestBlocks(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestBlocks(std::vector<const BasicBlock*> &Prefix); + }; +} + +bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { + // Clone the program to try hacking it apart... + DenseMap<const Value*, Value*> ValueMap; + Module *M = CloneModule(BD.getProgram(), ValueMap); + + // Convert list to set for fast lookup... + SmallPtrSet<BasicBlock*, 8> Blocks; + for (unsigned i = 0, e = BBs.size(); i != e; ++i) + Blocks.insert(cast<BasicBlock>(ValueMap[BBs[i]])); + + outs() << "Checking for crash with only these blocks:"; + unsigned NumPrint = Blocks.size(); + if (NumPrint > 10) NumPrint = 10; + for (unsigned i = 0, e = NumPrint; i != e; ++i) + outs() << " " << BBs[i]->getName(); + if (NumPrint < Blocks.size()) + outs() << "... <" << Blocks.size() << " total>"; + outs() << ": "; + + // Loop over and delete any hack up any blocks that are not listed... + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + for (Function::iterator BB = I->begin(), E = I->end(); BB != E; ++BB) + if (!Blocks.count(BB) && BB->getTerminator()->getNumSuccessors()) { + // Loop over all of the successors of this block, deleting any PHI nodes + // that might include it. + for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI) + (*SI)->removePredecessor(BB); + + TerminatorInst *BBTerm = BB->getTerminator(); + + if (BBTerm->getType()->isStructTy()) + BBTerm->replaceAllUsesWith(UndefValue::get(BBTerm->getType())); + else if (BB->getTerminator()->getType() != + Type::getVoidTy(BB->getContext())) + BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType())); + + // Replace the old terminator instruction. + BB->getInstList().pop_back(); + new UnreachableInst(BB->getContext(), BB); + } + + // The CFG Simplifier pass may delete one of the basic blocks we are + // interested in. If it does we need to take the block out of the list. Make + // a "persistent mapping" by turning basic blocks into <function, name> pairs. + // This won't work well if blocks are unnamed, but that is just the risk we + // have to take. + std::vector<std::pair<Function*, std::string> > BlockInfo; + + for (SmallPtrSet<BasicBlock*, 8>::iterator I = Blocks.begin(), + E = Blocks.end(); I != E; ++I) + BlockInfo.push_back(std::make_pair((*I)->getParent(), (*I)->getName())); + + // Now run the CFG simplify pass on the function... + PassManager Passes; + Passes.add(createCFGSimplificationPass()); + Passes.add(createVerifierPass()); + Passes.run(*M); + + // Try running on the hacked up program... + if (TestFn(BD, M)) { + BD.setNewProgram(M); // It crashed, keep the trimmed version... + + // Make sure to use basic block pointers that point into the now-current + // module, and that they don't include any deleted blocks. + BBs.clear(); + for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) { + ValueSymbolTable &ST = BlockInfo[i].first->getValueSymbolTable(); + Value* V = ST.lookup(BlockInfo[i].second); + if (V && V->getType() == Type::getLabelTy(V->getContext())) + BBs.push_back(cast<BasicBlock>(V)); + } + return true; + } + delete M; // It didn't crash, try something else. + return false; +} + +namespace { + /// ReduceCrashingInstructions reducer - This works by removing the specified + /// non-terminator instructions and replacing them with undef. + /// + class ReduceCrashingInstructions : public ListReducer<const Instruction*> { + BugDriver &BD; + bool (*TestFn)(BugDriver &, Module *); + public: + ReduceCrashingInstructions(BugDriver &bd, bool (*testFn)(BugDriver &, + Module *)) + : BD(bd), TestFn(testFn) {} + + virtual TestResult doTest(std::vector<const Instruction*> &Prefix, + std::vector<const Instruction*> &Kept, + std::string &Error) { + if (!Kept.empty() && TestInsts(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestInsts(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestInsts(std::vector<const Instruction*> &Prefix); + }; +} + +bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> + &Insts) { + // Clone the program to try hacking it apart... + DenseMap<const Value*, Value*> ValueMap; + Module *M = CloneModule(BD.getProgram(), ValueMap); + + // Convert list to set for fast lookup... + SmallPtrSet<Instruction*, 64> Instructions; + for (unsigned i = 0, e = Insts.size(); i != e; ++i) { + assert(!isa<TerminatorInst>(Insts[i])); + Instructions.insert(cast<Instruction>(ValueMap[Insts[i]])); + } + + outs() << "Checking for crash with only " << Instructions.size(); + if (Instructions.size() == 1) + outs() << " instruction: "; + else + outs() << " instructions: "; + + for (Module::iterator MI = M->begin(), ME = M->end(); MI != ME; ++MI) + for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI) + for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) { + Instruction *Inst = I++; + if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst)) { + if (Inst->getType() != Type::getVoidTy(Inst->getContext())) + Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); + Inst->eraseFromParent(); + } + } + + // Verify that this is still valid. + PassManager Passes; + Passes.add(createVerifierPass()); + Passes.run(*M); + + // Try running on the hacked up program... + if (TestFn(BD, M)) { + BD.setNewProgram(M); // It crashed, keep the trimmed version... + + // Make sure to use instruction pointers that point into the now-current + // module, and that they don't include any deleted blocks. + Insts.clear(); + for (SmallPtrSet<Instruction*, 64>::const_iterator I = Instructions.begin(), + E = Instructions.end(); I != E; ++I) + Insts.push_back(*I); + return true; + } + delete M; // It didn't crash, try something else. + return false; +} + +/// DebugACrash - Given a predicate that determines whether a component crashes +/// on a program, try to destructively reduce the program while still keeping +/// the predicate true. +static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *), + std::string &Error) { + // See if we can get away with nuking some of the global variable initializers + // in the program... + if (!NoGlobalRM && + BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { + // Now try to reduce the number of global variable initializers in the + // module to something small. + Module *M = CloneModule(BD.getProgram()); + bool DeletedInit = false; + + for (Module::global_iterator I = M->global_begin(), E = M->global_end(); + I != E; ++I) + if (I->hasInitializer()) { + I->setInitializer(0); + I->setLinkage(GlobalValue::ExternalLinkage); + DeletedInit = true; + } + + if (!DeletedInit) { + delete M; // No change made... + } else { + // See if the program still causes a crash... + outs() << "\nChecking to see if we can delete global inits: "; + + if (TestFn(BD, M)) { // Still crashes? + BD.setNewProgram(M); + outs() << "\n*** Able to remove all global initializers!\n"; + } else { // No longer crashes? + outs() << " - Removing all global inits hides problem!\n"; + delete M; + + std::vector<GlobalVariable*> GVs; + + for (Module::global_iterator I = BD.getProgram()->global_begin(), + E = BD.getProgram()->global_end(); I != E; ++I) + if (I->hasInitializer()) + GVs.push_back(I); + + if (GVs.size() > 1 && !BugpointIsInterrupted) { + outs() << "\n*** Attempting to reduce the number of global " + << "variables in the testcase\n"; + + unsigned OldSize = GVs.size(); + ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error); + if (!Error.empty()) + return true; + + if (GVs.size() < OldSize) + BD.EmitProgressBitcode("reduced-global-variables"); + } + } + } + } + + // Now try to reduce the number of functions in the module to something small. + std::vector<Function*> Functions; + for (Module::iterator I = BD.getProgram()->begin(), + E = BD.getProgram()->end(); I != E; ++I) + if (!I->isDeclaration()) + Functions.push_back(I); + + if (Functions.size() > 1 && !BugpointIsInterrupted) { + outs() << "\n*** Attempting to reduce the number of functions " + "in the testcase\n"; + + unsigned OldSize = Functions.size(); + ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error); + + if (Functions.size() < OldSize) + BD.EmitProgressBitcode("reduced-function"); + } + + // Attempt to delete entire basic blocks at a time to speed up + // convergence... this actually works by setting the terminator of the blocks + // to a return instruction then running simplifycfg, which can potentially + // shrinks the code dramatically quickly + // + if (!DisableSimplifyCFG && !BugpointIsInterrupted) { + std::vector<const BasicBlock*> Blocks; + for (Module::const_iterator I = BD.getProgram()->begin(), + E = BD.getProgram()->end(); I != E; ++I) + for (Function::const_iterator FI = I->begin(), E = I->end(); FI !=E; ++FI) + Blocks.push_back(FI); + unsigned OldSize = Blocks.size(); + ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); + if (Blocks.size() < OldSize) + BD.EmitProgressBitcode("reduced-blocks"); + } + + // Attempt to delete instructions using bisection. This should help out nasty + // cases with large basic blocks where the problem is at one end. + if (!BugpointIsInterrupted) { + std::vector<const Instruction*> Insts; + for (Module::const_iterator MI = BD.getProgram()->begin(), + ME = BD.getProgram()->end(); MI != ME; ++MI) + for (Function::const_iterator FI = MI->begin(), FE = MI->end(); FI != FE; + ++FI) + for (BasicBlock::const_iterator I = FI->begin(), E = FI->end(); + I != E; ++I) + if (!isa<TerminatorInst>(I)) + Insts.push_back(I); + + ReduceCrashingInstructions(BD, TestFn).reduceList(Insts, Error); + } + + // FIXME: This should use the list reducer to converge faster by deleting + // larger chunks of instructions at a time! + unsigned Simplification = 2; + do { + if (BugpointIsInterrupted) break; + --Simplification; + outs() << "\n*** Attempting to reduce testcase by deleting instruc" + << "tions: Simplification Level #" << Simplification << '\n'; + + // Now that we have deleted the functions that are unnecessary for the + // program, try to remove instructions that are not necessary to cause the + // crash. To do this, we loop through all of the instructions in the + // remaining functions, deleting them (replacing any values produced with + // nulls), and then running ADCE and SimplifyCFG. If the transformed input + // still triggers failure, keep deleting until we cannot trigger failure + // anymore. + // + unsigned InstructionsToSkipBeforeDeleting = 0; + TryAgain: + + // Loop over all of the (non-terminator) instructions remaining in the + // function, attempting to delete them. + unsigned CurInstructionNum = 0; + for (Module::const_iterator FI = BD.getProgram()->begin(), + E = BD.getProgram()->end(); FI != E; ++FI) + if (!FI->isDeclaration()) + for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E; + ++BI) + for (BasicBlock::const_iterator I = BI->begin(), E = --BI->end(); + I != E; ++I, ++CurInstructionNum) + if (InstructionsToSkipBeforeDeleting) { + --InstructionsToSkipBeforeDeleting; + } else { + if (BugpointIsInterrupted) goto ExitLoops; + + outs() << "Checking instruction: " << *I; + Module *M = BD.deleteInstructionFromProgram(I, Simplification); + + // Find out if the pass still crashes on this pass... + if (TestFn(BD, M)) { + // Yup, it does, we delete the old module, and continue trying + // to reduce the testcase... + BD.setNewProgram(M); + InstructionsToSkipBeforeDeleting = CurInstructionNum; + goto TryAgain; // I wish I had a multi-level break here! + } + + // This pass didn't crash without this instruction, try the next + // one. + delete M; + } + + if (InstructionsToSkipBeforeDeleting) { + InstructionsToSkipBeforeDeleting = 0; + goto TryAgain; + } + + } while (Simplification); +ExitLoops: + + // Try to clean up the testcase by running funcresolve and globaldce... + if (!BugpointIsInterrupted) { + outs() << "\n*** Attempting to perform final cleanups: "; + Module *M = CloneModule(BD.getProgram()); + M = BD.performFinalCleanups(M, true); + + // Find out if the pass still crashes on the cleaned up program... + if (TestFn(BD, M)) { + BD.setNewProgram(M); // Yup, it does, keep the reduced version... + } else { + delete M; + } + } + + BD.EmitProgressBitcode("reduced-simplified"); + + return false; +} + +static bool TestForOptimizerCrash(BugDriver &BD, Module *M) { + return BD.runPasses(M); +} + +/// debugOptimizerCrash - This method is called when some pass crashes on input. +/// It attempts to prune down the testcase to something reasonable, and figure +/// out exactly which pass is crashing. +/// +bool BugDriver::debugOptimizerCrash(const std::string &ID) { + outs() << "\n*** Debugging optimizer crash!\n"; + + std::string Error; + // Reduce the list of passes which causes the optimizer to crash... + if (!BugpointIsInterrupted) + ReducePassList(*this).reduceList(PassesToRun, Error); + assert(Error.empty()); + + outs() << "\n*** Found crashing pass" + << (PassesToRun.size() == 1 ? ": " : "es: ") + << getPassesString(PassesToRun) << '\n'; + + EmitProgressBitcode(ID); + + bool Success = DebugACrash(*this, TestForOptimizerCrash, Error); + assert(Error.empty()); + return Success; +} + +static bool TestForCodeGenCrash(BugDriver &BD, Module *M) { + std::string Error; + BD.compileProgram(M, &Error); + if (!Error.empty()) { + errs() << "<crash>\n"; + return true; // Tool is still crashing. + } + errs() << '\n'; + return false; +} + +/// debugCodeGeneratorCrash - This method is called when the code generator +/// crashes on an input. It attempts to reduce the input as much as possible +/// while still causing the code generator to crash. +bool BugDriver::debugCodeGeneratorCrash(std::string &Error) { + errs() << "*** Debugging code generator crash!\n"; + + return DebugACrash(*this, TestForCodeGenCrash, Error); +} diff --git a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp new file mode 100644 index 0000000..57f12d5 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp @@ -0,0 +1,497 @@ +//===- 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/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, RunCBE, CBE_bug, LLC_Safe,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(RunCBE, "run-cbe", "Compile with CBE"), + clEnumValN(CBE_bug,"cbe-bug", "Find CBE bugs"), + clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"), + clEnumValN(Custom, "run-custom", + "Use -exec-command to define a command to execute " + "the bitcode. Useful for cross-compilation."), + clEnumValEnd), + 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(RunCBE, "safe-run-cbe", "Compile with CBE"), + clEnumValN(Custom, "safe-run-custom", + "Use -exec-command to define a command to execute " + "the bitcode. Useful for cross-compilation."), + clEnumValEnd), + 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> + 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> + GCCBinary("gcc", cl::init("gcc"), + cl::desc("The gcc binary to use. (default 'gcc')")); + + cl::list<std::string> + GCCToolArgv("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. +/// +bool BugDriver::initializeExecutionEnvironment() { + outs() << "Initializing execution environment: "; + + // Create an instance of the AbstractInterpreter interface as specified on + // the command line + SafeInterpreter = 0; + std::string Message; + + switch (InterpreterSel) { + case AutoPick: + InterpreterSel = RunCBE; + Interpreter = + AbstractInterpreter::createCBE(getToolName(), Message, GCCBinary, + &ToolArgv, &GCCToolArgv); + if (!Interpreter) { + InterpreterSel = RunJIT; + Interpreter = AbstractInterpreter::createJIT(getToolName(), Message, + &ToolArgv); + } + if (!Interpreter) { + InterpreterSel = RunLLC; + Interpreter = AbstractInterpreter::createLLC(getToolName(), Message, + GCCBinary, &ToolArgv, + &GCCToolArgv); + } + 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, + GCCBinary, &ToolArgv, + &GCCToolArgv, + InterpreterSel == RunLLCIA); + break; + case RunJIT: + Interpreter = AbstractInterpreter::createJIT(getToolName(), Message, + &ToolArgv); + break; + case RunCBE: + case CBE_bug: + Interpreter = AbstractInterpreter::createCBE(getToolName(), Message, + GCCBinary, &ToolArgv, + &GCCToolArgv); + break; + case Custom: + Interpreter = AbstractInterpreter::createCustom(Message, CustomExecCommand); + break; + default: + Message = "Sorry, this back-end is not supported by bugpoint right now!\n"; + 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 "cbe-bug" mode, default to using LLC as the "safe" backend. + if (!SafeInterpreter && + InterpreterSel == CBE_bug) { + SafeInterpreterSel = RunLLC; + SafeToolArgs.push_back("--relocation-model=pic"); + SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, + GCCBinary, + &SafeToolArgs, + &GCCToolArgv); + } + + // 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, + GCCBinary, + &SafeToolArgs, + &GCCToolArgv); + } + + // Pick a backend that's different from the test backend. The JIT and + // LLC backends share a lot of code, so prefer to use the CBE as the + // safe back-end when testing them. + if (!SafeInterpreter && + InterpreterSel != RunCBE) { + SafeInterpreterSel = RunCBE; + SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message, + GCCBinary, + &SafeToolArgs, + &GCCToolArgv); + } + if (!SafeInterpreter && + InterpreterSel != RunLLC && + InterpreterSel != RunJIT) { + SafeInterpreterSel = RunLLC; + SafeToolArgs.push_back("--relocation-model=pic"); + SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, + GCCBinary, + &SafeToolArgs, + &GCCToolArgv); + } + if (!SafeInterpreter) { + SafeInterpreterSel = AutoPick; + Message = "Sorry, I can't automatically select an interpreter!\n"; + } + break; + case RunLLC: + case RunLLCIA: + SafeToolArgs.push_back("--relocation-model=pic"); + SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, + GCCBinary, &SafeToolArgs, + &GCCToolArgv, + SafeInterpreterSel == RunLLCIA); + break; + case RunCBE: + SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message, + GCCBinary, &SafeToolArgs, + &GCCToolArgv); + break; + case Custom: + SafeInterpreter = AbstractInterpreter::createCustom(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); } + + gcc = GCC::create(Message, GCCBinary, &GCCToolArgv); + if (!gcc) { outs() << Message << "\nExiting.\n"; exit(1); } + + // If there was an error creating the selected interpreter, quit with error. + return Interpreter == 0; +} + +/// compileProgram - Try to compile the specified module, returning false and +/// setting Error if an error occurs. This is used for code generation +/// crash testing. +/// +void BugDriver::compileProgram(Module *M, std::string *Error) { + // Emit the program to a bitcode file... + sys::Path BitcodeFile (OutputPrefix + "-test-program.bc"); + std::string ErrMsg; + if (BitcodeFile.makeUnique(true, &ErrMsg)) { + errs() << ToolName << ": Error making unique filename: " << ErrMsg + << "\n"; + exit(1); + } + if (writeProgramToFile(BitcodeFile.str(), M)) { + errs() << ToolName << ": Error emitting bitcode to file '" + << BitcodeFile.str() << "'!\n"; + exit(1); + } + + // Remove the temporary bitcode file when we are done. + FileRemover BitcodeFileRemover(BitcodeFile, !SaveTemps); + + // Actually compile the program! + Interpreter->compileProgram(BitcodeFile.str(), Error, 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. +/// +std::string BugDriver::executeProgram(std::string OutputFile, + std::string BitcodeFile, + const std::string &SharedObj, + AbstractInterpreter *AI, + std::string *Error) { + if (AI == 0) AI = Interpreter; + assert(AI && "Interpreter should have been created already!"); + bool CreatedBitcode = false; + std::string ErrMsg; + if (BitcodeFile.empty()) { + // Emit the program to a bitcode file... + sys::Path uniqueFilename(OutputPrefix + "-test-program.bc"); + if (uniqueFilename.makeUnique(true, &ErrMsg)) { + errs() << ToolName << ": Error making unique filename: " + << ErrMsg << "!\n"; + exit(1); + } + BitcodeFile = uniqueFilename.str(); + + if (writeProgramToFile(BitcodeFile, Program)) { + errs() << ToolName << ": Error emitting bitcode to file '" + << BitcodeFile << "'!\n"; + exit(1); + } + CreatedBitcode = true; + } + + // Remove the temporary bitcode file when we are done. + sys::Path BitcodePath(BitcodeFile); + FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps); + + if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output"; + + // Check to see if this is a valid output filename... + sys::Path uniqueFile(OutputFile); + if (uniqueFile.makeUnique(true, &ErrMsg)) { + errs() << ToolName << ": Error making unique filename: " + << ErrMsg << "\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); + + int RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile, OutputFile, + Error, AdditionalLinkerArgs, SharedObjs, + Timeout, MemoryLimit); + if (!Error->empty()) + return OutputFile; + + 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. +/// +std::string BugDriver::executeProgramSafely(std::string OutputFile, + std::string *Error) { + return executeProgram(OutputFile, "", "", SafeInterpreter, Error); +} + +std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, + std::string &Error) { + assert(Interpreter && "Interpreter should have been created already!"); + sys::Path OutputFile; + + // Using the known-good backend. + GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile, + Error); + if (!Error.empty()) + return ""; + + std::string SharedObjectFile; + bool Failure = gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile, + AdditionalLinkerArgs, Error); + if (!Error.empty()) + return ""; + if (Failure) + exit(1); + + // Remove the intermediate C file + OutputFile.eraseFromDisk(); + + 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. +/// +bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { + std::string Error; + compileProgram(Program, &Error); + if (!Error.empty()) + return false; + + ReferenceOutputFile = executeProgramSafely(Filename, &Error); + if (!Error.empty()) { + errs() << Error; + if (Interpreter != SafeInterpreter) { + errs() << "*** There is a bug running the \"safe\" backend. Either" + << " debug it (for example with the -run-cbe bugpoint option," + << " if CBE is being used as the \"safe\" backend), or fix the" + << " error some other way.\n"; + } + return false; + } + outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n"; + return true; +} + +/// diffProgram - This method executes the specified module and diffs the +/// output against the file specified by ReferenceOutputFile. If the output +/// is different, 1 is returned. If there is a problem with the code +/// generator (e.g., llc crashes), this will return -1 and set Error. +/// +bool BugDriver::diffProgram(const std::string &BitcodeFile, + const std::string &SharedObject, + bool RemoveBitcode, + std::string *ErrMsg) { + // Execute the program, generating an output file... + sys::Path Output(executeProgram("", BitcodeFile, SharedObject, 0, ErrMsg)); + if (!ErrMsg->empty()) + return false; + + std::string Error; + bool FilesDifferent = false; + if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile), + sys::Path(Output.str()), + 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. + Output.eraseFromDisk(); + } + + // Remove the bitcode file if we are supposed to. + if (RemoveBitcode) + sys::Path(BitcodeFile).eraseFromDisk(); + return FilesDifferent; +} + +bool BugDriver::isExecutingJIT() { + return InterpreterSel == RunJIT; +} + diff --git a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp new file mode 100644 index 0000000..eaa2c53 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp @@ -0,0 +1,378 @@ +//===- 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/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/FunctionUtils.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include "llvm/System/Signals.h" +#include <set> +using namespace llvm; + +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")); +} + +/// deleteInstructionFromProgram - 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. +/// +Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, + unsigned Simplification) const { + Module *Result = CloneModule(Program); + + const BasicBlock *PBB = I->getParent(); + const Function *PF = PBB->getParent(); + + Module::iterator RFI = Result->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()->isStructTy()) + TheInst->replaceAllUsesWith(UndefValue::get(TheInst->getType())); + else if (TheInst->getType() != Type::getVoidTy(I->getContext())) + TheInst->replaceAllUsesWith(Constant::getNullValue(TheInst->getType())); + + // Remove the instruction from the program. + TheInst->getParent()->getInstList().erase(TheInst); + + + //writeProgramToFile("current.bc", Result); + + // Spiff up the output a little bit. + PassManager Passes; + // Make sure that the appropriate target data is always used... + Passes.add(new TargetData(Result)); + + /// FIXME: If this used runPasses() like the methods below, we could get rid + /// of the -disable-* options! + if (Simplification > 1 && !NoDCE) + Passes.add(createDeadCodeEliminationPass()); + if (Simplification && !DisableSimplifyCFG) + Passes.add(createCFGSimplificationPass()); // Delete dead control flow + + Passes.add(createVerifierPass()); + Passes.run(*Result); + return Result; +} + +static const PassInfo *getPI(Pass *P) { + const PassInfo *PI = P->getPassInfo(); + delete P; + return PI; +} + +/// performFinalCleanups - This method clones the current Program and performs +/// a series of cleanups intended to get rid of extra cruft on the module +/// before handing it to the user. +/// +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<const PassInfo*> CleanupPasses; + CleanupPasses.push_back(getPI(createGlobalDCEPass())); + CleanupPasses.push_back(getPI(createDeadTypeEliminationPass())); + + if (MayModifySemantics) + CleanupPasses.push_back(getPI(createDeadArgHackingPass())); + else + CleanupPasses.push_back(getPI(createDeadArgEliminationPass())); + + Module *New = runPassesOn(M, CleanupPasses); + if (New == 0) { + errs() << "Final cleanups failed. Sorry. :( Please report a bug!\n"; + return M; + } + delete M; + return New; +} + + +/// ExtractLoop - 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. +Module *BugDriver::ExtractLoop(Module *M) { + std::vector<const PassInfo*> LoopExtractPasses; + LoopExtractPasses.push_back(getPI(createSingleLoopExtractorPass())); + + Module *NewM = runPassesOn(M, LoopExtractPasses); + if (NewM == 0) { + Module *Old = swapProgramIn(M); + outs() << "*** Loop extraction failed: "; + EmitProgressBitcode("loopextraction", true); + outs() << "*** Sorry. :( Please report a bug!\n"; + swapProgramIn(Old); + return 0; + } + + // 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) { + delete NewM; + return 0; + } 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; +} + + +// DeleteFunctionBody - "Remove" the function by deleting all of its basic +// blocks, making it external. +// +void llvm::DeleteFunctionBody(Function *F) { + // 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; + for (unsigned i = 0, e = TorList.size(); i != e; ++i) { + std::vector<Constant*> Elts; + Elts.push_back(ConstantInt::get( + Type::getInt32Ty(TorList[i].first->getContext()), TorList[i].second)); + Elts.push_back(TorList[i].first); + ArrayElts.push_back(ConstantStruct::get(TorList[i].first->getContext(), + Elts, false)); + } + 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, + DenseMap<const Value*, Value*> ValueMap) { + 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>(ValueMap[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); + } +} + + +/// SplitFunctionsOutOfModule - 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. +Module * +llvm::SplitFunctionsOutOfModule(Module *M, + const std::vector<Function*> &F, + DenseMap<const Value*, Value*> &ValueMap) { + // 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); + } + + DenseMap<const Value*, Value*> NewValueMap; + Module *New = CloneModule(M, NewValueMap); + + // Make sure global initializers exist only in the safe module (CBE->.so) + for (Module::global_iterator I = New->global_begin(), E = New->global_end(); + I != E; ++I) + I->setInitializer(0); // Delete the initializer to make it external + + // 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>(ValueMap[F[i]]); + DEBUG(errs() << "Removing function "); + DEBUG(WriteAsOperand(errs(), TNOF, false)); + DEBUG(errs() << "\n"); + TestFunctions.insert(cast<Function>(NewValueMap[TNOF])); + DeleteFunctionBody(TNOF); // Function is now external in this module! + } + + + // Remove the Safe functions from the Test module + for (Module::iterator I = New->begin(), E = New->end(); I != E; ++I) + if (!TestFunctions.count(I)) + DeleteFunctionBody(I); + + + // 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, NewValueMap); + SplitStaticCtorDtor("llvm.global_dtors", M, New, NewValueMap); + + return New; +} + +//===----------------------------------------------------------------------===// +// Basic Block Extraction Code +//===----------------------------------------------------------------------===// + +/// ExtractMappedBlocksFromModule - 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. +Module *BugDriver::ExtractMappedBlocksFromModule(const + std::vector<BasicBlock*> &BBs, + Module *M) { + sys::Path uniqueFilename(OutputPrefix + "-extractblocks"); + std::string ErrMsg; + if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) { + outs() << "*** Basic Block extraction failed!\n"; + errs() << "Error creating temporary file: " << ErrMsg << "\n"; + M = swapProgramIn(M); + EmitProgressBitcode("basicblockextractfail", true); + swapProgramIn(M); + return 0; + } + sys::RemoveFileOnSignal(uniqueFilename); + + std::string ErrorInfo; + raw_fd_ostream BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) { + outs() << "*** Basic Block extraction failed!\n"; + errs() << "Error writing list of blocks to not extract: " << ErrorInfo + << "\n"; + M = swapProgramIn(M); + EmitProgressBitcode("basicblockextractfail", true); + swapProgramIn(M); + return 0; + } + 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"); + BlocksToNotExtractFile << BB->getParent()->getNameStr() << " " + << BB->getName() << "\n"; + } + BlocksToNotExtractFile.close(); + + std::string uniqueFN = "--extract-blocks-file=" + uniqueFilename.str(); + const char *ExtraArg = uniqueFN.c_str(); + + std::vector<const PassInfo*> PI; + std::vector<BasicBlock *> EmptyBBs; // This parameter is ignored. + PI.push_back(getPI(createBlockExtractorPass(EmptyBBs))); + Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg); + + if (uniqueFilename.exists()) + uniqueFilename.eraseFromDisk(); // Free disk space + + if (Ret == 0) { + outs() << "*** Basic Block extraction failed, please report a bug!\n"; + M = swapProgramIn(M); + EmitProgressBitcode("basicblockextractfail", true); + swapProgramIn(M); + } + return Ret; +} diff --git a/contrib/llvm/tools/bugpoint/FindBugs.cpp b/contrib/llvm/tools/bugpoint/FindBugs.cpp new file mode 100644 index 0000000..224c717 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/FindBugs.cpp @@ -0,0 +1,113 @@ +//===-- 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 "ToolRunner.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <ctime> +using namespace llvm; + +/// runManyPasses - Take the specified pass list and create different +/// combinations of passes to compile the program with. Compile the program with +/// each set and mark test to see if it compiled correctly. If the passes +/// compiled correctly output nothing and rearrange the passes into a new order. +/// If the passes did not compile correctly, output the command required to +/// recreate the failure. This returns true if a compiler error is found. +/// +bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses, + std::string &ErrMsg) { + setPassesToRun(AllPasses); + outs() << "Starting bug finding procedure...\n\n"; + + // Creating a reference output if necessary + if (initializeExecutionEnvironment()) return false; + + outs() << "\n"; + if (ReferenceOutputFile.empty()) { + outs() << "Generating reference output from raw program: \n"; + if (!createReferenceFile(Program)) + return false; + } + + srand(time(NULL)); + + unsigned num = 1; + while(1) { + // + // Step 1: Randomize the order of the optimizer passes. + // + std::random_shuffle(PassesToRun.begin(), PassesToRun.end()); + + // + // 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]->getPassArgument() << " "; + } + + std::string Filename; + if(runPasses(PassesToRun, Filename, false)) { + outs() << "\n"; + outs() << "Optimizer passes caused failure!\n\n"; + debugOptimizerCrash(); + return true; + } else { + outs() << "Combination " << num << " optimized successfully!\n"; + } + + // + // Step 3: Compile the optimized code. + // + outs() << "Running the code generator to test for a crash: "; + std::string Error; + compileProgram(Program, &Error); + if (!Error.empty()) { + outs() << "\n*** compileProgram threw an exception: "; + outs() << Error; + return debugCodeGeneratorCrash(ErrMsg); + } + outs() << '\n'; + + // + // Step 4: Run the program and compare its output to the reference + // output (created above). + // + outs() << "*** Checking if passes caused miscompliation:\n"; + bool Diff = diffProgram(Filename, "", false, &Error); + if (Error.empty() && Diff) { + outs() << "\n*** diffProgram returned true!\n"; + debugMiscompilation(&Error); + if (Error.empty()) + return true; + } + if (!Error.empty()) { + errs() << Error; + debugCodeGeneratorCrash(ErrMsg); + return true; + } + outs() << "\n*** diff'd output matches!\n"; + + sys::Path(Filename).eraseFromDisk(); + + outs() << "\n\n"; + num++; + } //end while + + // Unreachable. +} diff --git a/contrib/llvm/tools/bugpoint/ListReducer.h b/contrib/llvm/tools/bugpoint/ListReducer.h new file mode 100644 index 0000000..5e9cff0 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/ListReducer.h @@ -0,0 +1,201 @@ +//===- 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 BUGPOINT_LIST_REDUCER_H +#define BUGPOINT_LIST_REDUCER_H + +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" +#include <vector> +#include <cstdlib> +#include <algorithm> + +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 + InternalError // Encountered an error trying to run the predicate + }; + + virtual ~ListReducer() {} + + // doTest - 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 TestResult doTest(std::vector<ElTy> &Prefix, + std::vector<ElTy> &Kept, + std::string &Error) = 0; + + // reduceList - 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. + // + bool reduceList(std::vector<ElTy> &TheList, std::string &Error) { + std::vector<ElTy> empty; + std::srand(0x6e5ea738); // Seed the random number generator + switch (doTest(TheList, empty, Error)) { + 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! + + case InternalError: + assert(!Error.empty()); + return true; + } + + // Maximal number of allowed splitting iterations, + // before the elements are randomly shuffled. + const unsigned MaxIterationsWithoutProgress = 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::random_shuffle(ShuffledList.begin(), ShuffledList.end()); + errs() << "\n\n*** Testing shuffled set...\n\n"; + // Check that random shuffle doesn't loose the bug + if (doTest(ShuffledList, empty, Error) == 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 inifinite 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()); + + switch (doTest(Prefix, Suffix, Error)) { + 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; + case InternalError: + return true; // Error was set by doTest. + } + assert(Error.empty() && "doTest did not return InternalError for error"); + } + + // 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; + 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); + + if (doTest(EmptyList, TestList, Error) == KeepSuffix) { + // We can trim down the list! + TheList.swap(TestList); + --i; // Don't skip an element of the list + Changed = true; + } + if (!Error.empty()) + return true; + } + // This can take a long time if left uncontrolled. For now, don't + // iterate. + break; + } + } + + return true; // there are some failure and we've narrowed them down + } +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/tools/bugpoint/Makefile b/contrib/llvm/tools/bugpoint/Makefile new file mode 100644 index 0000000..5d287ef --- /dev/null +++ b/contrib/llvm/tools/bugpoint/Makefile @@ -0,0 +1,16 @@ +##===- tools/bugpoint/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../.. + +TOOLNAME = bugpoint + +LINK_COMPONENTS := asmparser instrumentation scalaropts ipo \ + linker bitreader bitwriter + +include $(LEVEL)/Makefile.common diff --git a/contrib/llvm/tools/bugpoint/Miscompilation.cpp b/contrib/llvm/tools/bugpoint/Miscompilation.cpp new file mode 100644 index 0000000..71484a2 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/Miscompilation.cpp @@ -0,0 +1,1027 @@ +//===- Miscompilation.cpp - Debug program miscompilations -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements optimizer and code generation miscompilation debugging +// support. +// +//===----------------------------------------------------------------------===// + +#include "BugDriver.h" +#include "ListReducer.h" +#include "ToolRunner.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Instructions.h" +#include "llvm/Linker.h" +#include "llvm/Module.h" +#include "llvm/Pass.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Config/config.h" // for HAVE_LINK_R +using namespace llvm; + +namespace llvm { + extern cl::opt<std::string> OutputPrefix; + extern cl::list<std::string> InputArgv; +} + +namespace { + static llvm::cl::opt<bool> + DisableLoopExtraction("disable-loop-extraction", + cl::desc("Don't extract loops when searching for miscompilations"), + cl::init(false)); + static llvm::cl::opt<bool> + DisableBlockExtraction("disable-block-extraction", + cl::desc("Don't extract blocks when searching for miscompilations"), + cl::init(false)); + + class ReduceMiscompilingPasses : public ListReducer<const PassInfo*> { + BugDriver &BD; + public: + ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {} + + virtual TestResult doTest(std::vector<const PassInfo*> &Prefix, + std::vector<const PassInfo*> &Suffix, + std::string &Error); + }; +} + +/// TestResult - After passes have been split into a test group and a control +/// group, see if they still break the program. +/// +ReduceMiscompilingPasses::TestResult +ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, + std::vector<const PassInfo*> &Suffix, + std::string &Error) { + // First, run the program with just the Suffix passes. If it is still broken + // with JUST the kept passes, discard the prefix passes. + outs() << "Checking to see if '" << getPassesString(Suffix) + << "' compiles correctly: "; + + std::string BitcodeResult; + if (BD.runPasses(Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + errs() << " Error running this sequence of passes" + << " on the input program!\n"; + BD.setPassesToRun(Suffix); + BD.EmitProgressBitcode("pass-error", false); + exit(BD.debugOptimizerCrash()); + } + + // Check to see if the finished program matches the reference output... + bool Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, + &Error); + if (!Error.empty()) + return InternalError; + if (Diff) { + outs() << " nope.\n"; + if (Suffix.empty()) { + errs() << BD.getToolName() << ": I'm confused: the test fails when " + << "no passes are run, nondeterministic program?\n"; + exit(1); + } + return KeepSuffix; // Miscompilation detected! + } + outs() << " yup.\n"; // No miscompilation! + + if (Prefix.empty()) return NoFailure; + + // Next, see if the program is broken if we run the "prefix" passes first, + // then separately run the "kept" passes. + outs() << "Checking to see if '" << getPassesString(Prefix) + << "' compiles correctly: "; + + // If it is not broken with the kept passes, it's possible that the prefix + // passes must be run before the kept passes to break it. If the program + // WORKS after the prefix passes, but then fails if running the prefix AND + // kept passes, we can update our bitcode file to include the result of the + // prefix passes, then discard the prefix passes. + // + if (BD.runPasses(Prefix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + errs() << " Error running this sequence of passes" + << " on the input program!\n"; + BD.setPassesToRun(Prefix); + BD.EmitProgressBitcode("pass-error", false); + exit(BD.debugOptimizerCrash()); + } + + // If the prefix maintains the predicate by itself, only keep the prefix! + Diff = BD.diffProgram(BitcodeResult, "", false, &Error); + if (!Error.empty()) + return InternalError; + if (Diff) { + outs() << " nope.\n"; + sys::Path(BitcodeResult).eraseFromDisk(); + return KeepPrefix; + } + outs() << " yup.\n"; // No miscompilation! + + // Ok, so now we know that the prefix passes work, try running the suffix + // passes on the result of the prefix passes. + // + OwningPtr<Module> PrefixOutput(ParseInputFile(BitcodeResult, + BD.getContext())); + if (PrefixOutput == 0) { + errs() << BD.getToolName() << ": Error reading bitcode file '" + << BitcodeResult << "'!\n"; + exit(1); + } + sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk + + // Don't check if there are no passes in the suffix. + if (Suffix.empty()) + return NoFailure; + + outs() << "Checking to see if '" << getPassesString(Suffix) + << "' passes compile correctly after the '" + << getPassesString(Prefix) << "' passes: "; + + OwningPtr<Module> OriginalInput(BD.swapProgramIn(PrefixOutput.take())); + if (BD.runPasses(Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + errs() << " Error running this sequence of passes" + << " on the input program!\n"; + BD.setPassesToRun(Suffix); + BD.EmitProgressBitcode("pass-error", false); + exit(BD.debugOptimizerCrash()); + } + + // Run the result... + Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, &Error); + if (!Error.empty()) + return InternalError; + if (Diff) { + outs() << " nope.\n"; + return KeepSuffix; + } + + // Otherwise, we must not be running the bad pass anymore. + outs() << " yup.\n"; // No miscompilation! + // Restore orig program & free test. + delete BD.swapProgramIn(OriginalInput.take()); + return NoFailure; +} + +namespace { + class ReduceMiscompilingFunctions : public ListReducer<Function*> { + BugDriver &BD; + bool (*TestFn)(BugDriver &, Module *, Module *, std::string &); + public: + ReduceMiscompilingFunctions(BugDriver &bd, + bool (*F)(BugDriver &, Module *, Module *, + std::string &)) + : BD(bd), TestFn(F) {} + + virtual TestResult doTest(std::vector<Function*> &Prefix, + std::vector<Function*> &Suffix, + std::string &Error) { + if (!Suffix.empty()) { + bool Ret = TestFuncs(Suffix, Error); + if (!Error.empty()) + return InternalError; + if (Ret) + return KeepSuffix; + } + if (!Prefix.empty()) { + bool Ret = TestFuncs(Prefix, Error); + if (!Error.empty()) + return InternalError; + if (Ret) + return KeepPrefix; + } + return NoFailure; + } + + int TestFuncs(const std::vector<Function*> &Prefix, std::string &Error); + }; +} + +/// TestMergedProgram - Given two modules, link them together and run the +/// program, checking to see if the program matches the diff. If the diff +/// matches, return false, otherwise return true. If the DeleteInputs argument +/// is set to true then this function deletes both input modules before it +/// returns. +/// +static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, + bool DeleteInputs, std::string &Error) { + // Link the two portions of the program back to together. + std::string ErrorMsg; + if (!DeleteInputs) { + M1 = CloneModule(M1); + M2 = CloneModule(M2); + } + if (Linker::LinkModules(M1, M2, &ErrorMsg)) { + errs() << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << '\n'; + exit(1); + } + delete M2; // We are done with this module. + + OwningPtr<Module> OldProgram(BD.swapProgramIn(M1)); + + // Execute the program. If it does not match the expected output, we must + // return true. + bool Broken = BD.diffProgram("", "", false, &Error); + if (!Error.empty()) { + // Delete the linked module & restore the original + delete BD.swapProgramIn(OldProgram.take()); + } + return Broken; +} + +/// TestFuncs - split functions in a Module into two groups: those that are +/// under consideration for miscompilation vs. those that are not, and test +/// accordingly. Each group of functions becomes a separate Module. +/// +int ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, + std::string &Error) { + // Test to see if the function is misoptimized if we ONLY run it on the + // functions listed in Funcs. + outs() << "Checking to see if the program is misoptimized when " + << (Funcs.size()==1 ? "this function is" : "these functions are") + << " run through the pass" + << (BD.getPassesToRun().size() == 1 ? "" : "es") << ":"; + PrintFunctionList(Funcs); + outs() << '\n'; + + // Split the module into the two halves of the program we want. + DenseMap<const Value*, Value*> ValueMap; + Module *ToNotOptimize = CloneModule(BD.getProgram(), ValueMap); + Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, Funcs, + ValueMap); + + // Run the predicate, note that the predicate will delete both input modules. + return TestFn(BD, ToOptimize, ToNotOptimize, Error); +} + +/// DisambiguateGlobalSymbols - Give anonymous global values names. +/// +static void DisambiguateGlobalSymbols(Module *M) { + for (Module::global_iterator I = M->global_begin(), E = M->global_end(); + I != E; ++I) + if (!I->hasName()) + I->setName("anon_global"); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + if (!I->hasName()) + I->setName("anon_fn"); +} + +/// ExtractLoops - Given a reduced list of functions that still exposed the bug, +/// check to see if we can extract the loops in the region without obscuring the +/// bug. If so, it reduces the amount of code identified. +/// +static bool ExtractLoops(BugDriver &BD, + bool (*TestFn)(BugDriver &, Module *, Module *, + std::string &), + std::vector<Function*> &MiscompiledFunctions, + std::string &Error) { + bool MadeChange = false; + while (1) { + if (BugpointIsInterrupted) return MadeChange; + + DenseMap<const Value*, Value*> ValueMap; + Module *ToNotOptimize = CloneModule(BD.getProgram(), ValueMap); + Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, + MiscompiledFunctions, + ValueMap); + Module *ToOptimizeLoopExtracted = BD.ExtractLoop(ToOptimize); + if (!ToOptimizeLoopExtracted) { + // If the loop extractor crashed or if there were no extractible loops, + // then this chapter of our odyssey is over with. + delete ToNotOptimize; + delete ToOptimize; + return MadeChange; + } + + errs() << "Extracted a loop from the breaking portion of the program.\n"; + + // Bugpoint is intentionally not very trusting of LLVM transformations. In + // particular, we're not going to assume that the loop extractor works, so + // we're going to test the newly loop extracted program to make sure nothing + // has broken. If something broke, then we'll inform the user and stop + // extraction. + AbstractInterpreter *AI = BD.switchToSafeInterpreter(); + bool Failure = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, + false, Error); + if (!Error.empty()) + return false; + if (Failure) { + BD.switchToInterpreter(AI); + + // Merged program doesn't work anymore! + errs() << " *** ERROR: Loop extraction broke the program. :(" + << " Please report a bug!\n"; + errs() << " Continuing on with un-loop-extracted version.\n"; + + BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-tno.bc", + ToNotOptimize); + BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to.bc", + ToOptimize); + BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc", + ToOptimizeLoopExtracted); + + errs() << "Please submit the " + << OutputPrefix << "-loop-extract-fail-*.bc files.\n"; + delete ToOptimize; + delete ToNotOptimize; + delete ToOptimizeLoopExtracted; + return MadeChange; + } + delete ToOptimize; + BD.switchToInterpreter(AI); + + outs() << " Testing after loop extraction:\n"; + // Clone modules, the tester function will free them. + Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); + Module *TNOBackup = CloneModule(ToNotOptimize); + Failure = TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize, Error); + if (!Error.empty()) + return false; + if (!Failure) { + outs() << "*** Loop extraction masked the problem. Undoing.\n"; + // If the program is not still broken, then loop extraction did something + // that masked the error. Stop loop extraction now. + delete TOLEBackup; + delete TNOBackup; + return MadeChange; + } + ToOptimizeLoopExtracted = TOLEBackup; + ToNotOptimize = TNOBackup; + + outs() << "*** Loop extraction successful!\n"; + + std::vector<std::pair<std::string, const FunctionType*> > MisCompFunctions; + for (Module::iterator I = ToOptimizeLoopExtracted->begin(), + E = ToOptimizeLoopExtracted->end(); I != E; ++I) + if (!I->isDeclaration()) + MisCompFunctions.push_back(std::make_pair(I->getName(), + I->getFunctionType())); + + // Okay, great! Now we know that we extracted a loop and that loop + // extraction both didn't break the program, and didn't mask the problem. + // Replace the current program with the loop extracted version, and try to + // extract another loop. + std::string ErrorMsg; + if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, &ErrorMsg)){ + errs() << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << '\n'; + exit(1); + } + delete ToOptimizeLoopExtracted; + + // All of the Function*'s in the MiscompiledFunctions list are in the old + // module. Update this list to include all of the functions in the + // optimized and loop extracted module. + MiscompiledFunctions.clear(); + for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { + Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); + + assert(NewF && "Function not found??"); + assert(NewF->getFunctionType() == MisCompFunctions[i].second && + "found wrong function type?"); + MiscompiledFunctions.push_back(NewF); + } + + BD.setNewProgram(ToNotOptimize); + MadeChange = true; + } +} + +namespace { + class ReduceMiscompiledBlocks : public ListReducer<BasicBlock*> { + BugDriver &BD; + bool (*TestFn)(BugDriver &, Module *, Module *, std::string &); + std::vector<Function*> FunctionsBeingTested; + public: + ReduceMiscompiledBlocks(BugDriver &bd, + bool (*F)(BugDriver &, Module *, Module *, + std::string &), + const std::vector<Function*> &Fns) + : BD(bd), TestFn(F), FunctionsBeingTested(Fns) {} + + virtual TestResult doTest(std::vector<BasicBlock*> &Prefix, + std::vector<BasicBlock*> &Suffix, + std::string &Error) { + if (!Suffix.empty()) { + bool Ret = TestFuncs(Suffix, Error); + if (!Error.empty()) + return InternalError; + if (Ret) + return KeepSuffix; + } + if (!Prefix.empty()) { + bool Ret = TestFuncs(Prefix, Error); + if (!Error.empty()) + return InternalError; + if (Ret) + return KeepPrefix; + } + return NoFailure; + } + + bool TestFuncs(const std::vector<BasicBlock*> &BBs, std::string &Error); + }; +} + +/// TestFuncs - Extract all blocks for the miscompiled functions except for the +/// specified blocks. If the problem still exists, return true. +/// +bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs, + std::string &Error) { + // Test to see if the function is misoptimized if we ONLY run it on the + // functions listed in Funcs. + outs() << "Checking to see if the program is misoptimized when all "; + if (!BBs.empty()) { + outs() << "but these " << BBs.size() << " blocks are extracted: "; + for (unsigned i = 0, e = BBs.size() < 10 ? BBs.size() : 10; i != e; ++i) + outs() << BBs[i]->getName() << " "; + if (BBs.size() > 10) outs() << "..."; + } else { + outs() << "blocks are extracted."; + } + outs() << '\n'; + + // Split the module into the two halves of the program we want. + DenseMap<const Value*, Value*> ValueMap; + Module *ToNotOptimize = CloneModule(BD.getProgram(), ValueMap); + Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, + FunctionsBeingTested, + ValueMap); + + // Try the extraction. If it doesn't work, then the block extractor crashed + // or something, in which case bugpoint can't chase down this possibility. + if (Module *New = BD.ExtractMappedBlocksFromModule(BBs, ToOptimize)) { + delete ToOptimize; + // Run the predicate, not that the predicate will delete both input modules. + return TestFn(BD, New, ToNotOptimize, Error); + } + delete ToOptimize; + delete ToNotOptimize; + return false; +} + + +/// ExtractBlocks - Given a reduced list of functions that still expose the bug, +/// extract as many basic blocks from the region as possible without obscuring +/// the bug. +/// +static bool ExtractBlocks(BugDriver &BD, + bool (*TestFn)(BugDriver &, Module *, Module *, + std::string &), + std::vector<Function*> &MiscompiledFunctions, + std::string &Error) { + if (BugpointIsInterrupted) return false; + + std::vector<BasicBlock*> Blocks; + for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) + for (Function::iterator I = MiscompiledFunctions[i]->begin(), + E = MiscompiledFunctions[i]->end(); I != E; ++I) + Blocks.push_back(I); + + // Use the list reducer to identify blocks that can be extracted without + // obscuring the bug. The Blocks list will end up containing blocks that must + // be retained from the original program. + unsigned OldSize = Blocks.size(); + + // Check to see if all blocks are extractible first. + bool Ret = ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions) + .TestFuncs(std::vector<BasicBlock*>(), Error); + if (!Error.empty()) + return false; + if (Ret) { + Blocks.clear(); + } else { + ReduceMiscompiledBlocks(BD, TestFn, + MiscompiledFunctions).reduceList(Blocks, Error); + if (!Error.empty()) + return false; + if (Blocks.size() == OldSize) + return false; + } + + DenseMap<const Value*, Value*> ValueMap; + Module *ProgClone = CloneModule(BD.getProgram(), ValueMap); + Module *ToExtract = SplitFunctionsOutOfModule(ProgClone, + MiscompiledFunctions, + ValueMap); + Module *Extracted = BD.ExtractMappedBlocksFromModule(Blocks, ToExtract); + if (Extracted == 0) { + // Weird, extraction should have worked. + errs() << "Nondeterministic problem extracting blocks??\n"; + delete ProgClone; + delete ToExtract; + return false; + } + + // Otherwise, block extraction succeeded. Link the two program fragments back + // together. + delete ToExtract; + + std::vector<std::pair<std::string, const FunctionType*> > MisCompFunctions; + for (Module::iterator I = Extracted->begin(), E = Extracted->end(); + I != E; ++I) + if (!I->isDeclaration()) + MisCompFunctions.push_back(std::make_pair(I->getName(), + I->getFunctionType())); + + std::string ErrorMsg; + if (Linker::LinkModules(ProgClone, Extracted, &ErrorMsg)) { + errs() << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << '\n'; + exit(1); + } + delete Extracted; + + // Set the new program and delete the old one. + BD.setNewProgram(ProgClone); + + // Update the list of miscompiled functions. + MiscompiledFunctions.clear(); + + for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { + Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first); + assert(NewF && "Function not found??"); + assert(NewF->getFunctionType() == MisCompFunctions[i].second && + "Function has wrong type??"); + MiscompiledFunctions.push_back(NewF); + } + + return true; +} + + +/// DebugAMiscompilation - This is a generic driver to narrow down +/// miscompilations, either in an optimization or a code generator. +/// +static std::vector<Function*> +DebugAMiscompilation(BugDriver &BD, + bool (*TestFn)(BugDriver &, Module *, Module *, + std::string &), + std::string &Error) { + // Okay, now that we have reduced the list of passes which are causing the + // failure, see if we can pin down which functions are being + // miscompiled... first build a list of all of the non-external functions in + // the program. + std::vector<Function*> MiscompiledFunctions; + Module *Prog = BD.getProgram(); + for (Module::iterator I = Prog->begin(), E = Prog->end(); I != E; ++I) + if (!I->isDeclaration()) + MiscompiledFunctions.push_back(I); + + // Do the reduction... + if (!BugpointIsInterrupted) + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, + Error); + if (!Error.empty()) + return MiscompiledFunctions; + + outs() << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; + PrintFunctionList(MiscompiledFunctions); + outs() << '\n'; + + // See if we can rip any loops out of the miscompiled functions and still + // trigger the problem. + + if (!BugpointIsInterrupted && !DisableLoopExtraction) { + bool Ret = ExtractLoops(BD, TestFn, MiscompiledFunctions, Error); + if (!Error.empty()) + return MiscompiledFunctions; + if (Ret) { + // Okay, we extracted some loops and the problem still appears. See if + // we can eliminate some of the created functions from being candidates. + DisambiguateGlobalSymbols(BD.getProgram()); + + // Do the reduction... + if (!BugpointIsInterrupted) + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, + Error); + if (!Error.empty()) + return MiscompiledFunctions; + + outs() << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; + PrintFunctionList(MiscompiledFunctions); + outs() << '\n'; + } + } + + if (!BugpointIsInterrupted && !DisableBlockExtraction) { + bool Ret = ExtractBlocks(BD, TestFn, MiscompiledFunctions, Error); + if (!Error.empty()) + return MiscompiledFunctions; + if (Ret) { + // Okay, we extracted some blocks and the problem still appears. See if + // we can eliminate some of the created functions from being candidates. + DisambiguateGlobalSymbols(BD.getProgram()); + + // Do the reduction... + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, + Error); + if (!Error.empty()) + return MiscompiledFunctions; + + outs() << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; + PrintFunctionList(MiscompiledFunctions); + outs() << '\n'; + } + } + + return MiscompiledFunctions; +} + +/// TestOptimizer - This is the predicate function used to check to see if the +/// "Test" portion of the program is misoptimized. If so, return true. In any +/// case, both module arguments are deleted. +/// +static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe, + std::string &Error) { + // Run the optimization passes on ToOptimize, producing a transformed version + // of the functions being tested. + outs() << " Optimizing functions being tested: "; + Module *Optimized = BD.runPassesOn(Test, BD.getPassesToRun(), + /*AutoDebugCrashes*/true); + outs() << "done.\n"; + delete Test; + + outs() << " Checking to see if the merged program executes correctly: "; + bool Broken = TestMergedProgram(BD, Optimized, Safe, true, Error); + if (Error.empty()) outs() << (Broken ? " nope.\n" : " yup.\n"); + return Broken; +} + + +/// debugMiscompilation - This method is used when the passes selected are not +/// crashing, but the generated output is semantically different from the +/// input. +/// +void BugDriver::debugMiscompilation(std::string *Error) { + // Make sure something was miscompiled... + if (!BugpointIsInterrupted) + if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun, *Error)) { + if (Error->empty()) + errs() << "*** Optimized program matches reference output! No problem" + << " detected...\nbugpoint can't help you with your problem!\n"; + return; + } + + outs() << "\n*** Found miscompiling pass" + << (getPassesToRun().size() == 1 ? "" : "es") << ": " + << getPassesString(getPassesToRun()) << '\n'; + EmitProgressBitcode("passinput"); + + std::vector<Function *> MiscompiledFunctions = + DebugAMiscompilation(*this, TestOptimizer, *Error); + if (!Error->empty()) + return; + + // Output a bunch of bitcode files for the user... + outs() << "Outputting reduced bitcode files which expose the problem:\n"; + DenseMap<const Value*, Value*> ValueMap; + Module *ToNotOptimize = CloneModule(getProgram(), ValueMap); + Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, + MiscompiledFunctions, + ValueMap); + + outs() << " Non-optimized portion: "; + ToNotOptimize = swapProgramIn(ToNotOptimize); + EmitProgressBitcode("tonotoptimize", true); + setNewProgram(ToNotOptimize); // Delete hacked module. + + outs() << " Portion that is input to optimizer: "; + ToOptimize = swapProgramIn(ToOptimize); + EmitProgressBitcode("tooptimize"); + setNewProgram(ToOptimize); // Delete hacked module. + + return; +} + +/// CleanupAndPrepareModules - Get the specified modules ready for code +/// generator testing. +/// +static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, + Module *Safe) { + // Clean up the modules, removing extra cruft that we don't need anymore... + Test = BD.performFinalCleanups(Test); + + // If we are executing the JIT, we have several nasty issues to take care of. + if (!BD.isExecutingJIT()) return; + + // First, if the main function is in the Safe module, we must add a stub to + // the Test module to call into it. Thus, we create a new function `main' + // which just calls the old one. + if (Function *oldMain = Safe->getFunction("main")) + if (!oldMain->isDeclaration()) { + // Rename it + oldMain->setName("llvm_bugpoint_old_main"); + // Create a NEW `main' function with same type in the test module. + Function *newMain = Function::Create(oldMain->getFunctionType(), + GlobalValue::ExternalLinkage, + "main", Test); + // Create an `oldmain' prototype in the test module, which will + // corresponds to the real main function in the same module. + Function *oldMainProto = Function::Create(oldMain->getFunctionType(), + GlobalValue::ExternalLinkage, + oldMain->getName(), Test); + // Set up and remember the argument list for the main function. + std::vector<Value*> args; + for (Function::arg_iterator + I = newMain->arg_begin(), E = newMain->arg_end(), + OI = oldMain->arg_begin(); I != E; ++I, ++OI) { + I->setName(OI->getName()); // Copy argument names from oldMain + args.push_back(I); + } + + // Call the old main function and return its result + BasicBlock *BB = BasicBlock::Create(Safe->getContext(), "entry", newMain); + CallInst *call = CallInst::Create(oldMainProto, args.begin(), args.end(), + "", BB); + + // If the type of old function wasn't void, return value of call + ReturnInst::Create(Safe->getContext(), call, BB); + } + + // The second nasty issue we must deal with in the JIT is that the Safe + // module cannot directly reference any functions defined in the test + // module. Instead, we use a JIT API call to dynamically resolve the + // symbol. + + // Add the resolver to the Safe module. + // Prototype: void *getPointerToNamedFunction(const char* Name) + Constant *resolverFunc = + Safe->getOrInsertFunction("getPointerToNamedFunction", + Type::getInt8PtrTy(Safe->getContext()), + Type::getInt8PtrTy(Safe->getContext()), + (Type *)0); + + // Use the function we just added to get addresses of functions we need. + for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) { + if (F->isDeclaration() && !F->use_empty() && &*F != resolverFunc && + !F->isIntrinsic() /* ignore intrinsics */) { + Function *TestFn = Test->getFunction(F->getName()); + + // Don't forward functions which are external in the test module too. + if (TestFn && !TestFn->isDeclaration()) { + // 1. Add a string constant with its name to the global file + Constant *InitArray = ConstantArray::get(F->getContext(), F->getName()); + GlobalVariable *funcName = + new GlobalVariable(*Safe, InitArray->getType(), true /*isConstant*/, + GlobalValue::InternalLinkage, InitArray, + F->getName() + "_name"); + + // 2. Use `GetElementPtr *funcName, 0, 0' to convert the string to an + // sbyte* so it matches the signature of the resolver function. + + // GetElementPtr *funcName, ulong 0, ulong 0 + std::vector<Constant*> GEPargs(2, + Constant::getNullValue(Type::getInt32Ty(F->getContext()))); + Value *GEP = + ConstantExpr::getGetElementPtr(funcName, &GEPargs[0], 2); + std::vector<Value*> ResolverArgs; + ResolverArgs.push_back(GEP); + + // Rewrite uses of F in global initializers, etc. to uses of a wrapper + // function that dynamically resolves the calls to F via our JIT API + if (!F->use_empty()) { + // Create a new global to hold the cached function pointer. + Constant *NullPtr = ConstantPointerNull::get(F->getType()); + GlobalVariable *Cache = + new GlobalVariable(*F->getParent(), F->getType(), + false, GlobalValue::InternalLinkage, + NullPtr,F->getName()+".fpcache"); + + // Construct a new stub function that will re-route calls to F + const FunctionType *FuncTy = F->getFunctionType(); + Function *FuncWrapper = Function::Create(FuncTy, + GlobalValue::InternalLinkage, + F->getName() + "_wrapper", + F->getParent()); + BasicBlock *EntryBB = BasicBlock::Create(F->getContext(), + "entry", FuncWrapper); + BasicBlock *DoCallBB = BasicBlock::Create(F->getContext(), + "usecache", FuncWrapper); + BasicBlock *LookupBB = BasicBlock::Create(F->getContext(), + "lookupfp", FuncWrapper); + + // Check to see if we already looked up the value. + Value *CachedVal = new LoadInst(Cache, "fpcache", EntryBB); + Value *IsNull = new ICmpInst(*EntryBB, ICmpInst::ICMP_EQ, CachedVal, + NullPtr, "isNull"); + BranchInst::Create(LookupBB, DoCallBB, IsNull, EntryBB); + + // Resolve the call to function F via the JIT API: + // + // call resolver(GetElementPtr...) + CallInst *Resolver = + CallInst::Create(resolverFunc, ResolverArgs.begin(), + ResolverArgs.end(), "resolver", LookupBB); + + // Cast the result from the resolver to correctly-typed function. + CastInst *CastedResolver = + new BitCastInst(Resolver, + PointerType::getUnqual(F->getFunctionType()), + "resolverCast", LookupBB); + + // Save the value in our cache. + new StoreInst(CastedResolver, Cache, LookupBB); + BranchInst::Create(DoCallBB, LookupBB); + + PHINode *FuncPtr = PHINode::Create(NullPtr->getType(), + "fp", DoCallBB); + FuncPtr->addIncoming(CastedResolver, LookupBB); + FuncPtr->addIncoming(CachedVal, EntryBB); + + // Save the argument list. + std::vector<Value*> Args; + for (Function::arg_iterator i = FuncWrapper->arg_begin(), + e = FuncWrapper->arg_end(); i != e; ++i) + Args.push_back(i); + + // Pass on the arguments to the real function, return its result + if (F->getReturnType() == Type::getVoidTy(F->getContext())) { + CallInst::Create(FuncPtr, Args.begin(), Args.end(), "", DoCallBB); + ReturnInst::Create(F->getContext(), DoCallBB); + } else { + CallInst *Call = CallInst::Create(FuncPtr, Args.begin(), Args.end(), + "retval", DoCallBB); + ReturnInst::Create(F->getContext(),Call, DoCallBB); + } + + // Use the wrapper function instead of the old function + F->replaceAllUsesWith(FuncWrapper); + } + } + } + } + + if (verifyModule(*Test) || verifyModule(*Safe)) { + errs() << "Bugpoint has a bug, which corrupted a module!!\n"; + abort(); + } +} + + + +/// TestCodeGenerator - This is the predicate function used to check to see if +/// the "Test" portion of the program is miscompiled by the code generator under +/// test. If so, return true. In any case, both module arguments are deleted. +/// +static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, + std::string &Error) { + CleanupAndPrepareModules(BD, Test, Safe); + + sys::Path TestModuleBC("bugpoint.test.bc"); + std::string ErrMsg; + if (TestModuleBC.makeUnique(true, &ErrMsg)) { + errs() << BD.getToolName() << "Error making unique filename: " + << ErrMsg << "\n"; + exit(1); + } + if (BD.writeProgramToFile(TestModuleBC.str(), Test)) { + errs() << "Error writing bitcode to `" << TestModuleBC.str() + << "'\nExiting."; + exit(1); + } + delete Test; + + // Make the shared library + sys::Path SafeModuleBC("bugpoint.safe.bc"); + if (SafeModuleBC.makeUnique(true, &ErrMsg)) { + errs() << BD.getToolName() << "Error making unique filename: " + << ErrMsg << "\n"; + exit(1); + } + + if (BD.writeProgramToFile(SafeModuleBC.str(), Safe)) { + errs() << "Error writing bitcode to `" << SafeModuleBC.str() + << "'\nExiting."; + exit(1); + } + std::string SharedObject = BD.compileSharedObject(SafeModuleBC.str(), Error); + if (!Error.empty()) + return false; + delete Safe; + + // Run the code generator on the `Test' code, loading the shared library. + // The function returns whether or not the new output differs from reference. + bool Result = BD.diffProgram(TestModuleBC.str(), SharedObject, false, &Error); + if (!Error.empty()) + return false; + + if (Result) + errs() << ": still failing!\n"; + else + errs() << ": didn't fail.\n"; + TestModuleBC.eraseFromDisk(); + SafeModuleBC.eraseFromDisk(); + sys::Path(SharedObject).eraseFromDisk(); + + return Result; +} + + +/// debugCodeGenerator - debug errors in LLC, LLI, or CBE. +/// +bool BugDriver::debugCodeGenerator(std::string *Error) { + if ((void*)SafeInterpreter == (void*)Interpreter) { + std::string Result = executeProgramSafely("bugpoint.safe.out", Error); + if (Error->empty()) { + outs() << "\n*** The \"safe\" i.e. 'known good' backend cannot match " + << "the reference diff. This may be due to a\n front-end " + << "bug or a bug in the original program, but this can also " + << "happen if bugpoint isn't running the program with the " + << "right flags or input.\n I left the result of executing " + << "the program with the \"safe\" backend in this file for " + << "you: '" + << Result << "'.\n"; + } + return true; + } + + DisambiguateGlobalSymbols(Program); + + std::vector<Function*> Funcs = DebugAMiscompilation(*this, TestCodeGenerator, + *Error); + if (!Error->empty()) + return true; + + // Split the module into the two halves of the program we want. + DenseMap<const Value*, Value*> ValueMap; + Module *ToNotCodeGen = CloneModule(getProgram(), ValueMap); + Module *ToCodeGen = SplitFunctionsOutOfModule(ToNotCodeGen, Funcs, ValueMap); + + // Condition the modules + CleanupAndPrepareModules(*this, ToCodeGen, ToNotCodeGen); + + sys::Path TestModuleBC("bugpoint.test.bc"); + std::string ErrMsg; + if (TestModuleBC.makeUnique(true, &ErrMsg)) { + errs() << getToolName() << "Error making unique filename: " + << ErrMsg << "\n"; + exit(1); + } + + if (writeProgramToFile(TestModuleBC.str(), ToCodeGen)) { + errs() << "Error writing bitcode to `" << TestModuleBC.str() + << "'\nExiting."; + exit(1); + } + delete ToCodeGen; + + // Make the shared library + sys::Path SafeModuleBC("bugpoint.safe.bc"); + if (SafeModuleBC.makeUnique(true, &ErrMsg)) { + errs() << getToolName() << "Error making unique filename: " + << ErrMsg << "\n"; + exit(1); + } + + if (writeProgramToFile(SafeModuleBC.str(), ToNotCodeGen)) { + errs() << "Error writing bitcode to `" << SafeModuleBC.str() + << "'\nExiting."; + exit(1); + } + std::string SharedObject = compileSharedObject(SafeModuleBC.str(), *Error); + if (!Error->empty()) + return true; + delete ToNotCodeGen; + + outs() << "You can reproduce the problem with the command line: \n"; + if (isExecutingJIT()) { + outs() << " lli -load " << SharedObject << " " << TestModuleBC.str(); + } else { + outs() << " llc " << TestModuleBC.str() << " -o " << TestModuleBC.str() + << ".s\n"; + outs() << " gcc " << SharedObject << " " << TestModuleBC.str() + << ".s -o " << TestModuleBC.str() << ".exe"; +#if defined (HAVE_LINK_R) + outs() << " -Wl,-R."; +#endif + outs() << "\n"; + outs() << " " << TestModuleBC.str() << ".exe"; + } + for (unsigned i = 0, e = InputArgv.size(); i != e; ++i) + outs() << " " << InputArgv[i]; + outs() << '\n'; + outs() << "The shared object was created with:\n llc -march=c " + << SafeModuleBC.str() << " -o temporary.c\n" + << " gcc -xc temporary.c -O2 -o " << SharedObject; + if (TargetTriple.getArch() == Triple::sparc) + outs() << " -G"; // Compile a shared library, `-G' for Sparc + else + outs() << " -fPIC -shared"; // `-shared' for Linux/X86, maybe others + + outs() << " -fno-strict-aliasing\n"; + + return false; +} diff --git a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp new file mode 100644 index 0000000..3a6149b --- /dev/null +++ b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp @@ -0,0 +1,267 @@ +//===- 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. :) +// +//===----------------------------------------------------------------------===// + +// Note: as a short term hack, the old Unix-specific code and platform- +// independent code co-exist via conditional compilation until it is verified +// that the new code works correctly on Unix. + +#include "BugDriver.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include "llvm/System/Program.h" + +#define DONT_GET_PLUGIN_LOADER_OPTION +#include "llvm/Support/PluginLoader.h" + +#include <fstream> +using namespace llvm; + +namespace llvm { + extern cl::opt<std::string> OutputPrefix; +} + +namespace { + // ChildOutput - This option captures the name of the child output file that + // is set up by the parent bugpoint process + cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden); +} + +/// writeProgramToFile - This writes the current "Program" to the named bitcode +/// file. If an error occurs, true is returned. +/// +bool BugDriver::writeProgramToFile(const std::string &Filename, + Module *M) const { + std::string ErrInfo; + raw_fd_ostream Out(Filename.c_str(), ErrInfo, + raw_fd_ostream::F_Binary); + if (!ErrInfo.empty()) return true; + + WriteBitcodeToFile(M ? M : Program, Out); + return false; +} + + +/// EmitProgressBitcode - This function is used to output the current Program +/// to a file named "bugpoint-ID.bc". +/// +void BugDriver::EmitProgressBitcode(const std::string &ID, bool NoFlyer) { + // 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)) { + 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 << " "; + outs() << getPassesString(PassesToRun) << "\n"; +} + +int BugDriver::runPassesAsChild(const std::vector<const PassInfo*> &Passes) { + std::string ErrInfo; + raw_fd_ostream OutFile(ChildOutput.c_str(), ErrInfo, + raw_fd_ostream::F_Binary); + if (!ErrInfo.empty()) { + errs() << "Error opening bitcode file: " << ChildOutput << "\n"; + return 1; + } + + PassManager PM; + // Make sure that the appropriate target data is always used... + PM.add(new TargetData(Program)); + + for (unsigned i = 0, e = Passes.size(); i != e; ++i) { + if (Passes[i]->getNormalCtor()) + PM.add(Passes[i]->getNormalCtor()()); + else + errs() << "Cannot create pass yet: " << Passes[i]->getPassName() << "\n"; + } + // Check that the module is well formed on completion of optimization + PM.add(createVerifierPass()); + + // Write bitcode out to disk as the last step... + PM.add(createBitcodeWriterPass(OutFile)); + + // Run all queued passes. + PM.run(*Program); + + return 0; +} + +cl::opt<bool> SilencePasses("silence-passes", cl::desc("Suppress output of running passes (both stdout and stderr)")); + +/// 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(const std::vector<const PassInfo*> &Passes, + std::string &OutputFilename, bool DeleteOutput, + bool Quiet, unsigned NumExtraArgs, + const char * const *ExtraArgs) const { + // setup the output file name + outs().flush(); + sys::Path uniqueFilename(OutputPrefix + "-output.bc"); + std::string ErrMsg; + if (uniqueFilename.makeUnique(true, &ErrMsg)) { + errs() << getToolName() << ": Error making unique filename: " + << ErrMsg << "\n"; + return(1); + } + OutputFilename = uniqueFilename.str(); + + // set up the input file name + sys::Path inputFilename(OutputPrefix + "-input.bc"); + if (inputFilename.makeUnique(true, &ErrMsg)) { + errs() << getToolName() << ": Error making unique filename: " + << ErrMsg << "\n"; + return(1); + } + + std::string ErrInfo; + raw_fd_ostream InFile(inputFilename.c_str(), ErrInfo, + raw_fd_ostream::F_Binary); + + + if (!ErrInfo.empty()) { + errs() << "Error opening bitcode file: " << inputFilename.str() << "\n"; + return 1; + } + WriteBitcodeToFile(Program, InFile); + InFile.close(); + + // setup the child process' arguments + SmallVector<const char*, 8> Args; + sys::Path tool = sys::Program::FindProgramByName(ToolName); + 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(ToolName); + + Args.push_back("-as-child"); + Args.push_back("-child-output"); + 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<const PassInfo*>::const_iterator I = Passes.begin(), + E = Passes.end(); I != E; ++I ) + pass_args.push_back( std::string("-") + (*I)->getPassArgument() ); + 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(inputFilename.c_str()); + for (unsigned i = 0; i < NumExtraArgs; ++i) + Args.push_back(*ExtraArgs); + Args.push_back(0); + + sys::Path prog; + if (UseValgrind) + prog = sys::Program::FindProgramByName("valgrind"); + else + prog = tool; + + // Redirect stdout and stderr to nowhere if SilencePasses is given + sys::Path Nowhere; + const sys::Path *Redirects[3] = {0, &Nowhere, &Nowhere}; + + int result = sys::Program::ExecuteAndWait(prog, Args.data(), 0, + (SilencePasses ? Redirects : 0), + 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::Path(OutputFilename).eraseFromDisk(); + + // Remove the temporary input file as well + inputFilename.eraseFromDisk(); + + 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 with signal #" << abs(result) << "\n"; + } + if (result & 0x01000000) + outs() << "Dumped core\n"; + } + + // Was the child successful? + return result != 0; +} + + +/// runPassesOn - Carefully run the specified set of pass on the specified +/// module, returning the transformed module on success, or a null pointer on +/// failure. +Module *BugDriver::runPassesOn(Module *M, + const std::vector<const PassInfo*> &Passes, + bool AutoDebugCrashes, unsigned NumExtraArgs, + const char * const *ExtraArgs) { + Module *OldProgram = swapProgramIn(M); + std::string BitcodeResult; + if (runPasses(Passes, BitcodeResult, false/*delete*/, true/*quiet*/, + NumExtraArgs, ExtraArgs)) { + if (AutoDebugCrashes) { + errs() << " Error running this sequence of passes" + << " on the input program!\n"; + delete OldProgram; + EmitProgressBitcode("pass-error", false); + exit(debugOptimizerCrash()); + } + swapProgramIn(OldProgram); + return 0; + } + + // Restore the current program. + swapProgramIn(OldProgram); + + Module *Ret = ParseInputFile(BitcodeResult, Context); + if (Ret == 0) { + errs() << getToolName() << ": Error reading bitcode file '" + << BitcodeResult << "'!\n"; + exit(1); + } + sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk + return Ret; +} diff --git a/contrib/llvm/tools/bugpoint/TestPasses.cpp b/contrib/llvm/tools/bugpoint/TestPasses.cpp new file mode 100644 index 0000000..900bf63 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/TestPasses.cpp @@ -0,0 +1,75 @@ +//===- TestPasses.cpp - "buggy" passes used to test bugpoint --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains "buggy" passes that are used to test bugpoint, to check +// that it is narrowing down testcases correctly. +// +//===----------------------------------------------------------------------===// + +#include "llvm/BasicBlock.h" +#include "llvm/Constant.h" +#include "llvm/Instructions.h" +#include "llvm/Pass.h" +#include "llvm/Type.h" +#include "llvm/Support/InstVisitor.h" + +using namespace llvm; + +namespace { + /// CrashOnCalls - This pass is used to test bugpoint. It intentionally + /// crashes on any call instructions. + class CrashOnCalls : public BasicBlockPass { + public: + static char ID; // Pass ID, replacement for typeid + CrashOnCalls() : BasicBlockPass(&ID) {} + private: + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + + bool runOnBasicBlock(BasicBlock &BB) { + for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) + if (isa<CallInst>(*I)) + abort(); + + return false; + } + }; + + char CrashOnCalls::ID = 0; + RegisterPass<CrashOnCalls> + X("bugpoint-crashcalls", + "BugPoint Test Pass - Intentionally crash on CallInsts"); +} + +namespace { + /// DeleteCalls - This pass is used to test bugpoint. It intentionally + /// deletes some call instructions, "misoptimizing" the program. + class DeleteCalls : public BasicBlockPass { + public: + static char ID; // Pass ID, replacement for typeid + DeleteCalls() : BasicBlockPass(&ID) {} + private: + bool runOnBasicBlock(BasicBlock &BB) { + for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) + if (CallInst *CI = dyn_cast<CallInst>(I)) { + if (!CI->use_empty()) + CI->replaceAllUsesWith(Constant::getNullValue(CI->getType())); + CI->getParent()->getInstList().erase(CI); + break; + } + return false; + } + }; + + char DeleteCalls::ID = 0; + RegisterPass<DeleteCalls> + Y("bugpoint-deletecalls", + "BugPoint Test Pass - Intentionally 'misoptimize' CallInsts"); +} diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.cpp b/contrib/llvm/tools/bugpoint/ToolRunner.cpp new file mode 100644 index 0000000..3149a7a --- /dev/null +++ b/contrib/llvm/tools/bugpoint/ToolRunner.cpp @@ -0,0 +1,879 @@ +//===-- ToolRunner.cpp ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the interfaces described in the ToolRunner.h file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "toolrunner" +#include "ToolRunner.h" +#include "llvm/System/Program.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Config/config.h" // for HAVE_LINK_R +#include <fstream> +#include <sstream> +using namespace llvm; + +namespace llvm { + cl::opt<bool> + SaveTemps("save-temps", cl::init(false), cl::desc("Save temporary files")); +} + +namespace { + cl::opt<std::string> + RemoteClient("remote-client", + cl::desc("Remote execution client (rsh/ssh)")); + + cl::opt<std::string> + RemoteHost("remote-host", + cl::desc("Remote execution (rsh/ssh) host")); + + cl::opt<std::string> + RemotePort("remote-port", + cl::desc("Remote execution (rsh/ssh) port")); + + cl::opt<std::string> + RemoteUser("remote-user", + cl::desc("Remote execution (rsh/ssh) user id")); + + cl::opt<std::string> + RemoteExtra("remote-extra-options", + cl::desc("Remote execution (rsh/ssh) extra options")); +} + +/// RunProgramWithTimeout - This function provides an alternate interface +/// to the sys::Program::ExecuteAndWait interface. +/// @see sys::Program::ExecuteAndWait +static int RunProgramWithTimeout(const sys::Path &ProgramPath, + const char **Args, + const sys::Path &StdInFile, + const sys::Path &StdOutFile, + const sys::Path &StdErrFile, + unsigned NumSeconds = 0, + unsigned MemoryLimit = 0) { + const sys::Path* redirects[3]; + redirects[0] = &StdInFile; + redirects[1] = &StdOutFile; + redirects[2] = &StdErrFile; + +#if 0 // For debug purposes + { + errs() << "RUN:"; + for (unsigned i = 0; Args[i]; ++i) + errs() << " " << Args[i]; + errs() << "\n"; + } +#endif + + return + sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, + NumSeconds, MemoryLimit); +} + +/// RunProgramRemotelyWithTimeout - This function runs the given program +/// remotely using the given remote client and the sys::Program::ExecuteAndWait. +/// Returns the remote program exit code or reports a remote client error if it +/// fails. Remote client is required to return 255 if it failed or program exit +/// code otherwise. +/// @see sys::Program::ExecuteAndWait +static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, + const char **Args, + const sys::Path &StdInFile, + const sys::Path &StdOutFile, + const sys::Path &StdErrFile, + unsigned NumSeconds = 0, + unsigned MemoryLimit = 0) { + const sys::Path* redirects[3]; + redirects[0] = &StdInFile; + redirects[1] = &StdOutFile; + redirects[2] = &StdErrFile; + +#if 0 // For debug purposes + { + errs() << "RUN:"; + for (unsigned i = 0; Args[i]; ++i) + errs() << " " << Args[i]; + errs() << "\n"; + } +#endif + + // Run the program remotely with the remote client + int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args, + 0, redirects, NumSeconds, MemoryLimit); + + // Has the remote client fail? + if (255 == ReturnCode) { + std::ostringstream OS; + OS << "\nError running remote client:\n "; + for (const char **Arg = Args; *Arg; ++Arg) + OS << " " << *Arg; + OS << "\n"; + + // The error message is in the output file, let's print it out from there. + std::ifstream ErrorFile(StdOutFile.c_str()); + if (ErrorFile) { + std::copy(std::istreambuf_iterator<char>(ErrorFile), + std::istreambuf_iterator<char>(), + std::ostreambuf_iterator<char>(OS)); + ErrorFile.close(); + } + + errs() << OS; + } + + return ReturnCode; +} + +static std::string ProcessFailure(sys::Path ProgPath, const char** Args, + unsigned Timeout = 0, + unsigned MemoryLimit = 0) { + std::ostringstream OS; + OS << "\nError running tool:\n "; + for (const char **Arg = Args; *Arg; ++Arg) + OS << " " << *Arg; + OS << "\n"; + + // Rerun the compiler, capturing any error messages to print them. + sys::Path ErrorFilename("bugpoint.program_error_messages"); + std::string ErrMsg; + if (ErrorFilename.makeUnique(true, &ErrMsg)) { + errs() << "Error making unique filename: " << ErrMsg << "\n"; + exit(1); + } + RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename, + ErrorFilename, Timeout, MemoryLimit); + // FIXME: check return code ? + + // Print out the error messages generated by GCC if possible... + std::ifstream ErrorFile(ErrorFilename.c_str()); + if (ErrorFile) { + std::copy(std::istreambuf_iterator<char>(ErrorFile), + std::istreambuf_iterator<char>(), + std::ostreambuf_iterator<char>(OS)); + ErrorFile.close(); + } + + ErrorFilename.eraseFromDisk(); + return OS.str(); +} + +//===---------------------------------------------------------------------===// +// LLI Implementation of AbstractIntepreter interface +// +namespace { + class LLI : public AbstractInterpreter { + std::string LLIPath; // The path to the LLI executable + std::vector<std::string> ToolArgs; // Args to pass to LLI + public: + LLI(const std::string &Path, const std::vector<std::string> *Args) + : LLIPath(Path) { + ToolArgs.clear (); + if (Args) { ToolArgs = *Args; } + } + + virtual int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0); + }; +} + +int LLI::ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &SharedLibs, + unsigned Timeout, + unsigned MemoryLimit) { + std::vector<const char*> LLIArgs; + LLIArgs.push_back(LLIPath.c_str()); + LLIArgs.push_back("-force-interpreter=true"); + + for (std::vector<std::string>::const_iterator i = SharedLibs.begin(), e = SharedLibs.end(); i != e; ++i) { + LLIArgs.push_back("-load"); + LLIArgs.push_back((*i).c_str()); + } + + // Add any extra LLI args. + for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) + LLIArgs.push_back(ToolArgs[i].c_str()); + + LLIArgs.push_back(Bitcode.c_str()); + // Add optional parameters to the running program from Argv + for (unsigned i=0, e = Args.size(); i != e; ++i) + LLIArgs.push_back(Args[i].c_str()); + LLIArgs.push_back(0); + + outs() << "<lli>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i) + errs() << " " << LLIArgs[i]; + errs() << "\n"; + ); + return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0], + sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), + Timeout, MemoryLimit); +} + +// LLI create method - Try to find the LLI executable +AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0, + std::string &Message, + const std::vector<std::string> *ToolArgs) { + std::string LLIPath = + FindExecutable("lli", Argv0, (void *)(intptr_t)&createLLI).str(); + if (!LLIPath.empty()) { + Message = "Found lli: " + LLIPath + "\n"; + return new LLI(LLIPath, ToolArgs); + } + + Message = "Cannot find `lli' in executable directory or PATH!\n"; + return 0; +} + +//===---------------------------------------------------------------------===// +// Custom execution command implementation of AbstractIntepreter interface +// +// Allows using a custom command for executing the bitcode, thus allows, +// for example, to invoke a cross compiler for code generation followed by +// a simulator that executes the generated binary. +namespace { + class CustomExecutor : public AbstractInterpreter { + std::string ExecutionCommand; + std::vector<std::string> ExecutorArgs; + public: + CustomExecutor( + const std::string &ExecutionCmd, std::vector<std::string> ExecArgs) : + ExecutionCommand(ExecutionCmd), ExecutorArgs(ExecArgs) {} + + virtual int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0); + }; +} + +int CustomExecutor::ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &SharedLibs, + unsigned Timeout, + unsigned MemoryLimit) { + + std::vector<const char*> ProgramArgs; + ProgramArgs.push_back(ExecutionCommand.c_str()); + + for (std::size_t i = 0; i < ExecutorArgs.size(); ++i) + ProgramArgs.push_back(ExecutorArgs.at(i).c_str()); + ProgramArgs.push_back(Bitcode.c_str()); + ProgramArgs.push_back(0); + + // Add optional parameters to the running program from Argv + for (unsigned i = 0, e = Args.size(); i != e; ++i) + ProgramArgs.push_back(Args[i].c_str()); + + return RunProgramWithTimeout( + sys::Path(ExecutionCommand), + &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), + sys::Path(OutputFile), Timeout, MemoryLimit); +} + +// Custom execution environment create method, takes the execution command +// as arguments +AbstractInterpreter *AbstractInterpreter::createCustom( + std::string &Message, + const std::string &ExecCommandLine) { + + std::string Command = ""; + std::vector<std::string> Args; + std::string delimiters = " "; + + // Tokenize the ExecCommandLine to the command and the args to allow + // defining a full command line as the command instead of just the + // executed program. We cannot just pass the whole string after the command + // as a single argument because then program sees only a single + // command line argument (with spaces in it: "foo bar" instead + // of "foo" and "bar"). + + // code borrowed from: + // http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html + std::string::size_type lastPos = + ExecCommandLine.find_first_not_of(delimiters, 0); + std::string::size_type pos = + ExecCommandLine.find_first_of(delimiters, lastPos); + + while (std::string::npos != pos || std::string::npos != lastPos) { + std::string token = ExecCommandLine.substr(lastPos, pos - lastPos); + if (Command == "") + Command = token; + else + Args.push_back(token); + // Skip delimiters. Note the "not_of" + lastPos = ExecCommandLine.find_first_not_of(delimiters, pos); + // Find next "non-delimiter" + pos = ExecCommandLine.find_first_of(delimiters, lastPos); + } + + std::string CmdPath = sys::Program::FindProgramByName(Command).str(); + if (CmdPath.empty()) { + Message = + std::string("Cannot find '") + Command + + "' in executable directory or PATH!\n"; + return 0; + } + + Message = "Found command in: " + CmdPath + "\n"; + + return new CustomExecutor(CmdPath, Args); +} + +//===----------------------------------------------------------------------===// +// LLC Implementation of AbstractIntepreter interface +// +GCC::FileType LLC::OutputCode(const std::string &Bitcode, + sys::Path &OutputAsmFile, std::string &Error, + unsigned Timeout, unsigned MemoryLimit) { + const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); + sys::Path uniqueFile(Bitcode + Suffix); + std::string ErrMsg; + if (uniqueFile.makeUnique(true, &ErrMsg)) { + errs() << "Error making unique filename: " << ErrMsg << "\n"; + exit(1); + } + OutputAsmFile = uniqueFile; + std::vector<const char *> LLCArgs; + LLCArgs.push_back(LLCPath.c_str()); + + // Add any extra LLC args. + for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) + LLCArgs.push_back(ToolArgs[i].c_str()); + + LLCArgs.push_back("-o"); + LLCArgs.push_back(OutputAsmFile.c_str()); // Output to the Asm file + LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode + + if (UseIntegratedAssembler) + LLCArgs.push_back("-filetype=obj"); + + LLCArgs.push_back (0); + + outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>"); + outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i = 0, e = LLCArgs.size()-1; i != e; ++i) + errs() << " " << LLCArgs[i]; + errs() << "\n"; + ); + if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0], + sys::Path(), sys::Path(), sys::Path(), + Timeout, MemoryLimit)) + Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0], + Timeout, MemoryLimit); + return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; +} + +void LLC::compileProgram(const std::string &Bitcode, std::string *Error, + unsigned Timeout, unsigned MemoryLimit) { + sys::Path OutputAsmFile; + OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit); + OutputAsmFile.eraseFromDisk(); +} + +int LLC::ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &ArgsForGCC, + const std::vector<std::string> &SharedLibs, + unsigned Timeout, + unsigned MemoryLimit) { + + sys::Path OutputAsmFile; + GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, + MemoryLimit); + FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); + + std::vector<std::string> GCCArgs(ArgsForGCC); + GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); + + // Assuming LLC worked, compile the result with GCC and run it. + return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind, + InputFile, OutputFile, Error, GCCArgs, + Timeout, MemoryLimit); +} + +/// createLLC - Try to find the LLC executable +/// +LLC *AbstractInterpreter::createLLC(const char *Argv0, + std::string &Message, + const std::string &GCCBinary, + const std::vector<std::string> *Args, + const std::vector<std::string> *GCCArgs, + bool UseIntegratedAssembler) { + std::string LLCPath = + FindExecutable("llc", Argv0, (void *)(intptr_t)&createLLC).str(); + if (LLCPath.empty()) { + Message = "Cannot find `llc' in executable directory or PATH!\n"; + return 0; + } + + Message = "Found llc: " + LLCPath + "\n"; + GCC *gcc = GCC::create(Message, GCCBinary, GCCArgs); + if (!gcc) { + errs() << Message << "\n"; + exit(1); + } + return new LLC(LLCPath, gcc, Args, UseIntegratedAssembler); +} + +//===---------------------------------------------------------------------===// +// JIT Implementation of AbstractIntepreter interface +// +namespace { + class JIT : public AbstractInterpreter { + std::string LLIPath; // The path to the LLI executable + std::vector<std::string> ToolArgs; // Args to pass to LLI + public: + JIT(const std::string &Path, const std::vector<std::string> *Args) + : LLIPath(Path) { + ToolArgs.clear (); + if (Args) { ToolArgs = *Args; } + } + + virtual int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs = + std::vector<std::string>(), + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0); + }; +} + +int JIT::ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs, + const std::vector<std::string> &SharedLibs, + unsigned Timeout, + unsigned MemoryLimit) { + // Construct a vector of parameters, incorporating those from the command-line + std::vector<const char*> JITArgs; + JITArgs.push_back(LLIPath.c_str()); + JITArgs.push_back("-force-interpreter=false"); + + // Add any extra LLI args. + for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) + JITArgs.push_back(ToolArgs[i].c_str()); + + for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) { + JITArgs.push_back("-load"); + JITArgs.push_back(SharedLibs[i].c_str()); + } + JITArgs.push_back(Bitcode.c_str()); + // Add optional parameters to the running program from Argv + for (unsigned i=0, e = Args.size(); i != e; ++i) + JITArgs.push_back(Args[i].c_str()); + JITArgs.push_back(0); + + outs() << "<jit>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i) + errs() << " " << JITArgs[i]; + errs() << "\n"; + ); + DEBUG(errs() << "\nSending output to " << OutputFile << "\n"); + return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0], + sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), + Timeout, MemoryLimit); +} + +/// createJIT - Try to find the LLI executable +/// +AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0, + std::string &Message, const std::vector<std::string> *Args) { + std::string LLIPath = + FindExecutable("lli", Argv0, (void *)(intptr_t)&createJIT).str(); + if (!LLIPath.empty()) { + Message = "Found lli: " + LLIPath + "\n"; + return new JIT(LLIPath, Args); + } + + Message = "Cannot find `lli' in executable directory or PATH!\n"; + return 0; +} + +GCC::FileType CBE::OutputCode(const std::string &Bitcode, + sys::Path &OutputCFile, std::string &Error, + unsigned Timeout, unsigned MemoryLimit) { + sys::Path uniqueFile(Bitcode+".cbe.c"); + std::string ErrMsg; + if (uniqueFile.makeUnique(true, &ErrMsg)) { + errs() << "Error making unique filename: " << ErrMsg << "\n"; + exit(1); + } + OutputCFile = uniqueFile; + std::vector<const char *> LLCArgs; + LLCArgs.push_back(LLCPath.c_str()); + + // Add any extra LLC args. + for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) + LLCArgs.push_back(ToolArgs[i].c_str()); + + LLCArgs.push_back("-o"); + LLCArgs.push_back(OutputCFile.c_str()); // Output to the C file + LLCArgs.push_back("-march=c"); // Output C language + LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode + LLCArgs.push_back(0); + + outs() << "<cbe>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i = 0, e = LLCArgs.size()-1; i != e; ++i) + errs() << " " << LLCArgs[i]; + errs() << "\n"; + ); + if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(), + sys::Path(), Timeout, MemoryLimit)) + Error = ProcessFailure(LLCPath, &LLCArgs[0], Timeout, MemoryLimit); + return GCC::CFile; +} + +void CBE::compileProgram(const std::string &Bitcode, std::string *Error, + unsigned Timeout, unsigned MemoryLimit) { + sys::Path OutputCFile; + OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit); + OutputCFile.eraseFromDisk(); +} + +int CBE::ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &ArgsForGCC, + const std::vector<std::string> &SharedLibs, + unsigned Timeout, + unsigned MemoryLimit) { + sys::Path OutputCFile; + OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit); + + FileRemover CFileRemove(OutputCFile, !SaveTemps); + + std::vector<std::string> GCCArgs(ArgsForGCC); + GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); + + return gcc->ExecuteProgram(OutputCFile.str(), Args, GCC::CFile, + InputFile, OutputFile, Error, GCCArgs, + Timeout, MemoryLimit); +} + +/// createCBE - Try to find the 'llc' executable +/// +CBE *AbstractInterpreter::createCBE(const char *Argv0, + std::string &Message, + const std::string &GCCBinary, + const std::vector<std::string> *Args, + const std::vector<std::string> *GCCArgs) { + sys::Path LLCPath = + FindExecutable("llc", Argv0, (void *)(intptr_t)&createCBE); + if (LLCPath.isEmpty()) { + Message = + "Cannot find `llc' in executable directory or PATH!\n"; + return 0; + } + + Message = "Found llc: " + LLCPath.str() + "\n"; + GCC *gcc = GCC::create(Message, GCCBinary, GCCArgs); + if (!gcc) { + errs() << Message << "\n"; + exit(1); + } + return new CBE(LLCPath, gcc, Args); +} + +//===---------------------------------------------------------------------===// +// GCC abstraction +// + +static bool IsARMArchitecture(std::vector<std::string> Args) { + for (std::vector<std::string>::const_iterator + I = Args.begin(), E = Args.end(); I != E; ++I) { + if (StringRef(*I).equals_lower("-arch")) { + ++I; + if (I != E && StringRef(*I).substr(0, strlen("arm")).equals_lower("arm")) + return true; + } + } + + return false; +} + +int GCC::ExecuteProgram(const std::string &ProgramFile, + const std::vector<std::string> &Args, + FileType fileType, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &ArgsForGCC, + unsigned Timeout, + unsigned MemoryLimit) { + std::vector<const char*> GCCArgs; + + GCCArgs.push_back(GCCPath.c_str()); + + if (TargetTriple.getArch() == Triple::x86) + GCCArgs.push_back("-m32"); + + for (std::vector<std::string>::const_iterator + I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I) + GCCArgs.push_back(I->c_str()); + + // Specify -x explicitly in case the extension is wonky + if (fileType != ObjectFile) { + GCCArgs.push_back("-x"); + if (fileType == CFile) { + GCCArgs.push_back("c"); + GCCArgs.push_back("-fno-strict-aliasing"); + } else { + GCCArgs.push_back("assembler"); + + // For ARM architectures we don't want this flag. bugpoint isn't + // explicitly told what architecture it is working on, so we get + // it from gcc flags + if ((TargetTriple.getOS() == Triple::Darwin) && + !IsARMArchitecture(ArgsForGCC)) + GCCArgs.push_back("-force_cpusubtype_ALL"); + } + } + + GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename. + + GCCArgs.push_back("-x"); + GCCArgs.push_back("none"); + GCCArgs.push_back("-o"); + sys::Path OutputBinary (ProgramFile+".gcc.exe"); + std::string ErrMsg; + if (OutputBinary.makeUnique(true, &ErrMsg)) { + errs() << "Error making unique filename: " << ErrMsg << "\n"; + exit(1); + } + GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file... + + // Add any arguments intended for GCC. We locate them here because this is + // most likely -L and -l options that need to come before other libraries but + // after the source. Other options won't be sensitive to placement on the + // command line, so this should be safe. + for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i) + GCCArgs.push_back(ArgsForGCC[i].c_str()); + + GCCArgs.push_back("-lm"); // Hard-code the math library... + GCCArgs.push_back("-O2"); // Optimize the program a bit... +#if defined (HAVE_LINK_R) + GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files +#endif + if (TargetTriple.getArch() == Triple::sparc) + GCCArgs.push_back("-mcpu=v9"); + GCCArgs.push_back(0); // NULL terminator + + outs() << "<gcc>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i = 0, e = GCCArgs.size()-1; i != e; ++i) + errs() << " " << GCCArgs[i]; + errs() << "\n"; + ); + if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), + sys::Path())) { + *Error = ProcessFailure(GCCPath, &GCCArgs[0]); + return -1; + } + + std::vector<const char*> ProgramArgs; + + if (RemoteClientPath.isEmpty()) + ProgramArgs.push_back(OutputBinary.c_str()); + else { + ProgramArgs.push_back(RemoteClientPath.c_str()); + ProgramArgs.push_back(RemoteHost.c_str()); + if (!RemoteUser.empty()) { + ProgramArgs.push_back("-l"); + ProgramArgs.push_back(RemoteUser.c_str()); + } + if (!RemotePort.empty()) { + ProgramArgs.push_back("-p"); + ProgramArgs.push_back(RemotePort.c_str()); + } + if (!RemoteExtra.empty()) { + ProgramArgs.push_back(RemoteExtra.c_str()); + } + + // Full path to the binary. We need to cd to the exec directory because + // there is a dylib there that the exec expects to find in the CWD + char* env_pwd = getenv("PWD"); + std::string Exec = "cd "; + Exec += env_pwd; + Exec += "; ./"; + Exec += OutputBinary.c_str(); + ProgramArgs.push_back(Exec.c_str()); + } + + // Add optional parameters to the running program from Argv + for (unsigned i = 0, e = Args.size(); i != e; ++i) + ProgramArgs.push_back(Args[i].c_str()); + ProgramArgs.push_back(0); // NULL terminator + + // Now that we have a binary, run it! + outs() << "<program>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i = 0, e = ProgramArgs.size()-1; i != e; ++i) + errs() << " " << ProgramArgs[i]; + errs() << "\n"; + ); + + FileRemover OutputBinaryRemover(OutputBinary, !SaveTemps); + + if (RemoteClientPath.isEmpty()) { + DEBUG(errs() << "<run locally>"); + return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], + sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), + Timeout, MemoryLimit); + } else { + outs() << "<run remotely>"; outs().flush(); + return RunProgramRemotelyWithTimeout(sys::Path(RemoteClientPath), + &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), + sys::Path(OutputFile), Timeout, MemoryLimit); + } +} + +int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, + std::string &OutputFile, + const std::vector<std::string> &ArgsForGCC, + std::string &Error) { + sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT); + std::string ErrMsg; + if (uniqueFilename.makeUnique(true, &ErrMsg)) { + errs() << "Error making unique filename: " << ErrMsg << "\n"; + exit(1); + } + OutputFile = uniqueFilename.str(); + + std::vector<const char*> GCCArgs; + + GCCArgs.push_back(GCCPath.c_str()); + + if (TargetTriple.getArch() == Triple::x86) + GCCArgs.push_back("-m32"); + + for (std::vector<std::string>::const_iterator + I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I) + GCCArgs.push_back(I->c_str()); + + // Compile the C/asm file into a shared object + if (fileType != ObjectFile) { + GCCArgs.push_back("-x"); + GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c"); + } + GCCArgs.push_back("-fno-strict-aliasing"); + GCCArgs.push_back(InputFile.c_str()); // Specify the input filename. + GCCArgs.push_back("-x"); + GCCArgs.push_back("none"); + if (TargetTriple.getArch() == Triple::sparc) + GCCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc + else if (TargetTriple.getOS() == Triple::Darwin) { + // link all source files into a single module in data segment, rather than + // generating blocks. dynamic_lookup requires that you set + // MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for + // bugpoint to just pass that in the environment of GCC. + GCCArgs.push_back("-single_module"); + GCCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC + GCCArgs.push_back("-undefined"); + GCCArgs.push_back("dynamic_lookup"); + } else + GCCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others + + if ((TargetTriple.getArch() == Triple::alpha) || + (TargetTriple.getArch() == Triple::x86_64)) + GCCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC + + if (TargetTriple.getArch() == Triple::sparc) + GCCArgs.push_back("-mcpu=v9"); + + GCCArgs.push_back("-o"); + GCCArgs.push_back(OutputFile.c_str()); // Output to the right filename. + GCCArgs.push_back("-O2"); // Optimize the program a bit. + + + + // Add any arguments intended for GCC. We locate them here because this is + // most likely -L and -l options that need to come before other libraries but + // after the source. Other options won't be sensitive to placement on the + // command line, so this should be safe. + for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i) + GCCArgs.push_back(ArgsForGCC[i].c_str()); + GCCArgs.push_back(0); // NULL terminator + + + + outs() << "<gcc>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i = 0, e = GCCArgs.size()-1; i != e; ++i) + errs() << " " << GCCArgs[i]; + errs() << "\n"; + ); + if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), + sys::Path())) { + Error = ProcessFailure(GCCPath, &GCCArgs[0]); + return 1; + } + return 0; +} + +/// create - Try to find the `gcc' executable +/// +GCC *GCC::create(std::string &Message, + const std::string &GCCBinary, + const std::vector<std::string> *Args) { + sys::Path GCCPath = sys::Program::FindProgramByName(GCCBinary); + if (GCCPath.isEmpty()) { + Message = "Cannot find `"+ GCCBinary +"' in executable directory or PATH!\n"; + return 0; + } + + sys::Path RemoteClientPath; + if (!RemoteClient.empty()) + RemoteClientPath = sys::Program::FindProgramByName(RemoteClient); + + Message = "Found gcc: " + GCCPath.str() + "\n"; + return new GCC(GCCPath, RemoteClientPath, Args); +} diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.h b/contrib/llvm/tools/bugpoint/ToolRunner.h new file mode 100644 index 0000000..d966fc0 --- /dev/null +++ b/contrib/llvm/tools/bugpoint/ToolRunner.h @@ -0,0 +1,242 @@ +//===-- 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 BUGPOINT_TOOLRUNNER_H +#define BUGPOINT_TOOLRUNNER_H + +#include "llvm/ADT/Triple.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/System/Path.h" +#include <exception> +#include <vector> + +namespace llvm { + +extern cl::opt<bool> SaveTemps; +extern Triple TargetTriple; + +class CBE; +class LLC; + +//===---------------------------------------------------------------------===// +// GCC abstraction +// +class GCC { + sys::Path GCCPath; // The path to the gcc executable. + sys::Path RemoteClientPath; // The path to the rsh / ssh executable. + std::vector<std::string> gccArgs; // GCC-specific arguments. + GCC(const sys::Path &gccPath, const sys::Path &RemotePath, + const std::vector<std::string> *GCCArgs) + : GCCPath(gccPath), RemoteClientPath(RemotePath) { + if (GCCArgs) gccArgs = *GCCArgs; + } +public: + enum FileType { AsmFile, ObjectFile, CFile }; + + static GCC *create(std::string &Message, + const std::string &GCCBinary, + 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. + /// + int ExecuteProgram(const std::string &ProgramFile, + const std::vector<std::string> &Args, + FileType fileType, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error = 0, + const std::vector<std::string> &GCCArgs = + 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. + /// + int MakeSharedObject(const std::string &InputFile, FileType fileType, + std::string &OutputFile, + const std::vector<std::string> &ArgsForGCC, + std::string &Error); +}; + + +//===---------------------------------------------------------------------===// +/// 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 { +public: + static CBE *createCBE(const char *Argv0, std::string &Message, + const std::string &GCCBinary, + const std::vector<std::string> *Args = 0, + const std::vector<std::string> *GCCArgs = 0); + static LLC *createLLC(const char *Argv0, std::string &Message, + const std::string &GCCBinary, + const std::vector<std::string> *Args = 0, + const std::vector<std::string> *GCCArgs = 0, + bool UseIntegratedAssembler = false); + + static AbstractInterpreter* createLLI(const char *Argv0, std::string &Message, + const std::vector<std::string> *Args=0); + + static AbstractInterpreter* createJIT(const char *Argv0, std::string &Message, + const std::vector<std::string> *Args=0); + + static AbstractInterpreter* createCustom(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 void compileProgram(const std::string &Bitcode, std::string *Error, + unsigned Timeout = 0, unsigned MemoryLimit = 0) {} + + /// OutputCode - Compile the specified program from bitcode to code + /// understood by the GCC driver (either C or asm). If the code generator + /// fails, it sets Error, otherwise, this function returns the type of code + /// emitted. + virtual GCC::FileType OutputCode(const std::string &Bitcode, + sys::Path &OutFile, std::string &Error, + unsigned Timeout = 0, + unsigned MemoryLimit = 0) { + Error = "OutputCode not supported by this AbstractInterpreter!"; + return GCC::AsmFile; + } + + /// ExecuteProgram - Run the specified bitcode file, emitting output to the + /// specified filename. This sets RetVal to the exit code of the program or + /// returns false if a problem was encountered that prevented execution of + /// the program. + /// + virtual int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs = + std::vector<std::string>(), + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0) = 0; +}; + +//===---------------------------------------------------------------------===// +// CBE Implementation of AbstractIntepreter interface +// +class CBE : public AbstractInterpreter { + sys::Path LLCPath; // The path to the `llc' executable. + std::vector<std::string> ToolArgs; // Extra args to pass to LLC. + GCC *gcc; +public: + CBE(const sys::Path &llcPath, GCC *Gcc, + const std::vector<std::string> *Args) + : LLCPath(llcPath), gcc(Gcc) { + ToolArgs.clear (); + if (Args) ToolArgs = *Args; + } + ~CBE() { delete gcc; } + + /// 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. + virtual void compileProgram(const std::string &Bitcode, std::string *Error, + unsigned Timeout = 0, unsigned MemoryLimit = 0); + + virtual int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs = + std::vector<std::string>(), + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0); + + /// OutputCode - Compile the specified program from bitcode to code + /// understood by the GCC driver (either C or asm). If the code generator + /// fails, it sets Error, otherwise, this function returns the type of code + /// emitted. + virtual GCC::FileType OutputCode(const std::string &Bitcode, + sys::Path &OutFile, std::string &Error, + unsigned Timeout = 0, + unsigned MemoryLimit = 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. + GCC *gcc; + bool UseIntegratedAssembler; +public: + LLC(const std::string &llcPath, GCC *Gcc, + const std::vector<std::string> *Args, + bool useIntegratedAssembler) + : LLCPath(llcPath), gcc(Gcc), + UseIntegratedAssembler(useIntegratedAssembler) { + ToolArgs.clear(); + if (Args) ToolArgs = *Args; + } + ~LLC() { delete gcc; } + + /// 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. + virtual void compileProgram(const std::string &Bitcode, std::string *Error, + unsigned Timeout = 0, unsigned MemoryLimit = 0); + + virtual int ExecuteProgram(const std::string &Bitcode, + const std::vector<std::string> &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector<std::string> &GCCArgs = + std::vector<std::string>(), + const std::vector<std::string> &SharedLibs = + std::vector<std::string>(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0); + + /// OutputCode - Compile the specified program from bitcode to code + /// understood by the GCC driver (either C or asm). If the code generator + /// fails, it sets Error, otherwise, this function returns the type of code + /// emitted. + virtual GCC::FileType OutputCode(const std::string &Bitcode, + sys::Path &OutFile, std::string &Error, + unsigned Timeout = 0, + unsigned MemoryLimit = 0); +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm/tools/bugpoint/bugpoint.cpp new file mode 100644 index 0000000..ba5234b --- /dev/null +++ b/contrib/llvm/tools/bugpoint/bugpoint.cpp @@ -0,0 +1,159 @@ +//===- 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/LinkAllPasses.h" +#include "llvm/LLVMContext.h" +#include "llvm/Support/PassNameParser.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PluginLoader.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/StandardPasses.h" +#include "llvm/System/Process.h" +#include "llvm/System/Signals.h" +#include "llvm/System/Valgrind.h" +#include "llvm/LinkAllVMCore.h" +using namespace llvm; + +// AsChild - Specifies that this invocation of bugpoint is being generated +// from a parent process. It is not intended to be used by users so the +// option is hidden. +static cl::opt<bool> +AsChild("as-child", cl::desc("Run bugpoint as child process"), + cl::ReallyHidden); + +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 100MB (800MB under valgrind).")); + +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> +StandardCompileOpts("std-compile-opts", + cl::desc("Include the standard compile time optimizations")); + +static cl::opt<bool> +StandardLinkOpts("std-link-opts", + cl::desc("Include the standard link time optimizations")); + +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; + +static void BugpointInterruptFunction() { + BugpointIsInterrupted = true; +} + +// Hack to capture a pass list. +namespace { + class AddToDriver : public PassManager { + BugDriver &D; + public: + AddToDriver(BugDriver &_D) : D(_D) {} + + virtual void add(Pass *P) { + const PassInfo *PI = P->getPassInfo(); + D.addPasses(&PI, &PI + 1); + } + }; +} + +int main(int argc, char **argv) { + llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + cl::ParseCommandLineOptions(argc, argv, + "LLVM automatic testcase reducer. See\nhttp://" + "llvm.org/cmds/bugpoint.html" + " for more information.\n"); + sys::SetInterruptFunction(BugpointInterruptFunction); + + LLVMContext& Context = getGlobalContext(); + // If we have an override, set it and then track the triple we want Modules + // to use. + if (!OverrideTriple.empty()) { + TargetTriple.setTriple(OverrideTriple); + outs() << "Override triple set to '" << OverrideTriple << "'\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 = 100; + } + + BugDriver D(argv[0], AsChild, FindBugs, TimeoutValue, MemoryLimit, + UseValgrind, Context); + if (D.addSources(InputFilenames)) return 1; + + AddToDriver PM(D); + if (StandardCompileOpts) { + createStandardModulePasses(&PM, 3, + /*OptimizeSize=*/ false, + /*UnitAtATime=*/ true, + /*UnrollLoops=*/ true, + /*SimplifyLibCalls=*/ true, + /*HaveExceptions=*/ true, + createFunctionInliningPass()); + } + + if (StandardLinkOpts) + createStandardLTOPasses(&PM, /*Internalize=*/true, + /*RunInliner=*/true, + /*VerifyEach=*/false); + + D.addPasses(PassList.begin(), PassList.end()); + + // Bugpoint has the ability of generating a plethora of core files, so to + // avoid filling up the disk, we prevent it + sys::Process::PreventCoreFiles(); + + std::string Error; + bool Failure = D.run(Error); + if (!Error.empty()) { + errs() << Error; + return 1; + } + return Failure; +} |