diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-05-04 16:11:02 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-05-04 16:11:02 +0000 |
commit | 750ce4d809c7e2a298a389a512a17652ff5be3f2 (patch) | |
tree | 70fbd90da02177c8e6ef82adba9fa8ace285a5e3 /tools | |
parent | 5f970ec96e421f64db6b1c6509a902ea73d98cc7 (diff) | |
download | FreeBSD-src-750ce4d809c7e2a298a389a512a17652ff5be3f2.zip FreeBSD-src-750ce4d809c7e2a298a389a512a17652ff5be3f2.tar.gz |
Update LLVM to r103004.
Diffstat (limited to 'tools')
43 files changed, 1152 insertions, 669 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 8b5d77e..b9c77b1 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -31,6 +31,7 @@ add_subdirectory(llvm-extract) add_subdirectory(bugpoint) add_subdirectory(llvm-bcanalyzer) add_subdirectory(llvm-stub) +add_subdirectory(edis) add_subdirectory(llvmc) if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/clang/CMakeLists.txt ) diff --git a/tools/Makefile b/tools/Makefile index e124422..9d2e576 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -15,13 +15,16 @@ OPTIONAL_PARALLEL_DIRS := clang # NOTE: The tools are organized into five groups of four consisting of one # large and three small executables. This is done to minimize memory load # in parallel builds. Please retain this ordering. -DIRS := llvm-config + +# libEnhancedDisassembly must be built ahead of llvm-mc +# because llvm-mc links against libEnhancedDisassembly +DIRS := llvm-config edis llvm-mc PARALLEL_DIRS := opt llvm-as llvm-dis \ llc llvm-ranlib llvm-ar llvm-nm \ llvm-ld llvm-prof llvm-link \ lli llvm-extract \ bugpoint llvm-bcanalyzer llvm-stub \ - llvm-mc llvmc + llvmc # Let users override the set of tools to build from the command line. ifdef ONLY_TOOLS @@ -36,8 +39,6 @@ include $(LEVEL)/Makefile.config ifeq ($(ENABLE_PIC),1) # No support for dynamic libraries on windows targets. ifneq ($(TARGET_OS), $(filter $(TARGET_OS), Cygwin MingW)) - PARALLEL_DIRS += edis - # gold only builds if binutils is around. It requires "lto" to build before # it so it is added to DIRS. ifdef BINUTILS_INCDIR @@ -48,11 +49,6 @@ ifeq ($(ENABLE_PIC),1) endif endif -# Only build edis if X86 target support is enabled. -ifeq ($(filter $(TARGETS_TO_BUILD), X86),) - PARALLEL_DIRS := $(filter-out edis, $(PARALLEL_DIRS)) -endif - # Don't build edis if we explicitly disabled it. ifeq ($(DISABLE_EDIS),1) PARALLEL_DIRS := $(filter-out edis, $(PARALLEL_DIRS)) diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index d676a43..45a0d4d 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -115,30 +115,25 @@ 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!"); - try { - // Load the first input file. - Program = ParseInputFile(Filenames[0], Context); - if (Program == 0) return true; + // 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"; + 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; + 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() << "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; } - } catch (const std::string &Error) { - errs() << ToolName << ": error reading input '" << Error << "'\n"; - return true; } if (!run_as_child) @@ -153,7 +148,7 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { /// run - The top level method that is invoked after all of the instance /// variables are set up from command line arguments. /// -bool BugDriver::run() { +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. @@ -165,7 +160,7 @@ bool BugDriver::run() { if (run_find_bugs) { // Rearrange the passes and apply them to the program. Repeat this process // until the user kills the program or we find a bug. - return runManyPasses(PassesToRun); + return runManyPasses(PassesToRun, ErrMsg); } // If we're not running as a child, the first thing that we must do is @@ -186,14 +181,13 @@ bool BugDriver::run() { // Test to see if we have a code generator crash. outs() << "Running the code generator to test for a crash: "; - try { - compileProgram(Program); - outs() << '\n'; - } catch (ToolExecutionError &TEE) { - outs() << TEE.what(); - return debugCodeGeneratorCrash(); + 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 @@ -202,8 +196,8 @@ bool BugDriver::run() { bool CreatedOutput = false; if (ReferenceOutputFile.empty()) { outs() << "Generating reference output from raw program: "; - if(!createReferenceFile(Program)){ - return debugCodeGeneratorCrash(); + if (!createReferenceFile(Program)) { + return debugCodeGeneratorCrash(ErrMsg); } CreatedOutput = true; } @@ -217,24 +211,29 @@ bool BugDriver::run() { // matches, then we assume there is a miscompilation bug and try to // diagnose it. outs() << "*** Checking the code generator...\n"; - try { - if (!diffProgram()) { - outs() << "\n*** Output matches: Debugging miscompilation!\n"; - return debugMiscompilation(); + 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); } - } catch (ToolExecutionError &TEE) { - errs() << TEE.what(); - return debugCodeGeneratorCrash(); + return false; } outs() << "\n*** Input program does not match reference diff!\n"; outs() << "Debugging code generator problem!\n"; - try { - return debugCodeGenerator(); - } catch (ToolExecutionError &TEE) { - errs() << TEE.what(); - return debugCodeGeneratorCrash(); + bool Failure = debugCodeGenerator(&Error); + if (!Error.empty()) { + errs() << Error; + return debugCodeGeneratorCrash(ErrMsg); } + return Failure; } void llvm::PrintFunctionList(const std::vector<Function*> &Funcs) { diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index abc2498..e5b7373 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -88,7 +88,7 @@ public: /// 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(); + 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 @@ -99,12 +99,12 @@ public: /// 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(); + 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. - bool debugMiscompilation(); + 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 @@ -118,12 +118,13 @@ public: /// compileSharedObject - This method creates a SharedObject from a given /// BitcodeFile for debugging a code generator. /// - std::string compileSharedObject(const std::string &BitcodeFile); + 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(); + bool debugCodeGenerator(std::string *Error); /// isExecutingJIT - Returns true if bugpoint is currently testing the JIT /// @@ -164,28 +165,27 @@ public: /// the specified one as the current program. void setNewProgram(Module *M); - /// compileProgram - Try to compile the specified module, throwing an - /// exception if an error occurs, or returning normally if not. This is used - /// for code generation crash testing. + /// 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); + void compileProgram(Module *M, std::string *Error); /// 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. If there is a problem with the code - /// generator (e.g., llc crashes), this will throw an exception. + /// program to a file. A recommended filename may be optionally specified. /// - std::string executeProgram(std::string RequestedOutputFilename = "", - std::string Bitcode = "", - const std::string &SharedObjects = "", - AbstractInterpreter *AI = 0, - bool *ProgramExitedNonzero = 0); + 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 throw an exception. + /// the code generator (e.g., llc crashes), this will return false and set + /// Error. /// - std::string executeProgramSafely(std::string OutputFile = ""); + 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 @@ -197,13 +197,14 @@ public: /// diffProgram - This method executes the specified module and diffs the /// output against the file specified by ReferenceOutputFile. If the output - /// is different, true is returned. If there is a problem with the code - /// generator (e.g., llc crashes), this will throw an exception. + /// 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); - + bool RemoveBitcode = false, + std::string *Error = 0); + /// EmitProgressBitcode - This function is used to output the current Program /// to a file named "bugpoint-ID.bc". /// @@ -267,7 +268,8 @@ public: /// 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); + 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. diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt index 90f24ba..34b759f 100644 --- a/tools/bugpoint/CMakeLists.txt +++ b/tools/bugpoint/CMakeLists.txt @@ -1,6 +1,5 @@ set(LLVM_LINK_COMPONENTS asmparser instrumentation scalaropts ipo linker bitreader bitwriter) -set(LLVM_REQUIRES_EH 1) add_llvm_tool(bugpoint BugDriver.cpp diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index b51bdb4..46b33d2 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -53,13 +53,15 @@ namespace llvm { // 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::vector<const PassInfo*> &Kept, + std::string &Error); }; } ReducePassList::TestResult ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix) { + std::vector<const PassInfo*> &Suffix, + std::string &Error) { sys::Path PrefixOutput; Module *OrigProgram = 0; if (!Prefix.empty()) { @@ -107,27 +109,26 @@ namespace { bool (*TestFn)(BugDriver &, Module *); public: ReduceCrashingGlobalVariables(BugDriver &bd, - bool (*testFn)(BugDriver&, Module*)) + bool (*testFn)(BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} - virtual TestResult doTest(std::vector<GlobalVariable*>& Prefix, - std::vector<GlobalVariable*>& Kept) { + 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 TestGlobalVariables(std::vector<GlobalVariable*> &GVs); }; } bool ReduceCrashingGlobalVariables::TestGlobalVariables( - std::vector<GlobalVariable*>& GVs) { + std::vector<GlobalVariable*> &GVs) { // Clone the program to try hacking it apart... DenseMap<const Value*, Value*> ValueMap; Module *M = CloneModule(BD.getProgram(), ValueMap); @@ -182,7 +183,8 @@ namespace llvm { : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<Function*> &Prefix, - std::vector<Function*> &Kept) { + std::vector<Function*> &Kept, + std::string &Error) { if (!Kept.empty() && TestFuncs(Kept)) return KeepSuffix; if (!Prefix.empty() && TestFuncs(Prefix)) @@ -253,7 +255,8 @@ namespace { : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<const BasicBlock*> &Prefix, - std::vector<const BasicBlock*> &Kept) { + std::vector<const BasicBlock*> &Kept, + std::string &Error) { if (!Kept.empty() && TestBlocks(Kept)) return KeepSuffix; if (!Prefix.empty() && TestBlocks(Prefix)) @@ -355,7 +358,8 @@ namespace { : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<const Instruction*> &Prefix, - std::vector<const Instruction*> &Kept) { + std::vector<const Instruction*> &Kept, + std::string &Error) { if (!Kept.empty() && TestInsts(Kept)) return KeepSuffix; if (!Prefix.empty() && TestInsts(Prefix)) @@ -421,7 +425,8 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> /// 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 *)) { +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 && @@ -464,7 +469,9 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { << "variables in the testcase\n"; unsigned OldSize = GVs.size(); - ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs); + ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error); + if (!Error.empty()) + return true; if (GVs.size() < OldSize) BD.EmitProgressBitcode("reduced-global-variables"); @@ -485,7 +492,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { "in the testcase\n"; unsigned OldSize = Functions.size(); - ReduceCrashingFunctions(BD, TestFn).reduceList(Functions); + ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error); if (Functions.size() < OldSize) BD.EmitProgressBitcode("reduced-function"); @@ -503,7 +510,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { 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); + ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); if (Blocks.size() < OldSize) BD.EmitProgressBitcode("reduced-blocks"); } @@ -521,7 +528,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { if (!isa<TerminatorInst>(I)) Insts.push_back(I); - ReduceCrashingInstructions(BD, TestFn).reduceList(Insts); + ReduceCrashingInstructions(BD, TestFn).reduceList(Insts, Error); } // FIXME: This should use the list reducer to converge faster by deleting @@ -614,9 +621,11 @@ static bool TestForOptimizerCrash(BugDriver &BD, Module *M) { 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); + ReducePassList(*this).reduceList(PassesToRun, Error); + assert(Error.empty()); outs() << "\n*** Found crashing pass" << (PassesToRun.size() == 1 ? ": " : "es: ") @@ -624,25 +633,27 @@ bool BugDriver::debugOptimizerCrash(const std::string &ID) { EmitProgressBitcode(ID); - return DebugACrash(*this, TestForOptimizerCrash); + bool Success = DebugACrash(*this, TestForOptimizerCrash, Error); + assert(Error.empty()); + return Success; } static bool TestForCodeGenCrash(BugDriver &BD, Module *M) { - try { - BD.compileProgram(M); - errs() << '\n'; - return false; - } catch (ToolExecutionError &) { + 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() { +bool BugDriver::debugCodeGeneratorCrash(std::string &Error) { errs() << "*** Debugging code generator crash!\n"; - return DebugACrash(*this, TestForCodeGenCrash); + return DebugACrash(*this, TestForCodeGenCrash, Error); } diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index 7228c01..9eb3314 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -278,15 +278,15 @@ bool BugDriver::initializeExecutionEnvironment() { return Interpreter == 0; } -/// compileProgram - Try to compile the specified module, throwing an exception -/// if an error occurs, or returning normally if not. This is used for code -/// generation crash testing. +/// 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) { +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)) { + if (BitcodeFile.makeUnique(true, &ErrMsg)) { errs() << ToolName << ": Error making unique filename: " << ErrMsg << "\n"; exit(1); @@ -297,11 +297,11 @@ void BugDriver::compileProgram(Module *M) { exit(1); } - // Remove the temporary bitcode file when we are done. + // Remove the temporary bitcode file when we are done. FileRemover BitcodeFileRemover(BitcodeFile, !SaveTemps); // Actually compile the program! - Interpreter->compileProgram(BitcodeFile.str()); + Interpreter->compileProgram(BitcodeFile.str(), Error); } @@ -313,7 +313,7 @@ std::string BugDriver::executeProgram(std::string OutputFile, std::string BitcodeFile, const std::string &SharedObj, AbstractInterpreter *AI, - bool *ProgramExitedNonzero) { + std::string *Error) { if (AI == 0) AI = Interpreter; assert(AI && "Interpreter should have been created already!"); bool CreatedBitcode = false; @@ -337,7 +337,7 @@ std::string BugDriver::executeProgram(std::string OutputFile, } // Remove the temporary bitcode file when we are done. - sys::Path BitcodePath (BitcodeFile); + sys::Path BitcodePath(BitcodeFile); FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps); if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output"; @@ -356,9 +356,11 @@ std::string BugDriver::executeProgram(std::string OutputFile, if (!SharedObj.empty()) SharedObjs.push_back(SharedObj); - int RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile, - OutputFile, AdditionalLinkerArgs, SharedObjs, + int RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile, OutputFile, + Error, AdditionalLinkerArgs, SharedObjs, Timeout, MemoryLimit); + if (!Error->empty()) + return OutputFile; if (RetVal == -1) { errs() << "<timeout>"; @@ -379,9 +381,6 @@ std::string BugDriver::executeProgram(std::string OutputFile, outFile.close(); } - if (ProgramExitedNonzero != 0) - *ProgramExitedNonzero = (RetVal != 0); - // Return the filename we captured the output to. return OutputFile; } @@ -389,23 +388,28 @@ std::string BugDriver::executeProgram(std::string OutputFile, /// executeProgramSafely - Used to create reference output with the "safe" /// backend, if reference output is not provided. /// -std::string BugDriver::executeProgramSafely(std::string OutputFile) { - bool ProgramExitedNonzero; - std::string outFN = executeProgram(OutputFile, "", "", SafeInterpreter, - &ProgramExitedNonzero); - return outFN; +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 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); + GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile, + Error); + if (!Error.empty()) + return ""; std::string SharedObjectFile; - if (gcc->MakeSharedObject(OutputFile.str(), FT, - SharedObjectFile, AdditionalLinkerArgs)) + bool Failure = gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile, + AdditionalLinkerArgs, Error); + if (!Error.empty()) + return ""; + if (Failure) exit(1); // Remove the intermediate C file @@ -420,16 +424,14 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile) { /// this function. /// bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { - try { - compileProgram(Program); - } catch (ToolExecutionError &) { + std::string Error; + compileProgram(Program, &Error); + if (!Error.empty()) return false; - } - try { - ReferenceOutputFile = executeProgramSafely(Filename); - outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n"; - } catch (ToolExecutionError &TEE) { - errs() << TEE.what(); + + 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," @@ -438,22 +440,23 @@ bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { } 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, true is returned. If there is a problem with the code -/// generator (e.g., llc crashes), this will throw an exception. +/// 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) { - bool ProgramExitedNonzero; - + bool RemoveBitcode, + std::string *ErrMsg) { // Execute the program, generating an output file... - sys::Path Output(executeProgram("", BitcodeFile, SharedObject, 0, - &ProgramExitedNonzero)); + sys::Path Output(executeProgram("", BitcodeFile, SharedObject, 0, ErrMsg)); + if (!ErrMsg->empty()) + return false; std::string Error; bool FilesDifferent = false; diff --git a/tools/bugpoint/FindBugs.cpp b/tools/bugpoint/FindBugs.cpp index 2c11d29..224c717 100644 --- a/tools/bugpoint/FindBugs.cpp +++ b/tools/bugpoint/FindBugs.cpp @@ -29,7 +29,8 @@ using namespace llvm; /// 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) { +bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses, + std::string &ErrMsg) { setPassesToRun(AllPasses); outs() << "Starting bug finding procedure...\n\n"; @@ -57,7 +58,7 @@ bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses) { // outs() << "Running selected passes on program to test for crash: "; for(int i = 0, e = PassesToRun.size(); i != e; i++) { - outs() << "-" << PassesToRun[i]->getPassArgument( )<< " "; + outs() << "-" << PassesToRun[i]->getPassArgument() << " "; } std::string Filename; @@ -74,33 +75,33 @@ bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses) { // Step 3: Compile the optimized code. // outs() << "Running the code generator to test for a crash: "; - try { - compileProgram(Program); - outs() << '\n'; - } catch (ToolExecutionError &TEE) { + std::string Error; + compileProgram(Program, &Error); + if (!Error.empty()) { outs() << "\n*** compileProgram threw an exception: "; - outs() << TEE.what(); - return debugCodeGeneratorCrash(); + 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"; - try { - if (diffProgram(Filename, "", false)) { - outs() << "\n*** diffProgram returned true!\n"; - debugMiscompilation(); + bool Diff = diffProgram(Filename, "", false, &Error); + if (Error.empty() && Diff) { + outs() << "\n*** diffProgram returned true!\n"; + debugMiscompilation(&Error); + if (Error.empty()) return true; - } else { - outs() << "\n*** diff'd output matches!\n"; - } - } catch (ToolExecutionError &TEE) { - errs() << TEE.what(); - debugCodeGeneratorCrash(); + } + if (!Error.empty()) { + errs() << Error; + debugCodeGeneratorCrash(ErrMsg); return true; } + outs() << "\n*** diff'd output matches!\n"; sys::Path(Filename).eraseFromDisk(); diff --git a/tools/bugpoint/ListReducer.h b/tools/bugpoint/ListReducer.h index 8036d1f..5e9cff0 100644 --- a/tools/bugpoint/ListReducer.h +++ b/tools/bugpoint/ListReducer.h @@ -16,6 +16,7 @@ #define BUGPOINT_LIST_REDUCER_H #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" #include <vector> #include <cstdlib> #include <algorithm> @@ -29,7 +30,8 @@ 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 + KeepPrefix, // The prefix alone satisfies the predicate + InternalError // Encountered an error trying to run the predicate }; virtual ~ListReducer() {} @@ -40,16 +42,17 @@ struct ListReducer { // the prefix anyway, it can. // virtual TestResult doTest(std::vector<ElTy> &Prefix, - std::vector<ElTy> &Kept) = 0; + 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) { + 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)) { + switch (doTest(TheList, empty, Error)) { case KeepPrefix: if (TheList.size() == 1) // we are done, it's the base case and it fails return true; @@ -58,11 +61,15 @@ struct ListReducer { case KeepSuffix: // cannot be reached! - errs() << "bugpoint ListReducer internal error: selected empty set.\n"; - abort(); + 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, @@ -90,7 +97,7 @@ Backjump: 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) == KeepPrefix) { + if (doTest(ShuffledList, empty, Error) == KeepPrefix) { // If the bug is still here, use the shuffled list. TheList.swap(ShuffledList); MidTop = TheList.size(); @@ -109,7 +116,7 @@ Backjump: std::vector<ElTy> Prefix(TheList.begin(), TheList.begin()+Mid); std::vector<ElTy> Suffix(TheList.begin()+Mid, TheList.end()); - switch (doTest(Prefix, Suffix)) { + 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. @@ -133,7 +140,10 @@ Backjump: 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 @@ -167,12 +177,14 @@ Backjump: std::vector<ElTy> TestList(TheList); TestList.erase(TestList.begin()+i); - if (doTest(EmptyList, TestList) == KeepSuffix) { + 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. diff --git a/tools/bugpoint/Makefile b/tools/bugpoint/Makefile index b821b6c..5d287ef 100644 --- a/tools/bugpoint/Makefile +++ b/tools/bugpoint/Makefile @@ -12,6 +12,5 @@ TOOLNAME = bugpoint LINK_COMPONENTS := asmparser instrumentation scalaropts ipo \ linker bitreader bitwriter -REQUIRES_EH := 1 include $(LEVEL)/Makefile.common diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index c2b002f..45bb745 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -49,7 +49,8 @@ namespace { ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {} virtual TestResult doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix); + std::vector<const PassInfo*> &Suffix, + std::string &Error); }; } @@ -58,7 +59,8 @@ namespace { /// ReduceMiscompilingPasses::TestResult ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix) { + 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) @@ -74,7 +76,11 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, } // Check to see if the finished program matches the reference output... - if (BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/)) { + 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 " @@ -107,7 +113,10 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, } // If the prefix maintains the predicate by itself, only keep the prefix! - if (BD.diffProgram(BitcodeResult)) { + Diff = BD.diffProgram(BitcodeResult, "", false, &Error); + if (!Error.empty()) + return InternalError; + if (Diff) { outs() << " nope.\n"; sys::Path(BitcodeResult).eraseFromDisk(); return KeepPrefix; @@ -143,7 +152,10 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, } // Run the result... - if (BD.diffProgram(BitcodeResult, "", true/*delete bitcode*/)) { + Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, &Error); + if (!Error.empty()) + return InternalError; + if (Diff) { outs() << " nope.\n"; delete OriginalInput; // We pruned down the original input... return KeepSuffix; @@ -158,22 +170,34 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, namespace { class ReduceMiscompilingFunctions : public ListReducer<Function*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *, Module *); + bool (*TestFn)(BugDriver &, Module *, Module *, std::string &); public: ReduceMiscompilingFunctions(BugDriver &bd, - bool (*F)(BugDriver &, Module *, Module *)) + bool (*F)(BugDriver &, Module *, Module *, + std::string &)) : BD(bd), TestFn(F) {} virtual TestResult doTest(std::vector<Function*> &Prefix, - std::vector<Function*> &Suffix) { - if (!Suffix.empty() && TestFuncs(Suffix)) - return KeepSuffix; - if (!Prefix.empty() && TestFuncs(Prefix)) - return KeepPrefix; + 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; } - bool TestFuncs(const std::vector<Function*> &Prefix); + int TestFuncs(const std::vector<Function*> &Prefix, std::string &Error); }; } @@ -184,7 +208,7 @@ namespace { /// returns. /// static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, - bool DeleteInputs) { + bool DeleteInputs, std::string &Error) { // Link the two portions of the program back to together. std::string ErrorMsg; if (!DeleteInputs) { @@ -202,11 +226,12 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, // Execute the program. If it does not match the expected output, we must // return true. - bool Broken = BD.diffProgram(); - - // Delete the linked module & restore the original - BD.swapProgramIn(OldProgram); - delete M1; + bool Broken = BD.diffProgram("", "", false, &Error); + if (!Error.empty()) { + // Delete the linked module & restore the original + BD.swapProgramIn(OldProgram); + delete M1; + } return Broken; } @@ -214,7 +239,8 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, /// under consideration for miscompilation vs. those that are not, and test /// accordingly. Each group of functions becomes a separate Module. /// -bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*>&Funcs){ +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 " @@ -231,7 +257,7 @@ bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*>&Funcs){ ValueMap); // Run the predicate, note that the predicate will delete both input modules. - return TestFn(BD, ToOptimize, ToNotOptimize); + return TestFn(BD, ToOptimize, ToNotOptimize, Error); } /// DisambiguateGlobalSymbols - Give anonymous global values names. @@ -251,8 +277,10 @@ static void DisambiguateGlobalSymbols(Module *M) { /// bug. If so, it reduces the amount of code identified. /// static bool ExtractLoops(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *), - std::vector<Function*> &MiscompiledFunctions) { + bool (*TestFn)(BugDriver &, Module *, Module *, + std::string &), + std::vector<Function*> &MiscompiledFunctions, + std::string &Error) { bool MadeChange = false; while (1) { if (BugpointIsInterrupted) return MadeChange; @@ -279,7 +307,11 @@ static bool ExtractLoops(BugDriver &BD, // has broken. If something broke, then we'll inform the user and stop // extraction. AbstractInterpreter *AI = BD.switchToSafeInterpreter(); - if (TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, false)) { + bool Failure = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, + false, Error); + if (!Error.empty()) + return false; + if (Failure) { BD.switchToInterpreter(AI); // Merged program doesn't work anymore! @@ -308,7 +340,10 @@ static bool ExtractLoops(BugDriver &BD, // Clone modules, the tester function will free them. Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); Module *TNOBackup = CloneModule(ToNotOptimize); - if (!TestFn(BD, ToOptimizeLoopExtracted, 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. @@ -361,31 +396,44 @@ static bool ExtractLoops(BugDriver &BD, namespace { class ReduceMiscompiledBlocks : public ListReducer<BasicBlock*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *, Module *); + bool (*TestFn)(BugDriver &, Module *, Module *, std::string &); std::vector<Function*> FunctionsBeingTested; public: ReduceMiscompiledBlocks(BugDriver &bd, - bool (*F)(BugDriver &, Module *, Module *), + 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) { - if (!Suffix.empty() && TestFuncs(Suffix)) - return KeepSuffix; - if (TestFuncs(Prefix)) - return KeepPrefix; + 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*> &Prefix); + 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) { +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 "; @@ -411,7 +459,7 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs) { 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); + return TestFn(BD, New, ToNotOptimize, Error); } delete ToOptimize; delete ToNotOptimize; @@ -424,8 +472,10 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs) { /// the bug. /// static bool ExtractBlocks(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *), - std::vector<Function*> &MiscompiledFunctions) { + bool (*TestFn)(BugDriver &, Module *, Module *, + std::string &), + std::vector<Function*> &MiscompiledFunctions, + std::string &Error) { if (BugpointIsInterrupted) return false; std::vector<BasicBlock*> Blocks; @@ -440,11 +490,17 @@ static bool ExtractBlocks(BugDriver &BD, unsigned OldSize = Blocks.size(); // Check to see if all blocks are extractible first. - if (ReduceMiscompiledBlocks(BD, TestFn, - MiscompiledFunctions).TestFuncs(std::vector<BasicBlock*>())) { + 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); + ReduceMiscompiledBlocks(BD, TestFn, + MiscompiledFunctions).reduceList(Blocks, Error); + if (!Error.empty()) + return false; if (Blocks.size() == OldSize) return false; } @@ -505,7 +561,9 @@ static bool ExtractBlocks(BugDriver &BD, /// static std::vector<Function*> DebugAMiscompilation(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *)) { + 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 @@ -518,7 +576,10 @@ DebugAMiscompilation(BugDriver &BD, // Do the reduction... if (!BugpointIsInterrupted) - ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, + Error); + if (!Error.empty()) + return MiscompiledFunctions; outs() << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") @@ -529,37 +590,51 @@ DebugAMiscompilation(BugDriver &BD, // See if we can rip any loops out of the miscompiled functions and still // trigger the problem. - if (!BugpointIsInterrupted && !DisableLoopExtraction && - ExtractLoops(BD, TestFn, MiscompiledFunctions)) { - // 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); - - outs() << "\n*** The following function" - << (MiscompiledFunctions.size() == 1 ? " is" : "s are") - << " being miscompiled: "; - PrintFunctionList(MiscompiledFunctions); - outs() << '\n'; + 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 && - ExtractBlocks(BD, TestFn, MiscompiledFunctions)) { - // 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); - - 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; @@ -569,7 +644,8 @@ DebugAMiscompilation(BugDriver &BD, /// "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) { +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: "; @@ -579,8 +655,8 @@ static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe) { delete Test; outs() << " Checking to see if the merged program executes correctly: "; - bool Broken = TestMergedProgram(BD, Optimized, Safe, true); - outs() << (Broken ? " nope.\n" : " yup.\n"); + bool Broken = TestMergedProgram(BD, Optimized, Safe, true, Error); + if (Error.empty()) outs() << (Broken ? " nope.\n" : " yup.\n"); return Broken; } @@ -589,13 +665,14 @@ static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe) { /// crashing, but the generated output is semantically different from the /// input. /// -bool BugDriver::debugMiscompilation() { +void BugDriver::debugMiscompilation(std::string *Error) { // Make sure something was miscompiled... if (!BugpointIsInterrupted) - if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) { - errs() << "*** Optimized program matches reference output! No problem" - << " detected...\nbugpoint can't help you with your problem!\n"; - return false; + 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" @@ -603,8 +680,10 @@ bool BugDriver::debugMiscompilation() { << getPassesString(getPassesToRun()) << '\n'; EmitProgressBitcode("passinput"); - std::vector<Function*> MiscompiledFunctions = - DebugAMiscompilation(*this, TestOptimizer); + 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"; @@ -624,7 +703,7 @@ bool BugDriver::debugMiscompilation() { EmitProgressBitcode("tooptimize"); setNewProgram(ToOptimize); // Delete hacked module. - return false; + return; } /// CleanupAndPrepareModules - Get the specified modules ready for code @@ -797,7 +876,8 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, /// 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) { +static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, + std::string &Error) { CleanupAndPrepareModules(BD, Test, Safe); sys::Path TestModuleBC("bugpoint.test.bc"); @@ -827,12 +907,16 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { << "'\nExiting."; exit(1); } - std::string SharedObject = BD.compileSharedObject(SafeModuleBC.str()); + 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. - int Result = BD.diffProgram(TestModuleBC.str(), SharedObject, false); + bool Result = BD.diffProgram(TestModuleBC.str(), SharedObject, false, &Error); + if (!Error.empty()) + return false; if (Result) errs() << ": still failing!\n"; @@ -848,23 +932,28 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { /// debugCodeGenerator - debug errors in LLC, LLI, or CBE. /// -bool BugDriver::debugCodeGenerator() { +bool BugDriver::debugCodeGenerator(std::string *Error) { if ((void*)SafeInterpreter == (void*)Interpreter) { - std::string Result = executeProgramSafely("bugpoint.safe.out"); - 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"; + 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); + 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; @@ -902,14 +991,16 @@ bool BugDriver::debugCodeGenerator() { << "'\nExiting."; exit(1); } - std::string SharedObject = compileSharedObject(SafeModuleBC.str()); + 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 -f " << TestModuleBC.str() << " -o " << TestModuleBC.str() + outs() << " llc " << TestModuleBC.str() << " -o " << TestModuleBC.str() << ".s\n"; outs() << " gcc " << SharedObject << " " << TestModuleBC.str() << ".s -o " << TestModuleBC.str() << ".exe"; @@ -919,7 +1010,7 @@ bool BugDriver::debugCodeGenerator() { outs() << "\n"; outs() << " " << TestModuleBC.str() << ".exe"; } - for (unsigned i=0, e = InputArgv.size(); i != e; ++i) + 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 " diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 62df0f1..7ade778 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -50,11 +50,9 @@ namespace { cl::desc("Remote execution (rsh/ssh) extra options")); } -ToolExecutionError::~ToolExecutionError() throw() { } - /// RunProgramWithTimeout - This function provides an alternate interface /// to the sys::Program::ExecuteAndWait interface. -/// @see sys:Program::ExecuteAndWait +/// @see sys::Program::ExecuteAndWait static int RunProgramWithTimeout(const sys::Path &ProgramPath, const char **Args, const sys::Path &StdInFile, @@ -86,7 +84,7 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, /// 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 +/// @see sys::Program::ExecuteAndWait static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, const char **Args, const sys::Path &StdInFile, @@ -129,13 +127,13 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, ErrorFile.close(); } - throw ToolExecutionError(OS.str()); + errs() << OS; } return ReturnCode; } -static void ProcessFailure(sys::Path ProgPath, const char** Args) { +static std::string ProcessFailure(sys::Path ProgPath, const char** Args) { std::ostringstream OS; OS << "\nError running tool:\n "; for (const char **Arg = Args; *Arg; ++Arg) @@ -162,7 +160,7 @@ static void ProcessFailure(sys::Path ProgPath, const char** Args) { } ErrorFilename.eraseFromDisk(); - throw ToolExecutionError(OS.str()); + return OS.str(); } //===---------------------------------------------------------------------===// @@ -183,6 +181,7 @@ namespace { 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>(), @@ -195,6 +194,7 @@ 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, @@ -263,9 +263,10 @@ namespace { 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>(), + std::vector<std::string>(), unsigned Timeout = 0, unsigned MemoryLimit = 0); }; @@ -275,6 +276,7 @@ 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, @@ -289,7 +291,7 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode, ProgramArgs.push_back(0); // Add optional parameters to the running program from Argv - for (unsigned i=0, e = Args.size(); i != e; ++i) + for (unsigned i = 0, e = Args.size(); i != e; ++i) ProgramArgs.push_back(Args[i].c_str()); return RunProgramWithTimeout( @@ -351,7 +353,7 @@ AbstractInterpreter *AbstractInterpreter::createCustom( // LLC Implementation of AbstractIntepreter interface // GCC::FileType LLC::OutputCode(const std::string &Bitcode, - sys::Path &OutputAsmFile) { + sys::Path &OutputAsmFile, std::string &Error) { const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); sys::Path uniqueFile(Bitcode + Suffix); std::string ErrMsg; @@ -379,20 +381,19 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>"); outs().flush(); DEBUG(errs() << "\nAbout to run:\t"; - for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) + 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())) - ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]); - - return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; + Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]); + return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; } -void LLC::compileProgram(const std::string &Bitcode) { +void LLC::compileProgram(const std::string &Bitcode, std::string *Error) { sys::Path OutputAsmFile; - OutputCode(Bitcode, OutputAsmFile); + OutputCode(Bitcode, OutputAsmFile, *Error); OutputAsmFile.eraseFromDisk(); } @@ -400,13 +401,14 @@ 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); + GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error); FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); std::vector<std::string> GCCArgs(ArgsForGCC); @@ -415,7 +417,7 @@ int LLC::ExecuteProgram(const std::string &Bitcode, // Assuming LLC worked, compile the result with GCC and run it. return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind, - InputFile, OutputFile, GCCArgs, + InputFile, OutputFile, Error, GCCArgs, Timeout, MemoryLimit); } @@ -460,12 +462,13 @@ namespace { 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); + unsigned Timeout = 0, + unsigned MemoryLimit = 0); }; } @@ -473,6 +476,7 @@ 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, @@ -524,7 +528,7 @@ AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0, } GCC::FileType CBE::OutputCode(const std::string &Bitcode, - sys::Path &OutputCFile) { + sys::Path &OutputCFile, std::string &Error) { sys::Path uniqueFile(Bitcode+".cbe.c"); std::string ErrMsg; if (uniqueFile.makeUnique(true, &ErrMsg)) { @@ -533,34 +537,33 @@ GCC::FileType CBE::OutputCode(const std::string &Bitcode, } OutputCFile = uniqueFile; std::vector<const char *> LLCArgs; - LLCArgs.push_back (LLCPath.c_str()); + 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 ("-f"); // Overwrite as necessary... - LLCArgs.push_back (Bitcode.c_str()); // This is the input bitcode - LLCArgs.push_back (0); + 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) + 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())) - ProcessFailure(LLCPath, &LLCArgs[0]); + Error = ProcessFailure(LLCPath, &LLCArgs[0]); return GCC::CFile; } -void CBE::compileProgram(const std::string &Bitcode) { +void CBE::compileProgram(const std::string &Bitcode, std::string *Error) { sys::Path OutputCFile; - OutputCode(Bitcode, OutputCFile); + OutputCode(Bitcode, OutputCFile, *Error); OutputCFile.eraseFromDisk(); } @@ -568,12 +571,13 @@ 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); + OutputCode(Bitcode, OutputCFile, *Error); FileRemover CFileRemove(OutputCFile, !SaveTemps); @@ -581,7 +585,7 @@ int CBE::ExecuteProgram(const std::string &Bitcode, GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); return gcc->ExecuteProgram(OutputCFile.str(), Args, GCC::CFile, - InputFile, OutputFile, GCCArgs, + InputFile, OutputFile, Error, GCCArgs, Timeout, MemoryLimit); } @@ -631,6 +635,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, FileType fileType, const std::string &InputFile, const std::string &OutputFile, + std::string *Error, const std::vector<std::string> &ArgsForGCC, unsigned Timeout, unsigned MemoryLimit) { @@ -694,14 +699,14 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, outs() << "<gcc>"; outs().flush(); DEBUG(errs() << "\nAbout to run:\t"; - for (unsigned i=0, e = GCCArgs.size()-1; i != e; ++i) + 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())) { - ProcessFailure(GCCPath, &GCCArgs[0]); - exit(1); + *Error = ProcessFailure(GCCPath, &GCCArgs[0]); + return -1; } std::vector<const char*> ProgramArgs; @@ -734,14 +739,14 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, } // Add optional parameters to the running program from Argv - for (unsigned i=0, e = Args.size(); i != e; ++i) + 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) + for (unsigned i = 0, e = ProgramArgs.size()-1; i != e; ++i) errs() << " " << ProgramArgs[i]; errs() << "\n"; ); @@ -749,7 +754,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, FileRemover OutputBinaryRemover(OutputBinary, !SaveTemps); if (RemoteClientPath.isEmpty()) { - DEBUG(errs() << "<run locally>";); + DEBUG(errs() << "<run locally>"); return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), Timeout, MemoryLimit); @@ -763,7 +768,8 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, std::string &OutputFile, - const std::vector<std::string> &ArgsForGCC) { + const std::vector<std::string> &ArgsForGCC, + std::string &Error) { sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT); std::string ErrMsg; if (uniqueFilename.makeUnique(true, &ErrMsg)) { @@ -831,13 +837,13 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, outs() << "<gcc>"; outs().flush(); DEBUG(errs() << "\nAbout to run:\t"; - for (unsigned i=0, e = GCCArgs.size()-1; i != e; ++i) + 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())) { - ProcessFailure(GCCPath, &GCCArgs[0]); + Error = ProcessFailure(GCCPath, &GCCArgs[0]); return 1; } return 0; diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h index 0f75e99..cba10f2 100644 --- a/tools/bugpoint/ToolRunner.h +++ b/tools/bugpoint/ToolRunner.h @@ -19,6 +19,7 @@ #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> @@ -32,19 +33,6 @@ extern Triple TargetTriple; class CBE; class LLC; -/// ToolExecutionError - An instance of this class is thrown by the -/// AbstractInterpreter instances if there is an error running a tool (e.g., LLC -/// crashes) which prevents execution of the program. -/// -class ToolExecutionError : std::exception { - std::string Message; -public: - explicit ToolExecutionError(const std::string &M) : Message(M) {} - virtual ~ToolExecutionError() throw(); - virtual const char* what() const throw() { return Message.c_str(); } -}; - - //===---------------------------------------------------------------------===// // GCC abstraction // @@ -75,6 +63,7 @@ public: 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, @@ -85,7 +74,8 @@ public: /// int MakeSharedObject(const std::string &InputFile, FileType fileType, std::string &OutputFile, - const std::vector<std::string> &ArgsForGCC); + const std::vector<std::string> &ArgsForGCC, + std::string &Error); }; @@ -118,26 +108,29 @@ public: /// 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. If the code generator fails, an exception should be - /// thrown, otherwise, this function will just return. - virtual void compileProgram(const std::string &Bitcode) {} + /// the code generator. It returns false if the code generator fails. + virtual void compileProgram(const std::string &Bitcode, std::string *Error) {} /// OutputCode - Compile the specified program from bitcode to code /// understood by the GCC driver (either C or asm). If the code generator - /// fails, an exception should be thrown, otherwise, this function returns the - /// type of code emitted. + /// fails, it sets Error, otherwise, this function returns the type of code + /// emitted. virtual GCC::FileType OutputCode(const std::string &Bitcode, - sys::Path &OutFile) { - throw std::string("OutputCode not supported by this AbstractInterpreter!"); + sys::Path &OutFile, std::string &Error) { + Error = "OutputCode not supported by this AbstractInterpreter!"; + return GCC::AsmFile; } - + /// ExecuteProgram - Run the specified bitcode file, emitting output to the - /// specified filename. This returns the exit code of the program. + /// 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 = @@ -164,14 +157,14 @@ public: /// 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. If the code generator fails, an exception should be - /// thrown, otherwise, this function will just return. - virtual void compileProgram(const std::string &Bitcode); + /// the code generator. Returns false if the code generator fails. + virtual void compileProgram(const std::string &Bitcode, std::string *Error); 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 = @@ -181,10 +174,10 @@ public: /// OutputCode - Compile the specified program from bitcode to code /// understood by the GCC driver (either C or asm). If the code generator - /// fails, an exception should be thrown, otherwise, this function returns the - /// type of code emitted. + /// fails, it sets Error, otherwise, this function returns the type of code + /// emitted. virtual GCC::FileType OutputCode(const std::string &Bitcode, - sys::Path &OutFile); + sys::Path &OutFile, std::string &Error); }; @@ -212,14 +205,14 @@ public: /// 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. If the code generator fails, an exception should be - /// thrown, otherwise, this function will just return. - virtual void compileProgram(const std::string &Bitcode); + /// the code generator. Returns false if the code generator fails. + virtual void compileProgram(const std::string &Bitcode, std::string *Error); 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 = @@ -227,9 +220,12 @@ public: 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); - + sys::Path &OutFile, std::string &Error); }; } // End llvm namespace diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index e14f31e..ba5234b 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -149,23 +149,11 @@ int main(int argc, char **argv) { // avoid filling up the disk, we prevent it sys::Process::PreventCoreFiles(); - try { - return D.run(); - } catch (ToolExecutionError &TEE) { - errs() << "Tool execution error: " << TEE.what() << '\n'; - } catch (const std::string& msg) { - errs() << argv[0] << ": " << msg << "\n"; - } catch (const std::bad_alloc&) { - errs() << "Oh no, a bugpoint process ran out of memory!\n" - "To increase the allocation limits for bugpoint child\n" - "processes, use the -mlimit option.\n"; - } catch (const std::exception &e) { - errs() << "Whoops, a std::exception leaked out of bugpoint: " - << e.what() << "\n" - << "This is a bug in bugpoint!\n"; - } catch (...) { - errs() << "Whoops, an exception leaked out of bugpoint. " - << "This is a bug in bugpoint!\n"; + std::string Error; + bool Failure = D.run(Error); + if (!Error.empty()) { + errs() << Error; + return 1; } - return 1; + return Failure; } diff --git a/tools/edis/CMakeLists.txt b/tools/edis/CMakeLists.txt new file mode 100644 index 0000000..f7a199d --- /dev/null +++ b/tools/edis/CMakeLists.txt @@ -0,0 +1,25 @@ +set(LLVM_NO_RTTI 1) + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/EDInfo.inc + COMMAND ${LLVM_TABLEGEN_EXE} -o ${CMAKE_CURRENT_BINARY_DIR}/EDInfo.inc + -gen-enhanced-disassembly-header ${CMAKE_CURRENT_SOURCE_DIR}/EDInfo.td + DEPENDS tblgen + COMMENT "Building enhanced disassembly semantic information header (EDInfo.inc)") +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/EDInfo.inc PROPERTIES GENERATED 1) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +add_llvm_library(EnhancedDisassembly + EDDisassembler.cpp + EDInst.cpp + EDMain.cpp + EDOperand.cpp + EDToken.cpp + ../../include/llvm-c/EnhancedDisassembly.h + ${CMAKE_CURRENT_BINARY_DIR}/EDInfo.inc +) + +set_target_properties(EnhancedDisassembly + PROPERTIES + LINKER_LANGUAGE CXX) + diff --git a/tools/edis/EDDisassembler.cpp b/tools/edis/EDDisassembler.cpp index 8729b49..00b5d8d 100644 --- a/tools/edis/EDDisassembler.cpp +++ b/tools/edis/EDDisassembler.cpp @@ -13,8 +13,12 @@ // //===----------------------------------------------------------------------===// +#include "EDDisassembler.h" +#include "EDInst.h" + #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/MC/EDInstInfo.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" @@ -36,38 +40,34 @@ #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSelect.h" -#include "EDDisassembler.h" -#include "EDInst.h" - -#include "../../lib/Target/X86/X86GenEDInfo.inc" - using namespace llvm; bool EDDisassembler::sInitialized = false; EDDisassembler::DisassemblerMap_t EDDisassembler::sDisassemblers; -struct InfoMap { +struct TripleMap { Triple::ArchType Arch; const char *String; - const InstInfo *Info; }; -static struct InfoMap infomap[] = { - { Triple::x86, "i386-unknown-unknown", instInfoX86 }, - { Triple::x86_64, "x86_64-unknown-unknown", instInfoX86 }, - { Triple::InvalidArch, NULL, NULL } +static struct TripleMap triplemap[] = { + { Triple::x86, "i386-unknown-unknown" }, + { Triple::x86_64, "x86_64-unknown-unknown" }, + { Triple::arm, "arm-unknown-unknown" }, + { Triple::thumb, "thumb-unknown-unknown" }, + { Triple::InvalidArch, NULL, } }; -/// infoFromArch - Returns the InfoMap corresponding to a given architecture, +/// infoFromArch - Returns the TripleMap corresponding to a given architecture, /// or NULL if there is an error /// /// @arg arch - The Triple::ArchType for the desired architecture -static const InfoMap *infoFromArch(Triple::ArchType arch) { +static const char *tripleFromArch(Triple::ArchType arch) { unsigned int infoIndex; - for (infoIndex = 0; infomap[infoIndex].String != NULL; ++infoIndex) { - if(arch == infomap[infoIndex].Arch) - return &infomap[infoIndex]; + for (infoIndex = 0; triplemap[infoIndex].String != NULL; ++infoIndex) { + if (arch == triplemap[infoIndex].Arch) + return triplemap[infoIndex].String; } return NULL; @@ -95,23 +95,25 @@ static int getLLVMSyntaxVariant(Triple::ArchType arch, return 1; else return -1; + case kEDAssemblySyntaxARMUAL: + if (arch == Triple::arm || arch == Triple::thumb) + return 0; + else + return -1; } } -#define BRINGUP_TARGET(tgt) \ - LLVMInitialize##tgt##TargetInfo(); \ - LLVMInitialize##tgt##Target(); \ - LLVMInitialize##tgt##AsmPrinter(); \ - LLVMInitialize##tgt##AsmParser(); \ - LLVMInitialize##tgt##Disassembler(); - void EDDisassembler::initialize() { if (sInitialized) return; sInitialized = true; - BRINGUP_TARGET(X86) + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + InitializeAllDisassemblers(); } #undef BRINGUP_TARGET @@ -126,10 +128,9 @@ EDDisassembler *EDDisassembler::getDisassembler(Triple::ArchType arch, if (i != sDisassemblers.end()) { return i->second; - } - else { + } else { EDDisassembler* sdd = new EDDisassembler(key); - if(!sdd->valid()) { + if (!sdd->valid()) { delete sdd; return NULL; } @@ -150,17 +151,18 @@ EDDisassembler *EDDisassembler::getDisassembler(StringRef str, } EDDisassembler::EDDisassembler(CPUKey &key) : - Valid(false), ErrorString(), ErrorStream(ErrorString), Key(key) { - const InfoMap *infoMap = infoFromArch(key.Arch); - - if (!infoMap) + Valid(false), + HasSemantics(false), + ErrorStream(nulls()), + Key(key) { + const char *triple = tripleFromArch(key.Arch); + + if (!triple) return; - const char *triple = infoMap->String; - - int syntaxVariant = getLLVMSyntaxVariant(key.Arch, key.Syntax); + LLVMSyntaxVariant = getLLVMSyntaxVariant(key.Arch, key.Syntax); - if (syntaxVariant < 0) + if (LLVMSyntaxVariant < 0) return; std::string tripleString(triple); @@ -182,6 +184,8 @@ EDDisassembler::EDDisassembler(CPUKey &key) : if (!registerInfo) return; + + initMaps(*registerInfo); AsmInfo.reset(Tgt->createAsmInfo(tripleString)); @@ -192,10 +196,12 @@ EDDisassembler::EDDisassembler(CPUKey &key) : if (!Disassembler) return; + + InstInfos = Disassembler->getEDInfo(); InstString.reset(new std::string); InstStream.reset(new raw_string_ostream(*InstString)); - InstPrinter.reset(Tgt->createMCInstPrinter(syntaxVariant, *AsmInfo)); + InstPrinter.reset(Tgt->createMCInstPrinter(LLVMSyntaxVariant, *AsmInfo)); if (!InstPrinter) return; @@ -203,8 +209,6 @@ EDDisassembler::EDDisassembler(CPUKey &key) : GenericAsmLexer.reset(new AsmLexer(*AsmInfo)); SpecificAsmLexer.reset(Tgt->createAsmLexer(*AsmInfo)); SpecificAsmLexer->InstallLexer(*GenericAsmLexer); - - InstInfos = infoMap->Info; initMaps(*targetMachine->getRegisterInfo()); @@ -212,7 +216,7 @@ EDDisassembler::EDDisassembler(CPUKey &key) : } EDDisassembler::~EDDisassembler() { - if(!valid()) + if (!valid()) return; } @@ -230,10 +234,10 @@ namespace { uint64_t getBase() const { return 0x0; } uint64_t getExtent() const { return (uint64_t)-1; } int readByte(uint64_t address, uint8_t *ptr) const { - if(!Callback) + if (!Callback) return -1; - if(Callback(ptr, address, Arg)) + if (Callback(ptr, address, Arg)) return -1; return 0; @@ -256,9 +260,10 @@ EDInst *EDDisassembler::createInst(EDByteReaderCallback byteReader, ErrorStream)) { delete inst; return NULL; - } - else { - const InstInfo *thisInstInfo = &InstInfos[inst->getOpcode()]; + } else { + const llvm::EDInstInfo *thisInstInfo; + + thisInstInfo = &InstInfos[inst->getOpcode()]; EDInst* sdInst = new EDInst(inst, byteSize, *this, thisInstInfo); return sdInst; @@ -276,8 +281,11 @@ void EDDisassembler::initMaps(const TargetRegisterInfo ®isterInfo) { RegRMap[registerName] = registerIndex; } - if (Key.Arch == Triple::x86 || - Key.Arch == Triple::x86_64) { + switch (Key.Arch) { + default: + break; + case Triple::x86: + case Triple::x86_64: stackPointers.insert(registerIDWithName("SP")); stackPointers.insert(registerIDWithName("ESP")); stackPointers.insert(registerIDWithName("RSP")); @@ -285,6 +293,13 @@ void EDDisassembler::initMaps(const TargetRegisterInfo ®isterInfo) { programCounters.insert(registerIDWithName("IP")); programCounters.insert(registerIDWithName("EIP")); programCounters.insert(registerIDWithName("RIP")); + break; + case Triple::arm: + case Triple::thumb: + stackPointers.insert(registerIDWithName("SP")); + + programCounters.insert(registerIDWithName("PC")); + break; } } @@ -329,6 +344,16 @@ int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands, const std::string &str) { int ret = 0; + switch (Key.Arch) { + default: + return -1; + case Triple::x86: + case Triple::x86_64: + case Triple::arm: + case Triple::thumb: + break; + } + const char *cStr = str.c_str(); MemoryBuffer *buf = MemoryBuffer::getMemBuffer(cStr, cStr + strlen(cStr)); @@ -343,14 +368,16 @@ int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands, OwningPtr<TargetAsmParser> TargetParser(Tgt->createAsmParser(genericParser)); AsmToken OpcodeToken = genericParser.Lex(); - - if(OpcodeToken.is(AsmToken::Identifier)) { + AsmToken NextToken = genericParser.Lex(); // consume next token, because specificParser expects us to + + if (OpcodeToken.is(AsmToken::Identifier)) { instName = OpcodeToken.getString(); instLoc = OpcodeToken.getLoc(); - if (TargetParser->ParseInstruction(instName, instLoc, operands)) + + if (NextToken.isNot(AsmToken::Eof) && + TargetParser->ParseInstruction(instName, instLoc, operands)) ret = -1; - } - else { + } else { ret = -1; } diff --git a/tools/edis/EDDisassembler.h b/tools/edis/EDDisassembler.h index 6be9152..74a260e 100644 --- a/tools/edis/EDDisassembler.h +++ b/tools/edis/EDDisassembler.h @@ -48,6 +48,8 @@ template <typename T> class SmallVectorImpl; class SourceMgr; class Target; class TargetRegisterInfo; + +struct EDInstInfo; } /// EDDisassembler - Encapsulates a disassembler for a single architecture and @@ -113,13 +115,13 @@ struct EDDisassembler { // Per-object members // //////////////////////// - /// True only if the object has been fully and successfully initialized + /// True only if the object has been successfully initialized bool Valid; + /// True if the disassembler can provide semantic information + bool HasSemantics; - /// The string that stores disassembler errors from the backend - std::string ErrorString; - /// The stream that wraps the ErrorString - llvm::raw_string_ostream ErrorStream; + /// The stream to write errors to + llvm::raw_ostream &ErrorStream; /// The architecture/syntax pair for the current architecture CPUKey Key; @@ -143,7 +145,7 @@ struct EDDisassembler { llvm::sys::Mutex PrinterMutex; /// The array of instruction information provided by the TableGen backend for /// the target architecture - const InstInfo *InstInfos; + const llvm::EDInstInfo *InstInfos; /// The target-specific lexer for use in tokenizing strings, in /// target-independent and target-specific portions llvm::OwningPtr<llvm::AsmLexer> GenericAsmLexer; @@ -180,6 +182,12 @@ struct EDDisassembler { return Valid; } + /// hasSemantics - reports whether the disassembler can provide operands and + /// tokens. + bool hasSemantics() { + return HasSemantics; + } + ~EDDisassembler(); /// createInst - creates and returns an instruction given a callback and diff --git a/tools/edis/EDInfo.td b/tools/edis/EDInfo.td new file mode 100644 index 0000000..bd9ec07 --- /dev/null +++ b/tools/edis/EDInfo.td @@ -0,0 +1 @@ +// Intentionally empty. diff --git a/tools/edis/EDInst.cpp b/tools/edis/EDInst.cpp index 9ed2700..af3a54a 100644 --- a/tools/edis/EDInst.cpp +++ b/tools/edis/EDInst.cpp @@ -18,6 +18,7 @@ #include "EDOperand.h" #include "EDToken.h" +#include "llvm/MC/EDInstInfo.h" #include "llvm/MC/MCInst.h" using namespace llvm; @@ -25,7 +26,7 @@ using namespace llvm; EDInst::EDInst(llvm::MCInst *inst, uint64_t byteSize, EDDisassembler &disassembler, - const InstInfo *info) : + const llvm::EDInstInfo *info) : Disassembler(disassembler), Inst(inst), ThisInstInfo(info), @@ -33,6 +34,7 @@ EDInst::EDInst(llvm::MCInst *inst, BranchTarget(-1), MoveSource(-1), MoveTarget(-1) { + OperandOrder = ThisInstInfo->operandOrders[Disassembler.llvmSyntaxVariant()]; } EDInst::~EDInst() { @@ -60,8 +62,6 @@ int EDInst::stringify() { if (Disassembler.printInst(String, *Inst)) return StringifyResult.setResult(-1); - - OperandOrder = ThisInstInfo->operandOrders[Disassembler.llvmSyntaxVariant()]; return StringifyResult.setResult(0); } @@ -81,21 +81,21 @@ unsigned EDInst::instID() { bool EDInst::isBranch() { if (ThisInstInfo) - return ThisInstInfo->instructionFlags & kInstructionFlagBranch; + return ThisInstInfo->instructionType == kInstructionTypeBranch; else return false; } bool EDInst::isMove() { if (ThisInstInfo) - return ThisInstInfo->instructionFlags & kInstructionFlagMove; + return ThisInstInfo->instructionType == kInstructionTypeMove; else return false; } int EDInst::parseOperands() { if (ParseResult.valid()) - return ParseResult.result(); + return ParseResult.result(); if (!ThisInstInfo) return ParseResult.setResult(-1); diff --git a/tools/edis/EDInst.h b/tools/edis/EDInst.h index db03a78..c8a747f 100644 --- a/tools/edis/EDInst.h +++ b/tools/edis/EDInst.h @@ -23,6 +23,10 @@ #include <string> #include <vector> +namespace llvm { + struct EDInstInfo; +} + /// CachedResult - Encapsulates the result of a function along with the validity /// of that result, so that slow functions don't need to run twice struct CachedResult { @@ -54,7 +58,7 @@ struct EDInst { /// The containing MCInst llvm::MCInst *Inst; /// The instruction information provided by TableGen for this instruction - const InstInfo *ThisInstInfo; + const llvm::EDInstInfo *ThisInstInfo; /// The number of bytes for the machine code representation of the instruction uint64_t ByteSize; @@ -95,7 +99,7 @@ struct EDInst { EDInst(llvm::MCInst *inst, uint64_t byteSize, EDDisassembler &disassembler, - const InstInfo *instInfo); + const llvm::EDInstInfo *instInfo); ~EDInst(); /// byteSize - returns the number of bytes consumed by the machine code diff --git a/tools/edis/EDMain.cpp b/tools/edis/EDMain.cpp index 3585657..b6ca32f 100644 --- a/tools/edis/EDMain.cpp +++ b/tools/edis/EDMain.cpp @@ -29,8 +29,7 @@ int EDGetDisassembler(EDDisassemblerRef *disassembler, if (ret) { *disassembler = ret; return 0; - } - else { + } else { return -1; } } @@ -39,7 +38,7 @@ int EDGetRegisterName(const char** regName, EDDisassemblerRef disassembler, unsigned regID) { const char* name = disassembler->nameWithRegisterID(regID); - if(!name) + if (!name) return -1; *regName = name; return 0; @@ -63,10 +62,10 @@ unsigned int EDCreateInsts(EDInstRef *insts, void *arg) { unsigned int index; - for (index = 0; index < count; index++) { + for (index = 0; index < count; ++index) { EDInst *inst = disassembler->createInst(byteReader, address, arg); - if(!inst) + if (!inst) return index; insts[index] = inst; @@ -134,42 +133,42 @@ int EDOperandIndexForToken(EDTokenRef token) { } int EDTokenIsWhitespace(EDTokenRef token) { - if(token->type() == EDToken::kTokenWhitespace) + if (token->type() == EDToken::kTokenWhitespace) return 1; else return 0; } int EDTokenIsPunctuation(EDTokenRef token) { - if(token->type() == EDToken::kTokenPunctuation) + if (token->type() == EDToken::kTokenPunctuation) return 1; else return 0; } int EDTokenIsOpcode(EDTokenRef token) { - if(token->type() == EDToken::kTokenOpcode) + if (token->type() == EDToken::kTokenOpcode) return 1; else return 0; } int EDTokenIsLiteral(EDTokenRef token) { - if(token->type() == EDToken::kTokenLiteral) + if (token->type() == EDToken::kTokenLiteral) return 1; else return 0; } int EDTokenIsRegister(EDTokenRef token) { - if(token->type() == EDToken::kTokenRegister) + if (token->type() == EDToken::kTokenRegister) return 1; else return 0; } int EDTokenIsNegativeLiteral(EDTokenRef token) { - if(token->type() != EDToken::kTokenLiteral) + if (token->type() != EDToken::kTokenLiteral) return -1; return token->literalSign(); @@ -177,7 +176,7 @@ int EDTokenIsNegativeLiteral(EDTokenRef token) { int EDLiteralTokenAbsoluteValue(uint64_t *value, EDTokenRef token) { - if(token->type() != EDToken::kTokenLiteral) + if (token->type() != EDToken::kTokenLiteral) return -1; return token->literalAbsoluteValue(*value); @@ -185,7 +184,7 @@ int EDLiteralTokenAbsoluteValue(uint64_t *value, int EDRegisterTokenValue(unsigned *registerID, EDTokenRef token) { - if(token->type() != EDToken::kTokenRegister) + if (token->type() != EDToken::kTokenRegister) return -1; return token->registerID(*registerID); @@ -215,7 +214,7 @@ int EDOperandIsMemory(EDOperandRef operand) { int EDRegisterOperandValue(unsigned *value, EDOperandRef operand) { - if(!operand->isRegister()) + if (!operand->isRegister()) return -1; *value = operand->regVal(); return 0; @@ -223,7 +222,7 @@ int EDRegisterOperandValue(unsigned *value, int EDImmediateOperandValue(uint64_t *value, EDOperandRef operand) { - if(!operand->isImmediate()) + if (!operand->isImmediate()) return -1; *value = operand->immediateVal(); return 0; diff --git a/tools/edis/EDOperand.cpp b/tools/edis/EDOperand.cpp index da6797e..d63c1c6 100644 --- a/tools/edis/EDOperand.cpp +++ b/tools/edis/EDOperand.cpp @@ -17,6 +17,7 @@ #include "EDInst.h" #include "EDOperand.h" +#include "llvm/MC/EDInstInfo.h" #include "llvm/MC/MCInst.h" using namespace llvm; @@ -31,26 +32,77 @@ EDOperand::EDOperand(const EDDisassembler &disassembler, MCOpIndex(mcOpIndex) { unsigned int numMCOperands = 0; - if(Disassembler.Key.Arch == Triple::x86 || - Disassembler.Key.Arch == Triple::x86_64) { - uint8_t operandFlags = inst.ThisInstInfo->operandFlags[opIndex]; + if (Disassembler.Key.Arch == Triple::x86 || + Disassembler.Key.Arch == Triple::x86_64) { + uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex]; - if (operandFlags & kOperandFlagImmediate) { + switch (operandType) { + default: + break; + case kOperandTypeImmediate: numMCOperands = 1; - } - else if (operandFlags & kOperandFlagRegister) { + break; + case kOperandTypeRegister: numMCOperands = 1; + break; + case kOperandTypeX86Memory: + numMCOperands = 5; + break; + case kOperandTypeX86EffectiveAddress: + numMCOperands = 4; + break; + case kOperandTypeX86PCRelative: + numMCOperands = 1; + break; } - else if (operandFlags & kOperandFlagMemory) { - if (operandFlags & kOperandFlagPCRelative) { - numMCOperands = 1; - } - else { - numMCOperands = 5; - } - } - else if (operandFlags & kOperandFlagEffectiveAddress) { + } + else if (Disassembler.Key.Arch == Triple::arm || + Disassembler.Key.Arch == Triple::thumb) { + uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex]; + + switch (operandType) { + default: + case kOperandTypeARMRegisterList: + break; + case kOperandTypeImmediate: + case kOperandTypeRegister: + case kOperandTypeARMBranchTarget: + case kOperandTypeARMSoImm: + case kOperandTypeThumb2SoImm: + case kOperandTypeARMSoImm2Part: + case kOperandTypeARMPredicate: + case kOperandTypeThumbITMask: + case kOperandTypeThumb2AddrModeImm8Offset: + case kOperandTypeARMTBAddrMode: + case kOperandTypeThumb2AddrModeImm8s4Offset: + numMCOperands = 1; + break; + case kOperandTypeThumb2SoReg: + case kOperandTypeARMAddrMode2Offset: + case kOperandTypeARMAddrMode3Offset: + case kOperandTypeARMAddrMode4: + case kOperandTypeARMAddrMode5: + case kOperandTypeARMAddrModePC: + case kOperandTypeThumb2AddrModeImm8: + case kOperandTypeThumb2AddrModeImm12: + case kOperandTypeThumb2AddrModeImm8s4: + case kOperandTypeThumbAddrModeRR: + case kOperandTypeThumbAddrModeSP: + numMCOperands = 2; + break; + case kOperandTypeARMSoReg: + case kOperandTypeARMAddrMode2: + case kOperandTypeARMAddrMode3: + case kOperandTypeThumb2AddrModeSoReg: + case kOperandTypeThumbAddrModeS1: + case kOperandTypeThumbAddrModeS2: + case kOperandTypeThumbAddrModeS4: + case kOperandTypeARMAddrMode6Offset: + numMCOperands = 3; + break; + case kOperandTypeARMAddrMode6: numMCOperands = 4; + break; } } @@ -63,70 +115,103 @@ EDOperand::~EDOperand() { int EDOperand::evaluate(uint64_t &result, EDRegisterReaderCallback callback, void *arg) { - if (Disassembler.Key.Arch == Triple::x86 || - Disassembler.Key.Arch == Triple::x86_64) { - uint8_t operandFlags = Inst.ThisInstInfo->operandFlags[OpIndex]; - - if (operandFlags & kOperandFlagImmediate) { + uint8_t operandType = Inst.ThisInstInfo->operandTypes[OpIndex]; + + switch (Disassembler.Key.Arch) { + default: + return -1; + case Triple::x86: + case Triple::x86_64: + switch (operandType) { + default: + return -1; + case kOperandTypeImmediate: result = Inst.Inst->getOperand(MCOpIndex).getImm(); return 0; - } - if (operandFlags & kOperandFlagRegister) { + case kOperandTypeRegister: + { unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg(); return callback(&result, reg, arg); } - if (operandFlags & kOperandFlagMemory || - operandFlags & kOperandFlagEffectiveAddress){ - if(operandFlags & kOperandFlagPCRelative) { - int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm(); + case kOperandTypeX86PCRelative: + { + int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm(); - uint64_t ripVal; + uint64_t ripVal; - // TODO fix how we do this + // TODO fix how we do this - if (callback(&ripVal, Disassembler.registerIDWithName("RIP"), arg)) - return -1; + if (callback(&ripVal, Disassembler.registerIDWithName("RIP"), arg)) + return -1; - result = ripVal + displacement; - return 0; - } - else { - unsigned baseReg = Inst.Inst->getOperand(MCOpIndex).getReg(); - uint64_t scaleAmount = Inst.Inst->getOperand(MCOpIndex+1).getImm(); - unsigned indexReg = Inst.Inst->getOperand(MCOpIndex+2).getReg(); - int64_t displacement = Inst.Inst->getOperand(MCOpIndex+3).getImm(); - //unsigned segmentReg = Inst.Inst->getOperand(MCOpIndex+4).getReg(); + result = ripVal + displacement; + return 0; + } + case kOperandTypeX86Memory: + case kOperandTypeX86EffectiveAddress: + { + unsigned baseReg = Inst.Inst->getOperand(MCOpIndex).getReg(); + uint64_t scaleAmount = Inst.Inst->getOperand(MCOpIndex+1).getImm(); + unsigned indexReg = Inst.Inst->getOperand(MCOpIndex+2).getReg(); + int64_t displacement = Inst.Inst->getOperand(MCOpIndex+3).getImm(); + //unsigned segmentReg = Inst.Inst->getOperand(MCOpIndex+4).getReg(); - uint64_t addr = 0; + uint64_t addr = 0; - if(baseReg) { - uint64_t baseVal; - if (callback(&baseVal, baseReg, arg)) - return -1; - addr += baseVal; - } - - if(indexReg) { - uint64_t indexVal; - if (callback(&indexVal, indexReg, arg)) - return -1; - addr += (scaleAmount * indexVal); - } - - addr += displacement; + if (baseReg) { + uint64_t baseVal; + if (callback(&baseVal, baseReg, arg)) + return -1; + addr += baseVal; + } - result = addr; - return 0; + if (indexReg) { + uint64_t indexVal; + if (callback(&indexVal, indexReg, arg)) + return -1; + addr += (scaleAmount * indexVal); } + + addr += displacement; + + result = addr; + return 0; + } + } + break; + case Triple::arm: + case Triple::thumb: + switch (operandType) { + default: + return -1; + case kOperandTypeImmediate: + result = Inst.Inst->getOperand(MCOpIndex).getImm(); + return 0; + case kOperandTypeRegister: + { + unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg(); + return callback(&result, reg, arg); + } + case kOperandTypeARMBranchTarget: + { + int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm(); + + uint64_t pcVal; + + if (callback(&pcVal, Disassembler.registerIDWithName("PC"), arg)) + return -1; + + result = pcVal + displacement; + return 0; + } } - return -1; } return -1; } int EDOperand::isRegister() { - return(Inst.ThisInstInfo->operandFlags[OpIndex] & kOperandFlagRegister); + return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeRegister); } unsigned EDOperand::regVal() { @@ -134,7 +219,7 @@ unsigned EDOperand::regVal() { } int EDOperand::isImmediate() { - return(Inst.ThisInstInfo->operandFlags[OpIndex] & kOperandFlagImmediate); + return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeImmediate); } uint64_t EDOperand::immediateVal() { @@ -142,7 +227,38 @@ uint64_t EDOperand::immediateVal() { } int EDOperand::isMemory() { - return(Inst.ThisInstInfo->operandFlags[OpIndex] & kOperandFlagMemory); + uint8_t operandType = Inst.ThisInstInfo->operandTypes[OpIndex]; + + switch (operandType) { + default: + return 0; + case kOperandTypeX86Memory: + case kOperandTypeX86PCRelative: + case kOperandTypeX86EffectiveAddress: + case kOperandTypeARMSoReg: + case kOperandTypeARMSoImm: + case kOperandTypeARMAddrMode2: + case kOperandTypeARMAddrMode2Offset: + case kOperandTypeARMAddrMode3: + case kOperandTypeARMAddrMode3Offset: + case kOperandTypeARMAddrMode4: + case kOperandTypeARMAddrMode5: + case kOperandTypeARMAddrMode6: + case kOperandTypeARMAddrModePC: + case kOperandTypeARMBranchTarget: + case kOperandTypeThumbAddrModeS1: + case kOperandTypeThumbAddrModeS2: + case kOperandTypeThumbAddrModeS4: + case kOperandTypeThumbAddrModeRR: + case kOperandTypeThumbAddrModeSP: + case kOperandTypeThumb2SoImm: + case kOperandTypeThumb2AddrModeImm8: + case kOperandTypeThumb2AddrModeImm8Offset: + case kOperandTypeThumb2AddrModeImm12: + case kOperandTypeThumb2AddrModeSoReg: + case kOperandTypeThumb2AddrModeImm8s4: + return 1; + } } #ifdef __BLOCKS__ diff --git a/tools/edis/EDToken.cpp b/tools/edis/EDToken.cpp index cd79152..3bcb0a1 100644 --- a/tools/edis/EDToken.cpp +++ b/tools/edis/EDToken.cpp @@ -68,20 +68,20 @@ int EDToken::operandID() const { } int EDToken::literalSign() const { - if(Type != kTokenLiteral) + if (Type != kTokenLiteral) return -1; return (LiteralSign ? 1 : 0); } int EDToken::literalAbsoluteValue(uint64_t &value) const { - if(Type != kTokenLiteral) + if (Type != kTokenLiteral) return -1; value = LiteralAbsoluteValue; return 0; } int EDToken::registerID(unsigned ®isterID) const { - if(Type != kTokenRegister) + if (Type != kTokenRegister) return -1; registerID = RegisterID; return 0; @@ -94,7 +94,7 @@ int EDToken::tokenize(std::vector<EDToken*> &tokens, SmallVector<MCParsedAsmOperand*, 5> parsedOperands; SmallVector<AsmToken, 10> asmTokens; - if(disassembler.parseInst(parsedOperands, asmTokens, str)) + if (disassembler.parseInst(parsedOperands, asmTokens, str)) return -1; SmallVectorImpl<MCParsedAsmOperand*>::iterator operandIterator; @@ -115,7 +115,7 @@ int EDToken::tokenize(std::vector<EDToken*> &tokens, const char *tokenPointer = tokenLoc.getPointer(); - if(tokenPointer > wsPointer) { + if (tokenPointer > wsPointer) { unsigned long wsLength = tokenPointer - wsPointer; EDToken *whitespaceToken = new EDToken(StringRef(wsPointer, wsLength), @@ -164,7 +164,7 @@ int EDToken::tokenize(std::vector<EDToken*> &tokens, int64_t intVal = tokenIterator->getIntVal(); - if(intVal < 0) + if (intVal < 0) token->makeLiteral(true, -intVal); else token->makeLiteral(false, intVal); @@ -182,14 +182,14 @@ int EDToken::tokenize(std::vector<EDToken*> &tokens, } } - if(operandIterator != parsedOperands.end() && + if (operandIterator != parsedOperands.end() && tokenLoc.getPointer() >= (*operandIterator)->getStartLoc().getPointer()) { /// operandIndex == 0 means the operand is the instruction (which the /// AsmParser treats as an operand but edis does not). We therefore skip /// operandIndex == 0 and subtract 1 from all other operand indices. - if(operandIndex > 0) + if (operandIndex > 0) token->setOperandID(operandOrder[operandIndex - 1]); } @@ -200,7 +200,7 @@ int EDToken::tokenize(std::vector<EDToken*> &tokens, } int EDToken::getString(const char*& buf) { - if(PermStr.length() == 0) { + if (PermStr.length() == 0) { PermStr = Str.str(); } buf = PermStr.c_str(); diff --git a/tools/edis/EnhancedDisassembly.exports b/tools/edis/EnhancedDisassembly.exports index d3f8743..7050f7f 100644 --- a/tools/edis/EnhancedDisassembly.exports +++ b/tools/edis/EnhancedDisassembly.exports @@ -1,36 +1,36 @@ -_EDGetDisassembler -_EDGetRegisterName -_EDRegisterIsStackPointer -_EDRegisterIsProgramCounter -_EDCreateInsts -_EDReleaseInst -_EDInstByteSize -_EDGetInstString -_EDInstIsBranch -_EDInstIsMove -_EDBranchTargetID -_EDMoveSourceID -_EDMoveTargetID -_EDNumTokens -_EDGetToken -_EDGetTokenString -_EDOperandIndexForToken -_EDTokenIsWhitespace -_EDTokenIsPunctuation -_EDTokenIsOpcode -_EDTokenIsLiteral -_EDTokenIsRegister -_EDTokenIsNegativeLiteral -_EDLiteralTokenAbsoluteValue -_EDRegisterTokenValue -_EDNumOperands -_EDGetOperand -_EDOperandIsRegister -_EDOperandIsImmediate -_EDOperandIsMemory -_EDRegisterOperandValue -_EDImmediateOperandValue -_EDEvaluateOperand -_EDBlockCreateInsts -_EDBlockEvaluateOperand -_EDBlockVisitTokens +EDGetDisassembler +EDGetRegisterName +EDRegisterIsStackPointer +EDRegisterIsProgramCounter +EDCreateInsts +EDReleaseInst +EDInstByteSize +EDGetInstString +EDInstIsBranch +EDInstIsMove +EDBranchTargetID +EDMoveSourceID +EDMoveTargetID +EDNumTokens +EDGetToken +EDGetTokenString +EDOperandIndexForToken +EDTokenIsWhitespace +EDTokenIsPunctuation +EDTokenIsOpcode +EDTokenIsLiteral +EDTokenIsRegister +EDTokenIsNegativeLiteral +EDLiteralTokenAbsoluteValue +EDRegisterTokenValue +EDNumOperands +EDGetOperand +EDOperandIsRegister +EDOperandIsImmediate +EDOperandIsMemory +EDRegisterOperandValue +EDImmediateOperandValue +EDEvaluateOperand +EDBlockCreateInsts +EDBlockEvaluateOperand +EDBlockVisitTokens diff --git a/tools/edis/Makefile b/tools/edis/Makefile index 7f7b097..9151f62 100644 --- a/tools/edis/Makefile +++ b/tools/edis/Makefile @@ -12,13 +12,19 @@ LIBRARYNAME = EnhancedDisassembly BUILT_SOURCES = EDInfo.inc +EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/EnhancedDisassembly.exports + # Include this here so we can get the configuration of the targets # that have been configured for construction. We have to do this # early so we can set up LINK_COMPONENTS before including Makefile.rules include $(LEVEL)/Makefile.config -LINK_LIBS_IN_SHARED = 1 -SHARED_LIBRARY = 1 +ifeq ($(ENABLE_PIC),1) + ifneq ($(TARGET_OS), $(filter $(TARGET_OS), Cygwin MingW)) + LINK_LIBS_IN_SHARED = 1 + SHARED_LIBRARY = 1 + endif +endif LINK_COMPONENTS := $(TARGETS_TO_BUILD) x86asmprinter x86disassembler @@ -28,11 +34,10 @@ ifeq ($(HOST_OS),Darwin) # extra options to override libtool defaults LLVMLibsOptions := $(LLVMLibsOptions) \ -avoid-version \ - -Wl,-exported_symbols_list -Wl,$(PROJ_SRC_DIR)/EnhancedDisassembly.exports \ -Wl,-dead_strip ifdef EDIS_VERSION - LLVMLibsOptions := -Wl,-current_version -Wl,$(EDIS_VERSION) \ + LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version -Wl,$(EDIS_VERSION) \ -Wl,-compatibility_version -Wl,1 endif diff --git a/tools/gold/Makefile b/tools/gold/Makefile index 7bac4ec..77eacb7 100644 --- a/tools/gold/Makefile +++ b/tools/gold/Makefile @@ -10,6 +10,8 @@ LEVEL = ../.. LIBRARYNAME = libLLVMgold +EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/gold.exports + # Include this here so we can get the configuration of the targets # that have been configured for construction. We have to do this # early so we can set up LINK_COMPONENTS before including Makefile.rules diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 0e1db1b..16e645f 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -58,16 +58,16 @@ namespace { } namespace options { - bool generate_api_file = false; - const char *as_path = NULL; + static bool generate_api_file = false; + static const char *as_path = NULL; // Additional options to pass into the code generator. // Note: This array will contain all plugin options which are not claimed // as plugin exclusive to pass to the code generator. // For example, "generate-api-file" and "as"options are for the plugin // use only and will not be passed. - std::vector<std::string> extra; + static std::vector<std::string> extra; - void process_plugin_option(const char* opt) + static void process_plugin_option(const char* opt) { if (opt == NULL) return; @@ -88,10 +88,10 @@ namespace options { } } -ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, - int *claimed); -ld_plugin_status all_symbols_read_hook(void); -ld_plugin_status cleanup_hook(void); +static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, + int *claimed); +static ld_plugin_status all_symbols_read_hook(void); +static ld_plugin_status cleanup_hook(void); extern "C" ld_plugin_status onload(ld_plugin_tv *tv); ld_plugin_status onload(ld_plugin_tv *tv) { @@ -192,8 +192,8 @@ ld_plugin_status onload(ld_plugin_tv *tv) { /// claim_file_hook - called by gold to see whether this file is one that /// our plugin can handle. We'll try to open it and register all the symbols /// with add_symbol if possible. -ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, - int *claimed) { +static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, + int *claimed) { void *buf = NULL; if (file->offset) { // Gold has found what might be IR part-way inside of a file, such as @@ -316,7 +316,7 @@ ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, /// At this point, we use get_symbols to see if any of our definitions have /// been overridden by a native object file. Then, perform optimization and /// codegen. -ld_plugin_status all_symbols_read_hook(void) { +static ld_plugin_status all_symbols_read_hook(void) { lto_code_gen_t cg = lto_codegen_create(); for (std::list<claimed_file>::iterator I = Modules.begin(), @@ -340,9 +340,7 @@ ld_plugin_status all_symbols_read_hook(void) { E = Modules.end(); I != E; ++I) { (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]); for (unsigned i = 0, e = I->syms.size(); i != e; i++) { - if (I->syms[i].resolution == LDPR_PREVAILING_DEF || - (I->syms[i].def == LDPK_COMMON && - I->syms[i].resolution == LDPR_RESOLVED_IR)) { + if (I->syms[i].resolution == LDPR_PREVAILING_DEF) { lto_codegen_add_must_preserve_symbol(cg, I->syms[i].name); anySymbolsPreserved = true; @@ -387,7 +385,7 @@ ld_plugin_status all_symbols_read_hook(void) { (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); return LDPS_ERR; } - raw_fd_ostream *objFile = + raw_fd_ostream *objFile = new raw_fd_ostream(uniqueObjPath.c_str(), ErrMsg, raw_fd_ostream::F_Binary); if (!ErrMsg.empty()) { @@ -412,7 +410,7 @@ ld_plugin_status all_symbols_read_hook(void) { return LDPS_OK; } -ld_plugin_status cleanup_hook(void) { +static ld_plugin_status cleanup_hook(void) { std::string ErrMsg; for (int i = 0, e = Cleanup.size(); i != e; ++i) diff --git a/tools/gold/gold.exports b/tools/gold/gold.exports new file mode 100644 index 0000000..277a33a --- /dev/null +++ b/tools/gold/gold.exports @@ -0,0 +1 @@ +onload diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index dccfb26..378cc63 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -49,9 +49,6 @@ InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-")); static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); -static cl::opt<bool> -Force("f", cl::desc("Enable binary output on terminals")); - // Determine optimization level. static cl::opt<char> OptLevel("O", diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 81c17cd..4e3e07f 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -192,7 +192,7 @@ int main(int argc, char **argv, char * const *envp) { } else { // Otherwise, if there is a .bc suffix on the executable strip it off, it // might confuse the program. - if (InputFile.rfind(".bc") == InputFile.length() - 3) + if (StringRef(InputFile).endswith(".bc")) InputFile.erase(InputFile.length() - 3); } diff --git a/tools/llvm-ld/llvm-ld.cpp b/tools/llvm-ld/llvm-ld.cpp index 29b74b8..ce52b59 100644 --- a/tools/llvm-ld/llvm-ld.cpp +++ b/tools/llvm-ld/llvm-ld.cpp @@ -399,7 +399,7 @@ static int GenerateNative(const std::string &OutputFilename, // Run the compiler to assembly and link together the program. int R = sys::Program::ExecuteAndWait( - gcc, &Args[0], (const char**)clean_env, 0, 0, 0, &ErrMsg); + gcc, &Args[0], const_cast<const char **>(clean_env), 0, 0, 0, &ErrMsg); delete [] clean_env; return R; } diff --git a/tools/llvm-mc/CMakeLists.txt b/tools/llvm-mc/CMakeLists.txt index 49c2932..8b61a4e 100644 --- a/tools/llvm-mc/CMakeLists.txt +++ b/tools/llvm-mc/CMakeLists.txt @@ -1,3 +1,4 @@ +set( LLVM_USED_LIBS EnhancedDisassembly) set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC MCParser) add_llvm_tool(llvm-mc diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index 9fe0790..9234a14 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -15,6 +15,7 @@ #include "Disassembler.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" @@ -24,6 +25,9 @@ #include "llvm/Support/MemoryObject.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" + +#include "llvm-c/EnhancedDisassembly.h" + using namespace llvm; typedef std::vector<std::pair<unsigned char, const char*> > ByteArrayTy; @@ -64,8 +68,7 @@ static bool PrintInsts(const MCDisassembler &DisAsm, /*REMOVE*/ nulls())) { Printer.printInst(&Inst, outs()); outs() << "\n"; - } - else { + } else { SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second), "invalid instruction encoding", "warning"); if (Size == 0) @@ -76,37 +79,9 @@ static bool PrintInsts(const MCDisassembler &DisAsm, return false; } -int Disassembler::disassemble(const Target &T, const std::string &Triple, - MemoryBuffer &Buffer) { - // Set up disassembler. - OwningPtr<const MCAsmInfo> AsmInfo(T.createAsmInfo(Triple)); - - if (!AsmInfo) { - errs() << "error: no assembly info for target " << Triple << "\n"; - return -1; - } - - OwningPtr<const MCDisassembler> DisAsm(T.createMCDisassembler()); - if (!DisAsm) { - errs() << "error: no disassembler for target " << Triple << "\n"; - return -1; - } - - OwningPtr<MCInstPrinter> IP(T.createMCInstPrinter(0, *AsmInfo)); - if (!IP) { - errs() << "error: no instruction printer for target " << Triple << '\n'; - return -1; - } - - bool ErrorOccurred = false; - - SourceMgr SM; - SM.AddNewSourceBuffer(&Buffer, SMLoc()); - - // Convert the input to a vector for disassembly. - ByteArrayTy ByteArray; - - StringRef Str = Buffer.getBuffer(); +static bool ByteArrayFromString(ByteArrayTy &ByteArray, + StringRef &Str, + SourceMgr &SM) { while (!Str.empty()) { // Strip horizontal whitespace. if (size_t Pos = Str.find_first_not_of(" \t\r")) { @@ -119,9 +94,9 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple, if (Str[0] == '\n' || Str[0] == '#') { // Strip to the end of line if we already processed any bytes on this // line. This strips the comment and/or the \n. - if (Str[0] == '\n') + if (Str[0] == '\n') { Str = Str.substr(1); - else { + } else { Str = Str.substr(Str.find_first_of('\n')); if (!Str.empty()) Str = Str.substr(1); @@ -138,8 +113,7 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple, if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) { // If we have an error, print it and skip to the end of line. SM.PrintMessage(SMLoc::getFromPointer(Value.data()), - "invalid input token", "error"); - ErrorOccurred = true; + "invalid input token", "error"); Str = Str.substr(Str.find('\n')); ByteArray.clear(); continue; @@ -149,8 +123,231 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple, Str = Str.substr(Next); } + return false; +} + +int Disassembler::disassemble(const Target &T, const std::string &Triple, + MemoryBuffer &Buffer) { + // Set up disassembler. + OwningPtr<const MCAsmInfo> AsmInfo(T.createAsmInfo(Triple)); + + if (!AsmInfo) { + errs() << "error: no assembly info for target " << Triple << "\n"; + return -1; + } + + OwningPtr<const MCDisassembler> DisAsm(T.createMCDisassembler()); + if (!DisAsm) { + errs() << "error: no disassembler for target " << Triple << "\n"; + return -1; + } + + int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); + OwningPtr<MCInstPrinter> IP(T.createMCInstPrinter(AsmPrinterVariant, + *AsmInfo)); + if (!IP) { + errs() << "error: no instruction printer for target " << Triple << '\n'; + return -1; + } + + bool ErrorOccurred = false; + + SourceMgr SM; + SM.AddNewSourceBuffer(&Buffer, SMLoc()); + + // Convert the input to a vector for disassembly. + ByteArrayTy ByteArray; + StringRef Str = Buffer.getBuffer(); + + ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM); + if (!ByteArray.empty()) ErrorOccurred |= PrintInsts(*DisAsm, *IP, ByteArray, SM); return ErrorOccurred; } + +static int byteArrayReader(uint8_t *B, uint64_t A, void *Arg) { + ByteArrayTy &ByteArray = *((ByteArrayTy*)Arg); + + if (A >= ByteArray.size()) + return -1; + + *B = ByteArray[A].first; + + return 0; +} + +static int verboseEvaluator(uint64_t *V, unsigned R, void *Arg) { + EDDisassemblerRef &disassembler = *((EDDisassemblerRef*)Arg); + + const char *regName; + + if (!EDGetRegisterName(®Name, + disassembler, + R)) + outs() << "[" << regName << "/" << R << "]"; + if (EDRegisterIsStackPointer(disassembler, R)) + outs() << "(sp)"; + if (EDRegisterIsProgramCounter(disassembler, R)) + outs() << "(pc)"; + + *V = 0; + + return 0; +} + +int Disassembler::disassembleEnhanced(const std::string &TS, + MemoryBuffer &Buffer) { + ByteArrayTy ByteArray; + StringRef Str = Buffer.getBuffer(); + SourceMgr SM; + + SM.AddNewSourceBuffer(&Buffer, SMLoc()); + + if (ByteArrayFromString(ByteArray, Str, SM)) { + return -1; + } + + EDDisassemblerRef disassembler; + + Triple T(TS); + EDAssemblySyntax_t AS; + + switch (T.getArch()) { + default: + errs() << "error: no default assembly syntax for " << TS.c_str() << "\n"; + return -1; + case Triple::arm: + case Triple::thumb: + AS = kEDAssemblySyntaxARMUAL; + break; + case Triple::x86: + case Triple::x86_64: + AS = kEDAssemblySyntaxX86ATT; + break; + } + + if (EDGetDisassembler(&disassembler, + TS.c_str(), + AS)) { + errs() << "error: couldn't get disassembler for " << TS.c_str() << "\n"; + return -1; + } + + EDInstRef inst; + + if (EDCreateInsts(&inst, 1, disassembler, byteArrayReader, 0,&ByteArray) + != 1) { + errs() << "error: Didn't get an instruction\n"; + return -1; + } + + int numTokens = EDNumTokens(inst); + + if (numTokens < 0) { + errs() << "error: Couldn't count the instruction's tokens\n"; + return -1; + } + + int tokenIndex; + + for (tokenIndex = 0; tokenIndex < numTokens; ++tokenIndex) { + EDTokenRef token; + + if (EDGetToken(&token, inst, tokenIndex)) { + errs() << "error: Couldn't get token\n"; + return -1; + } + + const char *buf; + + if (EDGetTokenString(&buf, token)) { + errs() << "error: Couldn't get string for token\n"; + return -1; + } + + outs() << "["; + + int operandIndex = EDOperandIndexForToken(token); + + if (operandIndex >= 0) + outs() << operandIndex << "-"; + + if (EDTokenIsWhitespace(token)) { + outs() << "w"; + } else if (EDTokenIsPunctuation(token)) { + outs() << "p"; + } else if (EDTokenIsOpcode(token)) { + outs() << "o"; + } else if (EDTokenIsLiteral(token)) { + outs() << "l"; + } else if (EDTokenIsRegister(token)) { + outs() << "r"; + } else { + outs() << "?"; + } + + outs() << ":" << buf; + + if (EDTokenIsLiteral(token)) { + outs() << "="; + if (EDTokenIsNegativeLiteral(token)) + outs() << "-"; + uint64_t absoluteValue; + if (EDLiteralTokenAbsoluteValue(&absoluteValue, token)) { + errs() << "error: Couldn't get the value of a literal token\n"; + return -1; + } + outs() << absoluteValue; + } else if (EDTokenIsRegister(token)) { + outs() << "="; + unsigned regID; + if (EDRegisterTokenValue(®ID, token)) { + errs() << "error: Couldn't get the ID of a register token\n"; + return -1; + } + outs() << "r" << regID; + } + + outs() << "]"; + } + + outs() << " "; + + int numOperands = EDNumOperands(inst); + + if (numOperands < 0) { + errs() << "error: Couldn't count operands\n"; + return -1; + } + + int operandIndex; + + for (operandIndex = 0; operandIndex < numOperands; ++operandIndex) { + outs() << operandIndex << ":"; + + EDOperandRef operand; + + if (EDGetOperand(&operand, + inst, + operandIndex)) { + errs() << "error: Couldn't get operand\n"; + return -1; + } + + uint64_t evaluatedResult; + + EDEvaluateOperand(&evaluatedResult, + operand, + verboseEvaluator, + &disassembler); + + outs() << " "; + } + + outs() << "\n"; + + return 0; +} + diff --git a/tools/llvm-mc/Disassembler.h b/tools/llvm-mc/Disassembler.h index 78c2f85..3da2396 100644 --- a/tools/llvm-mc/Disassembler.h +++ b/tools/llvm-mc/Disassembler.h @@ -27,6 +27,9 @@ public: static int disassemble(const Target &target, const std::string &tripleString, MemoryBuffer &buffer); + + static int disassembleEnhanced(const std::string &tripleString, + MemoryBuffer &buffer); }; } // namespace llvm diff --git a/tools/llvm-mc/Makefile b/tools/llvm-mc/Makefile index 5b0fe3f..f92e643 100644 --- a/tools/llvm-mc/Makefile +++ b/tools/llvm-mc/Makefile @@ -22,3 +22,6 @@ include $(LEVEL)/Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) MCParser MC support include $(LLVM_SRC_ROOT)/Makefile.rules + +# Using LIBS instead of USEDLIBS to force static linking +LIBS += $(LLVMLibDir)/libEnhancedDisassembly.a diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index c6657f5..47f67c5 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -97,7 +97,8 @@ NoInitialTextSection("n", cl::desc( enum ActionType { AC_AsLex, AC_Assemble, - AC_Disassemble + AC_Disassemble, + AC_EDisassemble }; static cl::opt<ActionType> @@ -109,6 +110,8 @@ Action(cl::desc("Action to perform:"), "Assemble a .s file (default)"), clEnumValN(AC_Disassemble, "disassemble", "Disassemble strings of hex bytes"), + clEnumValN(AC_EDisassemble, "edis", + "Enhanced disassembly of strings of hex bytes"), clEnumValEnd)); static const Target *GetTarget(const char *ProgName) { @@ -325,7 +328,7 @@ static int AssembleInput(const char *ProgName) { return Res; } -static int DisassembleInput(const char *ProgName) { +static int DisassembleInput(const char *ProgName, bool Enhanced) { const Target *TheTarget = GetTarget(ProgName); if (!TheTarget) return 0; @@ -344,7 +347,10 @@ static int DisassembleInput(const char *ProgName) { return 1; } - return Disassembler::disassemble(*TheTarget, TripleName, *Buffer); + if (Enhanced) + return Disassembler::disassembleEnhanced(TripleName, *Buffer); + else + return Disassembler::disassemble(*TheTarget, TripleName, *Buffer); } @@ -371,7 +377,9 @@ int main(int argc, char **argv) { case AC_Assemble: return AssembleInput(argv[0]); case AC_Disassemble: - return DisassembleInput(argv[0]); + return DisassembleInput(argv[0], false); + case AC_EDisassemble: + return DisassembleInput(argv[0], true); } return 0; diff --git a/tools/llvmc/plugins/Base/Base.td.in b/tools/llvmc/plugins/Base/Base.td.in index 3c4f4e9..23f46b7 100644 --- a/tools/llvmc/plugins/Base/Base.td.in +++ b/tools/llvmc/plugins/Base/Base.td.in @@ -244,7 +244,7 @@ def llc : Tool< [(in_language ["llvm-bitcode", "llvm-assembler"]), (out_language "assembler"), (output_suffix "s"), - (command "llc -f"), + (command "llc"), (actions (case (switch_on "S"), (stop_compilation), (switch_on "O0"), (forward "O0"), @@ -263,7 +263,7 @@ def llc : Tool< // Base class for linkers class llvm_gcc_based_linker <string cmd_prefix> : Tool< -[(in_language "object-code"), +[(in_language ["object-code", "static-library"]), (out_language "executable"), (output_suffix "out"), (command cmd_prefix), @@ -317,6 +317,7 @@ def LanguageMap : LanguageMap< LangToSuffixes<"llvm-assembler", ["ll"]>, LangToSuffixes<"llvm-bitcode", ["bc"]>, LangToSuffixes<"object-code", ["o", "*empty*"]>, + LangToSuffixes<"static-library", ["a", "lib"]>, LangToSuffixes<"executable", ["out"]> ]>; diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index bc65b3a..1010592 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -328,7 +328,7 @@ void LTOCodeGenerator::applyScopeRestrictions() { } for (Module::global_iterator v = mergedModule->global_begin(), e = mergedModule->global_end(); v != e; ++v) { - if (v->isDeclaration() && + if (!v->isDeclaration() && _mustPreserveSymbols.count(mangler.getNameWithPrefix(v))) mustPreserveList.push_back(::strdup(v->getNameStr().c_str())); } @@ -353,24 +353,10 @@ bool LTOCodeGenerator::generateAssemblyCode(formatted_raw_ostream& out, Module* mergedModule = _linker.getModule(); - // If target supports exception handling then enable it now. - switch (_target->getMCAsmInfo()->getExceptionHandlingType()) { - case ExceptionHandling::Dwarf: - llvm::DwarfExceptionHandling = true; - break; - case ExceptionHandling::SjLj: - llvm::SjLjExceptionHandling = true; - break; - case ExceptionHandling::None: - break; - default: - assert (0 && "Unknown exception handling model!"); - } - // if options were requested, set them if ( !_codegenOptions.empty() ) cl::ParseCommandLineOptions(_codegenOptions.size(), - (char**)&_codegenOptions[0]); + const_cast<char **>(&_codegenOptions[0])); // Instantiate the pass manager to organize the passes. PassManager passes; diff --git a/tools/lto/Makefile b/tools/lto/Makefile index 3120aa5..8d57333 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -10,6 +10,8 @@ LEVEL = ../.. LIBRARYNAME = LTO +EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/lto.exports + # Include this here so we can get the configuration of the targets # that have been configured for construction. We have to do this # early so we can set up LINK_COMPONENTS before including Makefile.rules @@ -32,7 +34,6 @@ ifeq ($(HOST_OS),Darwin) # extra options to override libtool defaults LLVMLibsOptions := $(LLVMLibsOptions) \ -avoid-version \ - -Wl,-exported_symbols_list -Wl,$(PROJ_SRC_DIR)/lto.exports \ -Wl,-dead_strip \ -Wl,-seg1addr -Wl,0xE0000000 diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports index 01f43d1..9011cf6 100644 --- a/tools/lto/lto.exports +++ b/tools/lto/lto.exports @@ -1,24 +1,23 @@ -_lto_get_error_message -_lto_get_version -_lto_module_create -_lto_module_create_from_memory -_lto_module_get_num_symbols -_lto_module_get_symbol_attribute -_lto_module_get_symbol_name -_lto_module_get_target_triple -_lto_module_is_object_file -_lto_module_is_object_file_for_target -_lto_module_is_object_file_in_memory -_lto_module_is_object_file_in_memory_for_target -_lto_module_dispose -_lto_codegen_add_module -_lto_codegen_add_must_preserve_symbol -_lto_codegen_compile -_lto_codegen_create -_lto_codegen_dispose -_lto_codegen_set_debug_model -_lto_codegen_set_pic_model -_lto_codegen_write_merged_modules -_lto_codegen_debug_options -_lto_codegen_set_assembler_path - +lto_get_error_message +lto_get_version +lto_module_create +lto_module_create_from_memory +lto_module_get_num_symbols +lto_module_get_symbol_attribute +lto_module_get_symbol_name +lto_module_get_target_triple +lto_module_is_object_file +lto_module_is_object_file_for_target +lto_module_is_object_file_in_memory +lto_module_is_object_file_in_memory_for_target +lto_module_dispose +lto_codegen_add_module +lto_codegen_add_must_preserve_symbol +lto_codegen_compile +lto_codegen_create +lto_codegen_dispose +lto_codegen_set_debug_model +lto_codegen_set_pic_model +lto_codegen_write_merged_modules +lto_codegen_debug_options +lto_codegen_set_assembler_path diff --git a/tools/opt/AnalysisWrappers.cpp b/tools/opt/AnalysisWrappers.cpp index 18360f8..f548d00 100644 --- a/tools/opt/AnalysisWrappers.cpp +++ b/tools/opt/AnalysisWrappers.cpp @@ -22,7 +22,6 @@ #include "llvm/Support/CallSite.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Support/raw_ostream.h" -#include <iostream> using namespace llvm; namespace { diff --git a/tools/opt/GraphPrinters.cpp b/tools/opt/GraphPrinters.cpp index bbf8d12..86f9932 100644 --- a/tools/opt/GraphPrinters.cpp +++ b/tools/opt/GraphPrinters.cpp @@ -19,12 +19,11 @@ #include "llvm/Value.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/Dominators.h" -#include <iostream> -#include <fstream> +#include "llvm/Support/raw_ostream.h" using namespace llvm; template<typename GraphType> -static void WriteGraphToFile(std::ostream &O, const std::string &GraphName, +static void WriteGraphToFile(raw_ostream &O, const std::string &GraphName, const GraphType >) { std::string Filename = GraphName + ".dot"; O << "Writing '" << Filename << "'..."; @@ -69,7 +68,7 @@ namespace { CallGraphPrinter() : ModulePass(&ID) {} virtual bool runOnModule(Module &M) { - WriteGraphToFile(std::cerr, "callgraph", &getAnalysis<CallGraph>()); + WriteGraphToFile(llvm::errs(), "callgraph", &getAnalysis<CallGraph>()); return false; } diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 311f671..ff19942 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -141,15 +141,14 @@ struct CallGraphSCCPassPrinter : public CallGraphSCCPass { CallGraphSCCPassPrinter(const PassInfo *PI) : CallGraphSCCPass(&ID), PassToPrint(PI) {} - virtual bool runOnSCC(std::vector<CallGraphNode *>&SCC) { + virtual bool runOnSCC(CallGraphSCC &SCC) { if (!Quiet) { outs() << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; - for (unsigned i = 0, e = SCC.size(); i != e; ++i) { - Function *F = SCC[i]->getFunction(); - if (F) { + for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { + Function *F = (*I)->getFunction(); + if (F) getAnalysisID<Pass>(PassToPrint).print(outs(), F->getParent()); - } } } // Get and print pass... |