diff options
Diffstat (limited to 'tools')
102 files changed, 3000 insertions, 3429 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index b9c77b1..7ed10e9 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -27,8 +27,10 @@ add_subdirectory(llvm-link) add_subdirectory(lli) add_subdirectory(llvm-extract) +add_subdirectory(llvm-diff) add_subdirectory(bugpoint) +add_subdirectory(bugpoint-passes) add_subdirectory(llvm-bcanalyzer) add_subdirectory(llvm-stub) add_subdirectory(edis) diff --git a/tools/Makefile b/tools/Makefile index 9bc74fe..aa07a2b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -15,16 +15,13 @@ 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. - -# libEnhancedDisassembly must be built ahead of llvm-mc -# because llvm-mc links against libEnhancedDisassembly -DIRS := llvm-config edis llvm-mc +DIRS := llvm-config PARALLEL_DIRS := opt llvm-as llvm-dis \ llc llvm-ranlib llvm-ar llvm-nm \ llvm-ld llvm-prof llvm-link \ - lli llvm-extract \ + lli llvm-extract llvm-mc \ bugpoint llvm-bcanalyzer llvm-stub \ - llvmc + llvmc llvm-diff # Let users override the set of tools to build from the command line. ifdef ONLY_TOOLS @@ -34,6 +31,7 @@ endif include $(LEVEL)/Makefile.config + # These libraries build as dynamic libraries (.dylib /.so), they can only be # built if ENABLE_PIC is set. ifeq ($(ENABLE_PIC),1) @@ -46,6 +44,16 @@ ifeq ($(ENABLE_PIC),1) else PARALLEL_DIRS += lto endif + + PARALLEL_DIRS += bugpoint-passes + + # The edis library is only supported if ARM and/or X86 are enabled, and if + # LLVM is being built PIC on platforms that support dylibs. + ifneq ($(DISABLE_EDIS),1) + ifneq ($(filter $(TARGETS_TO_BUILD), X86 ARM),) + PARALLEL_DIRS += edis + endif + endif endif endif diff --git a/tools/bugpoint-passes/CMakeLists.txt b/tools/bugpoint-passes/CMakeLists.txt new file mode 100644 index 0000000..50109a5 --- /dev/null +++ b/tools/bugpoint-passes/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_loadable_module( BugpointPasses + TestPasses.cpp + ) diff --git a/tools/bugpoint-passes/Makefile b/tools/bugpoint-passes/Makefile new file mode 100644 index 0000000..b4ad3e4 --- /dev/null +++ b/tools/bugpoint-passes/Makefile @@ -0,0 +1,23 @@ +##===- tools/bugpoint-passes/Makefile -- -------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +LIBRARYNAME = BugpointPasses +LOADABLE_MODULE = 1 +USEDLIBS = + +# If we don't need RTTI or EH, there's no reason to export anything +# from this plugin. +ifneq ($(REQUIRES_RTTI), 1) +ifneq ($(REQUIRES_EH), 1) +EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/bugpoint.exports +endif +endif + +include $(LEVEL)/Makefile.common diff --git a/tools/bugpoint/TestPasses.cpp b/tools/bugpoint-passes/TestPasses.cpp index 900bf63..1535b03 100644 --- a/tools/bugpoint/TestPasses.cpp +++ b/tools/bugpoint-passes/TestPasses.cpp @@ -27,7 +27,7 @@ namespace { class CrashOnCalls : public BasicBlockPass { public: static char ID; // Pass ID, replacement for typeid - CrashOnCalls() : BasicBlockPass(&ID) {} + CrashOnCalls() : BasicBlockPass(ID) {} private: virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -41,12 +41,12 @@ namespace { return false; } }; +} - char CrashOnCalls::ID = 0; - RegisterPass<CrashOnCalls> +char CrashOnCalls::ID = 0; +static RegisterPass<CrashOnCalls> X("bugpoint-crashcalls", "BugPoint Test Pass - Intentionally crash on CallInsts"); -} namespace { /// DeleteCalls - This pass is used to test bugpoint. It intentionally @@ -54,7 +54,7 @@ namespace { class DeleteCalls : public BasicBlockPass { public: static char ID; // Pass ID, replacement for typeid - DeleteCalls() : BasicBlockPass(&ID) {} + DeleteCalls() : BasicBlockPass(ID) {} private: bool runOnBasicBlock(BasicBlock &BB) { for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) @@ -67,9 +67,9 @@ namespace { return false; } }; +} - char DeleteCalls::ID = 0; - RegisterPass<DeleteCalls> +char DeleteCalls::ID = 0; +static RegisterPass<DeleteCalls> Y("bugpoint-deletecalls", "BugPoint Test Pass - Intentionally 'misoptimize' CallInsts"); -} diff --git a/tools/bugpoint-passes/bugpoint.exports b/tools/bugpoint-passes/bugpoint.exports new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/bugpoint-passes/bugpoint.exports diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index 45a0d4d..6966671 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -56,22 +56,22 @@ void BugDriver::setNewProgram(Module *M) { /// getPassesString - Turn a list of passes into a string which indicates the /// command line options that must be passed to add the passes. /// -std::string llvm::getPassesString(const std::vector<const PassInfo*> &Passes) { +std::string llvm::getPassesString(const std::vector<std::string> &Passes) { std::string Result; for (unsigned i = 0, e = Passes.size(); i != e; ++i) { if (i) Result += " "; Result += "-"; - Result += Passes[i]->getPassArgument(); + Result += Passes[i]; } return Result; } -BugDriver::BugDriver(const char *toolname, bool as_child, bool find_bugs, +BugDriver::BugDriver(const char *toolname, bool find_bugs, unsigned timeout, unsigned memlimit, bool use_valgrind, LLVMContext& ctxt) : Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile), Program(0), Interpreter(0), SafeInterpreter(0), gcc(0), - run_as_child(as_child), run_find_bugs(find_bugs), Timeout(timeout), + run_find_bugs(find_bugs), Timeout(timeout), MemoryLimit(memlimit), UseValgrind(use_valgrind) {} BugDriver::~BugDriver() { @@ -119,15 +119,13 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { Program = ParseInputFile(Filenames[0], Context); if (Program == 0) return true; - if (!run_as_child) - outs() << "Read input file : '" << Filenames[0] << "'\n"; + outs() << "Read input file : '" << Filenames[0] << "'\n"; for (unsigned i = 1, e = Filenames.size(); i != e; ++i) { std::auto_ptr<Module> M(ParseInputFile(Filenames[i], Context)); if (M.get() == 0) return true; - if (!run_as_child) - outs() << "Linking in input file: '" << Filenames[i] << "'\n"; + 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] << "': " @@ -136,8 +134,7 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { } } - if (!run_as_child) - outs() << "*** All input ok\n"; + outs() << "*** All input ok\n"; // All input files read successfully! return false; @@ -149,14 +146,6 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { /// variables are set up from command line arguments. /// bool BugDriver::run(std::string &ErrMsg) { - // The first thing to do is determine if we're running as a child. If we are, - // then what to do is very narrow. This form of invocation is only called - // from the runPasses method to actually run those passes in a child process. - if (run_as_child) { - // Execute the passes - return runPassesAsChild(PassesToRun); - } - if (run_find_bugs) { // Rearrange the passes and apply them to the program. Repeat this process // until the user kills the program or we find a bug. @@ -172,7 +161,7 @@ bool BugDriver::run(std::string &ErrMsg) { // miscompilation. if (!PassesToRun.empty()) { outs() << "Running selected passes on program to test for crash: "; - if (runPasses(PassesToRun)) + if (runPasses(Program, PassesToRun)) return debugOptimizerCrash(); } @@ -211,7 +200,7 @@ bool BugDriver::run(std::string &ErrMsg) { // matches, then we assume there is a miscompilation bug and try to // diagnose it. outs() << "*** Checking the code generator...\n"; - bool Diff = diffProgram("", "", false, &Error); + bool Diff = diffProgram(Program, "", "", false, &Error); if (!Error.empty()) { errs() << Error; return debugCodeGeneratorCrash(ErrMsg); diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index 4f6bae5..e48806a 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -47,11 +47,10 @@ class BugDriver { const char *ToolName; // argv[0] of bugpoint std::string ReferenceOutputFile; // Name of `good' output file Module *Program; // The raw program, linked together - std::vector<const PassInfo*> PassesToRun; + std::vector<std::string> PassesToRun; AbstractInterpreter *Interpreter; // How to run the program AbstractInterpreter *SafeInterpreter; // To generate reference output, etc. GCC *gcc; - bool run_as_child; bool run_find_bugs; unsigned Timeout; unsigned MemoryLimit; @@ -62,25 +61,24 @@ class BugDriver { friend class ReduceMisCodegenFunctions; public: - BugDriver(const char *toolname, bool as_child, bool find_bugs, + BugDriver(const char *toolname, bool find_bugs, unsigned timeout, unsigned memlimit, bool use_valgrind, LLVMContext& ctxt); ~BugDriver(); const char *getToolName() const { return ToolName; } - LLVMContext& getContext() { return Context; } + LLVMContext& getContext() const { return Context; } // Set up methods... these methods are used to copy information about the // command line arguments into instance variables of BugDriver. // bool addSources(const std::vector<std::string> &FileNames); - template<class It> - void addPasses(It I, It E) { PassesToRun.insert(PassesToRun.end(), I, E); } - void setPassesToRun(const std::vector<const PassInfo*> &PTR) { + void addPass(std::string p) { PassesToRun.push_back(p); } + void setPassesToRun(const std::vector<std::string> &PTR) { PassesToRun = PTR; } - const std::vector<const PassInfo*> &getPassesToRun() const { + const std::vector<std::string> &getPassesToRun() const { return PassesToRun; } @@ -132,12 +130,8 @@ public: /// runPasses - Run all of the passes in the "PassesToRun" list, discard the /// output, and return true if any of the passes crashed. - bool runPasses(Module *M = 0) { - if (M == 0) M = Program; - std::swap(M, Program); - bool Result = runPasses(PassesToRun); - std::swap(M, Program); - return Result; + bool runPasses(Module *M) const { + return runPasses(M, PassesToRun); } Module *getProgram() const { return Program; } @@ -169,23 +163,26 @@ public: /// setting Error if an error occurs. This is used for code generation /// crash testing. /// - void compileProgram(Module *M, std::string *Error); + void compileProgram(Module *M, std::string *Error) const; /// executeProgram - This method runs "Program", capturing the output of the /// program to a file. A recommended filename may be optionally specified. /// - std::string executeProgram(std::string OutputFilename, + std::string executeProgram(const Module *Program, + std::string OutputFilename, std::string Bitcode, const std::string &SharedObjects, AbstractInterpreter *AI, - std::string *Error); + std::string *Error) const; /// executeProgramSafely - Used to create reference output with the "safe" /// backend, if reference output is not provided. If there is a problem with /// the code generator (e.g., llc crashes), this will return false and set /// Error. /// - std::string executeProgramSafely(std::string OutputFile, std::string *Error); + std::string executeProgramSafely(const Module *Program, + std::string OutputFile, + std::string *Error) const; /// createReferenceFile - calls compileProgram and then records the output /// into ReferenceOutputFile. Returns true if reference file created, false @@ -200,23 +197,24 @@ public: /// 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 = "", + bool diffProgram(const Module *Program, + const std::string &BitcodeFile = "", const std::string &SharedObj = "", bool RemoveBitcode = false, - std::string *Error = 0); + std::string *Error = 0) const; - /// EmitProgressBitcode - This function is used to output the current Program - /// to a file named "bugpoint-ID.bc". + /// EmitProgressBitcode - This function is used to output M to a file named + /// "bugpoint-ID.bc". /// - void EmitProgressBitcode(const std::string &ID, bool NoFlyer = false); + void EmitProgressBitcode(const Module *M, const std::string &ID, + bool NoFlyer = false) const; /// deleteInstructionFromProgram - This method clones the current Program and /// deletes the specified instruction from the cloned module. It then runs a /// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code /// which depends on the value. The modified module is then returned. /// - Module *deleteInstructionFromProgram(const Instruction *I, unsigned Simp) - const; + Module *deleteInstructionFromProgram(const Instruction *I, unsigned Simp); /// performFinalCleanups - This method clones the current Program and performs /// a series of cleanups intended to get rid of extra cruft on the module. If @@ -243,7 +241,7 @@ public: /// failure. If AutoDebugCrashes is set to true, then bugpoint will /// automatically attempt to track down a crashing pass if one exists, and /// this method will never return null. - Module *runPassesOn(Module *M, const std::vector<const PassInfo*> &Passes, + Module *runPassesOn(Module *M, const std::vector<std::string> &Passes, bool AutoDebugCrashes = false, unsigned NumExtraArgs = 0, const char * const *ExtraArgs = NULL); @@ -256,7 +254,8 @@ public: /// or failed, unless Quiet is set. ExtraArgs specifies additional arguments /// to pass to the child bugpoint instance. /// - bool runPasses(const std::vector<const PassInfo*> &PassesToRun, + bool runPasses(Module *Program, + const std::vector<std::string> &PassesToRun, std::string &OutputFilename, bool DeleteOutput = false, bool Quiet = false, unsigned NumExtraArgs = 0, const char * const *ExtraArgs = NULL) const; @@ -268,28 +267,26 @@ 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<std::string> &AllPasses, std::string &ErrMsg); /// writeProgramToFile - This writes the current "Program" to the named /// bitcode file. If an error occurs, true is returned. /// - bool writeProgramToFile(const std::string &Filename, Module *M = 0) const; + bool writeProgramToFile(const std::string &Filename, const Module *M) const; private: /// runPasses - Just like the method above, but this just returns true or /// false indicating whether or not the optimizer crashed on the specified /// input (true = crashed). /// - bool runPasses(const std::vector<const PassInfo*> &PassesToRun, + bool runPasses(Module *M, + const std::vector<std::string> &PassesToRun, bool DeleteOutput = true) const { std::string Filename; - return runPasses(PassesToRun, Filename, DeleteOutput); + return runPasses(M, PassesToRun, Filename, DeleteOutput); } - /// runAsChild - The actual "runPasses" guts that runs in a child process. - int runPassesAsChild(const std::vector<const PassInfo*> &PassesToRun); - /// initializeExecutionEnvironment - This method is used to set up the /// environment for executing LLVM programs. /// @@ -306,7 +303,7 @@ Module *ParseInputFile(const std::string &InputFilename, /// getPassesString - Turn a list of passes into a string which indicates the /// command line options that must be passed to add the passes. /// -std::string getPassesString(const std::vector<const PassInfo*> &Passes); +std::string getPassesString(const std::vector<std::string> &Passes); /// PrintFunctionList - prints out list of problematic functions /// diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt index 34b759f..e06feb1 100644 --- a/tools/bugpoint/CMakeLists.txt +++ b/tools/bugpoint/CMakeLists.txt @@ -9,7 +9,6 @@ add_llvm_tool(bugpoint FindBugs.cpp Miscompilation.cpp OptimizerDriver.cpp - TestPasses.cpp ToolRunner.cpp bugpoint.cpp ) diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index 2d0631c..57dc1c8 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -43,7 +43,7 @@ namespace { } namespace llvm { - class ReducePassList : public ListReducer<const PassInfo*> { + class ReducePassList : public ListReducer<std::string> { BugDriver &BD; public: ReducePassList(BugDriver &bd) : BD(bd) {} @@ -52,15 +52,15 @@ namespace llvm { // running the "Kept" passes fail when run on the output of the "removed" // passes. If we return true, we update the current module of bugpoint. // - virtual TestResult doTest(std::vector<const PassInfo*> &Removed, - std::vector<const PassInfo*> &Kept, + virtual TestResult doTest(std::vector<std::string> &Removed, + std::vector<std::string> &Kept, std::string &Error); }; } ReducePassList::TestResult -ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix, +ReducePassList::doTest(std::vector<std::string> &Prefix, + std::vector<std::string> &Suffix, std::string &Error) { sys::Path PrefixOutput; Module *OrigProgram = 0; @@ -68,7 +68,7 @@ ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, outs() << "Checking to see if these passes crash: " << getPassesString(Prefix) << ": "; std::string PfxOutput; - if (BD.runPasses(Prefix, PfxOutput)) + if (BD.runPasses(BD.getProgram(), Prefix, PfxOutput)) return KeepPrefix; PrefixOutput.set(PfxOutput); @@ -86,7 +86,7 @@ ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, outs() << "Checking to see if these passes crash: " << getPassesString(Suffix) << ": "; - if (BD.runPasses(Suffix)) { + if (BD.runPasses(BD.getProgram(), Suffix)) { delete OrigProgram; // The suffix crashes alone... return KeepSuffix; } @@ -106,10 +106,10 @@ namespace { /// class ReduceCrashingGlobalVariables : public ListReducer<GlobalVariable*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *); + bool (*TestFn)(const BugDriver &, Module *); public: ReduceCrashingGlobalVariables(BugDriver &bd, - bool (*testFn)(BugDriver &, Module *)) + bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<GlobalVariable*> &Prefix, @@ -176,10 +176,10 @@ namespace llvm { /// class ReduceCrashingFunctions : public ListReducer<Function*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *); + bool (*TestFn)(const BugDriver &, Module *); public: ReduceCrashingFunctions(BugDriver &bd, - bool (*testFn)(BugDriver &, Module *)) + bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<Function*> &Prefix, @@ -249,9 +249,10 @@ namespace { /// class ReduceCrashingBlocks : public ListReducer<const BasicBlock*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *); + bool (*TestFn)(const BugDriver &, Module *); public: - ReduceCrashingBlocks(BugDriver &bd, bool (*testFn)(BugDriver &, Module *)) + ReduceCrashingBlocks(BugDriver &bd, + bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<const BasicBlock*> &Prefix, @@ -311,17 +312,24 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { // a "persistent mapping" by turning basic blocks into <function, name> pairs. // This won't work well if blocks are unnamed, but that is just the risk we // have to take. - std::vector<std::pair<Function*, std::string> > BlockInfo; + std::vector<std::pair<std::string, std::string> > BlockInfo; for (SmallPtrSet<BasicBlock*, 8>::iterator I = Blocks.begin(), E = Blocks.end(); I != E; ++I) - BlockInfo.push_back(std::make_pair((*I)->getParent(), (*I)->getName())); + BlockInfo.push_back(std::make_pair((*I)->getParent()->getName(), + (*I)->getName())); // Now run the CFG simplify pass on the function... - PassManager Passes; - Passes.add(createCFGSimplificationPass()); - Passes.add(createVerifierPass()); - Passes.run(*M); + std::vector<std::string> Passes; + Passes.push_back("simplifycfg"); + Passes.push_back("verify"); + Module *New = BD.runPassesOn(M, Passes); + delete M; + if (!New) { + errs() << "simplifycfg failed!\n"; + exit(1); + } + M = New; // Try running on the hacked up program... if (TestFn(BD, M)) { @@ -330,8 +338,10 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { // Make sure to use basic block pointers that point into the now-current // module, and that they don't include any deleted blocks. BBs.clear(); + const ValueSymbolTable &GST = M->getValueSymbolTable(); for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) { - ValueSymbolTable &ST = BlockInfo[i].first->getValueSymbolTable(); + Function *F = cast<Function>(GST.lookup(BlockInfo[i].first)); + ValueSymbolTable &ST = F->getValueSymbolTable(); Value* V = ST.lookup(BlockInfo[i].second); if (V && V->getType() == Type::getLabelTy(V->getContext())) BBs.push_back(cast<BasicBlock>(V)); @@ -348,10 +358,10 @@ namespace { /// class ReduceCrashingInstructions : public ListReducer<const Instruction*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *); + bool (*TestFn)(const BugDriver &, Module *); public: - ReduceCrashingInstructions(BugDriver &bd, bool (*testFn)(BugDriver &, - Module *)) + ReduceCrashingInstructions(BugDriver &bd, + bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<const Instruction*> &Prefix, @@ -422,7 +432,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)(const BugDriver &, Module *), std::string &Error) { // See if we can get away with nuking some of the global variable initializers // in the program... @@ -471,7 +482,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *), return true; if (GVs.size() < OldSize) - BD.EmitProgressBitcode("reduced-global-variables"); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables"); } } } @@ -492,7 +503,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *), ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error); if (Functions.size() < OldSize) - BD.EmitProgressBitcode("reduced-function"); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); } // Attempt to delete entire basic blocks at a time to speed up @@ -509,7 +520,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *), unsigned OldSize = Blocks.size(); ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); if (Blocks.size() < OldSize) - BD.EmitProgressBitcode("reduced-blocks"); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks"); } // Attempt to delete instructions using bisection. This should help out nasty @@ -602,12 +613,12 @@ ExitLoops: } } - BD.EmitProgressBitcode("reduced-simplified"); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplified"); return false; } -static bool TestForOptimizerCrash(BugDriver &BD, Module *M) { +static bool TestForOptimizerCrash(const BugDriver &BD, Module *M) { return BD.runPasses(M); } @@ -628,14 +639,14 @@ bool BugDriver::debugOptimizerCrash(const std::string &ID) { << (PassesToRun.size() == 1 ? ": " : "es: ") << getPassesString(PassesToRun) << '\n'; - EmitProgressBitcode(ID); + EmitProgressBitcode(Program, ID); bool Success = DebugACrash(*this, TestForOptimizerCrash, Error); assert(Error.empty()); return Success; } -static bool TestForCodeGenCrash(BugDriver &BD, Module *M) { +static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) { std::string Error; BD.compileProgram(M, &Error); if (!Error.empty()) { diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index 57f12d5..7312484 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -293,7 +293,7 @@ bool BugDriver::initializeExecutionEnvironment() { /// setting Error if an error occurs. This is used for code generation /// crash testing. /// -void BugDriver::compileProgram(Module *M, std::string *Error) { +void BugDriver::compileProgram(Module *M, std::string *Error) const { // Emit the program to a bitcode file... sys::Path BitcodeFile (OutputPrefix + "-test-program.bc"); std::string ErrMsg; @@ -320,11 +320,12 @@ void BugDriver::compileProgram(Module *M, std::string *Error) { /// program to a file, returning the filename of the file. A recommended /// filename may be optionally specified. /// -std::string BugDriver::executeProgram(std::string OutputFile, +std::string BugDriver::executeProgram(const Module *Program, + std::string OutputFile, std::string BitcodeFile, const std::string &SharedObj, AbstractInterpreter *AI, - std::string *Error) { + std::string *Error) const { if (AI == 0) AI = Interpreter; assert(AI && "Interpreter should have been created already!"); bool CreatedBitcode = false; @@ -399,9 +400,10 @@ 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, - std::string *Error) { - return executeProgram(OutputFile, "", "", SafeInterpreter, Error); +std::string BugDriver::executeProgramSafely(const Module *Program, + std::string OutputFile, + std::string *Error) const { + return executeProgram(Program, OutputFile, "", "", SafeInterpreter, Error); } std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, @@ -440,7 +442,7 @@ bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { if (!Error.empty()) return false; - ReferenceOutputFile = executeProgramSafely(Filename, &Error); + ReferenceOutputFile = executeProgramSafely(Program, Filename, &Error); if (!Error.empty()) { errs() << Error; if (Interpreter != SafeInterpreter) { @@ -460,12 +462,14 @@ bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { /// 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, +bool BugDriver::diffProgram(const Module *Program, + const std::string &BitcodeFile, const std::string &SharedObject, bool RemoveBitcode, - std::string *ErrMsg) { + std::string *ErrMsg) const { // Execute the program, generating an output file... - sys::Path Output(executeProgram("", BitcodeFile, SharedObject, 0, ErrMsg)); + sys::Path Output(executeProgram(Program, "", BitcodeFile, SharedObject, 0, + ErrMsg)); if (!ErrMsg->empty()) return false; diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index d5611b5..524f130 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -55,13 +55,14 @@ namespace { /// depends on the value. The modified module is then returned. /// Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, - unsigned Simplification) const { - Module *Result = CloneModule(Program); + unsigned Simplification) { + // FIXME, use vmap? + Module *Clone = CloneModule(Program); const BasicBlock *PBB = I->getParent(); const Function *PF = PBB->getParent(); - Module::iterator RFI = Result->begin(); // Get iterator to corresponding fn + Module::iterator RFI = Clone->begin(); // Get iterator to corresponding fn std::advance(RFI, std::distance(PF->getParent()->begin(), Module::const_iterator(PF))); @@ -79,30 +80,23 @@ Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, // Remove the instruction from the program. TheInst->getParent()->getInstList().erase(TheInst); - - //writeProgramToFile("current.bc", Result); - // Spiff up the output a little bit. - PassManager Passes; - // Make sure that the appropriate target data is always used... - Passes.add(new TargetData(Result)); + std::vector<std::string> Passes; - /// FIXME: If this used runPasses() like the methods below, we could get rid - /// of the -disable-* options! + /// Can we get rid of the -disable-* options? if (Simplification > 1 && !NoDCE) - Passes.add(createDeadCodeEliminationPass()); + Passes.push_back("dce"); if (Simplification && !DisableSimplifyCFG) - Passes.add(createCFGSimplificationPass()); // Delete dead control flow - - Passes.add(createVerifierPass()); - Passes.run(*Result); - return Result; -} - -static const PassInfo *getPI(Pass *P) { - const PassInfo *PI = P->getPassInfo(); - delete P; - return PI; + Passes.push_back("simplifycfg"); // Delete dead control flow + + Passes.push_back("verify"); + Module *New = runPassesOn(Clone, Passes); + delete Clone; + if (!New) { + errs() << "Instruction removal failed. Sorry. :( Please report a bug!\n"; + exit(1); + } + return New; } /// performFinalCleanups - This method clones the current Program and performs @@ -114,15 +108,15 @@ Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) { for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) I->setLinkage(GlobalValue::ExternalLinkage); - std::vector<const PassInfo*> CleanupPasses; - CleanupPasses.push_back(getPI(createGlobalDCEPass())); + std::vector<std::string> CleanupPasses; + CleanupPasses.push_back("globaldce"); if (MayModifySemantics) - CleanupPasses.push_back(getPI(createDeadArgHackingPass())); + CleanupPasses.push_back("deadarghaX0r"); else - CleanupPasses.push_back(getPI(createDeadArgEliminationPass())); + CleanupPasses.push_back("deadargelim"); - CleanupPasses.push_back(getPI(createDeadTypeEliminationPass())); + CleanupPasses.push_back("deadtypeelim"); Module *New = runPassesOn(M, CleanupPasses); if (New == 0) { @@ -138,16 +132,14 @@ Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) { /// function. This returns null if there are no extractable loops in the /// program or if the loop extractor crashes. Module *BugDriver::ExtractLoop(Module *M) { - std::vector<const PassInfo*> LoopExtractPasses; - LoopExtractPasses.push_back(getPI(createSingleLoopExtractorPass())); + std::vector<std::string> LoopExtractPasses; + LoopExtractPasses.push_back("loop-extract-single"); Module *NewM = runPassesOn(M, LoopExtractPasses); if (NewM == 0) { - Module *Old = swapProgramIn(M); outs() << "*** Loop extraction failed: "; - EmitProgressBitcode("loopextraction", true); + EmitProgressBitcode(M, "loopextraction", true); outs() << "*** Sorry. :( Please report a bug!\n"; - swapProgramIn(Old); return 0; } @@ -201,7 +193,7 @@ static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) { /// static ctors/dtors, we need to add an llvm.global_[cd]tors global to M2, and /// prune appropriate entries out of M1s list. static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2, - ValueMap<const Value*, Value*> VMap) { + ValueMap<const Value*, Value*> &VMap) { GlobalVariable *GV = M1->getNamedGlobal(GlobalName); if (!GV || GV->isDeclaration() || GV->hasLocalLinkage() || !GV->use_empty()) return; @@ -327,22 +319,18 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) { outs() << "*** Basic Block extraction failed!\n"; errs() << "Error creating temporary file: " << ErrMsg << "\n"; - M = swapProgramIn(M); - EmitProgressBitcode("basicblockextractfail", true); - swapProgramIn(M); + EmitProgressBitcode(M, "basicblockextractfail", true); return 0; } sys::RemoveFileOnSignal(uniqueFilename); std::string ErrorInfo; - raw_fd_ostream BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); + tool_output_file BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); if (!ErrorInfo.empty()) { outs() << "*** Basic Block extraction failed!\n"; errs() << "Error writing list of blocks to not extract: " << ErrorInfo << "\n"; - M = swapProgramIn(M); - EmitProgressBitcode("basicblockextractfail", true); - swapProgramIn(M); + EmitProgressBitcode(M, "basicblockextractfail", true); return 0; } for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end(); @@ -351,26 +339,31 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const // If the BB doesn't have a name, give it one so we have something to key // off of. if (!BB->hasName()) BB->setName("tmpbb"); - BlocksToNotExtractFile << BB->getParent()->getNameStr() << " " - << BB->getName() << "\n"; + BlocksToNotExtractFile.os() << BB->getParent()->getNameStr() << " " + << BB->getName() << "\n"; + } + BlocksToNotExtractFile.os().close(); + if (BlocksToNotExtractFile.os().has_error()) { + errs() << "Error writing list of blocks to not extract: " << ErrorInfo + << "\n"; + EmitProgressBitcode(M, "basicblockextractfail", true); + BlocksToNotExtractFile.os().clear_error(); + return 0; } - BlocksToNotExtractFile.close(); + BlocksToNotExtractFile.keep(); std::string uniqueFN = "--extract-blocks-file=" + uniqueFilename.str(); const char *ExtraArg = uniqueFN.c_str(); - std::vector<const PassInfo*> PI; - std::vector<BasicBlock *> EmptyBBs; // This parameter is ignored. - PI.push_back(getPI(createBlockExtractorPass(EmptyBBs))); + std::vector<std::string> PI; + PI.push_back("extract-blocks"); Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg); uniqueFilename.eraseFromDisk(); // Free disk space if (Ret == 0) { outs() << "*** Basic Block extraction failed, please report a bug!\n"; - M = swapProgramIn(M); - EmitProgressBitcode("basicblockextractfail", true); - swapProgramIn(M); + EmitProgressBitcode(M, "basicblockextractfail", true); } return Ret; } diff --git a/tools/bugpoint/FindBugs.cpp b/tools/bugpoint/FindBugs.cpp index 224c717..a291f9f 100644 --- a/tools/bugpoint/FindBugs.cpp +++ b/tools/bugpoint/FindBugs.cpp @@ -29,7 +29,7 @@ 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<std::string> &AllPasses, std::string &ErrMsg) { setPassesToRun(AllPasses); outs() << "Starting bug finding procedure...\n\n"; @@ -58,11 +58,11 @@ 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] << " "; } std::string Filename; - if(runPasses(PassesToRun, Filename, false)) { + if(runPasses(Program, PassesToRun, Filename, false)) { outs() << "\n"; outs() << "Optimizer passes caused failure!\n\n"; debugOptimizerCrash(); @@ -89,7 +89,7 @@ bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses, // output (created above). // outs() << "*** Checking if passes caused miscompliation:\n"; - bool Diff = diffProgram(Filename, "", false, &Error); + bool Diff = diffProgram(Program, Filename, "", false, &Error); if (Error.empty() && Diff) { outs() << "\n*** diffProgram returned true!\n"; debugMiscompilation(&Error); diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index 47ac3c5..3f2b696 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -43,13 +43,13 @@ namespace { cl::desc("Don't extract blocks when searching for miscompilations"), cl::init(false)); - class ReduceMiscompilingPasses : public ListReducer<const PassInfo*> { + class ReduceMiscompilingPasses : public ListReducer<std::string> { BugDriver &BD; public: ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {} - virtual TestResult doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix, + virtual TestResult doTest(std::vector<std::string> &Prefix, + std::vector<std::string> &Suffix, std::string &Error); }; } @@ -58,8 +58,8 @@ namespace { /// group, see if they still break the program. /// ReduceMiscompilingPasses::TestResult -ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix, +ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, + std::vector<std::string> &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. @@ -67,17 +67,18 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, << "' compiles correctly: "; std::string BitcodeResult; - if (BD.runPasses(Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false/*delete*/, + true/*quiet*/)) { errs() << " Error running this sequence of passes" << " on the input program!\n"; BD.setPassesToRun(Suffix); - BD.EmitProgressBitcode("pass-error", false); + BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false); exit(BD.debugOptimizerCrash()); } // Check to see if the finished program matches the reference output... - bool Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, - &Error); + bool Diff = BD.diffProgram(BD.getProgram(), BitcodeResult, "", + true /*delete bitcode*/, &Error); if (!Error.empty()) return InternalError; if (Diff) { @@ -104,16 +105,17 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, // kept passes, we can update our bitcode file to include the result of the // prefix passes, then discard the prefix passes. // - if (BD.runPasses(Prefix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + if (BD.runPasses(BD.getProgram(), Prefix, BitcodeResult, false/*delete*/, + true/*quiet*/)) { errs() << " Error running this sequence of passes" << " on the input program!\n"; BD.setPassesToRun(Prefix); - BD.EmitProgressBitcode("pass-error", false); + BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false); exit(BD.debugOptimizerCrash()); } // If the prefix maintains the predicate by itself, only keep the prefix! - Diff = BD.diffProgram(BitcodeResult, "", false, &Error); + Diff = BD.diffProgram(BD.getProgram(), BitcodeResult, "", false, &Error); if (!Error.empty()) return InternalError; if (Diff) { @@ -144,16 +146,18 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, << getPassesString(Prefix) << "' passes: "; OwningPtr<Module> OriginalInput(BD.swapProgramIn(PrefixOutput.take())); - if (BD.runPasses(Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false/*delete*/, + true/*quiet*/)) { errs() << " Error running this sequence of passes" << " on the input program!\n"; BD.setPassesToRun(Suffix); - BD.EmitProgressBitcode("pass-error", false); + BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false); exit(BD.debugOptimizerCrash()); } // Run the result... - Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, &Error); + Diff = BD.diffProgram(BD.getProgram(), BitcodeResult, "", + true /*delete bitcode*/, &Error); if (!Error.empty()) return InternalError; if (Diff) { @@ -198,18 +202,20 @@ namespace { return NoFailure; } - int TestFuncs(const std::vector<Function*> &Prefix, std::string &Error); + bool TestFuncs(const std::vector<Function*> &Prefix, std::string &Error); }; } /// TestMergedProgram - Given two modules, link them together and run the -/// program, checking to see if the program matches the diff. If the diff -/// matches, return false, otherwise return true. If the DeleteInputs argument -/// is set to true then this function deletes both input modules before it -/// returns. +/// program, checking to see if the program matches the diff. If there is +/// an error, return NULL. If not, return the merged module. The Broken argument +/// will be set to true if the output is different. If the DeleteInputs +/// argument is set to true then this function deletes both input +/// modules before it returns. /// -static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, - bool DeleteInputs, std::string &Error) { +static Module *TestMergedProgram(const BugDriver &BD, Module *M1, Module *M2, + bool DeleteInputs, std::string &Error, + bool &Broken) { // Link the two portions of the program back to together. std::string ErrorMsg; if (!DeleteInputs) { @@ -223,24 +229,22 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, } delete M2; // We are done with this module. - OwningPtr<Module> OldProgram(BD.swapProgramIn(M1)); - - // Execute the program. If it does not match the expected output, we must - // return true. - bool Broken = BD.diffProgram("", "", false, &Error); + // Execute the program. + Broken = BD.diffProgram(M1, "", "", false, &Error); if (!Error.empty()) { - // Delete the linked module & restore the original - delete BD.swapProgramIn(OldProgram.take()); + // Delete the linked module + delete M1; + return NULL; } - return Broken; + return M1; } /// TestFuncs - split functions in a Module into two groups: those that are /// under consideration for miscompilation vs. those that are not, and test /// accordingly. Each group of functions becomes a separate Module. /// -int ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, - std::string &Error) { +bool 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 " @@ -250,14 +254,35 @@ int ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, PrintFunctionList(Funcs); outs() << '\n'; - // Split the module into the two halves of the program we want. + // Create a clone for two reasons: + // * If the optimization passes delete any function, the deleted function + // will be in the clone and Funcs will still point to valid memory + // * If the optimization passes use interprocedural information to break + // a function, we want to continue with the original function. Otherwise + // we can conclude that a function triggers the bug when in fact one + // needs a larger set of original functions to do so. ValueMap<const Value*, Value*> VMap; + Module *Clone = CloneModule(BD.getProgram(), VMap); + Module *Orig = BD.swapProgramIn(Clone); + + std::vector<Function*> FuncsOnClone; + for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { + Function *F = cast<Function>(VMap[Funcs[i]]); + FuncsOnClone.push_back(F); + } + + // Split the module into the two halves of the program we want. + VMap.clear(); Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); - Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, Funcs, + Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, FuncsOnClone, VMap); // Run the predicate, note that the predicate will delete both input modules. - return TestFn(BD, ToOptimize, ToNotOptimize, Error); + bool Broken = TestFn(BD, ToOptimize, ToNotOptimize, Error); + + delete BD.swapProgramIn(Orig); + + return Broken; } /// DisambiguateGlobalSymbols - Give anonymous global values names. @@ -307,10 +332,13 @@ static bool ExtractLoops(BugDriver &BD, // has broken. If something broke, then we'll inform the user and stop // extraction. AbstractInterpreter *AI = BD.switchToSafeInterpreter(); - bool Failure = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, - false, Error); - if (!Error.empty()) + bool Failure; + Module *New = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, + false, Error, Failure); + if (!New) return false; + // Delete the original and set the new program. + delete BD.swapProgramIn(New); if (Failure) { BD.switchToInterpreter(AI); @@ -449,18 +477,36 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs, // Split the module into the two halves of the program we want. ValueMap<const Value*, Value*> VMap; + Module *Clone = CloneModule(BD.getProgram(), VMap); + Module *Orig = BD.swapProgramIn(Clone); + std::vector<Function*> FuncsOnClone; + std::vector<BasicBlock*> BBsOnClone; + for (unsigned i = 0, e = FunctionsBeingTested.size(); i != e; ++i) { + Function *F = cast<Function>(VMap[FunctionsBeingTested[i]]); + FuncsOnClone.push_back(F); + } + for (unsigned i = 0, e = BBs.size(); i != e; ++i) { + BasicBlock *BB = cast<BasicBlock>(VMap[BBs[i]]); + BBsOnClone.push_back(BB); + } + VMap.clear(); + Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, - FunctionsBeingTested, + FuncsOnClone, VMap); // Try the extraction. If it doesn't work, then the block extractor crashed // or something, in which case bugpoint can't chase down this possibility. - if (Module *New = BD.ExtractMappedBlocksFromModule(BBs, ToOptimize)) { + if (Module *New = BD.ExtractMappedBlocksFromModule(BBsOnClone, ToOptimize)) { delete ToOptimize; - // Run the predicate, not that the predicate will delete both input modules. - return TestFn(BD, New, ToNotOptimize, Error); + // Run the predicate, + // note that the predicate will delete both input modules. + bool Ret = TestFn(BD, New, ToNotOptimize, Error); + delete BD.swapProgramIn(Orig); + return Ret; } + delete BD.swapProgramIn(Orig); delete ToOptimize; delete ToNotOptimize; return false; @@ -655,8 +701,13 @@ 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, Error); - if (Error.empty()) outs() << (Broken ? " nope.\n" : " yup.\n"); + bool Broken; + Module *New = TestMergedProgram(BD, Optimized, Safe, true, Error, Broken); + if (New) { + outs() << (Broken ? " nope.\n" : " yup.\n"); + // Delete the original and set the new program. + delete BD.swapProgramIn(New); + } return Broken; } @@ -678,7 +729,7 @@ void BugDriver::debugMiscompilation(std::string *Error) { outs() << "\n*** Found miscompiling pass" << (getPassesToRun().size() == 1 ? "" : "es") << ": " << getPassesString(getPassesToRun()) << '\n'; - EmitProgressBitcode("passinput"); + EmitProgressBitcode(Program, "passinput"); std::vector<Function *> MiscompiledFunctions = DebugAMiscompilation(*this, TestOptimizer, *Error); @@ -694,14 +745,12 @@ void BugDriver::debugMiscompilation(std::string *Error) { VMap); outs() << " Non-optimized portion: "; - ToNotOptimize = swapProgramIn(ToNotOptimize); - EmitProgressBitcode("tonotoptimize", true); - setNewProgram(ToNotOptimize); // Delete hacked module. + EmitProgressBitcode(ToNotOptimize, "tonotoptimize", true); + delete ToNotOptimize; // Delete hacked module. outs() << " Portion that is input to optimizer: "; - ToOptimize = swapProgramIn(ToOptimize); - EmitProgressBitcode("tooptimize"); - setNewProgram(ToOptimize); // Delete hacked module. + EmitProgressBitcode(ToOptimize, "tooptimize"); + delete ToOptimize; // Delete hacked module. return; } @@ -921,7 +970,8 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, // Run the code generator on the `Test' code, loading the shared library. // The function returns whether or not the new output differs from reference. - bool Result = BD.diffProgram(TestModuleBC.str(), SharedObject, false, &Error); + bool Result = BD.diffProgram(BD.getProgram(), TestModuleBC.str(), + SharedObject, false, &Error); if (!Error.empty()) return false; @@ -938,7 +988,8 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, /// bool BugDriver::debugCodeGenerator(std::string *Error) { if ((void*)SafeInterpreter == (void*)Interpreter) { - std::string Result = executeProgramSafely("bugpoint.safe.out", Error); + std::string Result = executeProgramSafely(Program, "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 " diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index 3a6149b..3600ca6 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -27,6 +27,8 @@ #include "llvm/Target/TargetData.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/System/Program.h" @@ -51,26 +53,34 @@ namespace { /// file. If an error occurs, true is returned. /// bool BugDriver::writeProgramToFile(const std::string &Filename, - Module *M) const { + const Module *M) const { std::string ErrInfo; - raw_fd_ostream Out(Filename.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); - if (!ErrInfo.empty()) return true; - - WriteBitcodeToFile(M ? M : Program, Out); - return false; + tool_output_file Out(Filename.c_str(), ErrInfo, + raw_fd_ostream::F_Binary); + if (ErrInfo.empty()) { + WriteBitcodeToFile(M, Out.os()); + Out.os().close(); + if (!Out.os().has_error()) { + Out.keep(); + return false; + } + } + Out.os().clear_error(); + return true; } /// EmitProgressBitcode - This function is used to output the current Program /// to a file named "bugpoint-ID.bc". /// -void BugDriver::EmitProgressBitcode(const std::string &ID, bool NoFlyer) { +void BugDriver::EmitProgressBitcode(const Module *M, + const std::string &ID, + bool NoFlyer) const { // Output the input to the current pass to a bitcode file, emit a message // telling the user how to reproduce it: opt -foo blah.bc // std::string Filename = OutputPrefix + "-" + ID + ".bc"; - if (writeProgramToFile(Filename)) { + if (writeProgramToFile(Filename, M)) { errs() << "Error opening file '" << Filename << "' for writing!\n"; return; } @@ -83,39 +93,12 @@ void BugDriver::EmitProgressBitcode(const std::string &ID, bool NoFlyer) { outs() << getPassesString(PassesToRun) << "\n"; } -int BugDriver::runPassesAsChild(const std::vector<const PassInfo*> &Passes) { - std::string ErrInfo; - raw_fd_ostream OutFile(ChildOutput.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); - if (!ErrInfo.empty()) { - errs() << "Error opening bitcode file: " << ChildOutput << "\n"; - return 1; - } - - PassManager PM; - // Make sure that the appropriate target data is always used... - PM.add(new TargetData(Program)); - - for (unsigned i = 0, e = Passes.size(); i != e; ++i) { - if (Passes[i]->getNormalCtor()) - PM.add(Passes[i]->getNormalCtor()()); - else - errs() << "Cannot create pass yet: " << Passes[i]->getPassName() << "\n"; - } - // Check that the module is well formed on completion of optimization - PM.add(createVerifierPass()); - - // Write bitcode out to disk as the last step... - PM.add(createBitcodeWriterPass(OutFile)); - - // Run all queued passes. - PM.run(*Program); - - return 0; -} - cl::opt<bool> SilencePasses("silence-passes", cl::desc("Suppress output of running passes (both stdout and stderr)")); +static cl::list<std::string> OptArgs("opt-args", cl::Positional, + cl::desc("<opt arguments>..."), + cl::ZeroOrMore, cl::PositionalEatsArgs); + /// runPasses - Run the specified passes on Program, outputting a bitcode file /// and writing the filename into OutputFile if successful. If the /// optimizations fail for some reason (optimizer crashes), return true, @@ -124,7 +107,8 @@ cl::opt<bool> SilencePasses("silence-passes", cl::desc("Suppress output of runni /// outs() a single line message indicating whether compilation was successful /// or failed. /// -bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, +bool BugDriver::runPasses(Module *Program, + const std::vector<std::string> &Passes, std::string &OutputFilename, bool DeleteOutput, bool Quiet, unsigned NumExtraArgs, const char * const *ExtraArgs) const { @@ -148,39 +132,47 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, } std::string ErrInfo; - raw_fd_ostream InFile(inputFilename.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); + tool_output_file InFile(inputFilename.c_str(), ErrInfo, + raw_fd_ostream::F_Binary); if (!ErrInfo.empty()) { errs() << "Error opening bitcode file: " << inputFilename.str() << "\n"; return 1; } - WriteBitcodeToFile(Program, InFile); - InFile.close(); + WriteBitcodeToFile(Program, InFile.os()); + InFile.os().close(); + if (InFile.os().has_error()) { + errs() << "Error writing bitcode file: " << inputFilename.str() << "\n"; + InFile.os().clear_error(); + return 1; + } + InFile.keep(); // setup the child process' arguments SmallVector<const char*, 8> Args; - sys::Path tool = sys::Program::FindProgramByName(ToolName); + sys::Path tool = FindExecutable("opt", getToolName(), (void*)"opt"); + std::string Opt = tool.str(); if (UseValgrind) { Args.push_back("valgrind"); Args.push_back("--error-exitcode=1"); Args.push_back("-q"); Args.push_back(tool.c_str()); } else - Args.push_back(ToolName); + Args.push_back(Opt.c_str()); - Args.push_back("-as-child"); - Args.push_back("-child-output"); + Args.push_back("-o"); Args.push_back(OutputFilename.c_str()); + for (unsigned i = 0, e = OptArgs.size(); i != e; ++i) + Args.push_back(OptArgs[i].c_str()); std::vector<std::string> pass_args; for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) { pass_args.push_back( std::string("-load")); pass_args.push_back( PluginLoader::getPlugin(i)); } - for (std::vector<const PassInfo*>::const_iterator I = Passes.begin(), + for (std::vector<std::string>::const_iterator I = Passes.begin(), E = Passes.end(); I != E; ++I ) - pass_args.push_back( std::string("-") + (*I)->getPassArgument() ); + pass_args.push_back( std::string("-") + (*I) ); for (std::vector<std::string>::const_iterator I = pass_args.begin(), E = pass_args.end(); I != E; ++I ) Args.push_back(I->c_str()); @@ -189,6 +181,12 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, Args.push_back(*ExtraArgs); Args.push_back(0); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i = 0, e = Args.size()-1; i != e; ++i) + errs() << " " << Args[i]; + errs() << "\n"; + ); + sys::Path prog; if (UseValgrind) prog = sys::Program::FindProgramByName("valgrind"); @@ -235,27 +233,22 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, /// module, returning the transformed module on success, or a null pointer on /// failure. Module *BugDriver::runPassesOn(Module *M, - const std::vector<const PassInfo*> &Passes, + const std::vector<std::string> &Passes, bool AutoDebugCrashes, unsigned NumExtraArgs, const char * const *ExtraArgs) { - Module *OldProgram = swapProgramIn(M); std::string BitcodeResult; - if (runPasses(Passes, BitcodeResult, false/*delete*/, true/*quiet*/, + if (runPasses(M, Passes, BitcodeResult, false/*delete*/, true/*quiet*/, NumExtraArgs, ExtraArgs)) { if (AutoDebugCrashes) { errs() << " Error running this sequence of passes" << " on the input program!\n"; - delete OldProgram; - EmitProgressBitcode("pass-error", false); + delete swapProgramIn(M); + EmitProgressBitcode(M, "pass-error", false); exit(debugOptimizerCrash()); } - swapProgramIn(OldProgram); return 0; } - // Restore the current program. - swapProgramIn(OldProgram); - Module *Ret = ParseInputFile(BitcodeResult, Context); if (Ret == 0) { errs() << getToolName() << ": Error reading bitcode file '" diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 3149a7a..36dbe14 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -627,8 +627,8 @@ CBE *AbstractInterpreter::createCBE(const char *Argv0, // GCC abstraction // -static bool IsARMArchitecture(std::vector<std::string> Args) { - for (std::vector<std::string>::const_iterator +static bool IsARMArchitecture(std::vector<const char*> Args) { + for (std::vector<const char*>::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { if (StringRef(*I).equals_lower("-arch")) { ++I; @@ -673,7 +673,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // explicitly told what architecture it is working on, so we get // it from gcc flags if ((TargetTriple.getOS() == Triple::Darwin) && - !IsARMArchitecture(ArgsForGCC)) + !IsARMArchitecture(GCCArgs)) GCCArgs.push_back("-force_cpusubtype_ALL"); } } @@ -721,6 +721,10 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, std::vector<const char*> ProgramArgs; + // Declared here so that the destructor only runs after + // ProgramArgs is used. + std::string Exec; + if (RemoteClientPath.isEmpty()) ProgramArgs.push_back(OutputBinary.c_str()); else { @@ -741,7 +745,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // Full path to the binary. We need to cd to the exec directory because // there is a dylib there that the exec expects to find in the CWD char* env_pwd = getenv("PWD"); - std::string Exec = "cd "; + Exec = "cd "; Exec += env_pwd; Exec += "; ./"; Exec += OutputBinary.c_str(); diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index ba5234b..79cf563 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -29,13 +29,6 @@ #include "llvm/LinkAllVMCore.h" using namespace llvm; -// AsChild - Specifies that this invocation of bugpoint is being generated -// from a parent process. It is not intended to be used by users so the -// option is hidden. -static cl::opt<bool> -AsChild("as-child", cl::desc("Run bugpoint as child process"), - cl::ReallyHidden); - static cl::opt<bool> FindBugs("find-bugs", cl::desc("Run many different optimization sequences " "on program to find bugs"), cl::init(false)); @@ -90,8 +83,9 @@ namespace { AddToDriver(BugDriver &_D) : D(_D) {} virtual void add(Pass *P) { - const PassInfo *PI = P->getPassInfo(); - D.addPasses(&PI, &PI + 1); + const void *ID = P->getPassID(); + const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID); + D.addPass(PI->getPassArgument()); } }; } @@ -110,8 +104,8 @@ int main(int argc, char **argv) { // If we have an override, set it and then track the triple we want Modules // to use. if (!OverrideTriple.empty()) { - TargetTriple.setTriple(OverrideTriple); - outs() << "Override triple set to '" << OverrideTriple << "'\n"; + TargetTriple.setTriple(Triple::normalize(OverrideTriple)); + outs() << "Override triple set to '" << TargetTriple.getTriple() << "'\n"; } if (MemoryLimit < 0) { @@ -123,7 +117,7 @@ int main(int argc, char **argv) { MemoryLimit = 100; } - BugDriver D(argv[0], AsChild, FindBugs, TimeoutValue, MemoryLimit, + BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit, UseValgrind, Context); if (D.addSources(InputFilenames)) return 1; @@ -143,7 +137,13 @@ int main(int argc, char **argv) { /*RunInliner=*/true, /*VerifyEach=*/false); - D.addPasses(PassList.begin(), PassList.end()); + + for (std::vector<const PassInfo*>::iterator I = PassList.begin(), + E = PassList.end(); + I != E; ++I) { + const PassInfo* PI = *I; + D.addPass(PI->getPassArgument()); + } // Bugpoint has the ability of generating a plethora of core files, so to // avoid filling up the disk, we prevent it diff --git a/tools/edis/CMakeLists.txt b/tools/edis/CMakeLists.txt index f7a199d..2019995 100644 --- a/tools/edis/CMakeLists.txt +++ b/tools/edis/CMakeLists.txt @@ -1,22 +1,10 @@ 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 + EDMain.cpp ) set_target_properties(EnhancedDisassembly diff --git a/tools/edis/EDDisassembler.cpp b/tools/edis/EDDisassembler.cpp deleted file mode 100644 index 85e41e6..0000000 --- a/tools/edis/EDDisassembler.cpp +++ /dev/null @@ -1,407 +0,0 @@ -//===-EDDisassembler.cpp - LLVM Enhanced Disassembler ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Enhanced Disassembly library's disassembler class. -// The disassembler is responsible for vending individual instructions according -// to a given architecture and disassembly syntax. -// -//===----------------------------------------------------------------------===// - -#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" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstPrinter.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCParser/AsmLexer.h" -#include "llvm/MC/MCParser/AsmParser.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCParser/MCParsedAsmOperand.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/MemoryObject.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Target/TargetAsmLexer.h" -#include "llvm/Target/TargetAsmParser.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Target/TargetSelect.h" - -using namespace llvm; - -bool EDDisassembler::sInitialized = false; -EDDisassembler::DisassemblerMap_t EDDisassembler::sDisassemblers; - -struct TripleMap { - Triple::ArchType Arch; - const char *String; -}; - -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 TripleMap corresponding to a given architecture, -/// or NULL if there is an error -/// -/// @arg arch - The Triple::ArchType for the desired architecture -static const char *tripleFromArch(Triple::ArchType arch) { - unsigned int infoIndex; - - for (infoIndex = 0; triplemap[infoIndex].String != NULL; ++infoIndex) { - if (arch == triplemap[infoIndex].Arch) - return triplemap[infoIndex].String; - } - - return NULL; -} - -/// getLLVMSyntaxVariant - gets the constant to use to get an assembly printer -/// for the desired assembly syntax, suitable for passing to -/// Target::createMCInstPrinter() -/// -/// @arg arch - The target architecture -/// @arg syntax - The assembly syntax in sd form -static int getLLVMSyntaxVariant(Triple::ArchType arch, - EDAssemblySyntax_t syntax) { - switch (syntax) { - default: - return -1; - // Mappings below from X86AsmPrinter.cpp - case kEDAssemblySyntaxX86ATT: - if (arch == Triple::x86 || arch == Triple::x86_64) - return 0; - else - return -1; - case kEDAssemblySyntaxX86Intel: - if (arch == Triple::x86 || arch == Triple::x86_64) - return 1; - else - return -1; - case kEDAssemblySyntaxARMUAL: - if (arch == Triple::arm || arch == Triple::thumb) - return 0; - else - return -1; - } -} - -void EDDisassembler::initialize() { - if (sInitialized) - return; - - sInitialized = true; - - InitializeAllTargetInfos(); - InitializeAllTargets(); - InitializeAllAsmPrinters(); - InitializeAllAsmParsers(); - InitializeAllDisassemblers(); -} - -#undef BRINGUP_TARGET - -EDDisassembler *EDDisassembler::getDisassembler(Triple::ArchType arch, - EDAssemblySyntax_t syntax) { - CPUKey key; - key.Arch = arch; - key.Syntax = syntax; - - EDDisassembler::DisassemblerMap_t::iterator i = sDisassemblers.find(key); - - if (i != sDisassemblers.end()) { - return i->second; - } else { - EDDisassembler* sdd = new EDDisassembler(key); - if (!sdd->valid()) { - delete sdd; - return NULL; - } - - sDisassemblers[key] = sdd; - - return sdd; - } - - return NULL; -} - -EDDisassembler *EDDisassembler::getDisassembler(StringRef str, - EDAssemblySyntax_t syntax) { - Triple triple(str); - - return getDisassembler(triple.getArch(), syntax); -} - -EDDisassembler::EDDisassembler(CPUKey &key) : - Valid(false), - HasSemantics(false), - ErrorStream(nulls()), - Key(key) { - const char *triple = tripleFromArch(key.Arch); - - if (!triple) - return; - - LLVMSyntaxVariant = getLLVMSyntaxVariant(key.Arch, key.Syntax); - - if (LLVMSyntaxVariant < 0) - return; - - std::string tripleString(triple); - std::string errorString; - - Tgt = TargetRegistry::lookupTarget(tripleString, - errorString); - - if (!Tgt) - return; - - std::string featureString; - - OwningPtr<const TargetMachine> - targetMachine(Tgt->createTargetMachine(tripleString, - featureString)); - - const TargetRegisterInfo *registerInfo = targetMachine->getRegisterInfo(); - - if (!registerInfo) - return; - - initMaps(*registerInfo); - - AsmInfo.reset(Tgt->createAsmInfo(tripleString)); - - if (!AsmInfo) - return; - - Disassembler.reset(Tgt->createMCDisassembler()); - - if (!Disassembler) - return; - - InstInfos = Disassembler->getEDInfo(); - - InstString.reset(new std::string); - InstStream.reset(new raw_string_ostream(*InstString)); - InstPrinter.reset(Tgt->createMCInstPrinter(LLVMSyntaxVariant, *AsmInfo)); - - if (!InstPrinter) - return; - - GenericAsmLexer.reset(new AsmLexer(*AsmInfo)); - SpecificAsmLexer.reset(Tgt->createAsmLexer(*AsmInfo)); - SpecificAsmLexer->InstallLexer(*GenericAsmLexer); - - initMaps(*targetMachine->getRegisterInfo()); - - Valid = true; -} - -EDDisassembler::~EDDisassembler() { - if (!valid()) - return; -} - -namespace { - /// EDMemoryObject - a subclass of MemoryObject that allows use of a callback - /// as provided by the sd interface. See MemoryObject. - class EDMemoryObject : public llvm::MemoryObject { - private: - EDByteReaderCallback Callback; - void *Arg; - public: - EDMemoryObject(EDByteReaderCallback callback, - void *arg) : Callback(callback), Arg(arg) { } - ~EDMemoryObject() { } - 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) - return -1; - - if (Callback(ptr, address, Arg)) - return -1; - - return 0; - } - }; -} - -EDInst *EDDisassembler::createInst(EDByteReaderCallback byteReader, - uint64_t address, - void *arg) { - EDMemoryObject memoryObject(byteReader, arg); - - MCInst* inst = new MCInst; - uint64_t byteSize; - - if (!Disassembler->getInstruction(*inst, - byteSize, - memoryObject, - address, - ErrorStream)) { - delete inst; - return NULL; - } else { - const llvm::EDInstInfo *thisInstInfo; - - thisInstInfo = &InstInfos[inst->getOpcode()]; - - EDInst* sdInst = new EDInst(inst, byteSize, *this, thisInstInfo); - return sdInst; - } -} - -void EDDisassembler::initMaps(const TargetRegisterInfo ®isterInfo) { - unsigned numRegisters = registerInfo.getNumRegs(); - unsigned registerIndex; - - for (registerIndex = 0; registerIndex < numRegisters; ++registerIndex) { - const char* registerName = registerInfo.get(registerIndex).Name; - - RegVec.push_back(registerName); - RegRMap[registerName] = registerIndex; - } - - switch (Key.Arch) { - default: - break; - case Triple::x86: - case Triple::x86_64: - stackPointers.insert(registerIDWithName("SP")); - stackPointers.insert(registerIDWithName("ESP")); - stackPointers.insert(registerIDWithName("RSP")); - - 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; - } -} - -const char *EDDisassembler::nameWithRegisterID(unsigned registerID) const { - if (registerID >= RegVec.size()) - return NULL; - else - return RegVec[registerID].c_str(); -} - -unsigned EDDisassembler::registerIDWithName(const char *name) const { - regrmap_t::const_iterator iter = RegRMap.find(std::string(name)); - if (iter == RegRMap.end()) - return 0; - else - return (*iter).second; -} - -bool EDDisassembler::registerIsStackPointer(unsigned registerID) { - return (stackPointers.find(registerID) != stackPointers.end()); -} - -bool EDDisassembler::registerIsProgramCounter(unsigned registerID) { - return (programCounters.find(registerID) != programCounters.end()); -} - -int EDDisassembler::printInst(std::string &str, MCInst &inst) { - PrinterMutex.acquire(); - - InstPrinter->printInst(&inst, *InstStream); - InstStream->flush(); - str = *InstString; - InstString->clear(); - - PrinterMutex.release(); - - return 0; -} - -int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands, - SmallVectorImpl<AsmToken> &tokens, - 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)); - - StringRef instName; - SMLoc instLoc; - - SourceMgr sourceMgr; - sourceMgr.AddNewSourceBuffer(buf, SMLoc()); // ownership of buf handed over - MCContext context(*AsmInfo); - OwningPtr<MCStreamer> streamer(createNullStreamer(context)); - AsmParser genericParser(*Tgt, sourceMgr, context, *streamer, *AsmInfo); - OwningPtr<TargetAsmParser> TargetParser(Tgt->createAsmParser(genericParser)); - - AsmToken OpcodeToken = genericParser.Lex(); - AsmToken NextToken = genericParser.Lex(); // consume next token, because specificParser expects us to - - if (OpcodeToken.is(AsmToken::Identifier)) { - instName = OpcodeToken.getString(); - instLoc = OpcodeToken.getLoc(); - - if (NextToken.isNot(AsmToken::Eof) && - TargetParser->ParseInstruction(instName, instLoc, operands)) - ret = -1; - } else { - ret = -1; - } - - ParserMutex.acquire(); - - if (!ret) { - GenericAsmLexer->setBuffer(buf); - - while (SpecificAsmLexer->Lex(), - SpecificAsmLexer->isNot(AsmToken::Eof) && - SpecificAsmLexer->isNot(AsmToken::EndOfStatement)) { - if (SpecificAsmLexer->is(AsmToken::Error)) { - ret = -1; - break; - } - tokens.push_back(SpecificAsmLexer->getTok()); - } - } - - ParserMutex.release(); - - return ret; -} - -int EDDisassembler::llvmSyntaxVariant() const { - return LLVMSyntaxVariant; -} diff --git a/tools/edis/EDDisassembler.h b/tools/edis/EDDisassembler.h deleted file mode 100644 index 74a260e..0000000 --- a/tools/edis/EDDisassembler.h +++ /dev/null @@ -1,256 +0,0 @@ -//===-EDDisassembler.h - LLVM Enhanced Disassembler -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the interface for the Enhanced Disassembly library's -// disassembler class. The disassembler is responsible for vending individual -// instructions according to a given architecture and disassembly syntax. -// -//===----------------------------------------------------------------------===// - -#ifndef EDDisassembler_ -#define EDDisassembler_ - -#include "EDInfo.inc" - -#include "llvm-c/EnhancedDisassembly.h" - -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/System/Mutex.h" - -#include <map> -#include <set> -#include <string> -#include <vector> - -namespace llvm { -class AsmLexer; -class AsmToken; -class MCContext; -class MCAsmInfo; -class MCAsmLexer; -class AsmParser; -class TargetAsmLexer; -class TargetAsmParser; -class MCDisassembler; -class MCInstPrinter; -class MCInst; -class MCParsedAsmOperand; -class MCStreamer; -template <typename T> class SmallVectorImpl; -class SourceMgr; -class Target; -class TargetRegisterInfo; - -struct EDInstInfo; -} - -/// EDDisassembler - Encapsulates a disassembler for a single architecture and -/// disassembly syntax. Also manages the static disassembler registry. -struct EDDisassembler { - //////////////////// - // Static members // - //////////////////// - - /// CPUKey - Encapsulates the descriptor of an architecture/disassembly-syntax - /// pair - struct CPUKey { - /// The architecture type - llvm::Triple::ArchType Arch; - - /// The assembly syntax - EDAssemblySyntax_t Syntax; - - /// operator== - Equality operator - bool operator==(const CPUKey &key) const { - return (Arch == key.Arch && - Syntax == key.Syntax); - } - - /// operator< - Less-than operator - bool operator<(const CPUKey &key) const { - if(Arch > key.Arch) - return false; - if(Syntax >= key.Syntax) - return false; - return true; - } - }; - - typedef std::map<CPUKey, EDDisassembler*> DisassemblerMap_t; - - /// True if the disassembler registry has been initialized; false if not - static bool sInitialized; - /// A map from disassembler specifications to disassemblers. Populated - /// lazily. - static DisassemblerMap_t sDisassemblers; - - /// getDisassembler - Returns the specified disassemble, or NULL on failure - /// - /// @arg arch - The desired architecture - /// @arg syntax - The desired disassembly syntax - static EDDisassembler *getDisassembler(llvm::Triple::ArchType arch, - EDAssemblySyntax_t syntax); - - /// getDisassembler - Returns the disassembler for a given combination of - /// CPU type, CPU subtype, and assembly syntax, or NULL on failure - /// - /// @arg str - The string representation of the architecture triple, e.g., - /// "x86_64-apple-darwin" - /// @arg syntax - The disassembly syntax for the required disassembler - static EDDisassembler *getDisassembler(llvm::StringRef str, - EDAssemblySyntax_t syntax); - - /// initialize - Initializes the disassembler registry and the LLVM backend - static void initialize(); - - //////////////////////// - // Per-object members // - //////////////////////// - - /// True only if the object has been successfully initialized - bool Valid; - /// True if the disassembler can provide semantic information - bool HasSemantics; - - /// The stream to write errors to - llvm::raw_ostream &ErrorStream; - - /// The architecture/syntax pair for the current architecture - CPUKey Key; - /// The LLVM target corresponding to the disassembler - const llvm::Target *Tgt; - /// The assembly information for the target architecture - llvm::OwningPtr<const llvm::MCAsmInfo> AsmInfo; - /// The disassembler for the target architecture - llvm::OwningPtr<const llvm::MCDisassembler> Disassembler; - /// The output string for the instruction printer; must be guarded with - /// PrinterMutex - llvm::OwningPtr<std::string> InstString; - /// The output stream for the disassembler; must be guarded with - /// PrinterMutex - llvm::OwningPtr<llvm::raw_string_ostream> InstStream; - /// The instruction printer for the target architecture; must be guarded with - /// PrinterMutex when printing - llvm::OwningPtr<llvm::MCInstPrinter> InstPrinter; - /// The mutex that guards the instruction printer's printing functions, which - /// use a shared stream - llvm::sys::Mutex PrinterMutex; - /// The array of instruction information provided by the TableGen backend for - /// the target architecture - 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; - llvm::OwningPtr<llvm::TargetAsmLexer> SpecificAsmLexer; - /// The guard for the above - llvm::sys::Mutex ParserMutex; - /// The LLVM number used for the target disassembly syntax variant - int LLVMSyntaxVariant; - - typedef std::vector<std::string> regvec_t; - typedef std::map<std::string, unsigned> regrmap_t; - - /// A vector of registers for quick mapping from LLVM register IDs to names - regvec_t RegVec; - /// A map of registers for quick mapping from register names to LLVM IDs - regrmap_t RegRMap; - - /// A set of register IDs for aliases of the stack pointer for the current - /// architecture - std::set<unsigned> stackPointers; - /// A set of register IDs for aliases of the program counter for the current - /// architecture - std::set<unsigned> programCounters; - - /// Constructor - initializes a disassembler with all the necessary objects, - /// which come pre-allocated from the registry accessor function - /// - /// @arg key - the architecture and disassembly syntax for the - /// disassembler - EDDisassembler(CPUKey& key); - - /// valid - reports whether there was a failure in the constructor. - bool valid() { - 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 - /// memory address, or NULL on failure - /// - /// @arg byteReader - A callback function that provides machine code bytes - /// @arg address - The address of the first byte of the instruction, - /// suitable for passing to byteReader - /// @arg arg - An opaque argument for byteReader - EDInst *createInst(EDByteReaderCallback byteReader, - uint64_t address, - void *arg); - - /// initMaps - initializes regVec and regRMap using the provided register - /// info - /// - /// @arg registerInfo - the register information to use as a source - void initMaps(const llvm::TargetRegisterInfo ®isterInfo); - /// nameWithRegisterID - Returns the name (owned by the EDDisassembler) of a - /// register for a given register ID, or NULL on failure - /// - /// @arg registerID - the ID of the register to be queried - const char *nameWithRegisterID(unsigned registerID) const; - /// registerIDWithName - Returns the ID of a register for a given register - /// name, or (unsigned)-1 on failure - /// - /// @arg name - The name of the register - unsigned registerIDWithName(const char *name) const; - - /// registerIsStackPointer - reports whether a register ID is an alias for the - /// stack pointer register - /// - /// @arg registerID - The LLVM register ID - bool registerIsStackPointer(unsigned registerID); - /// registerIsStackPointer - reports whether a register ID is an alias for the - /// stack pointer register - /// - /// @arg registerID - The LLVM register ID - bool registerIsProgramCounter(unsigned registerID); - - /// printInst - prints an MCInst to a string, returning 0 on success, or -1 - /// otherwise - /// - /// @arg str - A reference to a string which is filled in with the string - /// representation of the instruction - /// @arg inst - A reference to the MCInst to be printed - int printInst(std::string& str, - llvm::MCInst& inst); - - /// parseInst - extracts operands and tokens from a string for use in - /// tokenizing the string. Returns 0 on success, or -1 otherwise. - /// - /// @arg operands - A reference to a vector that will be filled in with the - /// parsed operands - /// @arg tokens - A reference to a vector that will be filled in with the - /// tokens - /// @arg str - The string representation of the instruction - int parseInst(llvm::SmallVectorImpl<llvm::MCParsedAsmOperand*> &operands, - llvm::SmallVectorImpl<llvm::AsmToken> &tokens, - const std::string &str); - - /// llvmSyntaxVariant - returns the LLVM syntax variant for this disassembler - int llvmSyntaxVariant() const; -}; - -#endif diff --git a/tools/edis/EDInfo.td b/tools/edis/EDInfo.td deleted file mode 100644 index bd9ec07..0000000 --- a/tools/edis/EDInfo.td +++ /dev/null @@ -1 +0,0 @@ -// Intentionally empty. diff --git a/tools/edis/EDInst.cpp b/tools/edis/EDInst.cpp deleted file mode 100644 index c009f0f..0000000 --- a/tools/edis/EDInst.cpp +++ /dev/null @@ -1,207 +0,0 @@ -//===-EDInst.cpp - LLVM Enhanced Disassembler -----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Enhanced Disassembly library's instruction class. -// The instruction is responsible for vending the string representation, -// individual tokens, and operands for a single instruction. -// -//===----------------------------------------------------------------------===// - -#include "EDDisassembler.h" -#include "EDInst.h" -#include "EDOperand.h" -#include "EDToken.h" - -#include "llvm/MC/EDInstInfo.h" -#include "llvm/MC/MCInst.h" - -using namespace llvm; - -EDInst::EDInst(llvm::MCInst *inst, - uint64_t byteSize, - EDDisassembler &disassembler, - const llvm::EDInstInfo *info) : - Disassembler(disassembler), - Inst(inst), - ThisInstInfo(info), - ByteSize(byteSize), - BranchTarget(-1), - MoveSource(-1), - MoveTarget(-1) { - OperandOrder = ThisInstInfo->operandOrders[Disassembler.llvmSyntaxVariant()]; -} - -EDInst::~EDInst() { - unsigned int index; - unsigned int numOperands = Operands.size(); - - for (index = 0; index < numOperands; ++index) - delete Operands[index]; - - unsigned int numTokens = Tokens.size(); - - for (index = 0; index < numTokens; ++index) - delete Tokens[index]; - - delete Inst; -} - -uint64_t EDInst::byteSize() { - return ByteSize; -} - -int EDInst::stringify() { - if (StringifyResult.valid()) - return StringifyResult.result(); - - if (Disassembler.printInst(String, *Inst)) - return StringifyResult.setResult(-1); - - return StringifyResult.setResult(0); -} - -int EDInst::getString(const char*& str) { - if (stringify()) - return -1; - - str = String.c_str(); - - return 0; -} - -unsigned EDInst::instID() { - return Inst->getOpcode(); -} - -bool EDInst::isBranch() { - if (ThisInstInfo) - return - ThisInstInfo->instructionType == kInstructionTypeBranch || - ThisInstInfo->instructionType == kInstructionTypeCall; - else - return false; -} - -bool EDInst::isMove() { - if (ThisInstInfo) - return ThisInstInfo->instructionType == kInstructionTypeMove; - else - return false; -} - -int EDInst::parseOperands() { - if (ParseResult.valid()) - return ParseResult.result(); - - if (!ThisInstInfo) - return ParseResult.setResult(-1); - - unsigned int opIndex; - unsigned int mcOpIndex = 0; - - for (opIndex = 0; opIndex < ThisInstInfo->numOperands; ++opIndex) { - if (isBranch() && - (ThisInstInfo->operandFlags[opIndex] & kOperandFlagTarget)) { - BranchTarget = opIndex; - } - else if (isMove()) { - if (ThisInstInfo->operandFlags[opIndex] & kOperandFlagSource) - MoveSource = opIndex; - else if (ThisInstInfo->operandFlags[opIndex] & kOperandFlagTarget) - MoveTarget = opIndex; - } - - EDOperand *operand = new EDOperand(Disassembler, *this, opIndex, mcOpIndex); - - Operands.push_back(operand); - } - - return ParseResult.setResult(0); -} - -int EDInst::branchTargetID() { - if (parseOperands()) - return -1; - return BranchTarget; -} - -int EDInst::moveSourceID() { - if (parseOperands()) - return -1; - return MoveSource; -} - -int EDInst::moveTargetID() { - if (parseOperands()) - return -1; - return MoveTarget; -} - -int EDInst::numOperands() { - if (parseOperands()) - return -1; - return Operands.size(); -} - -int EDInst::getOperand(EDOperand *&operand, unsigned int index) { - if (parseOperands()) - return -1; - - if (index >= Operands.size()) - return -1; - - operand = Operands[index]; - return 0; -} - -int EDInst::tokenize() { - if (TokenizeResult.valid()) - return TokenizeResult.result(); - - if (stringify()) - return TokenizeResult.setResult(-1); - - return TokenizeResult.setResult(EDToken::tokenize(Tokens, - String, - OperandOrder, - Disassembler)); - -} - -int EDInst::numTokens() { - if (tokenize()) - return -1; - return Tokens.size(); -} - -int EDInst::getToken(EDToken *&token, unsigned int index) { - if (tokenize()) - return -1; - token = Tokens[index]; - return 0; -} - -#ifdef __BLOCKS__ -int EDInst::visitTokens(EDTokenVisitor_t visitor) { - if (tokenize()) - return -1; - - tokvec_t::iterator iter; - - for (iter = Tokens.begin(); iter != Tokens.end(); ++iter) { - int ret = visitor(*iter); - if (ret == 1) - return 0; - if (ret != 0) - return -1; - } - - return 0; -} -#endif diff --git a/tools/edis/EDInst.h b/tools/edis/EDInst.h deleted file mode 100644 index c8a747f..0000000 --- a/tools/edis/EDInst.h +++ /dev/null @@ -1,175 +0,0 @@ -//===-EDInst.h - LLVM Enhanced Disassembler ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the interface for the Enhanced Disassembly library's -// instruction class. The instruction is responsible for vending the string -// representation, individual tokens and operands for a single instruction. -// -//===----------------------------------------------------------------------===// - -#ifndef EDInst_ -#define EDInst_ - -#include "llvm-c/EnhancedDisassembly.h" - -#include "llvm/ADT/SmallVector.h" - -#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 { - /// True if the result has been obtained by executing the function - bool Valid; - /// The result last obtained from the function - int Result; - - /// Constructor - Initializes an invalid result - CachedResult() : Valid(false) { } - /// valid - Returns true if the result has been obtained by executing the - /// function and false otherwise - bool valid() { return Valid; } - /// result - Returns the result of the function or an undefined value if - /// valid() is false - int result() { return Result; } - /// setResult - Sets the result of the function and declares it valid - /// returning the result (so that setResult() can be called from inside a - /// return statement) - /// @arg result - The result of the function - int setResult(int result) { Result = result; Valid = true; return result; } -}; - -/// EDInst - Encapsulates a single instruction, which can be queried for its -/// string representation, as well as its operands and tokens -struct EDInst { - /// The parent disassembler - EDDisassembler &Disassembler; - /// The containing MCInst - llvm::MCInst *Inst; - /// The instruction information provided by TableGen for this instruction - const llvm::EDInstInfo *ThisInstInfo; - /// The number of bytes for the machine code representation of the instruction - uint64_t ByteSize; - - /// The result of the stringify() function - CachedResult StringifyResult; - /// The string representation of the instruction - std::string String; - /// The order in which operands from the InstInfo's operand information appear - /// in String - const char* OperandOrder; - - /// The result of the parseOperands() function - CachedResult ParseResult; - typedef llvm::SmallVector<EDOperand*, 5> opvec_t; - /// The instruction's operands - opvec_t Operands; - /// The operand corresponding to the target, if the instruction is a branch - int BranchTarget; - /// The operand corresponding to the source, if the instruction is a move - int MoveSource; - /// The operand corresponding to the target, if the instruction is a move - int MoveTarget; - - /// The result of the tokenize() function - CachedResult TokenizeResult; - typedef std::vector<EDToken*> tokvec_t; - /// The instruction's tokens - tokvec_t Tokens; - - /// Constructor - initializes an instruction given the output of the LLVM - /// C++ disassembler - /// - /// @arg inst - The MCInst, which will now be owned by this object - /// @arg byteSize - The size of the consumed instruction, in bytes - /// @arg disassembler - The parent disassembler - /// @arg instInfo - The instruction information produced by the table - /// generator for this instruction - EDInst(llvm::MCInst *inst, - uint64_t byteSize, - EDDisassembler &disassembler, - const llvm::EDInstInfo *instInfo); - ~EDInst(); - - /// byteSize - returns the number of bytes consumed by the machine code - /// representation of the instruction - uint64_t byteSize(); - /// instID - returns the LLVM instruction ID of the instruction - unsigned instID(); - - /// stringify - populates the String and AsmString members of the instruction, - /// returning 0 on success or -1 otherwise - int stringify(); - /// getString - retrieves a pointer to the string representation of the - /// instructinon, returning 0 on success or -1 otherwise - /// - /// @arg str - A reference to a pointer that, on success, is set to point to - /// the string representation of the instruction; this string is still owned - /// by the instruction and will be deleted when it is - int getString(const char *&str); - - /// isBranch - Returns true if the instruction is a branch - bool isBranch(); - /// isMove - Returns true if the instruction is a move - bool isMove(); - - /// parseOperands - populates the Operands member of the instruction, - /// returning 0 on success or -1 otherwise - int parseOperands(); - /// branchTargetID - returns the ID (suitable for use with getOperand()) of - /// the target operand if the instruction is a branch, or -1 otherwise - int branchTargetID(); - /// moveSourceID - returns the ID of the source operand if the instruction - /// is a move, or -1 otherwise - int moveSourceID(); - /// moveTargetID - returns the ID of the target operand if the instruction - /// is a move, or -1 otherwise - int moveTargetID(); - - /// numOperands - returns the number of operands available to retrieve, or -1 - /// on error - int numOperands(); - /// getOperand - retrieves an operand from the instruction's operand list by - /// index, returning 0 on success or -1 on error - /// - /// @arg operand - A reference whose target is pointed at the operand on - /// success, although the operand is still owned by the EDInst - /// @arg index - The index of the operand in the instruction - int getOperand(EDOperand *&operand, unsigned int index); - - /// tokenize - populates the Tokens member of the instruction, returning 0 on - /// success or -1 otherwise - int tokenize(); - /// numTokens - returns the number of tokens in the instruction, or -1 on - /// error - int numTokens(); - /// getToken - retrieves a token from the instruction's token list by index, - /// returning 0 on success or -1 on error - /// - /// @arg token - A reference whose target is pointed at the token on success, - /// although the token is still owned by the EDInst - /// @arg index - The index of the token in the instrcutino - int getToken(EDToken *&token, unsigned int index); - -#ifdef __BLOCKS__ - /// visitTokens - Visits each token in turn and applies a block to it, - /// returning 0 if all blocks are visited and/or the block signals - /// termination by returning 1; returns -1 on error - /// - /// @arg visitor - The visitor block to apply to all tokens. - int visitTokens(EDTokenVisitor_t visitor); -#endif -}; - -#endif diff --git a/tools/edis/EDMain.cpp b/tools/edis/EDMain.cpp index b6ca32f..16855b3 100644 --- a/tools/edis/EDMain.cpp +++ b/tools/edis/EDMain.cpp @@ -1,4 +1,4 @@ -//===-EDMain.cpp - LLVM Enhanced Disassembly C API ------------------------===// +//===-- EDMain.cpp - LLVM Enhanced Disassembly C API ----------------------===// // // The LLVM Compiler Infrastructure // @@ -11,33 +11,46 @@ // //===----------------------------------------------------------------------===// -#include "EDDisassembler.h" -#include "EDInst.h" -#include "EDOperand.h" -#include "EDToken.h" - +// FIXME: This code isn't layered right, the headers should be moved to +// include llvm/MC/MCDisassembler or something. +#include "../../lib/MC/MCDisassembler/EDDisassembler.h" +#include "../../lib/MC/MCDisassembler/EDInst.h" +#include "../../lib/MC/MCDisassembler/EDOperand.h" +#include "../../lib/MC/MCDisassembler/EDToken.h" #include "llvm-c/EnhancedDisassembly.h" +using namespace llvm; int EDGetDisassembler(EDDisassemblerRef *disassembler, const char *triple, EDAssemblySyntax_t syntax) { EDDisassembler::initialize(); - EDDisassemblerRef ret = EDDisassembler::getDisassembler(triple, - syntax); + EDDisassembler::AssemblySyntax Syntax; + switch (syntax) { + default: assert(0 && "Unknown assembly syntax!"); + case kEDAssemblySyntaxX86Intel: + Syntax = EDDisassembler::kEDAssemblySyntaxX86Intel; + break; + case kEDAssemblySyntaxX86ATT: + Syntax = EDDisassembler::kEDAssemblySyntaxX86ATT; + break; + case kEDAssemblySyntaxARMUAL: + Syntax = EDDisassembler::kEDAssemblySyntaxARMUAL; + break; + } + + EDDisassemblerRef ret = EDDisassembler::getDisassembler(triple, Syntax); - if (ret) { - *disassembler = ret; - return 0; - } else { + if (!ret) return -1; - } + *disassembler = ret; + return 0; } int EDGetRegisterName(const char** regName, EDDisassemblerRef disassembler, unsigned regID) { - const char* name = disassembler->nameWithRegisterID(regID); + const char *name = ((EDDisassembler*)disassembler)->nameWithRegisterID(regID); if (!name) return -1; *regName = name; @@ -46,24 +59,25 @@ int EDGetRegisterName(const char** regName, int EDRegisterIsStackPointer(EDDisassemblerRef disassembler, unsigned regID) { - return disassembler->registerIsStackPointer(regID) ? 1 : 0; + return ((EDDisassembler*)disassembler)->registerIsStackPointer(regID) ? 1 : 0; } int EDRegisterIsProgramCounter(EDDisassemblerRef disassembler, unsigned regID) { - return disassembler->registerIsProgramCounter(regID) ? 1 : 0; + return ((EDDisassembler*)disassembler)->registerIsProgramCounter(regID) ? 1:0; } unsigned int EDCreateInsts(EDInstRef *insts, unsigned int count, EDDisassemblerRef disassembler, - EDByteReaderCallback byteReader, + ::EDByteReaderCallback byteReader, uint64_t address, void *arg) { unsigned int index; for (index = 0; index < count; ++index) { - EDInst *inst = disassembler->createInst(byteReader, address, arg); + EDInst *inst = ((EDDisassembler*)disassembler)->createInst(byteReader, + address, arg); if (!inst) return index; @@ -76,163 +90,143 @@ unsigned int EDCreateInsts(EDInstRef *insts, } void EDReleaseInst(EDInstRef inst) { - delete inst; + delete ((EDInst*)inst); } int EDInstByteSize(EDInstRef inst) { - return inst->byteSize(); + return ((EDInst*)inst)->byteSize(); } int EDGetInstString(const char **buf, EDInstRef inst) { - return inst->getString(*buf); + return ((EDInst*)inst)->getString(*buf); } int EDInstID(unsigned *instID, EDInstRef inst) { - *instID = inst->instID(); + *instID = ((EDInst*)inst)->instID(); return 0; } int EDInstIsBranch(EDInstRef inst) { - return inst->isBranch(); + return ((EDInst*)inst)->isBranch(); } int EDInstIsMove(EDInstRef inst) { - return inst->isMove(); + return ((EDInst*)inst)->isMove(); } int EDBranchTargetID(EDInstRef inst) { - return inst->branchTargetID(); + return ((EDInst*)inst)->branchTargetID(); } int EDMoveSourceID(EDInstRef inst) { - return inst->moveSourceID(); + return ((EDInst*)inst)->moveSourceID(); } int EDMoveTargetID(EDInstRef inst) { - return inst->moveTargetID(); + return ((EDInst*)inst)->moveTargetID(); } int EDNumTokens(EDInstRef inst) { - return inst->numTokens(); + return ((EDInst*)inst)->numTokens(); } int EDGetToken(EDTokenRef *token, EDInstRef inst, int index) { - return inst->getToken(*token, index); + return ((EDInst*)inst)->getToken(*(EDToken**)token, index); } int EDGetTokenString(const char **buf, EDTokenRef token) { - return token->getString(*buf); + return ((EDToken*)token)->getString(*buf); } int EDOperandIndexForToken(EDTokenRef token) { - return token->operandID(); + return ((EDToken*)token)->operandID(); } int EDTokenIsWhitespace(EDTokenRef token) { - if (token->type() == EDToken::kTokenWhitespace) - return 1; - else - return 0; + return ((EDToken*)token)->type() == EDToken::kTokenWhitespace; } int EDTokenIsPunctuation(EDTokenRef token) { - if (token->type() == EDToken::kTokenPunctuation) - return 1; - else - return 0; + return ((EDToken*)token)->type() == EDToken::kTokenPunctuation; } int EDTokenIsOpcode(EDTokenRef token) { - if (token->type() == EDToken::kTokenOpcode) - return 1; - else - return 0; + return ((EDToken*)token)->type() == EDToken::kTokenOpcode; } int EDTokenIsLiteral(EDTokenRef token) { - if (token->type() == EDToken::kTokenLiteral) - return 1; - else - return 0; + return ((EDToken*)token)->type() == EDToken::kTokenLiteral; } int EDTokenIsRegister(EDTokenRef token) { - if (token->type() == EDToken::kTokenRegister) - return 1; - else - return 0; + return ((EDToken*)token)->type() == EDToken::kTokenRegister; } int EDTokenIsNegativeLiteral(EDTokenRef token) { - if (token->type() != EDToken::kTokenLiteral) + if (((EDToken*)token)->type() != EDToken::kTokenLiteral) return -1; - return token->literalSign(); + return ((EDToken*)token)->literalSign(); } -int EDLiteralTokenAbsoluteValue(uint64_t *value, - EDTokenRef token) { - if (token->type() != EDToken::kTokenLiteral) +int EDLiteralTokenAbsoluteValue(uint64_t *value, EDTokenRef token) { + if (((EDToken*)token)->type() != EDToken::kTokenLiteral) return -1; - return token->literalAbsoluteValue(*value); + return ((EDToken*)token)->literalAbsoluteValue(*value); } int EDRegisterTokenValue(unsigned *registerID, EDTokenRef token) { - if (token->type() != EDToken::kTokenRegister) + if (((EDToken*)token)->type() != EDToken::kTokenRegister) return -1; - return token->registerID(*registerID); + return ((EDToken*)token)->registerID(*registerID); } int EDNumOperands(EDInstRef inst) { - return inst->numOperands(); + return ((EDInst*)inst)->numOperands(); } int EDGetOperand(EDOperandRef *operand, EDInstRef inst, int index) { - return inst->getOperand(*operand, index); + return ((EDInst*)inst)->getOperand(*(EDOperand**)operand, index); } int EDOperandIsRegister(EDOperandRef operand) { - return operand->isRegister(); + return ((EDOperand*)operand)->isRegister(); } int EDOperandIsImmediate(EDOperandRef operand) { - return operand->isImmediate(); + return ((EDOperand*)operand)->isImmediate(); } int EDOperandIsMemory(EDOperandRef operand) { - return operand->isMemory(); + return ((EDOperand*)operand)->isMemory(); } -int EDRegisterOperandValue(unsigned *value, - EDOperandRef operand) { - if (!operand->isRegister()) +int EDRegisterOperandValue(unsigned *value, EDOperandRef operand) { + if (!((EDOperand*)operand)->isRegister()) return -1; - *value = operand->regVal(); + *value = ((EDOperand*)operand)->regVal(); return 0; } -int EDImmediateOperandValue(uint64_t *value, - EDOperandRef operand) { - if (!operand->isImmediate()) +int EDImmediateOperandValue(uint64_t *value, EDOperandRef operand) { + if (!((EDOperand*)operand)->isImmediate()) return -1; - *value = operand->immediateVal(); + *value = ((EDOperand*)operand)->immediateVal(); return 0; } -int EDEvaluateOperand(uint64_t *result, - EDOperandRef operand, - EDRegisterReaderCallback regReader, - void *arg) { - return operand->evaluate(*result, regReader, arg); +int EDEvaluateOperand(uint64_t *result, EDOperandRef operand, + ::EDRegisterReaderCallback regReader, void *arg) { + return ((EDOperand*)operand)->evaluate(*result, regReader, arg); } #ifdef __BLOCKS__ @@ -264,15 +258,13 @@ unsigned int EDBlockCreateInsts(EDInstRef *insts, (void*)&wrapper); } -int EDBlockEvaluateOperand(uint64_t *result, - EDOperandRef operand, +int EDBlockEvaluateOperand(uint64_t *result, EDOperandRef operand, EDRegisterBlock_t regBlock) { - return operand->evaluate(*result, regBlock); + return ((EDOperand*)operand)->evaluate(*result, regBlock); } -int EDBlockVisitTokens(EDInstRef inst, - EDTokenVisitor_t visitor) { - return inst->visitTokens(visitor); +int EDBlockVisitTokens(EDInstRef inst, ::EDTokenVisitor_t visitor) { + return ((EDInst*)inst)->visitTokens((llvm::EDTokenVisitor_t)visitor); } #else diff --git a/tools/edis/EDOperand.cpp b/tools/edis/EDOperand.cpp deleted file mode 100644 index d63c1c6..0000000 --- a/tools/edis/EDOperand.cpp +++ /dev/null @@ -1,284 +0,0 @@ -//===-EDOperand.cpp - LLVM Enhanced Disassembler --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Enhanced Disassembly library's operand class. The -// operand is responsible for allowing evaluation given a particular register -// context. -// -//===----------------------------------------------------------------------===// - -#include "EDDisassembler.h" -#include "EDInst.h" -#include "EDOperand.h" - -#include "llvm/MC/EDInstInfo.h" -#include "llvm/MC/MCInst.h" - -using namespace llvm; - -EDOperand::EDOperand(const EDDisassembler &disassembler, - const EDInst &inst, - unsigned int opIndex, - unsigned int &mcOpIndex) : - Disassembler(disassembler), - Inst(inst), - OpIndex(opIndex), - MCOpIndex(mcOpIndex) { - unsigned int numMCOperands = 0; - - if (Disassembler.Key.Arch == Triple::x86 || - Disassembler.Key.Arch == Triple::x86_64) { - uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex]; - - switch (operandType) { - default: - break; - case kOperandTypeImmediate: - numMCOperands = 1; - break; - case kOperandTypeRegister: - numMCOperands = 1; - break; - case kOperandTypeX86Memory: - numMCOperands = 5; - break; - case kOperandTypeX86EffectiveAddress: - numMCOperands = 4; - break; - case kOperandTypeX86PCRelative: - numMCOperands = 1; - break; - } - } - 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; - } - } - - mcOpIndex += numMCOperands; -} - -EDOperand::~EDOperand() { -} - -int EDOperand::evaluate(uint64_t &result, - EDRegisterReaderCallback callback, - void *arg) { - 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; - case kOperandTypeRegister: - { - unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg(); - return callback(&result, reg, arg); - } - case kOperandTypeX86PCRelative: - { - int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm(); - - uint64_t ripVal; - - // TODO fix how we do this - - if (callback(&ripVal, Disassembler.registerIDWithName("RIP"), arg)) - return -1; - - 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; - - 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; - - 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; -} - -int EDOperand::isRegister() { - return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeRegister); -} - -unsigned EDOperand::regVal() { - return Inst.Inst->getOperand(MCOpIndex).getReg(); -} - -int EDOperand::isImmediate() { - return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeImmediate); -} - -uint64_t EDOperand::immediateVal() { - return Inst.Inst->getOperand(MCOpIndex).getImm(); -} - -int EDOperand::isMemory() { - 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__ -struct RegisterReaderWrapper { - EDRegisterBlock_t regBlock; -}; - -int readerWrapperCallback(uint64_t *value, - unsigned regID, - void *arg) { - struct RegisterReaderWrapper *wrapper = (struct RegisterReaderWrapper *)arg; - return wrapper->regBlock(value, regID); -} - -int EDOperand::evaluate(uint64_t &result, - EDRegisterBlock_t regBlock) { - struct RegisterReaderWrapper wrapper; - wrapper.regBlock = regBlock; - return evaluate(result, - readerWrapperCallback, - (void*)&wrapper); -} -#endif diff --git a/tools/edis/EDOperand.h b/tools/edis/EDOperand.h deleted file mode 100644 index ad9345b..0000000 --- a/tools/edis/EDOperand.h +++ /dev/null @@ -1,78 +0,0 @@ -//===-EDOperand.h - LLVM Enhanced Disassembler ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the interface for the Enhanced Disassembly library's -// operand class. The operand is responsible for allowing evaluation given a -// particular register context. -// -//===----------------------------------------------------------------------===// - -#ifndef EDOperand_ -#define EDOperand_ - -#include "llvm-c/EnhancedDisassembly.h" - -/// EDOperand - Encapsulates a single operand, which can be evaluated by the -/// client -struct EDOperand { - /// The parent disassembler - const EDDisassembler &Disassembler; - /// The parent instruction - const EDInst &Inst; - - /// The index of the operand in the EDInst - unsigned int OpIndex; - /// The index of the first component of the operand in the MCInst - unsigned int MCOpIndex; - - /// Constructor - Initializes an EDOperand - /// - /// @arg disassembler - The disassembler responsible for the operand - /// @arg inst - The instruction containing this operand - /// @arg opIndex - The index of the operand in inst - /// @arg mcOpIndex - The index of the operand in the original MCInst - EDOperand(const EDDisassembler &disassembler, - const EDInst &inst, - unsigned int opIndex, - unsigned int &mcOpIndex); - ~EDOperand(); - - /// evaluate - Returns the numeric value of an operand to the extent possible, - /// returning 0 on success or -1 if there was some problem (such as a - /// register not being readable) - /// - /// @arg result - A reference whose target is filled in with the value of - /// the operand (the address if it is a memory operand) - /// @arg callback - A function to call to obtain register values - /// @arg arg - An opaque argument to pass to callback - int evaluate(uint64_t &result, - EDRegisterReaderCallback callback, - void *arg); - - /// isRegister - Returns 1 if the operand is a register or 0 otherwise - int isRegister(); - /// regVal - Returns the register value. - unsigned regVal(); - - /// isImmediate - Returns 1 if the operand is an immediate or 0 otherwise - int isImmediate(); - /// immediateVal - Returns the immediate value. - uint64_t immediateVal(); - - /// isMemory - Returns 1 if the operand is a memory location or 0 otherwise - int isMemory(); - -#ifdef __BLOCKS__ - /// evaluate - Like evaluate for a callback, but uses a block instead - int evaluate(uint64_t &result, - EDRegisterBlock_t regBlock); -#endif -}; - -#endif diff --git a/tools/edis/EDToken.cpp b/tools/edis/EDToken.cpp deleted file mode 100644 index 3bcb0a1..0000000 --- a/tools/edis/EDToken.cpp +++ /dev/null @@ -1,208 +0,0 @@ -//===-EDToken.cpp - LLVM Enhanced Disassembler ----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Enhanced Disassembler library's token class. The -// token is responsible for vending information about the token, such as its -// type and logical value. -// -//===----------------------------------------------------------------------===// - -#include "EDDisassembler.h" -#include "EDToken.h" - -#include "llvm/ADT/SmallVector.h" -#include "llvm/MC/MCParser/MCAsmLexer.h" -#include "llvm/MC/MCParser/MCParsedAsmOperand.h" - -using namespace llvm; - -EDToken::EDToken(StringRef str, - enum tokenType type, - uint64_t localType, - EDDisassembler &disassembler) : - Disassembler(disassembler), - Str(str), - Type(type), - LocalType(localType), - OperandID(-1) { -} - -EDToken::~EDToken() { -} - -void EDToken::makeLiteral(bool sign, uint64_t absoluteValue) { - Type = kTokenLiteral; - LiteralSign = sign; - LiteralAbsoluteValue = absoluteValue; -} - -void EDToken::makeRegister(unsigned registerID) { - Type = kTokenRegister; - RegisterID = registerID; -} - -void EDToken::setOperandID(int operandID) { - OperandID = operandID; -} - -enum EDToken::tokenType EDToken::type() const { - return Type; -} - -uint64_t EDToken::localType() const { - return LocalType; -} - -StringRef EDToken::string() const { - return Str; -} - -int EDToken::operandID() const { - return OperandID; -} - -int EDToken::literalSign() const { - if (Type != kTokenLiteral) - return -1; - return (LiteralSign ? 1 : 0); -} - -int EDToken::literalAbsoluteValue(uint64_t &value) const { - if (Type != kTokenLiteral) - return -1; - value = LiteralAbsoluteValue; - return 0; -} - -int EDToken::registerID(unsigned ®isterID) const { - if (Type != kTokenRegister) - return -1; - registerID = RegisterID; - return 0; -} - -int EDToken::tokenize(std::vector<EDToken*> &tokens, - std::string &str, - const char *operandOrder, - EDDisassembler &disassembler) { - SmallVector<MCParsedAsmOperand*, 5> parsedOperands; - SmallVector<AsmToken, 10> asmTokens; - - if (disassembler.parseInst(parsedOperands, asmTokens, str)) - return -1; - - SmallVectorImpl<MCParsedAsmOperand*>::iterator operandIterator; - unsigned int operandIndex; - SmallVectorImpl<AsmToken>::iterator tokenIterator; - - operandIterator = parsedOperands.begin(); - operandIndex = 0; - - bool readOpcode = false; - - const char *wsPointer = asmTokens.begin()->getLoc().getPointer(); - - for (tokenIterator = asmTokens.begin(); - tokenIterator != asmTokens.end(); - ++tokenIterator) { - SMLoc tokenLoc = tokenIterator->getLoc(); - - const char *tokenPointer = tokenLoc.getPointer(); - - if (tokenPointer > wsPointer) { - unsigned long wsLength = tokenPointer - wsPointer; - - EDToken *whitespaceToken = new EDToken(StringRef(wsPointer, wsLength), - EDToken::kTokenWhitespace, - 0, - disassembler); - - tokens.push_back(whitespaceToken); - } - - wsPointer = tokenPointer + tokenIterator->getString().size(); - - while (operandIterator != parsedOperands.end() && - tokenLoc.getPointer() > - (*operandIterator)->getEndLoc().getPointer()) { - ++operandIterator; - ++operandIndex; - } - - EDToken *token; - - switch (tokenIterator->getKind()) { - case AsmToken::Identifier: - if (!readOpcode) { - token = new EDToken(tokenIterator->getString(), - EDToken::kTokenOpcode, - (uint64_t)tokenIterator->getKind(), - disassembler); - readOpcode = true; - break; - } - // any identifier that isn't an opcode is mere punctuation; so we fall - // through - default: - token = new EDToken(tokenIterator->getString(), - EDToken::kTokenPunctuation, - (uint64_t)tokenIterator->getKind(), - disassembler); - break; - case AsmToken::Integer: - { - token = new EDToken(tokenIterator->getString(), - EDToken::kTokenLiteral, - (uint64_t)tokenIterator->getKind(), - disassembler); - - int64_t intVal = tokenIterator->getIntVal(); - - if (intVal < 0) - token->makeLiteral(true, -intVal); - else - token->makeLiteral(false, intVal); - break; - } - case AsmToken::Register: - { - token = new EDToken(tokenIterator->getString(), - EDToken::kTokenLiteral, - (uint64_t)tokenIterator->getKind(), - disassembler); - - token->makeRegister((unsigned)tokenIterator->getRegVal()); - break; - } - } - - 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) - token->setOperandID(operandOrder[operandIndex - 1]); - } - - tokens.push_back(token); - } - - return 0; -} - -int EDToken::getString(const char*& buf) { - if (PermStr.length() == 0) { - PermStr = Str.str(); - } - buf = PermStr.c_str(); - return 0; -} diff --git a/tools/edis/EDToken.h b/tools/edis/EDToken.h deleted file mode 100644 index e4ae91f..0000000 --- a/tools/edis/EDToken.h +++ /dev/null @@ -1,135 +0,0 @@ -//===-EDToken.h - LLVM Enhanced Disassembler --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the interface for the Enhanced Disassembly library's token -// class. The token is responsible for vending information about the token, -// such as its type and logical value. -// -//===----------------------------------------------------------------------===// - -#ifndef EDToken_ -#define EDToken_ - -#include "llvm-c/EnhancedDisassembly.h" -#include "llvm/ADT/StringRef.h" - -#include <string> -#include <vector> - -/// EDToken - Encapsulates a single token, which can provide a string -/// representation of itself or interpret itself in various ways, depending -/// on the token type. -struct EDToken { - enum tokenType { - kTokenWhitespace, - kTokenOpcode, - kTokenLiteral, - kTokenRegister, - kTokenPunctuation - }; - - /// The parent disassembler - EDDisassembler &Disassembler; - - /// The token's string representation - llvm::StringRef Str; - /// The token's string representation, but in a form suitable for export - std::string PermStr; - /// The type of the token, as exposed through the external API - enum tokenType Type; - /// The type of the token, as recorded by the syntax-specific tokenizer - uint64_t LocalType; - /// The operand corresponding to the token, or (unsigned int)-1 if not - /// part of an operand. - int OperandID; - - /// The sign if the token is a literal (1 if negative, 0 otherwise) - bool LiteralSign; - /// The absolute value if the token is a literal - uint64_t LiteralAbsoluteValue; - /// The LLVM register ID if the token is a register name - unsigned RegisterID; - - /// Constructor - Initializes an EDToken with the information common to all - /// tokens - /// - /// @arg str - The string corresponding to the token - /// @arg type - The token's type as exposed through the public API - /// @arg localType - The token's type as recorded by the tokenizer - /// @arg disassembler - The disassembler responsible for the token - EDToken(llvm::StringRef str, - enum tokenType type, - uint64_t localType, - EDDisassembler &disassembler); - - /// makeLiteral - Adds the information specific to a literal - /// @arg sign - The sign of the literal (1 if negative, 0 - /// otherwise) - /// - /// @arg absoluteValue - The absolute value of the literal - void makeLiteral(bool sign, uint64_t absoluteValue); - /// makeRegister - Adds the information specific to a register - /// - /// @arg registerID - The LLVM register ID - void makeRegister(unsigned registerID); - - /// setOperandID - Links the token to a numbered operand - /// - /// @arg operandID - The operand ID to link to - void setOperandID(int operandID); - - ~EDToken(); - - /// type - Returns the public type of the token - enum tokenType type() const; - /// localType - Returns the tokenizer-specific type of the token - uint64_t localType() const; - /// string - Returns the string representation of the token - llvm::StringRef string() const; - /// operandID - Returns the operand ID of the token - int operandID() const; - - /// literalSign - Returns the sign of the token - /// (1 if negative, 0 if positive or unsigned, -1 if it is not a literal) - int literalSign() const; - /// literalAbsoluteValue - Retrieves the absolute value of the token, and - /// returns -1 if the token is not a literal - /// @arg value - A reference to a value that is filled in with the absolute - /// value, if it is valid - int literalAbsoluteValue(uint64_t &value) const; - /// registerID - Retrieves the register ID of the token, and returns -1 if the - /// token is not a register - /// - /// @arg registerID - A reference to a value that is filled in with the - /// register ID, if it is valid - int registerID(unsigned ®isterID) const; - - /// tokenize - Tokenizes a string using the platform- and syntax-specific - /// tokenizer, and returns 0 on success (-1 on failure) - /// - /// @arg tokens - A vector that will be filled in with pointers to - /// allocated tokens - /// @arg str - The string, as outputted by the AsmPrinter - /// @arg operandOrder - The order of the operands from the operandFlags array - /// as they appear in str - /// @arg disassembler - The disassembler for the desired target and - // assembly syntax - static int tokenize(std::vector<EDToken*> &tokens, - std::string &str, - const char *operandOrder, - EDDisassembler &disassembler); - - /// getString - Directs a character pointer to the string, returning 0 on - /// success (-1 on failure) - /// @arg buf - A reference to a pointer that is set to point to the string. - /// The string is still owned by the token. - int getString(const char*& buf); -}; - -#endif diff --git a/tools/edis/Makefile b/tools/edis/Makefile index 0d2e26f..92484bf 100644 --- a/tools/edis/Makefile +++ b/tools/edis/Makefile @@ -9,8 +9,8 @@ LEVEL = ../.. LIBRARYNAME = EnhancedDisassembly - -BUILT_SOURCES = EDInfo.inc +LINK_LIBS_IN_SHARED = 1 +SHARED_LIBRARY = 1 EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/EnhancedDisassembly.exports @@ -19,23 +19,23 @@ EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/EnhancedDisassembly.exports # early so we can set up LINK_COMPONENTS before including Makefile.rules include $(LEVEL)/Makefile.config -ifeq ($(ENABLE_PIC),1) - ifneq ($(DISABLE_EDIS),1) - ifneq ($(TARGET_OS), $(filter $(TARGET_OS), Cygwin MingW)) - LINK_LIBS_IN_SHARED = 1 - SHARED_LIBRARY = 1 - endif - endif +LINK_COMPONENTS := mcdisassembler + +# If the X86 target is enabled, link in the asmprinter and disassembler. +ifneq ($(filter $(TARGETS_TO_BUILD), X86),) +LINK_COMPONENTS += x86asmprinter x86disassembler endif -LINK_COMPONENTS := $(TARGETS_TO_BUILD) x86asmprinter x86disassembler +# If the X86 target is enabled, link in the asmprinter and disassembler. +ifneq ($(filter $(TARGETS_TO_BUILD), ARM),) +LINK_COMPONENTS += armasmprinter armdisassembler +endif include $(LEVEL)/Makefile.common ifeq ($(HOST_OS),Darwin) # extra options to override libtool defaults LLVMLibsOptions := $(LLVMLibsOptions) \ - -avoid-version \ -Wl,-dead_strip ifdef EDIS_VERSION @@ -47,14 +47,8 @@ ifeq ($(HOST_OS),Darwin) DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ - -no-undefined -Wl,-install_name \ + -Wl,-install_name \ -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif -EDInfo.inc: $(TBLGEN) - $(Echo) "Building semantic information header" - $(Verb) $(TableGen) -o $(call SYSPATH, $@) -gen-enhanced-disassembly-header /dev/null - -clean:: - -$(Verb) $(RM) -f EDInfo.inc diff --git a/tools/gold/README.txt b/tools/gold/README.txt index 92ee3d1..a906a90 100644 --- a/tools/gold/README.txt +++ b/tools/gold/README.txt @@ -14,8 +14,8 @@ Then build binutils with "make all-gold". To build the LLVMgold plugin, configure LLVM with the option --with-binutils-include=/path/to/binutils/src/include/ --enable-pic. To use the -plugin, run "ld-new --plugin /path/to/libLLVMgold.so". -Without PIC libLTO and libLLVMgold are not being built (because they would fail +plugin, run "ld-new --plugin /path/to/LLVMgold.so". +Without PIC libLTO and LLVMgold are not being built (because they would fail link on x86-64 with a relocation error: PIC and non-PIC can't be combined). As an alternative to passing --enable-pic, you can use 'make ENABLE_PIC=1' in your entire LLVM build. diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 2d0f5bd..4b58fae 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -66,8 +66,11 @@ namespace options { static generate_bc generate_bc_file = BC_NO; static std::string bc_path; static std::string as_path; + static std::vector<std::string> as_args; static std::vector<std::string> pass_through; static std::string extra_library_path; + static std::string triple; + static std::string mcpu; // 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. @@ -83,6 +86,8 @@ namespace options { if (opt == "generate-api-file") { generate_api_file = true; + } else if (opt.startswith("mcpu=")) { + mcpu = opt.substr(strlen("mcpu=")); } else if (opt.startswith("as=")) { if (!as_path.empty()) { (*message)(LDPL_WARNING, "Path to as specified twice. " @@ -90,11 +95,16 @@ namespace options { } else { as_path = opt.substr(strlen("as=")); } + } else if (opt.startswith("as-arg=")) { + llvm::StringRef item = opt.substr(strlen("as-arg=")); + as_args.push_back(item.str()); } else if (opt.startswith("extra-library-path=")) { extra_library_path = opt.substr(strlen("extra_library_path=")); } else if (opt.startswith("pass-through=")) { llvm::StringRef item = opt.substr(strlen("pass-through=")); pass_through.push_back(item.str()); + } else if (opt.startswith("mtriple=")) { + triple = opt.substr(strlen("mtriple=")); } else if (opt == "emit-llvm") { generate_bc_file = BC_ONLY; } else if (opt == "also-emit-llvm") { @@ -270,6 +280,10 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, lto_get_error_message()); return LDPS_ERR; } + + if (!options::triple.empty()) + lto_module_set_target_triple(cf.M, options::triple.c_str()); + cf.handle = file->handle; unsigned sym_count = lto_module_get_num_symbols(cf.M); cf.syms.reserve(sym_count); @@ -394,6 +408,17 @@ static ld_plugin_status all_symbols_read_hook(void) { sys::Path p = sys::Program::FindProgramByName(options::as_path); lto_codegen_set_assembler_path(cg, p.c_str()); } + if (!options::as_args.empty()) { + std::vector<const char *> as_args_p; + for (std::vector<std::string>::iterator I = options::as_args.begin(), + E = options::as_args.end(); I != E; ++I) { + as_args_p.push_back(I->c_str()); + } + lto_codegen_set_assembler_args(cg, &as_args_p[0], as_args_p.size()); + } + if (!options::mcpu.empty()) + lto_codegen_set_cpu(cg, options::mcpu.c_str()); + // Pass through extra options to the code generator. if (!options::extra.empty()) { for (std::vector<std::string>::iterator it = options::extra.begin(); @@ -428,15 +453,22 @@ static ld_plugin_status all_symbols_read_hook(void) { (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); return LDPS_ERR; } - raw_fd_ostream objFile(uniqueObjPath.c_str(), ErrMsg, - raw_fd_ostream::F_Binary); + tool_output_file objFile(uniqueObjPath.c_str(), ErrMsg, + raw_fd_ostream::F_Binary); if (!ErrMsg.empty()) { (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); return LDPS_ERR; } - objFile.write(buffer, bufsize); - objFile.close(); + objFile.os().write(buffer, bufsize); + objFile.os().close(); + if (objFile.os().has_error()) { + (*message)(LDPL_ERROR, "Error writing output file '%s'", + uniqueObjPath.c_str()); + objFile.os().clear_error(); + return LDPS_ERR; + } + objFile.keep(); lto_codegen_dispose(cg); diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 199a1a9..8bcc2d8 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -18,7 +18,6 @@ #include "llvm/PassManager.h" #include "llvm/Pass.h" #include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Verifier.h" #include "llvm/Support/IRReader.h" #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" @@ -76,6 +75,11 @@ MAttrs("mattr", cl::desc("Target specific attributes (-mattr=help for details)"), cl::value_desc("a1,+a2,-a3,...")); +static cl::opt<bool> +RelaxAll("mc-relax-all", + cl::desc("When used with filetype=obj, " + "relax all fixups in the emitted object file")); + cl::opt<TargetMachine::CodeGenFileType> FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile), cl::desc("Choose a file type (not all types are supported by all targets):"), @@ -119,87 +123,67 @@ GetFileNameRoot(const std::string &InputFilename) { return outputFilename; } -static formatted_raw_ostream *GetOutputStream(const char *TargetName, - Triple::OSType OS, - const char *ProgName) { - if (OutputFilename != "") { - if (OutputFilename == "-") - return new formatted_raw_ostream(outs(), - formatted_raw_ostream::PRESERVE_STREAM); - - // Make sure that the Out file gets unlinked from the disk if we get a - // SIGINT - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - - std::string error; - raw_fd_ostream *FDOut = - new raw_fd_ostream(OutputFilename.c_str(), error, - raw_fd_ostream::F_Binary); - if (!error.empty()) { - errs() << error << '\n'; - delete FDOut; - return 0; +static tool_output_file *GetOutputStream(const char *TargetName, + Triple::OSType OS, + const char *ProgName) { + // If we don't yet have an output filename, make one. + if (OutputFilename.empty()) { + if (InputFilename == "-") + OutputFilename = "-"; + else { + OutputFilename = GetFileNameRoot(InputFilename); + + switch (FileType) { + default: assert(0 && "Unknown file type"); + case TargetMachine::CGFT_AssemblyFile: + if (TargetName[0] == 'c') { + if (TargetName[1] == 0) + OutputFilename += ".cbe.c"; + else if (TargetName[1] == 'p' && TargetName[2] == 'p') + OutputFilename += ".cpp"; + else + OutputFilename += ".s"; + } else + OutputFilename += ".s"; + break; + case TargetMachine::CGFT_ObjectFile: + if (OS == Triple::Win32) + OutputFilename += ".obj"; + else + OutputFilename += ".o"; + break; + case TargetMachine::CGFT_Null: + OutputFilename += ".null"; + break; + } } - formatted_raw_ostream *Out = - new formatted_raw_ostream(*FDOut, formatted_raw_ostream::DELETE_STREAM); - - return Out; - } - - if (InputFilename == "-") { - OutputFilename = "-"; - return new formatted_raw_ostream(outs(), - formatted_raw_ostream::PRESERVE_STREAM); } - OutputFilename = GetFileNameRoot(InputFilename); - + // Decide if we need "binary" output. bool Binary = false; switch (FileType) { default: assert(0 && "Unknown file type"); case TargetMachine::CGFT_AssemblyFile: - if (TargetName[0] == 'c') { - if (TargetName[1] == 0) - OutputFilename += ".cbe.c"; - else if (TargetName[1] == 'p' && TargetName[2] == 'p') - OutputFilename += ".cpp"; - else - OutputFilename += ".s"; - } else - OutputFilename += ".s"; break; case TargetMachine::CGFT_ObjectFile: - if (OS == Triple::Win32) - OutputFilename += ".obj"; - else - OutputFilename += ".o"; - Binary = true; - break; case TargetMachine::CGFT_Null: - OutputFilename += ".null"; Binary = true; break; } - // Make sure that the Out file gets unlinked from the disk if we get a - // SIGINT - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - + // Open the file. std::string error; unsigned OpenFlags = 0; if (Binary) OpenFlags |= raw_fd_ostream::F_Binary; - raw_fd_ostream *FDOut = new raw_fd_ostream(OutputFilename.c_str(), error, - OpenFlags); + tool_output_file *FDOut = new tool_output_file(OutputFilename.c_str(), error, + OpenFlags); if (!error.empty()) { errs() << error << '\n'; delete FDOut; return 0; } - formatted_raw_ostream *Out = - new formatted_raw_ostream(*FDOut, formatted_raw_ostream::DELETE_STREAM); - - return Out; + return FDOut; } // main - Entry point for the llc compiler. @@ -234,7 +218,7 @@ int main(int argc, char **argv) { // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) - mod.setTargetTriple(TargetTriple); + mod.setTargetTriple(Triple::normalize(TargetTriple)); Triple TheTriple(mod.getTargetTriple()); if (TheTriple.getTriple().empty()) @@ -290,9 +274,9 @@ int main(int argc, char **argv) { TargetMachine &Target = *target.get(); // Figure out where we are going to send the output... - formatted_raw_ostream *Out = GetOutputStream(TheTarget->getName(), - TheTriple.getOS(), argv[0]); - if (Out == 0) return 1; + OwningPtr<tool_output_file> Out + (GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0])); + if (!Out) return 1; CodeGenOpt::Level OLvl = CodeGenOpt::Default; switch (OptLevel) { @@ -306,14 +290,6 @@ int main(int argc, char **argv) { case '3': OLvl = CodeGenOpt::Aggressive; break; } - // Request that addPassesToEmitFile run the Verifier after running - // passes which modify the IR. -#ifndef NDEBUG - bool DisableVerify = false; -#else - bool DisableVerify = true; -#endif - // Build up all of the passes that we want to do to the module. PassManager PM; @@ -323,27 +299,32 @@ int main(int argc, char **argv) { else PM.add(new TargetData(&mod)); - if (!NoVerify) - PM.add(createVerifierPass()); - // Override default to generate verbose assembly. Target.setAsmVerbosityDefault(true); - // Ask the target to add backend passes as necessary. - if (Target.addPassesToEmitFile(PM, *Out, FileType, OLvl, - DisableVerify)) { - errs() << argv[0] << ": target does not support generation of this" - << " file type!\n"; - delete Out; - // And the Out file is empty and useless, so remove it now. - sys::Path(OutputFilename).eraseFromDisk(); - return 1; + if (RelaxAll) { + if (FileType != TargetMachine::CGFT_ObjectFile) + errs() << argv[0] + << ": warning: ignoring -mc-relax-all because filetype != obj"; + else + Target.setMCRelaxAll(true); } - PM.run(mod); + { + formatted_raw_ostream FOS(Out->os()); + + // Ask the target to add backend passes as necessary. + if (Target.addPassesToEmitFile(PM, FOS, FileType, OLvl, NoVerify)) { + errs() << argv[0] << ": target does not support generation of this" + << " file type!\n"; + return 1; + } + + PM.run(mod); + } - // Delete the ostream. - delete Out; + // Declare success. + Out->keep(); return 0; } diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 4e3e07f..4c37780 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -16,6 +16,7 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Type.h" +#include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" #include "llvm/ExecutionEngine/GenericValue.h" @@ -157,7 +158,7 @@ int main(int argc, char **argv, char * const *envp) { // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) - Mod->setTargetTriple(TargetTriple); + Mod->setTargetTriple(Triple::normalize(TargetTriple)); CodeGenOpt::Level OLvl = CodeGenOpt::Default; switch (OptLevel) { diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp index d39d6c8..1eaa4b3 100644 --- a/tools/llvm-as/llvm-as.cpp +++ b/tools/llvm-as/llvm-as.cpp @@ -68,22 +68,20 @@ static void WriteOutputFile(const Module *M) { } } - // Make sure that the Out file gets unlinked from the disk if we get a - // SIGINT. - if (OutputFilename != "-") - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - std::string ErrorInfo; - std::auto_ptr<raw_ostream> Out - (new raw_fd_ostream(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + OwningPtr<tool_output_file> Out + (new tool_output_file(OutputFilename.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; exit(1); } - if (Force || !CheckBitcodeOutputToConsole(*Out, true)) - WriteBitcodeToFile(M, *Out); + if (Force || !CheckBitcodeOutputToConsole(Out->os(), true)) + WriteBitcodeToFile(M, Out->os()); + + // Declare success. + Out->keep(); } int main(int argc, char **argv) { diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 732ff11..9c0d675 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -46,9 +46,6 @@ using namespace llvm; static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-")); -static cl::opt<std::string> - OutputFilename("-o", cl::init("-"), cl::desc("<output file>")); - static cl::opt<bool> Dump("dump", cl::desc("Dump low level bitcode trace")); //===----------------------------------------------------------------------===// @@ -239,6 +236,8 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::FUNC_CODE_INST_VSELECT: return "INST_VSELECT"; case bitc::FUNC_CODE_DEBUG_LOC: return "DEBUG_LOC"; case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: return "DEBUG_LOC_AGAIN"; + case bitc::FUNC_CODE_INST_CALL2: return "INST_CALL2"; + case bitc::FUNC_CODE_DEBUG_LOC2: return "DEBUG_LOC2"; } case bitc::TYPE_SYMTAB_BLOCK_ID: switch (CodeID) { @@ -259,13 +258,17 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::METADATA_BLOCK_ID: switch(CodeID) { default:return 0; - case bitc::METADATA_STRING: return "MDSTRING"; - case bitc::METADATA_NODE: return "MDNODE"; - case bitc::METADATA_FN_NODE: return "FN_MDNODE"; + case bitc::METADATA_STRING: return "METADATA_STRING"; + case bitc::METADATA_NODE: return "METADATA_NODE"; + case bitc::METADATA_FN_NODE: return "METADATA_FN_NODE"; case bitc::METADATA_NAME: return "METADATA_NAME"; - case bitc::METADATA_NAMED_NODE: return "NAMEDMDNODE"; + case bitc::METADATA_NAMED_NODE: return "METADATA_NAMED_NODE"; case bitc::METADATA_KIND: return "METADATA_KIND"; case bitc::METADATA_ATTACHMENT: return "METADATA_ATTACHMENT"; + case bitc::METADATA_NODE2: return "METADATA_NODE2"; + case bitc::METADATA_FN_NODE2: return "METADATA_FN_NODE2"; + case bitc::METADATA_NAMED_NODE2: return "METADATA_NAMED_NODE2"; + case bitc::METADATA_ATTACHMENT2: return "METADATA_ATTACHMENT2"; } } } diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index 7a43dba..663cae5 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -78,7 +78,7 @@ add_custom_command(OUTPUT ${LIBDEPS_TMP} add_custom_command(OUTPUT ${LIBDEPS} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LIBDEPS_TMP} ${LIBDEPS} DEPENDS ${LIBDEPS_TMP} - COMMENT "Updated ${LIBDEPS} because dependencies changed") + COMMENT "Updating ${LIBDEPS} if necessary...") add_custom_command(OUTPUT ${FINAL_LIBDEPS} COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/find-cycles.pl < ${LIBDEPS} > ${FINAL_LIBDEPS} || ${CMAKE_COMMAND} -E remove -f ${FINAL_LIBDEPS} diff --git a/tools/llvm-diff/CMakeLists.txt b/tools/llvm-diff/CMakeLists.txt new file mode 100644 index 0000000..f6d65c9 --- /dev/null +++ b/tools/llvm-diff/CMakeLists.txt @@ -0,0 +1,6 @@ +set(LLVM_LINK_COMPONENTS support asmparser bitreader) + +add_llvm_tool(llvm-diff + llvm-diff.cpp + DifferenceEngine.cpp + ) diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp new file mode 100644 index 0000000..b0a24d0 --- /dev/null +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -0,0 +1,676 @@ +//===-- DifferenceEngine.cpp - Structural function/module comparison ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the implementation of the LLVM difference +// engine, which structurally compares global values within a module. +// +//===----------------------------------------------------------------------===// + +#include "DifferenceEngine.h" + +#include "llvm/Function.h" +#include "llvm/Instructions.h" +#include "llvm/Module.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/CallSite.h" +#include "llvm/Support/CFG.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/type_traits.h" + +#include <utility> + +using namespace llvm; + +namespace { + +/// A priority queue, implemented as a heap. +template <class T, class Sorter, unsigned InlineCapacity> +class PriorityQueue { + Sorter Precedes; + llvm::SmallVector<T, InlineCapacity> Storage; + +public: + PriorityQueue(const Sorter &Precedes) : Precedes(Precedes) {} + + /// Checks whether the heap is empty. + bool empty() const { return Storage.empty(); } + + /// Insert a new value on the heap. + void insert(const T &V) { + unsigned Index = Storage.size(); + Storage.push_back(V); + if (Index == 0) return; + + T *data = Storage.data(); + while (true) { + unsigned Target = (Index + 1) / 2 - 1; + if (!Precedes(data[Index], data[Target])) return; + std::swap(data[Index], data[Target]); + if (Target == 0) return; + Index = Target; + } + } + + /// Remove the minimum value in the heap. Only valid on a non-empty heap. + T remove_min() { + assert(!empty()); + T tmp = Storage[0]; + + unsigned NewSize = Storage.size() - 1; + if (NewSize) { + // Move the slot at the end to the beginning. + if (isPodLike<T>::value) + Storage[0] = Storage[NewSize]; + else + std::swap(Storage[0], Storage[NewSize]); + + // Bubble the root up as necessary. + unsigned Index = 0; + while (true) { + // With a 1-based index, the children would be Index*2 and Index*2+1. + unsigned R = (Index + 1) * 2; + unsigned L = R - 1; + + // If R is out of bounds, we're done after this in any case. + if (R >= NewSize) { + // If L is also out of bounds, we're done immediately. + if (L >= NewSize) break; + + // Otherwise, test whether we should swap L and Index. + if (Precedes(Storage[L], Storage[Index])) + std::swap(Storage[L], Storage[Index]); + break; + } + + // Otherwise, we need to compare with the smaller of L and R. + // Prefer R because it's closer to the end of the array. + unsigned IndexToTest = (Precedes(Storage[L], Storage[R]) ? L : R); + + // If Index is >= the min of L and R, then heap ordering is restored. + if (!Precedes(Storage[IndexToTest], Storage[Index])) + break; + + // Otherwise, keep bubbling up. + std::swap(Storage[IndexToTest], Storage[Index]); + Index = IndexToTest; + } + } + Storage.pop_back(); + + return tmp; + } +}; + +/// A function-scope difference engine. +class FunctionDifferenceEngine { + DifferenceEngine &Engine; + + /// The current mapping from old local values to new local values. + DenseMap<Value*, Value*> Values; + + /// The current mapping from old blocks to new blocks. + DenseMap<BasicBlock*, BasicBlock*> Blocks; + + DenseSet<std::pair<Value*, Value*> > TentativeValues; + + unsigned getUnprocPredCount(BasicBlock *Block) const { + unsigned Count = 0; + for (pred_iterator I = pred_begin(Block), E = pred_end(Block); I != E; ++I) + if (!Blocks.count(*I)) Count++; + return Count; + } + + typedef std::pair<BasicBlock*, BasicBlock*> BlockPair; + + /// A type which sorts a priority queue by the number of unprocessed + /// predecessor blocks it has remaining. + /// + /// This is actually really expensive to calculate. + struct QueueSorter { + const FunctionDifferenceEngine &fde; + explicit QueueSorter(const FunctionDifferenceEngine &fde) : fde(fde) {} + + bool operator()(const BlockPair &Old, const BlockPair &New) { + return fde.getUnprocPredCount(Old.first) + < fde.getUnprocPredCount(New.first); + } + }; + + /// A queue of unified blocks to process. + PriorityQueue<BlockPair, QueueSorter, 20> Queue; + + /// Try to unify the given two blocks. Enqueues them for processing + /// if they haven't already been processed. + /// + /// Returns true if there was a problem unifying them. + bool tryUnify(BasicBlock *L, BasicBlock *R) { + BasicBlock *&Ref = Blocks[L]; + + if (Ref) { + if (Ref == R) return false; + + Engine.logf("successor %l cannot be equivalent to %r; " + "it's already equivalent to %r") + << L << R << Ref; + return true; + } + + Ref = R; + Queue.insert(BlockPair(L, R)); + return false; + } + + /// Unifies two instructions, given that they're known not to have + /// structural differences. + void unify(Instruction *L, Instruction *R) { + DifferenceEngine::Context C(Engine, L, R); + + bool Result = diff(L, R, true, true); + assert(!Result && "structural differences second time around?"); + (void) Result; + if (!L->use_empty()) + Values[L] = R; + } + + void processQueue() { + while (!Queue.empty()) { + BlockPair Pair = Queue.remove_min(); + diff(Pair.first, Pair.second); + } + } + + void diff(BasicBlock *L, BasicBlock *R) { + DifferenceEngine::Context C(Engine, L, R); + + BasicBlock::iterator LI = L->begin(), LE = L->end(); + BasicBlock::iterator RI = R->begin(), RE = R->end(); + + llvm::SmallVector<std::pair<Instruction*,Instruction*>, 20> TentativePairs; + + do { + assert(LI != LE && RI != RE); + Instruction *LeftI = &*LI, *RightI = &*RI; + + // If the instructions differ, start the more sophisticated diff + // algorithm at the start of the block. + if (diff(LeftI, RightI, false, false)) { + TentativeValues.clear(); + return runBlockDiff(L->begin(), R->begin()); + } + + // Otherwise, tentatively unify them. + if (!LeftI->use_empty()) + TentativeValues.insert(std::make_pair(LeftI, RightI)); + + ++LI, ++RI; + } while (LI != LE); // This is sufficient: we can't get equality of + // terminators if there are residual instructions. + + // Unify everything in the block, non-tentatively this time. + TentativeValues.clear(); + for (LI = L->begin(), RI = R->begin(); LI != LE; ++LI, ++RI) + unify(&*LI, &*RI); + } + + bool matchForBlockDiff(Instruction *L, Instruction *R); + void runBlockDiff(BasicBlock::iterator LI, BasicBlock::iterator RI); + + bool diffCallSites(CallSite L, CallSite R, bool Complain) { + // FIXME: call attributes + if (!equivalentAsOperands(L.getCalledValue(), R.getCalledValue())) { + if (Complain) Engine.log("called functions differ"); + return true; + } + if (L.arg_size() != R.arg_size()) { + if (Complain) Engine.log("argument counts differ"); + return true; + } + for (unsigned I = 0, E = L.arg_size(); I != E; ++I) + if (!equivalentAsOperands(L.getArgument(I), R.getArgument(I))) { + if (Complain) + Engine.logf("arguments %l and %r differ") + << L.getArgument(I) << R.getArgument(I); + return true; + } + return false; + } + + bool diff(Instruction *L, Instruction *R, bool Complain, bool TryUnify) { + // FIXME: metadata (if Complain is set) + + // Different opcodes always imply different operations. + if (L->getOpcode() != R->getOpcode()) { + if (Complain) Engine.log("different instruction types"); + return true; + } + + if (isa<CmpInst>(L)) { + if (cast<CmpInst>(L)->getPredicate() + != cast<CmpInst>(R)->getPredicate()) { + if (Complain) Engine.log("different predicates"); + return true; + } + } else if (isa<CallInst>(L)) { + return diffCallSites(CallSite(L), CallSite(R), Complain); + } else if (isa<PHINode>(L)) { + // FIXME: implement. + + // This is really wierd; type uniquing is broken? + if (L->getType() != R->getType()) { + if (!L->getType()->isPointerTy() || !R->getType()->isPointerTy()) { + if (Complain) Engine.log("different phi types"); + return true; + } + } + return false; + + // Terminators. + } else if (isa<InvokeInst>(L)) { + InvokeInst *LI = cast<InvokeInst>(L); + InvokeInst *RI = cast<InvokeInst>(R); + if (diffCallSites(CallSite(LI), CallSite(RI), Complain)) + return true; + + if (TryUnify) { + tryUnify(LI->getNormalDest(), RI->getNormalDest()); + tryUnify(LI->getUnwindDest(), RI->getUnwindDest()); + } + return false; + + } else if (isa<BranchInst>(L)) { + BranchInst *LI = cast<BranchInst>(L); + BranchInst *RI = cast<BranchInst>(R); + if (LI->isConditional() != RI->isConditional()) { + if (Complain) Engine.log("branch conditionality differs"); + return true; + } + + if (LI->isConditional()) { + if (!equivalentAsOperands(LI->getCondition(), RI->getCondition())) { + if (Complain) Engine.log("branch conditions differ"); + return true; + } + if (TryUnify) tryUnify(LI->getSuccessor(1), RI->getSuccessor(1)); + } + if (TryUnify) tryUnify(LI->getSuccessor(0), RI->getSuccessor(0)); + return false; + + } else if (isa<SwitchInst>(L)) { + SwitchInst *LI = cast<SwitchInst>(L); + SwitchInst *RI = cast<SwitchInst>(R); + if (!equivalentAsOperands(LI->getCondition(), RI->getCondition())) { + if (Complain) Engine.log("switch conditions differ"); + return true; + } + if (TryUnify) tryUnify(LI->getDefaultDest(), RI->getDefaultDest()); + + bool Difference = false; + + DenseMap<ConstantInt*,BasicBlock*> LCases; + for (unsigned I = 1, E = LI->getNumCases(); I != E; ++I) + LCases[LI->getCaseValue(I)] = LI->getSuccessor(I); + for (unsigned I = 1, E = RI->getNumCases(); I != E; ++I) { + ConstantInt *CaseValue = RI->getCaseValue(I); + BasicBlock *LCase = LCases[CaseValue]; + if (LCase) { + if (TryUnify) tryUnify(LCase, RI->getSuccessor(I)); + LCases.erase(CaseValue); + } else if (!Difference) { + if (Complain) + Engine.logf("right switch has extra case %r") << CaseValue; + Difference = true; + } + } + if (!Difference) + for (DenseMap<ConstantInt*,BasicBlock*>::iterator + I = LCases.begin(), E = LCases.end(); I != E; ++I) { + if (Complain) + Engine.logf("left switch has extra case %l") << I->first; + Difference = true; + } + return Difference; + } else if (isa<UnreachableInst>(L)) { + return false; + } + + if (L->getNumOperands() != R->getNumOperands()) { + if (Complain) Engine.log("instructions have different operand counts"); + return true; + } + + for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I) { + Value *LO = L->getOperand(I), *RO = R->getOperand(I); + if (!equivalentAsOperands(LO, RO)) { + if (Complain) Engine.logf("operands %l and %r differ") << LO << RO; + return true; + } + } + + return false; + } + + bool equivalentAsOperands(Constant *L, Constant *R) { + // Use equality as a preliminary filter. + if (L == R) + return true; + + if (L->getValueID() != R->getValueID()) + return false; + + // Ask the engine about global values. + if (isa<GlobalValue>(L)) + return Engine.equivalentAsOperands(cast<GlobalValue>(L), + cast<GlobalValue>(R)); + + // Compare constant expressions structurally. + if (isa<ConstantExpr>(L)) + return equivalentAsOperands(cast<ConstantExpr>(L), + cast<ConstantExpr>(R)); + + // Nulls of the "same type" don't always actually have the same + // type; I don't know why. Just white-list them. + if (isa<ConstantPointerNull>(L)) + return true; + + // Block addresses only match if we've already encountered the + // block. FIXME: tentative matches? + if (isa<BlockAddress>(L)) + return Blocks[cast<BlockAddress>(L)->getBasicBlock()] + == cast<BlockAddress>(R)->getBasicBlock(); + + return false; + } + + bool equivalentAsOperands(ConstantExpr *L, ConstantExpr *R) { + if (L == R) + return true; + if (L->getOpcode() != R->getOpcode()) + return false; + + switch (L->getOpcode()) { + case Instruction::ICmp: + case Instruction::FCmp: + if (L->getPredicate() != R->getPredicate()) + return false; + break; + + case Instruction::GetElementPtr: + // FIXME: inbounds? + break; + + default: + break; + } + + if (L->getNumOperands() != R->getNumOperands()) + return false; + + for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I) + if (!equivalentAsOperands(L->getOperand(I), R->getOperand(I))) + return false; + + return true; + } + + bool equivalentAsOperands(Value *L, Value *R) { + // Fall out if the values have different kind. + // This possibly shouldn't take priority over oracles. + if (L->getValueID() != R->getValueID()) + return false; + + // Value subtypes: Argument, Constant, Instruction, BasicBlock, + // InlineAsm, MDNode, MDString, PseudoSourceValue + + if (isa<Constant>(L)) + return equivalentAsOperands(cast<Constant>(L), cast<Constant>(R)); + + if (isa<Instruction>(L)) + return Values[L] == R || TentativeValues.count(std::make_pair(L, R)); + + if (isa<Argument>(L)) + return Values[L] == R; + + if (isa<BasicBlock>(L)) + return Blocks[cast<BasicBlock>(L)] != R; + + // Pretend everything else is identical. + return true; + } + + // Avoid a gcc warning about accessing 'this' in an initializer. + FunctionDifferenceEngine *this_() { return this; } + +public: + FunctionDifferenceEngine(DifferenceEngine &Engine) : + Engine(Engine), Queue(QueueSorter(*this_())) {} + + void diff(Function *L, Function *R) { + if (L->arg_size() != R->arg_size()) + Engine.log("different argument counts"); + + // Map the arguments. + for (Function::arg_iterator + LI = L->arg_begin(), LE = L->arg_end(), + RI = R->arg_begin(), RE = R->arg_end(); + LI != LE && RI != RE; ++LI, ++RI) + Values[&*LI] = &*RI; + + tryUnify(&*L->begin(), &*R->begin()); + processQueue(); + } +}; + +struct DiffEntry { + DiffEntry() : Cost(0) {} + + unsigned Cost; + llvm::SmallVector<char, 8> Path; // actually of DifferenceEngine::DiffChange +}; + +bool FunctionDifferenceEngine::matchForBlockDiff(Instruction *L, + Instruction *R) { + return !diff(L, R, false, false); +} + +void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, + BasicBlock::iterator RStart) { + BasicBlock::iterator LE = LStart->getParent()->end(); + BasicBlock::iterator RE = RStart->getParent()->end(); + + unsigned NL = std::distance(LStart, LE); + + SmallVector<DiffEntry, 20> Paths1(NL+1); + SmallVector<DiffEntry, 20> Paths2(NL+1); + + DiffEntry *Cur = Paths1.data(); + DiffEntry *Next = Paths2.data(); + + const unsigned LeftCost = 2; + const unsigned RightCost = 2; + const unsigned MatchCost = 0; + + assert(TentativeValues.empty()); + + // Initialize the first column. + for (unsigned I = 0; I != NL+1; ++I) { + Cur[I].Cost = I * LeftCost; + for (unsigned J = 0; J != I; ++J) + Cur[I].Path.push_back(DifferenceEngine::DC_left); + } + + for (BasicBlock::iterator RI = RStart; RI != RE; ++RI) { + // Initialize the first row. + Next[0] = Cur[0]; + Next[0].Cost += RightCost; + Next[0].Path.push_back(DifferenceEngine::DC_right); + + unsigned Index = 1; + for (BasicBlock::iterator LI = LStart; LI != LE; ++LI, ++Index) { + if (matchForBlockDiff(&*LI, &*RI)) { + Next[Index] = Cur[Index-1]; + Next[Index].Cost += MatchCost; + Next[Index].Path.push_back(DifferenceEngine::DC_match); + TentativeValues.insert(std::make_pair(&*LI, &*RI)); + } else if (Next[Index-1].Cost <= Cur[Index].Cost) { + Next[Index] = Next[Index-1]; + Next[Index].Cost += LeftCost; + Next[Index].Path.push_back(DifferenceEngine::DC_left); + } else { + Next[Index] = Cur[Index]; + Next[Index].Cost += RightCost; + Next[Index].Path.push_back(DifferenceEngine::DC_right); + } + } + + std::swap(Cur, Next); + } + + // We don't need the tentative values anymore; everything from here + // on out should be non-tentative. + TentativeValues.clear(); + + SmallVectorImpl<char> &Path = Cur[NL].Path; + BasicBlock::iterator LI = LStart, RI = RStart; + + DifferenceEngine::DiffLogBuilder Diff(Engine); + + // Drop trailing matches. + while (Path.back() == DifferenceEngine::DC_match) + Path.pop_back(); + + // Skip leading matches. + SmallVectorImpl<char>::iterator + PI = Path.begin(), PE = Path.end(); + while (PI != PE && *PI == DifferenceEngine::DC_match) { + unify(&*LI, &*RI); + ++PI, ++LI, ++RI; + } + + for (; PI != PE; ++PI) { + switch (static_cast<DifferenceEngine::DiffChange>(*PI)) { + case DifferenceEngine::DC_match: + assert(LI != LE && RI != RE); + { + Instruction *L = &*LI, *R = &*RI; + unify(L, R); + Diff.addMatch(L, R); + } + ++LI; ++RI; + break; + + case DifferenceEngine::DC_left: + assert(LI != LE); + Diff.addLeft(&*LI); + ++LI; + break; + + case DifferenceEngine::DC_right: + assert(RI != RE); + Diff.addRight(&*RI); + ++RI; + break; + } + } + + // Finishing unifying and complaining about the tails of the block, + // which should be matches all the way through. + while (LI != LE) { + assert(RI != RE); + unify(&*LI, &*RI); + ++LI, ++RI; + } + + // If the terminators have different kinds, but one is an invoke and the + // other is an unconditional branch immediately following a call, unify + // the results and the destinations. + TerminatorInst *LTerm = LStart->getParent()->getTerminator(); + TerminatorInst *RTerm = RStart->getParent()->getTerminator(); + if (isa<BranchInst>(LTerm) && isa<InvokeInst>(RTerm)) { + if (cast<BranchInst>(LTerm)->isConditional()) return; + BasicBlock::iterator I = LTerm; + if (I == LStart->getParent()->begin()) return; + --I; + if (!isa<CallInst>(*I)) return; + CallInst *LCall = cast<CallInst>(&*I); + InvokeInst *RInvoke = cast<InvokeInst>(RTerm); + if (!equivalentAsOperands(LCall->getCalledValue(), RInvoke->getCalledValue())) + return; + if (!LCall->use_empty()) + Values[LCall] = RInvoke; + tryUnify(LTerm->getSuccessor(0), RInvoke->getNormalDest()); + } else if (isa<InvokeInst>(LTerm) && isa<BranchInst>(RTerm)) { + if (cast<BranchInst>(RTerm)->isConditional()) return; + BasicBlock::iterator I = RTerm; + if (I == RStart->getParent()->begin()) return; + --I; + if (!isa<CallInst>(*I)) return; + CallInst *RCall = cast<CallInst>(I); + InvokeInst *LInvoke = cast<InvokeInst>(LTerm); + if (!equivalentAsOperands(LInvoke->getCalledValue(), RCall->getCalledValue())) + return; + if (!LInvoke->use_empty()) + Values[LInvoke] = RCall; + tryUnify(LInvoke->getNormalDest(), RTerm->getSuccessor(0)); + } +} + +} + +void DifferenceEngine::diff(Function *L, Function *R) { + Context C(*this, L, R); + + // FIXME: types + // FIXME: attributes and CC + // FIXME: parameter attributes + + // If both are declarations, we're done. + if (L->empty() && R->empty()) + return; + else if (L->empty()) + log("left function is declaration, right function is definition"); + else if (R->empty()) + log("right function is declaration, left function is definition"); + else + FunctionDifferenceEngine(*this).diff(L, R); +} + +void DifferenceEngine::diff(Module *L, Module *R) { + StringSet<> LNames; + SmallVector<std::pair<Function*,Function*>, 20> Queue; + + for (Module::iterator I = L->begin(), E = L->end(); I != E; ++I) { + Function *LFn = &*I; + LNames.insert(LFn->getName()); + + if (Function *RFn = R->getFunction(LFn->getName())) + Queue.push_back(std::make_pair(LFn, RFn)); + else + logf("function %l exists only in left module") << LFn; + } + + for (Module::iterator I = R->begin(), E = R->end(); I != E; ++I) { + Function *RFn = &*I; + if (!LNames.count(RFn->getName())) + logf("function %r exists only in right module") << RFn; + } + + for (SmallVectorImpl<std::pair<Function*,Function*> >::iterator + I = Queue.begin(), E = Queue.end(); I != E; ++I) + diff(I->first, I->second); +} + +bool DifferenceEngine::equivalentAsOperands(GlobalValue *L, GlobalValue *R) { + if (globalValueOracle) return (*globalValueOracle)(L, R); + return L->getName() == R->getName(); +} diff --git a/tools/llvm-diff/DifferenceEngine.h b/tools/llvm-diff/DifferenceEngine.h new file mode 100644 index 0000000..6eefb06 --- /dev/null +++ b/tools/llvm-diff/DifferenceEngine.h @@ -0,0 +1,179 @@ +//===-- DifferenceEngine.h - Module comparator ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the interface to the LLVM difference engine, +// which structurally compares functions within a module. +// +//===----------------------------------------------------------------------===// + +#ifndef _LLVM_DIFFERENCE_ENGINE_H_ +#define _LLVM_DIFFERENCE_ENGINE_H_ + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +#include <utility> + +namespace llvm { + class Function; + class GlobalValue; + class Instruction; + class LLVMContext; + class Module; + class Twine; + class Value; + + /// A class for performing structural comparisons of LLVM assembly. + class DifferenceEngine { + public: + /// A temporary-object class for building up log messages. + class LogBuilder { + DifferenceEngine &Engine; + + /// The use of a stored StringRef here is okay because + /// LogBuilder should be used only as a temporary, and as a + /// temporary it will be destructed before whatever temporary + /// might be initializing this format. + StringRef Format; + + SmallVector<Value*, 4> Arguments; + + public: + LogBuilder(DifferenceEngine &Engine, StringRef Format) + : Engine(Engine), Format(Format) {} + + LogBuilder &operator<<(Value *V) { + Arguments.push_back(V); + return *this; + } + + ~LogBuilder() { + Engine.consumer.logf(*this); + } + + StringRef getFormat() const { return Format; } + + unsigned getNumArguments() const { return Arguments.size(); } + Value *getArgument(unsigned I) const { return Arguments[I]; } + }; + + enum DiffChange { DC_match, DC_left, DC_right }; + + /// A temporary-object class for building up diff messages. + class DiffLogBuilder { + typedef std::pair<Instruction*,Instruction*> DiffRecord; + SmallVector<DiffRecord, 20> Diff; + + DifferenceEngine &Engine; + + public: + DiffLogBuilder(DifferenceEngine &Engine) : Engine(Engine) {} + ~DiffLogBuilder() { Engine.consumer.logd(*this); } + + void addMatch(Instruction *L, Instruction *R) { + Diff.push_back(DiffRecord(L, R)); + } + void addLeft(Instruction *L) { + // HACK: VS 2010 has a bug in the stdlib that requires this. + Diff.push_back(DiffRecord(L, DiffRecord::second_type(0))); + } + void addRight(Instruction *R) { + // HACK: VS 2010 has a bug in the stdlib that requires this. + Diff.push_back(DiffRecord(DiffRecord::first_type(0), R)); + } + + unsigned getNumLines() const { return Diff.size(); } + DiffChange getLineKind(unsigned I) const { + return (Diff[I].first ? (Diff[I].second ? DC_match : DC_left) + : DC_right); + } + Instruction *getLeft(unsigned I) const { return Diff[I].first; } + Instruction *getRight(unsigned I) const { return Diff[I].second; } + }; + + /// The interface for consumers of difference data. + struct Consumer { + /// Record that a local context has been entered. Left and + /// Right are IR "containers" of some sort which are being + /// considered for structural equivalence: global variables, + /// functions, blocks, instructions, etc. + virtual void enterContext(Value *Left, Value *Right) = 0; + + /// Record that a local context has been exited. + virtual void exitContext() = 0; + + /// Record a difference within the current context. + virtual void log(StringRef Text) = 0; + + /// Record a formatted difference within the current context. + virtual void logf(const LogBuilder &Log) = 0; + + /// Record a line-by-line instruction diff. + virtual void logd(const DiffLogBuilder &Log) = 0; + + protected: + virtual ~Consumer() {} + }; + + /// A RAII object for recording the current context. + struct Context { + Context(DifferenceEngine &Engine, Value *L, Value *R) : Engine(Engine) { + Engine.consumer.enterContext(L, R); + } + + ~Context() { + Engine.consumer.exitContext(); + } + + private: + DifferenceEngine &Engine; + }; + + /// An oracle for answering whether two values are equivalent as + /// operands. + struct Oracle { + virtual bool operator()(Value *L, Value *R) = 0; + + protected: + virtual ~Oracle() {} + }; + + DifferenceEngine(LLVMContext &context, Consumer &consumer) + : context(context), consumer(consumer), globalValueOracle(0) {} + + void diff(Module *L, Module *R); + void diff(Function *L, Function *R); + + void log(StringRef text) { + consumer.log(text); + } + + LogBuilder logf(StringRef text) { + return LogBuilder(*this, text); + } + + /// Installs an oracle to decide whether two global values are + /// equivalent as operands. Without an oracle, global values are + /// considered equivalent as operands precisely when they have the + /// same name. + void setGlobalValueOracle(Oracle *oracle) { + globalValueOracle = oracle; + } + + /// Determines whether two global values are equivalent. + bool equivalentAsOperands(GlobalValue *L, GlobalValue *R); + + private: + LLVMContext &context; + Consumer &consumer; + Oracle *globalValueOracle; + }; +} + +#endif diff --git a/tools/llvmc/example/Skeleton/plugins/Plugin/Makefile b/tools/llvm-diff/Makefile index 54f7221..58e49fa 100644 --- a/tools/llvmc/example/Skeleton/plugins/Plugin/Makefile +++ b/tools/llvm-diff/Makefile @@ -1,17 +1,17 @@ -##===- llvmc/example/Skeleton/plugins/Plugin/Makefile ------*- Makefile -*-===## -# +##===- tools/llvm-diff/Makefile ----------------------------*- Makefile -*-===## +# # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. -# +# ##===----------------------------------------------------------------------===## -LEVEL = $(LLVMC_BASE_LEVEL)/../.. - -# Change this to the name of your plugin. -LLVMC_PLUGIN = Plugin +LEVEL = ../.. +TOOLNAME = llvm-diff +LINK_COMPONENTS := asmparser bitreader -BUILT_SOURCES = AutoGenerated.inc +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 include $(LEVEL)/Makefile.common diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp new file mode 100644 index 0000000..16a990f --- /dev/null +++ b/tools/llvm-diff/llvm-diff.cpp @@ -0,0 +1,331 @@ +//===-- llvm-diff.cpp - Module comparator command-line driver ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the command-line driver for the difference engine. +// +//===----------------------------------------------------------------------===// + +#include "DifferenceEngine.h" + +#include "llvm/Instructions.h" +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/Assembly/Parser.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SourceMgr.h" + +#include <string> +#include <utility> + + +using namespace llvm; + +/// Reads a module from a file. If the filename ends in .ll, it is +/// interpreted as an assembly file; otherwise, it is interpreted as +/// bitcode. On error, messages are written to stderr and null is +/// returned. +static Module *ReadModule(LLVMContext &Context, StringRef Name) { + // LLVM assembly path. + if (Name.endswith(".ll")) { + SMDiagnostic Diag; + Module *M = ParseAssemblyFile(Name, Diag, Context); + if (M) return M; + + Diag.Print("llvmdiff", errs()); + return 0; + } + + // Bitcode path. + MemoryBuffer *Buffer = MemoryBuffer::getFile(Name); + + // ParseBitcodeFile takes ownership of the buffer if it succeeds. + std::string Error; + Module *M = ParseBitcodeFile(Buffer, Context, &Error); + if (M) return M; + + errs() << "error parsing " << Name << ": " << Error; + delete Buffer; + return 0; +} + +namespace { +struct DiffContext { + DiffContext(Value *L, Value *R) + : L(L), R(R), Differences(false), IsFunction(isa<Function>(L)) {} + Value *L; + Value *R; + bool Differences; + bool IsFunction; + DenseMap<Value*,unsigned> LNumbering; + DenseMap<Value*,unsigned> RNumbering; +}; + +void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering) { + unsigned IN = 0; + + // Arguments get the first numbers. + for (Function::arg_iterator + AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) + if (!AI->hasName()) + Numbering[&*AI] = IN++; + + // Walk the basic blocks in order. + for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) { + if (!FI->hasName()) + Numbering[&*FI] = IN++; + + // Walk the instructions in order. + for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) + // void instructions don't get numbers. + if (!BI->hasName() && !BI->getType()->isVoidTy()) + Numbering[&*BI] = IN++; + } + + assert(!Numbering.empty() && "asked for numbering but numbering was no-op"); +} + +class DiffConsumer : public DifferenceEngine::Consumer { +private: + raw_ostream &out; + Module *LModule; + Module *RModule; + SmallVector<DiffContext, 5> contexts; + bool Differences; + unsigned Indent; + + void printValue(Value *V, bool isL) { + if (V->hasName()) { + out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName(); + return; + } + if (V->getType()->isVoidTy()) { + if (isa<StoreInst>(V)) { + out << "store to "; + printValue(cast<StoreInst>(V)->getPointerOperand(), isL); + } else if (isa<CallInst>(V)) { + out << "call to "; + printValue(cast<CallInst>(V)->getCalledValue(), isL); + } else if (isa<InvokeInst>(V)) { + out << "invoke to "; + printValue(cast<InvokeInst>(V)->getCalledValue(), isL); + } else { + out << *V; + } + return; + } + + unsigned N = contexts.size(); + while (N > 0) { + --N; + DiffContext &ctxt = contexts[N]; + if (!ctxt.IsFunction) continue; + if (isL) { + if (ctxt.LNumbering.empty()) + ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering); + out << '%' << ctxt.LNumbering[V]; + return; + } else { + if (ctxt.RNumbering.empty()) + ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering); + out << '%' << ctxt.RNumbering[V]; + return; + } + } + + out << "<anonymous>"; + } + + void header() { + if (contexts.empty()) return; + for (SmallVectorImpl<DiffContext>::iterator + I = contexts.begin(), E = contexts.end(); I != E; ++I) { + if (I->Differences) continue; + if (isa<Function>(I->L)) { + // Extra newline between functions. + if (Differences) out << "\n"; + + Function *L = cast<Function>(I->L); + Function *R = cast<Function>(I->R); + if (L->getName() != R->getName()) + out << "in function " << L->getName() + << " / " << R->getName() << ":\n"; + else + out << "in function " << L->getName() << ":\n"; + } else if (isa<BasicBlock>(I->L)) { + BasicBlock *L = cast<BasicBlock>(I->L); + BasicBlock *R = cast<BasicBlock>(I->R); + if (L->hasName() && R->hasName() && L->getName() == R->getName()) + out << " in block %" << L->getName() << ":\n"; + else { + out << " in block "; + printValue(L, true); + out << " / "; + printValue(R, false); + out << ":\n"; + } + } else if (isa<Instruction>(I->L)) { + out << " in instruction "; + printValue(I->L, true); + out << " / "; + printValue(I->R, false); + out << ":\n"; + } + + I->Differences = true; + } + } + + void indent() { + unsigned N = Indent; + while (N--) out << ' '; + } + +public: + DiffConsumer(Module *L, Module *R) + : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {} + + bool hadDifferences() const { return Differences; } + + void enterContext(Value *L, Value *R) { + contexts.push_back(DiffContext(L, R)); + Indent += 2; + } + void exitContext() { + Differences |= contexts.back().Differences; + contexts.pop_back(); + Indent -= 2; + } + + void log(StringRef text) { + header(); + indent(); + out << text << '\n'; + } + + void logf(const DifferenceEngine::LogBuilder &Log) { + header(); + indent(); + + unsigned arg = 0; + + StringRef format = Log.getFormat(); + while (true) { + size_t percent = format.find('%'); + if (percent == StringRef::npos) { + out << format; + break; + } + assert(format[percent] == '%'); + + if (percent > 0) out << format.substr(0, percent); + + switch (format[percent+1]) { + case '%': out << '%'; break; + case 'l': printValue(Log.getArgument(arg++), true); break; + case 'r': printValue(Log.getArgument(arg++), false); break; + default: llvm_unreachable("unknown format character"); + } + + format = format.substr(percent+2); + } + + out << '\n'; + } + + void logd(const DifferenceEngine::DiffLogBuilder &Log) { + header(); + + for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { + indent(); + switch (Log.getLineKind(I)) { + case DifferenceEngine::DC_match: + out << " "; + Log.getLeft(I)->dump(); + //printValue(Log.getLeft(I), true); + break; + case DifferenceEngine::DC_left: + out << "< "; + Log.getLeft(I)->dump(); + //printValue(Log.getLeft(I), true); + break; + case DifferenceEngine::DC_right: + out << "> "; + Log.getRight(I)->dump(); + //printValue(Log.getRight(I), false); + break; + } + //out << "\n"; + } + } + +}; +} + +static void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R, + StringRef Name) { + // Drop leading sigils from the global name. + if (Name.startswith("@")) Name = Name.substr(1); + + Function *LFn = L->getFunction(Name); + Function *RFn = R->getFunction(Name); + if (LFn && RFn) + Engine.diff(LFn, RFn); + else if (!LFn && !RFn) + errs() << "No function named @" << Name << " in either module\n"; + else if (!LFn) + errs() << "No function named @" << Name << " in left module\n"; + else + errs() << "No function named @" << Name << " in right module\n"; +} + +cl::opt<std::string> LeftFilename(cl::Positional, + cl::desc("<first file>"), + cl::Required); +cl::opt<std::string> RightFilename(cl::Positional, + cl::desc("<second file>"), + cl::Required); +cl::list<std::string> GlobalsToCompare(cl::Positional, + cl::desc("<globals to compare>")); + +int main(int argc, char **argv) { + cl::ParseCommandLineOptions(argc, argv); + + LLVMContext Context; + + // Load both modules. Die if that fails. + Module *LModule = ReadModule(Context, LeftFilename); + Module *RModule = ReadModule(Context, RightFilename); + if (!LModule || !RModule) return 1; + + DiffConsumer Consumer(LModule, RModule); + DifferenceEngine Engine(Context, Consumer); + + // If any global names were given, just diff those. + if (!GlobalsToCompare.empty()) { + for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I) + diffGlobal(Engine, LModule, RModule, GlobalsToCompare[I]); + + // Otherwise, diff everything in the module. + } else { + Engine.diff(LModule, RModule); + } + + delete LModule; + delete RModule; + + return Consumer.hadDifferences(); +} diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index b8b1a39..9d2d31d 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -18,14 +18,16 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" +#include "llvm/Type.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Signals.h" -#include <memory> using namespace llvm; static cl::opt<std::string> @@ -41,6 +43,29 @@ Force("f", cl::desc("Enable binary output on terminals")); static cl::opt<bool> DontPrint("disable-output", cl::desc("Don't output the .ll file"), cl::Hidden); +static cl::opt<bool> +ShowAnnotations("show-annotations", + cl::desc("Add informational comments to the .ll file")); + +namespace { + +class CommentWriter : public AssemblyAnnotationWriter { +public: + void emitFunctionAnnot(const Function *F, + formatted_raw_ostream &OS) { + OS << "; [#uses=" << F->getNumUses() << ']'; // Output # uses + OS << '\n'; + } + void printInfoComment(const Value &V, formatted_raw_ostream &OS) { + if (V.getType()->isVoidTy()) return; + + OS.PadToColumn(50); + OS << "; [#uses=" << V.getNumUses() << ']'; // Output # uses + } +}; + +} // end anon namespace + int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); @@ -88,23 +113,25 @@ int main(int argc, char **argv) { } } - // Make sure that the Out file gets unlinked from the disk if we get a - // SIGINT. - if (OutputFilename != "-") - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - std::string ErrorInfo; - std::auto_ptr<raw_fd_ostream> - Out(new raw_fd_ostream(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + OwningPtr<tool_output_file> + Out(new tool_output_file(OutputFilename.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary)); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; } + OwningPtr<AssemblyAnnotationWriter> Annotator; + if (ShowAnnotations) + Annotator.reset(new CommentWriter()); + // All that llvm-dis does is write the assembly to a file. if (!DontPrint) - *Out << *M; + M->print(Out->os(), Annotator.get()); + + // Declare success. + Out->keep(); return 0; } diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index e6b5b84..91a59e5 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -44,10 +44,6 @@ Force("f", cl::desc("Enable binary output on terminals")); static cl::opt<bool> DeleteFn("delete", cl::desc("Delete specified Globals from Module")); -static cl::opt<bool> -Relink("relink", - cl::desc("Turn external linkage for callees of function to delete")); - // ExtractFuncs - The functions to extract from the module... static cl::list<std::string> ExtractFuncs("func", cl::desc("Specify function to extract"), @@ -71,9 +67,10 @@ int main(int argc, char **argv) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); + // Use lazy loading, since we only care about selected global values. SMDiagnostic Err; std::auto_ptr<Module> M; - M.reset(ParseIRFile(InputFilename, Err, Context)); + M.reset(getLazyIRFileModule(InputFilename, Err, Context)); if (M.get() == 0) { Err.Print(argv[0], errs()); @@ -104,36 +101,47 @@ int main(int argc, char **argv) { GVs.push_back(GV); } + // Materialize requisite global values. + for (size_t i = 0, e = GVs.size(); i != e; ++i) { + GlobalValue *GV = GVs[i]; + if (GV->isMaterializable()) { + std::string ErrInfo; + if (GV->Materialize(&ErrInfo)) { + errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; + return 1; + } + } + } + // In addition to deleting all other functions, we also want to spiff it // up a little bit. Do this now. PassManager Passes; Passes.add(new TargetData(M.get())); // Use correct TargetData - Passes.add(createGVExtractionPass(GVs, DeleteFn, Relink)); + Passes.add(createGVExtractionPass(GVs, DeleteFn)); if (!DeleteFn) Passes.add(createGlobalDCEPass()); // Delete unreachable globals Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info Passes.add(createDeadTypeEliminationPass()); // Remove dead types... Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls - // Make sure that the Output file gets unlinked from the disk if we get a - // SIGINT - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - std::string ErrorInfo; - raw_fd_ostream Out(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary); + tool_output_file Out(OutputFilename.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; } if (OutputAssembly) - Passes.add(createPrintModulePass(&Out)); - else if (Force || !CheckBitcodeOutputToConsole(Out, true)) - Passes.add(createBitcodeWriterPass(Out)); + Passes.add(createPrintModulePass(&Out.os())); + else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true)) + Passes.add(createBitcodeWriterPass(Out.os())); Passes.run(*M.get()); + // Declare success. + Out.keep(); + return 0; } diff --git a/tools/llvm-ld/llvm-ld.cpp b/tools/llvm-ld/llvm-ld.cpp index ad6956c..3bbea9d 100644 --- a/tools/llvm-ld/llvm-ld.cpp +++ b/tools/llvm-ld/llvm-ld.cpp @@ -145,8 +145,8 @@ static void PrintCommand(const std::vector<const char*> &args) { std::vector<const char*>::const_iterator I = args.begin(), E = args.end(); for (; I != E; ++I) if (*I) - outs() << "'" << *I << "'" << " "; - outs() << "\n"; outs().flush(); + errs() << "'" << *I << "'" << " "; + errs() << "\n"; } /// CopyEnv - This function takes an array of environment variables and makes a @@ -232,17 +232,20 @@ static void RemoveEnv(const char * name, char ** const envp) { void GenerateBitcode(Module* M, const std::string& FileName) { if (Verbose) - outs() << "Generating Bitcode To " << FileName << '\n'; + errs() << "Generating Bitcode To " << FileName << '\n'; // Create the output file. std::string ErrorInfo; - raw_fd_ostream Out(FileName.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary); - if (!ErrorInfo.empty()) + tool_output_file Out(FileName.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary); + if (!ErrorInfo.empty()) { PrintAndExit(ErrorInfo, M); + return; + } // Write it out - WriteBitcodeToFile(M, Out); + WriteBitcodeToFile(M, Out.os()); + Out.keep(); } /// GenerateAssembly - generates a native assembly language source file from the @@ -272,7 +275,7 @@ static int GenerateAssembly(const std::string &OutputFilename, args.push_back(0); if (Verbose) { - outs() << "Generating Assembly With: \n"; + errs() << "Generating Assembly With: \n"; PrintCommand(args); } @@ -294,7 +297,7 @@ static int GenerateCFile(const std::string &OutputFile, args.push_back(0); if (Verbose) { - outs() << "Generating C Source With: \n"; + errs() << "Generating C Source With: \n"; PrintCommand(args); } @@ -391,7 +394,7 @@ static int GenerateNative(const std::string &OutputFilename, Args.push_back(0); if (Verbose) { - outs() << "Generating Native Executable With:\n"; + errs() << "Generating Native Executable With:\n"; PrintCommand(Args); } @@ -406,7 +409,7 @@ static int GenerateNative(const std::string &OutputFilename, /// bitcode file for the program. static void EmitShellScript(char **argv, Module *M) { if (Verbose) - outs() << "Emitting Shell Script\n"; + errs() << "Emitting Shell Script\n"; #if defined(_WIN32) || defined(__CYGWIN__) // Windows doesn't support #!/bin/sh style shell scripts in .exe files. To // support windows systems, we copy the llvm-stub.exe executable from the @@ -425,14 +428,14 @@ static void EmitShellScript(char **argv, Module *M) { // Output the script to start the program... std::string ErrorInfo; - raw_fd_ostream Out2(OutputFilename.c_str(), ErrorInfo); + tool_output_file Out2(OutputFilename.c_str(), ErrorInfo); if (!ErrorInfo.empty()) PrintAndExit(ErrorInfo, M); - Out2 << "#!/bin/sh\n"; + Out2.os() << "#!/bin/sh\n"; // Allow user to setenv LLVMINTERP if lli is not in their PATH. - Out2 << "lli=${LLVMINTERP-lli}\n"; - Out2 << "exec $lli \\\n"; + Out2.os() << "lli=${LLVMINTERP-lli}\n"; + Out2.os() << "exec $lli \\\n"; // gcc accepts -l<lib> and implicitly searches /lib and /usr/lib. LibPaths.push_back("/lib"); LibPaths.push_back("/usr/lib"); @@ -463,9 +466,10 @@ static void EmitShellScript(char **argv, Module *M) { if (FullLibraryPath.isEmpty()) FullLibraryPath = sys::Path::FindLibrary(*i); if (!FullLibraryPath.isEmpty()) - Out2 << " -load=" << FullLibraryPath.str() << " \\\n"; + Out2.os() << " -load=" << FullLibraryPath.str() << " \\\n"; } - Out2 << " " << BitcodeOutputFilename << " ${1+\"$@\"}\n"; + Out2.os() << " " << BitcodeOutputFilename << " ${1+\"$@\"}\n"; + Out2.keep(); } // BuildLinkItems -- This function generates a LinkItemList for the LinkItems diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index f7dad3d..e55d0de 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -116,19 +116,13 @@ int main(int argc, char **argv) { if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; std::string ErrorInfo; - std::auto_ptr<raw_ostream> - Out(new raw_fd_ostream(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary)); + tool_output_file Out(OutputFilename.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; } - // Make sure that the Out file gets unlinked from the disk if we get a - // SIGINT - if (OutputFilename != "-") - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - if (verifyModule(*Composite)) { errs() << argv[0] << ": linked module is broken!\n"; return 1; @@ -136,9 +130,12 @@ int main(int argc, char **argv) { if (Verbose) errs() << "Writing bitcode...\n"; if (OutputAssembly) { - *Out << *Composite; - } else if (Force || !CheckBitcodeOutputToConsole(*Out, true)) - WriteBitcodeToFile(Composite.get(), *Out); + Out.os() << *Composite; + } else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true)) + WriteBitcodeToFile(Composite.get(), Out.os()); + + // Declare success. + Out.keep(); return 0; } diff --git a/tools/llvm-mc/CMakeLists.txt b/tools/llvm-mc/CMakeLists.txt index 8b61a4e..805caf4 100644 --- a/tools/llvm-mc/CMakeLists.txt +++ b/tools/llvm-mc/CMakeLists.txt @@ -1,5 +1,4 @@ -set( LLVM_USED_LIBS EnhancedDisassembly) -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC MCParser) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC MCParser MCDisassembler) add_llvm_tool(llvm-mc llvm-mc.cpp diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index 37b2cb8..13080b4 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -13,21 +13,21 @@ //===----------------------------------------------------------------------===// #include "Disassembler.h" - -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/Triple.h" +#include "../../lib/MC/MCDisassembler/EDDisassembler.h" +#include "../../lib/MC/MCDisassembler/EDInst.h" +#include "../../lib/MC/MCDisassembler/EDOperand.h" +#include "../../lib/MC/MCDisassembler/EDToken.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/Target/TargetRegistry.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/MemoryBuffer.h" #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; @@ -53,7 +53,7 @@ public: static bool PrintInsts(const MCDisassembler &DisAsm, MCInstPrinter &Printer, const ByteArrayTy &Bytes, - SourceMgr &SM) { + SourceMgr &SM, raw_ostream &Out) { // Wrap the vector in a MemoryObject. VectorMemoryObject memoryObject(Bytes); @@ -66,8 +66,8 @@ static bool PrintInsts(const MCDisassembler &DisAsm, if (DisAsm.getInstruction(Inst, Size, memoryObject, Index, /*REMOVE*/ nulls())) { - Printer.printInst(&Inst, outs()); - outs() << "\n"; + Printer.printInst(&Inst, Out); + Out << "\n"; } else { SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second), "invalid instruction encoding", "warning"); @@ -127,7 +127,8 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray, } int Disassembler::disassemble(const Target &T, const std::string &Triple, - MemoryBuffer &Buffer) { + MemoryBuffer &Buffer, + raw_ostream &Out) { // Set up disassembler. OwningPtr<const MCAsmInfo> AsmInfo(T.createAsmInfo(Triple)); @@ -162,7 +163,7 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple, ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM); if (!ByteArray.empty()) - ErrorOccurred |= PrintInsts(*DisAsm, *IP, ByteArray, SM); + ErrorOccurred |= PrintInsts(*DisAsm, *IP, ByteArray, SM, Out); return ErrorOccurred; } @@ -179,26 +180,24 @@ static int byteArrayReader(uint8_t *B, uint64_t A, void *Arg) { } static int verboseEvaluator(uint64_t *V, unsigned R, void *Arg) { - EDDisassemblerRef &disassembler = *((EDDisassemblerRef*)Arg); + EDDisassembler &disassembler = *(EDDisassembler *)((void **)Arg)[0]; + raw_ostream &Out = *(raw_ostream *)((void **)Arg)[1]; - const char *regName; + if (const char *regName = disassembler.nameWithRegisterID(R)) + Out << "[" << regName << "/" << R << "]"; - if (!EDGetRegisterName(®Name, - disassembler, - R)) - outs() << "[" << regName << "/" << R << "]"; - if (EDRegisterIsStackPointer(disassembler, R)) - outs() << "(sp)"; - if (EDRegisterIsProgramCounter(disassembler, R)) - outs() << "(pc)"; + if (disassembler.registerIsStackPointer(R)) + Out << "(sp)"; + if (disassembler.registerIsProgramCounter(R)) + Out << "(pc)"; *V = 0; - return 0; } int Disassembler::disassembleEnhanced(const std::string &TS, - MemoryBuffer &Buffer) { + MemoryBuffer &Buffer, + raw_ostream &Out) { ByteArrayTy ByteArray; StringRef Str = Buffer.getBuffer(); SourceMgr SM; @@ -209,10 +208,8 @@ int Disassembler::disassembleEnhanced(const std::string &TS, return -1; } - EDDisassemblerRef disassembler; - Triple T(TS); - EDAssemblySyntax_t AS; + EDDisassembler::AssemblySyntax AS; switch (T.getArch()) { default: @@ -220,140 +217,121 @@ int Disassembler::disassembleEnhanced(const std::string &TS, return -1; case Triple::arm: case Triple::thumb: - AS = kEDAssemblySyntaxARMUAL; + AS = EDDisassembler::kEDAssemblySyntaxARMUAL; break; case Triple::x86: case Triple::x86_64: - AS = kEDAssemblySyntaxX86ATT; + AS = EDDisassembler::kEDAssemblySyntaxX86ATT; break; } - if (EDGetDisassembler(&disassembler, - TS.c_str(), - AS)) { - errs() << "error: couldn't get disassembler for " << TS.c_str() << "\n"; + EDDisassembler::initialize(); + EDDisassembler *disassembler = + EDDisassembler::getDisassembler(TS.c_str(), AS); + + if (disassembler == 0) { + errs() << "error: couldn't get disassembler for " << TS << '\n'; return -1; } - EDInstRef inst; - - if (EDCreateInsts(&inst, 1, disassembler, byteArrayReader, 0,&ByteArray) - != 1) { + EDInst *inst = + disassembler->createInst(byteArrayReader, 0, &ByteArray); + + if (inst == 0) { 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"; + unsigned numTokens = inst->numTokens(); + if ((int)numTokens < 0) { + errs() << "error: couldn't count the instruction's tokens\n"; return -1; } - int tokenIndex; - - for (tokenIndex = 0; tokenIndex < numTokens; ++tokenIndex) { - EDTokenRef token; + for (unsigned tokenIndex = 0; tokenIndex != numTokens; ++tokenIndex) { + EDToken *token; - if (EDGetToken(&token, inst, tokenIndex)) { + if (inst->getToken(token, tokenIndex)) { errs() << "error: Couldn't get token\n"; return -1; } const char *buf; - - if (EDGetTokenString(&buf, token)) { + if (token->getString(buf)) { errs() << "error: Couldn't get string for token\n"; return -1; } - outs() << "["; - - int operandIndex = EDOperandIndexForToken(token); + Out << '['; + int operandIndex = token->operandID(); if (operandIndex >= 0) - outs() << operandIndex << "-"; + Out << 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() << "?"; + switch (token->type()) { + default: Out << "?"; break; + case EDToken::kTokenWhitespace: Out << "w"; break; + case EDToken::kTokenPunctuation: Out << "p"; break; + case EDToken::kTokenOpcode: Out << "o"; break; + case EDToken::kTokenLiteral: Out << "l"; break; + case EDToken::kTokenRegister: Out << "r"; break; } - outs() << ":" << buf; + Out << ":" << buf; - if (EDTokenIsLiteral(token)) { - outs() << "="; - if (EDTokenIsNegativeLiteral(token)) - outs() << "-"; + if (token->type() == EDToken::kTokenLiteral) { + Out << "="; + if (token->literalSign()) + Out << "-"; uint64_t absoluteValue; - if (EDLiteralTokenAbsoluteValue(&absoluteValue, token)) { + if (token->literalAbsoluteValue(absoluteValue)) { errs() << "error: Couldn't get the value of a literal token\n"; return -1; } - outs() << absoluteValue; - } else if (EDTokenIsRegister(token)) { - outs() << "="; + Out << absoluteValue; + } else if (token->type() == EDToken::kTokenRegister) { + Out << "="; unsigned regID; - if (EDRegisterTokenValue(®ID, token)) { + if (token->registerID(regID)) { errs() << "error: Couldn't get the ID of a register token\n"; return -1; } - outs() << "r" << regID; + Out << "r" << regID; } - outs() << "]"; + Out << "]"; } - outs() << " "; + Out << " "; - if (EDInstIsBranch(inst)) - outs() << "<br> "; - if (EDInstIsMove(inst)) - outs() << "<mov> "; + if (inst->isBranch()) + Out << "<br> "; + if (inst->isMove()) + Out << "<mov> "; - int numOperands = EDNumOperands(inst); + unsigned numOperands = inst->numOperands(); - if (numOperands < 0) { + if ((int)numOperands < 0) { errs() << "error: Couldn't count operands\n"; return -1; } - int operandIndex; - - for (operandIndex = 0; operandIndex < numOperands; ++operandIndex) { - outs() << operandIndex << ":"; - - EDOperandRef operand; + for (unsigned operandIndex = 0; operandIndex != numOperands; ++operandIndex) { + Out << operandIndex << ":"; - if (EDGetOperand(&operand, - inst, - operandIndex)) { - errs() << "error: Couldn't get operand\n"; + EDOperand *operand; + if (inst->getOperand(operand, operandIndex)) { + errs() << "error: couldn't get operand\n"; return -1; } uint64_t evaluatedResult; - - EDEvaluateOperand(&evaluatedResult, - operand, - verboseEvaluator, - &disassembler); - - outs() << "=" << evaluatedResult; - - outs() << " "; + void *Arg[] = { disassembler, &Out }; + evaluatedResult = operand->evaluate(evaluatedResult, verboseEvaluator, Arg); + Out << "=" << evaluatedResult << " "; } - outs() << "\n"; + Out << '\n'; return 0; } diff --git a/tools/llvm-mc/Disassembler.h b/tools/llvm-mc/Disassembler.h index 3da2396..b56f2e9 100644 --- a/tools/llvm-mc/Disassembler.h +++ b/tools/llvm-mc/Disassembler.h @@ -21,15 +21,18 @@ namespace llvm { class Target; class MemoryBuffer; +class raw_ostream; class Disassembler { public: static int disassemble(const Target &target, const std::string &tripleString, - MemoryBuffer &buffer); + MemoryBuffer &buffer, + raw_ostream &Out); static int disassembleEnhanced(const std::string &tripleString, - MemoryBuffer &buffer); + MemoryBuffer &buffer, + raw_ostream &Out); }; } // namespace llvm diff --git a/tools/llvm-mc/Makefile b/tools/llvm-mc/Makefile index a127493..934a6e4 100644 --- a/tools/llvm-mc/Makefile +++ b/tools/llvm-mc/Makefile @@ -18,9 +18,7 @@ TOOL_NO_EXPORTS = 1 # early so we can set up LINK_COMPONENTS before including Makefile.rules include $(LEVEL)/Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) MCParser MC support +LINK_COMPONENTS := $(TARGETS_TO_BUILD) MCDisassembler 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 fc8a1c5..aef0a3d 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -12,13 +12,13 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCParser/AsmParser.h" #include "llvm/Target/TargetAsmBackend.h" #include "llvm/Target/TargetAsmParser.h" #include "llvm/Target/TargetData.h" @@ -27,6 +27,7 @@ #include "llvm/Target/TargetSelect.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" @@ -51,6 +52,10 @@ ShowEncoding("show-encoding", cl::desc("Show instruction encodings")); static cl::opt<bool> ShowInst("show-inst", cl::desc("Show internal instruction representation")); +static cl::opt<bool> +ShowInstOperands("show-inst-operands", + cl::desc("Show instructions operands as parsed")); + static cl::opt<unsigned> OutputAsmVariant("output-asm-variant", cl::desc("Syntax variant to use for output printing")); @@ -135,6 +140,22 @@ static const Target *GetTarget(const char *ProgName) { return 0; } +static tool_output_file *GetOutputStream() { + if (OutputFilename == "") + OutputFilename = "-"; + + std::string Err; + tool_output_file *Out = new tool_output_file(OutputFilename.c_str(), Err, + raw_fd_ostream::F_Binary); + if (!Err.empty()) { + errs() << Err << '\n'; + delete Out; + return 0; + } + + return Out; +} + static int AsLexInput(const char *ProgName) { std::string ErrorMessage; MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename, @@ -165,9 +186,13 @@ static int AsLexInput(const char *ProgName) { assert(MAI && "Unable to create target asm info!"); AsmLexer Lexer(*MAI); - + Lexer.setBuffer(SrcMgr.getMemoryBuffer(0)); + + OwningPtr<tool_output_file> Out(GetOutputStream()); + if (!Out) + return 1; + bool Error = false; - while (Lexer.Lex().isNot(AsmToken::Eof)) { switch (Lexer.getKind()) { default: @@ -178,69 +203,51 @@ static int AsLexInput(const char *ProgName) { Error = true; // error already printed. break; case AsmToken::Identifier: - outs() << "identifier: " << Lexer.getTok().getString() << '\n'; + Out->os() << "identifier: " << Lexer.getTok().getString() << '\n'; break; case AsmToken::String: - outs() << "string: " << Lexer.getTok().getString() << '\n'; + Out->os() << "string: " << Lexer.getTok().getString() << '\n'; break; case AsmToken::Integer: - outs() << "int: " << Lexer.getTok().getString() << '\n'; + Out->os() << "int: " << Lexer.getTok().getString() << '\n'; break; - case AsmToken::Amp: outs() << "Amp\n"; break; - case AsmToken::AmpAmp: outs() << "AmpAmp\n"; break; - case AsmToken::Caret: outs() << "Caret\n"; break; - case AsmToken::Colon: outs() << "Colon\n"; break; - case AsmToken::Comma: outs() << "Comma\n"; break; - case AsmToken::Dollar: outs() << "Dollar\n"; break; - case AsmToken::EndOfStatement: outs() << "EndOfStatement\n"; break; - case AsmToken::Eof: outs() << "Eof\n"; break; - case AsmToken::Equal: outs() << "Equal\n"; break; - case AsmToken::EqualEqual: outs() << "EqualEqual\n"; break; - case AsmToken::Exclaim: outs() << "Exclaim\n"; break; - case AsmToken::ExclaimEqual: outs() << "ExclaimEqual\n"; break; - case AsmToken::Greater: outs() << "Greater\n"; break; - case AsmToken::GreaterEqual: outs() << "GreaterEqual\n"; break; - case AsmToken::GreaterGreater: outs() << "GreaterGreater\n"; break; - case AsmToken::LParen: outs() << "LParen\n"; break; - case AsmToken::Less: outs() << "Less\n"; break; - case AsmToken::LessEqual: outs() << "LessEqual\n"; break; - case AsmToken::LessGreater: outs() << "LessGreater\n"; break; - case AsmToken::LessLess: outs() << "LessLess\n"; break; - case AsmToken::Minus: outs() << "Minus\n"; break; - case AsmToken::Percent: outs() << "Percent\n"; break; - case AsmToken::Pipe: outs() << "Pipe\n"; break; - case AsmToken::PipePipe: outs() << "PipePipe\n"; break; - case AsmToken::Plus: outs() << "Plus\n"; break; - case AsmToken::RParen: outs() << "RParen\n"; break; - case AsmToken::Slash: outs() << "Slash\n"; break; - case AsmToken::Star: outs() << "Star\n"; break; - case AsmToken::Tilde: outs() << "Tilde\n"; break; + case AsmToken::Amp: Out->os() << "Amp\n"; break; + case AsmToken::AmpAmp: Out->os() << "AmpAmp\n"; break; + case AsmToken::Caret: Out->os() << "Caret\n"; break; + case AsmToken::Colon: Out->os() << "Colon\n"; break; + case AsmToken::Comma: Out->os() << "Comma\n"; break; + case AsmToken::Dollar: Out->os() << "Dollar\n"; break; + case AsmToken::EndOfStatement: Out->os() << "EndOfStatement\n"; break; + case AsmToken::Eof: Out->os() << "Eof\n"; break; + case AsmToken::Equal: Out->os() << "Equal\n"; break; + case AsmToken::EqualEqual: Out->os() << "EqualEqual\n"; break; + case AsmToken::Exclaim: Out->os() << "Exclaim\n"; break; + case AsmToken::ExclaimEqual: Out->os() << "ExclaimEqual\n"; break; + case AsmToken::Greater: Out->os() << "Greater\n"; break; + case AsmToken::GreaterEqual: Out->os() << "GreaterEqual\n"; break; + case AsmToken::GreaterGreater: Out->os() << "GreaterGreater\n"; break; + case AsmToken::LParen: Out->os() << "LParen\n"; break; + case AsmToken::Less: Out->os() << "Less\n"; break; + case AsmToken::LessEqual: Out->os() << "LessEqual\n"; break; + case AsmToken::LessGreater: Out->os() << "LessGreater\n"; break; + case AsmToken::LessLess: Out->os() << "LessLess\n"; break; + case AsmToken::Minus: Out->os() << "Minus\n"; break; + case AsmToken::Percent: Out->os() << "Percent\n"; break; + case AsmToken::Pipe: Out->os() << "Pipe\n"; break; + case AsmToken::PipePipe: Out->os() << "PipePipe\n"; break; + case AsmToken::Plus: Out->os() << "Plus\n"; break; + case AsmToken::RParen: Out->os() << "RParen\n"; break; + case AsmToken::Slash: Out->os() << "Slash\n"; break; + case AsmToken::Star: Out->os() << "Star\n"; break; + case AsmToken::Tilde: Out->os() << "Tilde\n"; break; } } - - return Error; -} -static formatted_raw_ostream *GetOutputStream() { - if (OutputFilename == "") - OutputFilename = "-"; - - // Make sure that the Out file gets unlinked from the disk if we get a - // SIGINT. - if (OutputFilename != "-") - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - - std::string Err; - raw_fd_ostream *Out = new raw_fd_ostream(OutputFilename.c_str(), Err, - raw_fd_ostream::F_Binary); - if (!Err.empty()) { - errs() << Err << '\n'; - delete Out; - return 0; - } - - return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM); + // Keep output if no errors. + if (Error == 0) Out->keep(); + + return Error; } static int AssembleInput(const char *ProgName) { @@ -273,10 +280,6 @@ static int AssembleInput(const char *ProgName) { assert(MAI && "Unable to create target asm info!"); MCContext Ctx(*MAI); - formatted_raw_ostream *Out = GetOutputStream(); - if (!Out) - return 1; - // FIXME: We shouldn't need to do this (and link in codegen). OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(TripleName, "")); @@ -287,47 +290,52 @@ static int AssembleInput(const char *ProgName) { return 1; } - OwningPtr<MCCodeEmitter> CE; + OwningPtr<tool_output_file> Out(GetOutputStream()); + if (!Out) + return 1; + + formatted_raw_ostream FOS(Out->os()); OwningPtr<MCStreamer> Str; - OwningPtr<TargetAsmBackend> TAB; if (FileType == OFT_AssemblyFile) { MCInstPrinter *IP = TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI); + MCCodeEmitter *CE = 0; if (ShowEncoding) - CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); - Str.reset(createAsmStreamer(Ctx, *Out,TM->getTargetData()->isLittleEndian(), - /*asmverbose*/true, IP, CE.get(), ShowInst)); + CE = TheTarget->createCodeEmitter(*TM, Ctx); + Str.reset(createAsmStreamer(Ctx, FOS, + TM->getTargetData()->isLittleEndian(), + /*asmverbose*/true, IP, CE, ShowInst)); } else if (FileType == OFT_Null) { Str.reset(createNullStreamer(Ctx)); } else { assert(FileType == OFT_ObjectFile && "Invalid file type!"); - CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); - TAB.reset(TheTarget->createAsmBackend(TripleName)); + MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM, Ctx); + TargetAsmBackend *TAB = TheTarget->createAsmBackend(TripleName); Str.reset(TheTarget->createObjectStreamer(TripleName, Ctx, *TAB, - *Out, CE.get(), RelaxAll)); + FOS, CE, RelaxAll)); } if (EnableLogging) { Str.reset(createLoggingStreamer(Str.take(), errs())); } - AsmParser Parser(*TheTarget, SrcMgr, Ctx, *Str.get(), *MAI); - OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(Parser)); + OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx, + *Str.get(), *MAI)); + OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(*Parser, *TM)); if (!TAP) { errs() << ProgName << ": error: this target does not support assembly parsing.\n"; return 1; } - Parser.setTargetParser(*TAP.get()); + Parser->setShowParsedOperands(ShowInstOperands); + Parser->setTargetParser(*TAP.get()); - int Res = Parser.Run(NoInitialTextSection); - delete Out; + int Res = Parser->Run(NoInitialTextSection); - // Delete output on errors. - if (Res && OutputFilename != "-") - sys::Path(OutputFilename).eraseFromDisk(); + // Keep output if no errors. + if (Res == 0) Out->keep(); return Res; } @@ -351,10 +359,20 @@ static int DisassembleInput(const char *ProgName, bool Enhanced) { return 1; } + OwningPtr<tool_output_file> Out(GetOutputStream()); + if (!Out) + return 1; + + int Res; if (Enhanced) - return Disassembler::disassembleEnhanced(TripleName, *Buffer); + Res = Disassembler::disassembleEnhanced(TripleName, *Buffer, Out->os()); else - return Disassembler::disassemble(*TheTarget, TripleName, *Buffer); + Res = Disassembler::disassemble(*TheTarget, TripleName, *Buffer, Out->os()); + + // Keep output if no errors. + if (Res == 0) Out->keep(); + + return Res; } @@ -373,6 +391,7 @@ int main(int argc, char **argv) { llvm::InitializeAllDisassemblers(); cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n"); + TripleName = Triple::normalize(TripleName); switch (Action) { default: diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index fd7e7f6..daa8571 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -88,10 +88,13 @@ static char TypeCharForSymbol(GlobalValue &GV) { static void DumpSymbolNameForGlobalValue(GlobalValue &GV) { // Private linkage and available_externally linkage don't exist in symtab. - if (GV.hasPrivateLinkage() || GV.hasLinkerPrivateLinkage() || - GV.hasLinkerPrivateWeakLinkage() || GV.hasAvailableExternallyLinkage()) + if (GV.hasPrivateLinkage() || + GV.hasLinkerPrivateLinkage() || + GV.hasLinkerPrivateWeakLinkage() || + GV.hasLinkerPrivateWeakDefAutoLinkage() || + GV.hasAvailableExternallyLinkage()) return; - + const std::string SymbolAddrStr = " "; // Not used yet... char TypeChar = TypeCharForSymbol(GV); if ((TypeChar != 'U') && UndefinedOnly) @@ -145,13 +148,13 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { Module *Result = 0; if (Buffer.get()) Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); - + if (Result) { DumpSymbolNamesFromModule(Result); delete Result; } else errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; - + } else if (aPath.isArchive()) { std::string ErrMsg; Archive* archive = Archive::OpenAndLoad(sys::Path(Filename), Context, @@ -176,7 +179,7 @@ int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n"); diff --git a/tools/llvm-prof/llvm-prof.cpp b/tools/llvm-prof/llvm-prof.cpp index 88adeb4..1c63d97 100644 --- a/tools/llvm-prof/llvm-prof.cpp +++ b/tools/llvm-prof/llvm-prof.cpp @@ -17,12 +17,13 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/PassManager.h" -#include "llvm/Assembly/AsmAnnotationWriter.h" +#include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/Analysis/ProfileInfo.h" #include "llvm/Analysis/ProfileInfoLoader.h" #include "llvm/Analysis/Passes.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" @@ -75,9 +76,10 @@ namespace { class ProfileAnnotator : public AssemblyAnnotationWriter { ProfileInfo &PI; public: - ProfileAnnotator(ProfileInfo& pi) : PI(pi) {} + ProfileAnnotator(ProfileInfo &pi) : PI(pi) {} - virtual void emitFunctionAnnot(const Function *F, raw_ostream &OS) { + virtual void emitFunctionAnnot(const Function *F, + formatted_raw_ostream &OS) { double w = PI.getExecutionCount(F); if (w != ProfileInfo::MissingValue) { OS << ";;; %" << F->getName() << " called "<<(unsigned)w @@ -85,7 +87,7 @@ namespace { } } virtual void emitBasicBlockStartAnnot(const BasicBlock *BB, - raw_ostream &OS) { + formatted_raw_ostream &OS) { double w = PI.getExecutionCount(BB); if (w != ProfileInfo::MissingValue) { if (w != 0) { @@ -96,7 +98,8 @@ namespace { } } - virtual void emitBasicBlockEndAnnot(const BasicBlock *BB, raw_ostream &OS) { + virtual void emitBasicBlockEndAnnot(const BasicBlock *BB, + formatted_raw_ostream &OS) { // Figure out how many times each successor executed. std::vector<std::pair<ProfileInfo::Edge, double> > SuccCounts; @@ -128,7 +131,7 @@ namespace { public: static char ID; // Class identification, replacement for typeinfo. explicit ProfileInfoPrinterPass(ProfileInfoLoader &_PIL) - : ModulePass(&ID), PIL(_PIL) {} + : ModulePass(ID), PIL(_PIL) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); diff --git a/tools/llvm-shlib/Makefile b/tools/llvm-shlib/Makefile index ce29bf8..5238130 100644 --- a/tools/llvm-shlib/Makefile +++ b/tools/llvm-shlib/Makefile @@ -15,6 +15,17 @@ NO_BUILD_ARCHIVE = 1 LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 +include $(LEVEL)/Makefile.config + +ifeq ($(HOST_OS), $(filter $(HOST_OS), Cygwin MingW)) + EXPORTED_SYMBOL_FILE = $(ObjDir)/$(LIBRARYNAME).exports + + # It is needed to force static-stdc++.a linked. + # FIXME: It should be omitted when configure detects system's stdc++.dll. + SHLIB_FRAG_NAMES += stdc++.a.o + +endif + include $(LEVEL)/Makefile.common # Include all archives in libLLVM.(so|dylib) except the ones that have @@ -38,7 +49,6 @@ ifeq ($(HOST_OS),Darwin) LLVMLibsOptions := $(LLVMLibsOptions) -all_load # extra options to override libtool defaults LLVMLibsOptions := $(LLVMLibsOptions) \ - -avoid-version \ -Wl,-dead_strip \ -Wl,-seg1addr -Wl,0xE0000000 @@ -58,3 +68,44 @@ ifeq ($(HOST_OS), Linux) # Don't allow unresolved symbols. LLVMLibsOptions += -Wl,--no-undefined endif + +ifeq ($(HOST_OS), $(filter $(HOST_OS), Cygwin MingW)) + +SHLIB_STUBS := $(addprefix $(ObjDir)/, $(SHLIB_FRAG_NAMES)) +SHLIB_FRAGS := $(patsubst %.a.o, $(ObjDir)/%.syms.txt, $(LIBRARYNAME).a.o $(SHLIB_FRAG_NAMES)) +LLVMLibsOptions := $(SHLIB_STUBS) $(LLVMLibsOptions) + +$(LibName.SO): $(SHLIB_STUBS) + +%.syms.txt: %.a.o + $(Echo) Collecting global symbols of $(notdir $*) + $(Verb) $(NM_PATH) -g $< > $@ + +$(ObjDir)/$(LIBRARYNAME).exports: $(SHLIB_FRAGS) $(ObjDir)/.dir + $(Echo) Generating exports for $(LIBRARYNAME) + $(Verb) ($(SED) -n \ + -e "s/^.* T _\([^.][^.]*\)$$/\1/p" \ + -e "s/^.* [BDR] _\([^.][^.]*\)$$/\1 DATA/p" \ + $(SHLIB_FRAGS) \ + | sort -u) > $@ + +$(ObjDir)/$(LIBRARYNAME).a.o: $(LLVMLibsPaths) $(ObjDir)/.dir + $(Echo) Linking all LLVMLibs together for $(LIBRARYNAME) + $(Verb) $(Link) -nostartfiles -Wl,-r -nodefaultlibs -o $@ \ + -Wl,--whole-archive $(LLVMLibsPaths) \ + -Wl,--no-whole-archive + +$(ObjDir)/stdc++.a.o: $(ObjDir)/.dir + $(Echo) Linking all libs together for static libstdc++.a + $(Verb) $(Link) -nostartfiles -Wl,-r -nodefaultlibs -o $@ \ + -Wl,--whole-archive -lstdc++ \ + -Wl,--no-whole-archive +# FIXME: workaround to invalidate -lstdc++ + $(Echo) Making dummy -lstdc++ to lib + $(Verb) $(AR) rc $(ToolDir)/libstdc++.dll.a +# FIXME: Is install-local needed? + +clean-local:: + $(Verb) $(RM) -f $(ToolDir)/libstdc++.dll.a + +endif diff --git a/tools/llvmc/CMakeLists.txt b/tools/llvmc/CMakeLists.txt index bebaaeb..10ad5d8 100644 --- a/tools/llvmc/CMakeLists.txt +++ b/tools/llvmc/CMakeLists.txt @@ -1,4 +1,4 @@ -# add_subdirectory(driver) +# add_subdirectory(src) # TODO: support plugins and user-configured builds. # See ./doc/LLVMC-Reference.rst "Customizing LLVMC: the compilation graph" diff --git a/tools/llvmc/Makefile b/tools/llvmc/Makefile index 8f99526..7c03e2a 100644 --- a/tools/llvmc/Makefile +++ b/tools/llvmc/Makefile @@ -9,10 +9,10 @@ LEVEL = ../.. -export LLVMC_BASED_DRIVER_NAME = llvmc -export LLVMC_BUILTIN_PLUGINS = Base Clang -REQUIRES_RTTI = 1 +DIRS = src -DIRS = plugins driver +ifeq ($(BUILD_EXAMPLES),1) + OPTIONAL_DIRS += examples +endif include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/doc/LLVMC-Reference.rst b/tools/llvmc/doc/LLVMC-Reference.rst index ca8500d..d160e75 100644 --- a/tools/llvmc/doc/LLVMC-Reference.rst +++ b/tools/llvmc/doc/LLVMC-Reference.rst @@ -299,7 +299,7 @@ separate option groups syntactically. * Possible option types: - ``switch_option`` - a simple boolean switch without arguments, for example - ``-O2`` or ``-time``. At most one occurrence is allowed. + ``-O2`` or ``-time``. At most one occurrence is allowed by default. - ``parameter_option`` - option that takes one argument, for example ``-std=c99``. It is also allowed to use spaces instead of the equality @@ -321,6 +321,13 @@ separate option groups syntactically. option types, aliases are not allowed to have any properties besides the aliased option name. Usage example: ``(alias_option "preprocess", "E")`` + - ``switch_list_option`` - like ``switch_option`` with the ``zero_or_more`` + property, but remembers how many times the switch was turned on. Useful + mostly for forwarding. Example: when ``-foo`` is a switch option (with the + ``zero_or_more`` property), the command ``driver -foo -foo`` is forwarded + as ``some-tool -foo``, but when ``-foo`` is a switch list, the same command + is forwarded as ``some-tool -foo -foo``. + * Possible option properties: diff --git a/tools/llvmc/example/Hello/Hello.cpp b/tools/llvmc/example/Hello/Hello.cpp deleted file mode 100644 index a7179ea..0000000 --- a/tools/llvmc/example/Hello/Hello.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===- Hello.cpp - Example code from "Writing an LLVMC Plugin" ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Test plugin for LLVMC. Shows how to write plugins without using TableGen. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CompilerDriver/CompilationGraph.h" -#include "llvm/CompilerDriver/Plugin.h" -#include "llvm/Support/raw_ostream.h" - -namespace { -struct MyPlugin : public llvmc::BasePlugin { - - void PreprocessOptions() const - {} - - void PopulateLanguageMap(llvmc::LanguageMap&) const - { outs() << "Hello!\n"; } - - void PopulateCompilationGraph(llvmc::CompilationGraph&) const - {} -}; - -static llvmc::RegisterPlugin<MyPlugin> RP("Hello", "Hello World plugin"); - -} diff --git a/tools/llvmc/example/Simple/PluginMain.cpp b/tools/llvmc/example/Simple/PluginMain.cpp deleted file mode 100644 index add8acb..0000000 --- a/tools/llvmc/example/Simple/PluginMain.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "AutoGenerated.inc" diff --git a/tools/llvmc/example/Skeleton/Makefile b/tools/llvmc/example/Skeleton/Makefile deleted file mode 100644 index f489abf..0000000 --- a/tools/llvmc/example/Skeleton/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -##===- llvmc/example/Skeleton/Makefile ---------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -# Change this so that $(BASE_LEVEL)/Makefile.common refers to -# $LLVM_DIR/Makefile.common or $YOUR_LLVM_BASED_PROJECT/Makefile.common. -export LLVMC_BASE_LEVEL = ../../../.. - -# Change this to the name of your LLVMC-based driver. -export LLVMC_BASED_DRIVER_NAME = llvmc-skeleton - -# List your plugin names here -export LLVMC_BUILTIN_PLUGINS = # Plugin - -LEVEL = $(LLVMC_BASE_LEVEL) - -DIRS = plugins driver - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/Skeleton/driver/Makefile b/tools/llvmc/example/Skeleton/driver/Makefile deleted file mode 100644 index 93e795b..0000000 --- a/tools/llvmc/example/Skeleton/driver/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -##===- llvmc/example/Skeleton/driver/Makefile --------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = $(LLVMC_BASE_LEVEL)/.. -LLVMC_BASED_DRIVER = $(LLVMC_BASED_DRIVER_NAME) - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/Skeleton/plugins/Makefile b/tools/llvmc/example/Skeleton/plugins/Makefile deleted file mode 100644 index fb07f23..0000000 --- a/tools/llvmc/example/Skeleton/plugins/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- llvmc/example/Skeleton/plugins/Makefile -------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = $(LLVMC_BASE_LEVEL)/.. - -ifneq ($(LLVMC_BUILTIN_PLUGINS),) -DIRS = $(LLVMC_BUILTIN_PLUGINS) -endif - -export LLVMC_BUILTIN_PLUGIN=1 - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/Skeleton/plugins/Plugin/PluginMain.cpp b/tools/llvmc/example/Skeleton/plugins/Plugin/PluginMain.cpp deleted file mode 100644 index add8acb..0000000 --- a/tools/llvmc/example/Skeleton/plugins/Plugin/PluginMain.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "AutoGenerated.inc" diff --git a/tools/llvmc/example/mcc16/Makefile b/tools/llvmc/example/mcc16/Makefile deleted file mode 100644 index e94bca2..0000000 --- a/tools/llvmc/example/mcc16/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- llvmc/example/mcc16/Makefile ------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -export LLVMC_BASE_LEVEL = ../../../.. -export LLVMC_BASED_DRIVER_NAME = mcc16 -export LLVMC_BUILTIN_PLUGINS = PIC16Base - -LEVEL = $(LLVMC_BASE_LEVEL) - -DIRS = plugins driver - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/mcc16/driver/Makefile b/tools/llvmc/example/mcc16/driver/Makefile deleted file mode 100644 index 670d8bd..0000000 --- a/tools/llvmc/example/mcc16/driver/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -##===- llvmc/example/mcc16/driver/Makefile -----------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = $(LLVMC_BASE_LEVEL)/.. -LLVMC_BASED_DRIVER = $(LLVMC_BASED_DRIVER_NAME) - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/mcc16/plugins/Makefile b/tools/llvmc/example/mcc16/plugins/Makefile deleted file mode 100644 index fb07f23..0000000 --- a/tools/llvmc/example/mcc16/plugins/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- llvmc/example/Skeleton/plugins/Makefile -------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = $(LLVMC_BASE_LEVEL)/.. - -ifneq ($(LLVMC_BUILTIN_PLUGINS),) -DIRS = $(LLVMC_BUILTIN_PLUGINS) -endif - -export LLVMC_BUILTIN_PLUGIN=1 - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/mcc16/plugins/PIC16Base/Makefile b/tools/llvmc/example/mcc16/plugins/PIC16Base/Makefile deleted file mode 100644 index 5d785fd..0000000 --- a/tools/llvmc/example/mcc16/plugins/PIC16Base/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- llvmc/example/Skeleton/plugins/Plugin/Makefile ------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = $(LLVMC_BASE_LEVEL)/../.. - -# Change this to the name of your plugin. -LLVMC_PLUGIN = PIC16Base - -BUILT_SOURCES = AutoGenerated.inc - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/examples/Hello/Hello.cpp b/tools/llvmc/examples/Hello/Hello.cpp new file mode 100644 index 0000000..71f04fd --- /dev/null +++ b/tools/llvmc/examples/Hello/Hello.cpp @@ -0,0 +1,29 @@ +//===- Hello.cpp - Example code from "Writing an LLVMC Plugin" ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Shows how to write llvmc-based drivers without using TableGen. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/AutoGenerated.h" +#include "llvm/CompilerDriver/Main.inc" + +#include "llvm/Support/raw_ostream.h" + +namespace llvmc { +namespace autogenerated { + +int PreprocessOptions () { return 0; } + +int PopulateLanguageMap (LanguageMap&) { llvm::outs() << "Hello!\n"; return 0; } + +int PopulateCompilationGraph (CompilationGraph&) { return 0; } + +} +} diff --git a/tools/llvmc/example/Hello/Makefile b/tools/llvmc/examples/Hello/Makefile index 10325e6..c281be6 100644 --- a/tools/llvmc/example/Hello/Makefile +++ b/tools/llvmc/examples/Hello/Makefile @@ -1,4 +1,4 @@ -##===- tools/llvmc/plugins/Hello/Makefile ------------------*- Makefile -*-===## +##===- tools/llvmc/examples/Hello/Makefile -----------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -9,6 +9,6 @@ LEVEL = ../../../.. -LLVMC_PLUGIN = Hello +LLVMC_BASED_DRIVER = Hello include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/Simple/Makefile b/tools/llvmc/examples/Makefile index d7adb5d..8468e93 100644 --- a/tools/llvmc/example/Simple/Makefile +++ b/tools/llvmc/examples/Makefile @@ -1,4 +1,4 @@ -##===- tools/llvmc/plugins/Simple/Makefile -----------------*- Makefile -*-===## +##===- tools/llvmc/examples/Makefile -----------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -7,9 +7,8 @@ # ##===----------------------------------------------------------------------===## -LEVEL = ../../../.. +LEVEL=../../.. -LLVMC_PLUGIN = Simple -BUILT_SOURCES = AutoGenerated.inc +PARALLEL_DIRS := Hello Simple mcc16 Skeleton include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/plugins/Clang/Makefile b/tools/llvmc/examples/Simple/Makefile index 5e5b88a..c10387c 100644 --- a/tools/llvmc/plugins/Clang/Makefile +++ b/tools/llvmc/examples/Simple/Makefile @@ -1,4 +1,4 @@ -##===- tools/llvmc/plugins/Clang/Makefile ------------------*- Makefile -*-===## +##===- llvmc/examples/Simple/Makefile ----------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -9,7 +9,7 @@ LEVEL = ../../../.. -LLVMC_PLUGIN = Clang -BUILT_SOURCES = AutoGenerated.inc +LLVMC_BASED_DRIVER = Simple +BUILT_SOURCES = Simple.inc include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/examples/Simple/Simple.cpp b/tools/llvmc/examples/Simple/Simple.cpp new file mode 100644 index 0000000..8ac7313 --- /dev/null +++ b/tools/llvmc/examples/Simple/Simple.cpp @@ -0,0 +1,2 @@ +#include "llvm/CompilerDriver/Main.inc" +#include "Simple.inc" diff --git a/tools/llvmc/example/Simple/Simple.td b/tools/llvmc/examples/Simple/Simple.td index 87bc385..b47483b 100644 --- a/tools/llvmc/example/Simple/Simple.td +++ b/tools/llvmc/examples/Simple/Simple.td @@ -1,4 +1,4 @@ -//===- Simple.td - A simple plugin for LLVMC ------------------------------===// +//===- Simple.td - A simple LLVMC-based driver ----------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,19 +7,19 @@ // //===----------------------------------------------------------------------===// // -// A simple LLVMC-based gcc wrapper that shows how to write LLVMC plugins. +// A simple LLVMC-based gcc wrapper. // // To compile, use this command: // -// $ cd $LLVMC_DIR/example/Simple -// $ make +// $ cd $LLVM_OBJ_DIR/tools/llvmc +// $ make BUILD_EXAMPLES=1 // // Run as: // -// $ llvmc -load $LLVM_DIR/Release/lib/plugin_llvmc_Simple.so +// $ $LLVM_OBJ_DIR/$(BuildMode)/bin/Simple // // For instructions on how to build your own LLVMC-based driver, see -// the 'example/Skeleton' directory. +// the 'examples/Skeleton' directory. //===----------------------------------------------------------------------===// include "llvm/CompilerDriver/Common.td" @@ -28,10 +28,14 @@ def gcc : Tool< [(in_language "c"), (out_language "executable"), (output_suffix "out"), - (cmd_line "gcc $INFILE -o $OUTFILE"), - (sink) + (command "gcc"), + (sink), + + // -o is what is used by default, out_file_option here is included for + // instructive purposes. + (out_file_option "-o") ]>; -def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>; +def LanguageMap : LanguageMap<[(lang_to_suffixes "c", "c")]>; -def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>; +def CompilationGraph : CompilationGraph<[(edge "root", "gcc")]>; diff --git a/tools/llvmc/example/Skeleton/plugins/Plugin/Plugin.td b/tools/llvmc/examples/Skeleton/AutoGenerated.td index febb9ad..97483ce 100644 --- a/tools/llvmc/example/Skeleton/plugins/Plugin/Plugin.td +++ b/tools/llvmc/examples/Skeleton/AutoGenerated.td @@ -1,6 +1,6 @@ -//===- Plugin.td - A skeleton plugin for LLVMC -------------*- tablegen -*-===// +//===- AutoGenerated.td ------------------------------------*- tablegen -*-===// // -// Write the code for your plugin here. +// Write the TableGen description of your llvmc-based driver here. // //===----------------------------------------------------------------------===// diff --git a/tools/llvmc/examples/Skeleton/Hooks.cpp b/tools/llvmc/examples/Skeleton/Hooks.cpp new file mode 100644 index 0000000..ddd38f6 --- /dev/null +++ b/tools/llvmc/examples/Skeleton/Hooks.cpp @@ -0,0 +1,12 @@ +//===--- Hooks.cpp - The LLVM Compiler Driver -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Hook definitions should go here. +// +//===----------------------------------------------------------------------===// diff --git a/tools/llvmc/driver/Main.cpp b/tools/llvmc/examples/Skeleton/Main.cpp index b1f5b67..24c7768 100644 --- a/tools/llvmc/driver/Main.cpp +++ b/tools/llvmc/examples/Skeleton/Main.cpp @@ -7,8 +7,9 @@ // //===----------------------------------------------------------------------===// // -// Just include CompilerDriver/Main.inc. +// Just include CompilerDriver/Main.inc and AutoGenerated.inc. // //===----------------------------------------------------------------------===// #include "llvm/CompilerDriver/Main.inc" +#include "AutoGenerated.inc" diff --git a/tools/llvmc/examples/Skeleton/Makefile b/tools/llvmc/examples/Skeleton/Makefile new file mode 100644 index 0000000..41ca823 --- /dev/null +++ b/tools/llvmc/examples/Skeleton/Makefile @@ -0,0 +1,20 @@ +##===- llvmc/examples/Skeleton/Makefile --------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open +# Source License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +# Change this so that $(LEVEL)/Makefile.common refers to +# $LLVM_OBJ_DIR/Makefile.common or $YOUR_LLVM_BASED_PROJECT/Makefile.common. +export LEVEL = ../../../.. + +# Change this to the name of your LLVMC-based driver. +LLVMC_BASED_DRIVER = llvmc-skeleton + +# Change this to the name of .inc file built from your .td file. +BUILT_SOURCES = AutoGenerated.inc + +include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/Skeleton/README b/tools/llvmc/examples/Skeleton/README index 92216ae..61ff6fb 100644 --- a/tools/llvmc/example/Skeleton/README +++ b/tools/llvmc/examples/Skeleton/README @@ -1,6 +1,6 @@ This is a template that can be used to create your own LLVMC-based drivers. Just copy the `Skeleton` directory to the location of your preference and edit -`Skeleton/Makefile` and `Skeleton/plugins/Plugin`. +`Skeleton/Makefile` and `Skeleton/AutoGenerated.inc`. The build system assumes that your project is based on LLVM. diff --git a/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp b/tools/llvmc/examples/mcc16/Hooks.cpp index 9b2f9fc5..edb91e1 100644 --- a/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp +++ b/tools/llvmc/examples/mcc16/Hooks.cpp @@ -1,19 +1,23 @@ -#include "AutoGenerated.inc" - #include "llvm/System/Path.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" -using namespace llvm; +#include <string> namespace llvmc { extern char *ProgramName; + + namespace autogenerated { + extern llvm::cl::opt<std::string> Parameter_p; + } } - +using namespace llvm; +using namespace llvmc; // Returns the platform specific directory separator via #ifdefs. -// FIXME: This currently work on linux and windows only. It does not -// work on other unices. +// FIXME: This currently work on linux and windows only. It does not +// work on other unices. static std::string GetDirSeparator() { #if __linux__ || __APPLE__ return "/"; @@ -28,14 +32,14 @@ namespace hooks { std::string GetLowerCasePartDefine(void) { std::string Partname; - if (AutoGeneratedParameter_p.empty()) { + if (autogenerated::Parameter_p.empty()) { Partname = "16f1xxx"; } else { - Partname = AutoGeneratedParameter_p; + Partname = autogenerated::Parameter_p; } std::string LowerCase; - for (unsigned i = 0; i <= Partname.size(); i++) { + for (unsigned i = 0; i < Partname.size(); i++) { LowerCase.push_back(std::tolower(Partname[i])); } @@ -45,26 +49,25 @@ GetLowerCasePartDefine(void) { std::string GetUpperCasePartDefine(void) { std::string Partname; - if (AutoGeneratedParameter_p.empty()) { + if (autogenerated::Parameter_p.empty()) { Partname = "16f1xxx"; } else { - Partname = AutoGeneratedParameter_p; + Partname = autogenerated::Parameter_p; } std::string UpperCase; - for (unsigned i = 0; i <= Partname.size(); i++) { + for (unsigned i = 0; i < Partname.size(); i++) { UpperCase.push_back(std::toupper(Partname[i])); } return "__" + UpperCase; } - // Get the dir where c16 executables reside. std::string GetBinDir() { - // Construct a Path object from the program name. + // Construct a Path object from the program name. void *P = (void*) (intptr_t) GetBinDir; - sys::Path ProgramFullPath + sys::Path ProgramFullPath = sys::Path::GetMainExecutable(llvmc::ProgramName, P); // Get the dir name for the program. It's last component should be 'bin'. @@ -80,7 +83,7 @@ std::string GetInstallDir() { // Go one more level up to get the install dir. std::string InstallDir = BinDirPath.getDirname(); - + return InstallDir + GetDirSeparator(); } diff --git a/tools/llvmc/example/mcc16/driver/Main.cpp b/tools/llvmc/examples/mcc16/Main.cpp index e66e2f9..55ae912 100644 --- a/tools/llvmc/example/mcc16/driver/Main.cpp +++ b/tools/llvmc/examples/mcc16/Main.cpp @@ -13,21 +13,25 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Config/config.h" #include "llvm/CompilerDriver/BuiltinOptions.h" -#include "llvm/CompilerDriver/ForceLinkage.h" +#include "llvm/CompilerDriver/Main.h" + #include "llvm/System/Path.h" +#include "llvm/Config/config.h" + #include <iostream> -namespace llvmc { - int Main(int argc, char** argv); -} +#include "PIC16.inc" + +namespace { // Modify the PACKAGE_VERSION to use build number in top level configure file. void PIC16VersionPrinter(void) { std::cout << "MPLAB C16 1.0 " << PACKAGE_VERSION << "\n"; } +} + int main(int argc, char** argv) { // HACK @@ -36,7 +40,7 @@ int main(int argc, char** argv) { Languages.setHiddenFlag(llvm::cl::Hidden); DryRun.setHiddenFlag(llvm::cl::Hidden); - llvm::cl::SetVersionPrinter(PIC16VersionPrinter); + llvm::cl::SetVersionPrinter(PIC16VersionPrinter); // Ask for a standard temp dir, but just cache its basename., and delete it. llvm::sys::Path tempDir; @@ -49,6 +53,5 @@ int main(int argc, char** argv) { tempDir = TempDirname; tempDir.eraseFromDisk(true); - llvmc::ForceLinkage(); return llvmc::Main(argc, argv); } diff --git a/tools/llvmc/plugins/Base/Makefile b/tools/llvmc/examples/mcc16/Makefile index ebc4335..4409cff 100644 --- a/tools/llvmc/plugins/Base/Makefile +++ b/tools/llvmc/examples/mcc16/Makefile @@ -1,4 +1,4 @@ -##===- tools/llvmc/plugins/Base/Makefile -------------------*- Makefile -*-===## +##===- llvmc/examples/mcc16/Makefile -----------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -9,7 +9,7 @@ LEVEL = ../../../.. -LLVMC_PLUGIN = Base -BUILT_SOURCES = AutoGenerated.inc +LLVMC_BASED_DRIVER = mcc16 +BUILT_SOURCES = PIC16.inc include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td b/tools/llvmc/examples/mcc16/PIC16.td index 25149ad..6f04196 100644 --- a/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td +++ b/tools/llvmc/examples/mcc16/PIC16.td @@ -1,4 +1,4 @@ -//===- PIC16Base.td - PIC16 toolchain driver ---------------*- tablegen -*-===// +//===- PIC16.td - PIC16 toolchain driver -------------------*- tablegen -*-===// // // A basic driver for the PIC16 toolchain. // @@ -202,33 +202,33 @@ def mplink : Tool<[ // Language map def LanguageMap : LanguageMap<[ - LangToSuffixes<"c", ["c"]>, - LangToSuffixes<"c-cpp-output", ["i"]>, - LangToSuffixes<"assembler", ["s"]>, - LangToSuffixes<"assembler-with-cpp", ["S"]>, - LangToSuffixes<"llvm-assembler", ["ll"]>, - LangToSuffixes<"llvm-bitcode", ["bc"]>, - LangToSuffixes<"object-code", ["o"]>, - LangToSuffixes<"executable", ["cof"]> + (lang_to_suffixes "c", "c"), + (lang_to_suffixes "c-cpp-output", "i"), + (lang_to_suffixes "assembler", "s"), + (lang_to_suffixes "assembler-with-cpp", "S"), + (lang_to_suffixes "llvm-assembler", "ll"), + (lang_to_suffixes "llvm-bitcode", "bc"), + (lang_to_suffixes "object-code", "o"), + (lang_to_suffixes "executable", "cof") ]>; // Compilation graph def CompilationGraph : CompilationGraph<[ - Edge<"root", "clang_cc">, - Edge<"root", "llvm_ld">, - OptionalEdge<"root", "llvm_ld_optimizer", (case - (switch_on "S"), (inc_weight), - (switch_on "c"), (inc_weight))>, - Edge<"root", "gpasm">, - Edge<"root", "mplink">, - Edge<"clang_cc", "llvm_ld">, - OptionalEdge<"clang_cc", "llvm_ld_optimizer", (case - (switch_on "S"), (inc_weight), - (switch_on "c"), (inc_weight))>, - Edge<"llvm_ld", "pic16passes">, - Edge<"llvm_ld_optimizer", "pic16passes">, - Edge<"pic16passes", "llc">, - Edge<"llc", "gpasm">, - Edge<"gpasm", "mplink"> + (edge "root", "clang_cc"), + (edge "root", "llvm_ld"), + (optional_edge "root", "llvm_ld_optimizer", + (case (switch_on "S"), (inc_weight), + (switch_on "c"), (inc_weight))), + (edge "root", "gpasm"), + (edge "root", "mplink"), + (edge "clang_cc", "llvm_ld"), + (optional_edge "clang_cc", "llvm_ld_optimizer", + (case (switch_on "S"), (inc_weight), + (switch_on "c"), (inc_weight))), + (edge "llvm_ld", "pic16passes"), + (edge "llvm_ld_optimizer", "pic16passes"), + (edge "pic16passes", "llc"), + (edge "llc", "gpasm"), + (edge "gpasm", "mplink") ]>; diff --git a/tools/llvmc/example/mcc16/README b/tools/llvmc/examples/mcc16/README index eeef6a4..6d2b73d 100644 --- a/tools/llvmc/example/mcc16/README +++ b/tools/llvmc/examples/mcc16/README @@ -1,5 +1,5 @@ This is a basic compiler driver for the PIC16 toolchain that shows how to create -your own llvmc-based drivers. It is based on the example/Skeleton template. +your own llvmc-based drivers. It is based on the examples/Skeleton template. The PIC16 toolchain looks like this: diff --git a/tools/llvmc/plugins/Base/PluginMain.cpp b/tools/llvmc/plugins/Base/PluginMain.cpp deleted file mode 100644 index add8acb..0000000 --- a/tools/llvmc/plugins/Base/PluginMain.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "AutoGenerated.inc" diff --git a/tools/llvmc/plugins/Clang/PluginMain.cpp b/tools/llvmc/plugins/Clang/PluginMain.cpp deleted file mode 100644 index add8acb..0000000 --- a/tools/llvmc/plugins/Clang/PluginMain.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "AutoGenerated.inc" diff --git a/tools/llvmc/plugins/Makefile b/tools/llvmc/plugins/Makefile deleted file mode 100644 index 37dac6f..0000000 --- a/tools/llvmc/plugins/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- tools/llvmc/plugins/Makefile ------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. - -ifneq ($(LLVMC_BUILTIN_PLUGINS),) -DIRS = $(LLVMC_BUILTIN_PLUGINS) -endif - -export LLVMC_BUILTIN_PLUGIN=1 - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/src/AutoGenerated.td b/tools/llvmc/src/AutoGenerated.td new file mode 100644 index 0000000..8507b1f --- /dev/null +++ b/tools/llvmc/src/AutoGenerated.td @@ -0,0 +1,17 @@ +//===- AutoGenerated.td - LLVMC toolchain descriptions -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains compilation graph description used by llvmc. +// +//===----------------------------------------------------------------------===// + +include "llvm/CompilerDriver/Common.td" + +include "Base.td" +include "Clang.td" diff --git a/tools/llvmc/plugins/Base/Base.td.in b/tools/llvmc/src/Base.td.in index a042997..0c4de4c 100644 --- a/tools/llvmc/plugins/Base/Base.td.in +++ b/tools/llvmc/src/Base.td.in @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -include "llvm/CompilerDriver/Common.td" // Options @@ -263,7 +262,7 @@ def llc : Tool< // Base class for linkers class llvm_gcc_based_linker <string cmd_prefix, dag on_empty> : Tool< -[(in_language ["object-code", "static-library"]), +[(in_language ["object-code", "static-library", "dynamic-library"]), (out_language "executable"), (output_suffix "out"), (command cmd_prefix), @@ -305,73 +304,79 @@ def llvm_gcc_cpp_linker : llvm_gcc_based_linker<"@LLVMGXXCOMMAND@", // Language map -def LanguageMap : LanguageMap< - [LangToSuffixes<"c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]>, - LangToSuffixes<"c++-header", ["hpp"]>, - LangToSuffixes<"c", ["c"]>, - LangToSuffixes<"c-header", ["h"]>, - LangToSuffixes<"c-cpp-output", ["i"]>, - LangToSuffixes<"objective-c-cpp-output", ["mi"]>, - LangToSuffixes<"objective-c++", ["mm"]>, - LangToSuffixes<"objective-c++-header", ["hmm"]>, - LangToSuffixes<"objective-c", ["m"]>, - LangToSuffixes<"objective-c-header", ["hm"]>, - LangToSuffixes<"assembler", ["s"]>, - LangToSuffixes<"assembler-with-cpp", ["S"]>, - LangToSuffixes<"llvm-assembler", ["ll"]>, - LangToSuffixes<"llvm-bitcode", ["bc"]>, - LangToSuffixes<"object-code", ["o", "*empty*"]>, - LangToSuffixes<"static-library", ["a", "lib"]>, - LangToSuffixes<"executable", ["out"]> - ]>; +def LanguageMap : LanguageMap<[ + (lang_to_suffixes "c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]), + (lang_to_suffixes "c++-header", "hpp"), + (lang_to_suffixes "c", "c"), + (lang_to_suffixes "c-header", "h"), + (lang_to_suffixes "c-cpp-output", "i"), + (lang_to_suffixes "objective-c-cpp-output", "mi"), + (lang_to_suffixes "objective-c++", "mm"), + (lang_to_suffixes "objective-c++-header", "hmm"), + (lang_to_suffixes "objective-c", "m"), + (lang_to_suffixes "objective-c-header", "hm"), + (lang_to_suffixes "assembler", "s"), + (lang_to_suffixes "assembler-with-cpp", "S"), + (lang_to_suffixes "llvm-assembler", "ll"), + (lang_to_suffixes "llvm-bitcode", "bc"), + (lang_to_suffixes "object-code", ["o", "*empty*"]), + (lang_to_suffixes "static-library", ["a", "lib"]), + (lang_to_suffixes "dynamic-library", ["so", "dylib", "dll"]), + (lang_to_suffixes "executable", ["out"]) +]>; // Compilation graph def CompilationGraph : CompilationGraph<[ - Edge<"root", "llvm_gcc_c">, - Edge<"root", "llvm_gcc_assembler">, - Edge<"root", "llvm_gcc_cpp">, - Edge<"root", "llvm_gcc_m">, - Edge<"root", "llvm_gcc_mxx">, - Edge<"root", "llc">, + (edge "root", "llvm_gcc_c"), + (edge "root", "llvm_gcc_assembler"), + (edge "root", "llvm_gcc_cpp"), + (edge "root", "llvm_gcc_m"), + (edge "root", "llvm_gcc_mxx"), + (edge "root", "llc"), - Edge<"root", "llvm_gcc_c_pch">, - Edge<"root", "llvm_gcc_cpp_pch">, - Edge<"root", "llvm_gcc_m_pch">, - Edge<"root", "llvm_gcc_mxx_pch">, + (edge "root", "llvm_gcc_c_pch"), + (edge "root", "llvm_gcc_cpp_pch"), + (edge "root", "llvm_gcc_m_pch"), + (edge "root", "llvm_gcc_mxx_pch"), - Edge<"llvm_gcc_c", "llc">, - Edge<"llvm_gcc_cpp", "llc">, - Edge<"llvm_gcc_m", "llc">, - Edge<"llvm_gcc_mxx", "llc">, - Edge<"llvm_as", "llc">, + (edge "llvm_gcc_c", "llc"), + (edge "llvm_gcc_cpp", "llc"), + (edge "llvm_gcc_m", "llc"), + (edge "llvm_gcc_mxx", "llc"), + (edge "llvm_as", "llc"), - OptionalEdge<"root", "llvm_as", - (case (switch_on "emit-llvm"), (inc_weight))>, - OptionalEdge<"llvm_gcc_c", "opt", (case (switch_on "opt"), (inc_weight))>, - OptionalEdge<"llvm_gcc_cpp", "opt", (case (switch_on "opt"), (inc_weight))>, - OptionalEdge<"llvm_gcc_m", "opt", (case (switch_on "opt"), (inc_weight))>, - OptionalEdge<"llvm_gcc_mxx", "opt", (case (switch_on "opt"), (inc_weight))>, - OptionalEdge<"llvm_as", "opt", (case (switch_on "opt"), (inc_weight))>, - Edge<"opt", "llc">, + (optional_edge "root", "llvm_as", + (case (switch_on "emit-llvm"), (inc_weight))), + (optional_edge "llvm_gcc_c", "opt", + (case (switch_on "opt"), (inc_weight))), + (optional_edge "llvm_gcc_cpp", "opt", + (case (switch_on "opt"), (inc_weight))), + (optional_edge "llvm_gcc_m", "opt", + (case (switch_on "opt"), (inc_weight))), + (optional_edge "llvm_gcc_mxx", "opt", + (case (switch_on "opt"), (inc_weight))), + (optional_edge "llvm_as", "opt", + (case (switch_on "opt"), (inc_weight))), + (edge "opt", "llc"), - Edge<"llc", "llvm_gcc_assembler">, - Edge<"llvm_gcc_assembler", "llvm_gcc_linker">, - OptionalEdge<"llvm_gcc_assembler", "llvm_gcc_cpp_linker", + (edge "llc", "llvm_gcc_assembler"), + (edge "llvm_gcc_assembler", "llvm_gcc_linker"), + (optional_edge "llvm_gcc_assembler", "llvm_gcc_cpp_linker", (case (or (input_languages_contain "c++"), (input_languages_contain "objective-c++")), (inc_weight), (or (parameter_equals "linker", "g++"), - (parameter_equals "linker", "c++")), (inc_weight))>, + (parameter_equals "linker", "c++")), (inc_weight))), - Edge<"root", "llvm_gcc_linker">, - OptionalEdge<"root", "llvm_gcc_cpp_linker", + (edge "root", "llvm_gcc_linker"), + (optional_edge "root", "llvm_gcc_cpp_linker", (case (or (input_languages_contain "c++"), (input_languages_contain "objective-c++")), (inc_weight), (or (parameter_equals "linker", "g++"), - (parameter_equals "linker", "c++")), (inc_weight))> - ]>; + (parameter_equals "linker", "c++")), (inc_weight))) +]>; diff --git a/tools/llvmc/plugins/Clang/Clang.td b/tools/llvmc/src/Clang.td index 988d9b1..1d75743 100644 --- a/tools/llvmc/plugins/Clang/Clang.td +++ b/tools/llvmc/src/Clang.td @@ -1,22 +1,18 @@ -include "llvm/CompilerDriver/Common.td" +//===- Clang.td - LLVMC toolchain descriptions -------------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains compilation graph description used by llvmc. +// +//===----------------------------------------------------------------------===// -def Priority : PluginPriority<1>; def Options : OptionList<[ -// Extern options -(switch_option "E", (extern)), -(switch_option "S", (extern)), -(switch_option "c", (extern)), -(switch_option "fsyntax-only", (extern)), -(switch_option "emit-llvm", (extern)), -(switch_option "pthread", (extern)), -(parameter_list_option "I", (extern)), -(parameter_list_option "include", (extern)), -(parameter_list_option "L", (extern)), -(parameter_list_option "l", (extern)), -(prefix_list_option "Wa,", (extern)), -(prefix_list_option "Wl,", (extern)), - (switch_option "clang", (help "Use Clang instead of llvm-gcc")) ]>; @@ -71,31 +67,21 @@ def llvm_ld : Tool< (join) ]>; -// Language map - -def LanguageMap : LanguageMap<[ - LangToSuffixes<"c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]>, - LangToSuffixes<"c", ["c"]>, - LangToSuffixes<"objective-c", ["m"]>, - LangToSuffixes<"c-cpp-output", ["i"]>, - LangToSuffixes<"objective-c-cpp-output", ["mi"]> -]>; - // Compilation graph -def CompilationGraph : CompilationGraph<[ - OptionalEdge<"root", "clang_c", - (case (switch_on "clang"), (inc_weight))>, - OptionalEdge<"root", "clang_cpp", - (case (switch_on "clang"), (inc_weight))>, - OptionalEdge<"root", "clang_objective_c", - (case (switch_on "clang"), (inc_weight))>, - OptionalEdge<"root", "clang_objective_cpp", - (case (switch_on "clang"), (inc_weight))>, - Edge<"clang_c", "llc">, - Edge<"clang_cpp", "llc">, - Edge<"clang_objective_c", "llc">, - Edge<"clang_objective_cpp", "llc">, - OptionalEdge<"llc", "as", (case (switch_on "clang"), (inc_weight))>, - Edge<"as", "llvm_ld"> +def ClangCompilationGraph : CompilationGraph<[ + (optional_edge "root", "clang_c", + (case (switch_on "clang"), (inc_weight))), + (optional_edge "root", "clang_cpp", + (case (switch_on "clang"), (inc_weight))), + (optional_edge "root", "clang_objective_c", + (case (switch_on "clang"), (inc_weight))), + (optional_edge "root", "clang_objective_cpp", + (case (switch_on "clang"), (inc_weight))), + (edge "clang_c", "llc"), + (edge "clang_cpp", "llc"), + (edge "clang_objective_c", "llc"), + (edge "clang_objective_cpp", "llc"), + (optional_edge "llc", "as", (case (switch_on "clang"), (inc_weight))), + (edge "as", "llvm_ld") ]>; diff --git a/tools/llvmc/plugins/Base/Hooks.cpp b/tools/llvmc/src/Hooks.cpp index 661a914..661a914 100644 --- a/tools/llvmc/plugins/Base/Hooks.cpp +++ b/tools/llvmc/src/Hooks.cpp diff --git a/tools/llvmc/example/Skeleton/driver/Main.cpp b/tools/llvmc/src/Main.cpp index b1f5b67..9f9c71a 100644 --- a/tools/llvmc/example/Skeleton/driver/Main.cpp +++ b/tools/llvmc/src/Main.cpp @@ -7,8 +7,10 @@ // //===----------------------------------------------------------------------===// // -// Just include CompilerDriver/Main.inc. +// Just include AutoGenerated.inc and CompilerDriver/Main.inc. // //===----------------------------------------------------------------------===// +#include "AutoGenerated.inc" + #include "llvm/CompilerDriver/Main.inc" diff --git a/tools/llvmc/driver/Makefile b/tools/llvmc/src/Makefile index 2f3104b..f3f3091 100644 --- a/tools/llvmc/driver/Makefile +++ b/tools/llvmc/src/Makefile @@ -1,4 +1,4 @@ -##===- tools/llvmc/driver/Makefile -------------------------*- Makefile -*-===## +##===- tools/llvmc/src/Makefile ----------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -8,6 +8,7 @@ ##===----------------------------------------------------------------------===## LEVEL = ../../.. -LLVMC_BASED_DRIVER = $(LLVMC_BASED_DRIVER_NAME) +LLVMC_BASED_DRIVER = llvmc +BUILT_SOURCES = AutoGenerated.inc include $(LEVEL)/Makefile.common diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index 911fddf..671348c 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -119,6 +119,11 @@ bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model, return true; } +void LTOCodeGenerator::setCpu(const char* mCpu) +{ + _mCpu = mCpu; +} + void LTOCodeGenerator::setAssemblerPath(const char* path) { if ( _assemblerPath ) @@ -126,6 +131,14 @@ void LTOCodeGenerator::setAssemblerPath(const char* path) _assemblerPath = new sys::Path(path); } +void LTOCodeGenerator::setAssemblerArgs(const char** args, int nargs) +{ + for (int i = 0; i < nargs; ++i) { + const char *arg = args[i]; + _assemblerArgs.push_back(arg); + } +} + void LTOCodeGenerator::addMustPreserveSymbol(const char* sym) { _mustPreserveSymbols[sym] = 1; @@ -142,8 +155,8 @@ bool LTOCodeGenerator::writeMergedModules(const char *path, // create output file std::string ErrInfo; - raw_fd_ostream Out(path, ErrInfo, - raw_fd_ostream::F_Binary); + tool_output_file Out(path, ErrInfo, + raw_fd_ostream::F_Binary); if (!ErrInfo.empty()) { errMsg = "could not open bitcode file for writing: "; errMsg += path; @@ -151,16 +164,17 @@ bool LTOCodeGenerator::writeMergedModules(const char *path, } // write bitcode to it - WriteBitcodeToFile(_linker.getModule(), Out); - Out.close(); + WriteBitcodeToFile(_linker.getModule(), Out.os()); + Out.os().close(); - if (Out.has_error()) { + if (Out.os().has_error()) { errMsg = "could not write bitcode file: "; errMsg += path; - Out.clear_error(); + Out.os().clear_error(); return true; } + Out.keep(); return false; } @@ -176,11 +190,16 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) // generate assembly code bool genResult = false; { - raw_fd_ostream asmFD(uniqueAsmPath.c_str(), errMsg); - formatted_raw_ostream asmFile(asmFD); + tool_output_file asmFile(uniqueAsmPath.c_str(), errMsg); if (!errMsg.empty()) return NULL; - genResult = this->generateAssemblyCode(asmFile, errMsg); + genResult = this->generateAssemblyCode(asmFile.os(), errMsg); + asmFile.os().close(); + if (asmFile.os().has_error()) { + asmFile.os().clear_error(); + return NULL; + } + asmFile.keep(); } if ( genResult ) { uniqueAsmPath.eraseFromDisk(); @@ -257,6 +276,11 @@ bool LTOCodeGenerator::assemble(const std::string& asmPath, args.push_back("-c"); args.push_back("-x"); args.push_back("assembler"); + } else { + for (std::vector<std::string>::iterator I = _assemblerArgs.begin(), + E = _assemblerArgs.end(); I != E; ++I) { + args.push_back(I->c_str()); + } } args.push_back("-o"); args.push_back(objPath.c_str()); @@ -301,7 +325,7 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) // construct LTModule, hand over ownership of module and target SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures("" /* cpu */, llvm::Triple(Triple)); + Features.getDefaultSubtargetFeatures(_mCpu, llvm::Triple(Triple)); std::string FeatureStr = Features.getString(); _target = march->createTargetMachine(Triple, FeatureStr); } @@ -343,7 +367,7 @@ void LTOCodeGenerator::applyScopeRestrictions() { } /// Optimize merged modules using various IPO passes -bool LTOCodeGenerator::generateAssemblyCode(formatted_raw_ostream& out, +bool LTOCodeGenerator::generateAssemblyCode(raw_ostream& out, std::string& errMsg) { if ( this->determineTarget(errMsg) ) @@ -378,7 +402,9 @@ bool LTOCodeGenerator::generateAssemblyCode(formatted_raw_ostream& out, codeGenPasses->add(new TargetData(*_target->getTargetData())); - if (_target->addPassesToEmitFile(*codeGenPasses, out, + formatted_raw_ostream Out(out); + + if (_target->addPassesToEmitFile(*codeGenPasses, Out, TargetMachine::CGFT_AssemblyFile, CodeGenOpt::Aggressive)) { errMsg = "target file type not supported"; diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h index cac3b8c..f5b78a6 100644 --- a/tools/lto/LTOCodeGenerator.h +++ b/tools/lto/LTOCodeGenerator.h @@ -36,14 +36,16 @@ struct LTOCodeGenerator { bool addModule(struct LTOModule*, std::string& errMsg); bool setDebugInfo(lto_debug_model, std::string& errMsg); bool setCodePICModel(lto_codegen_model, std::string& errMsg); + void setCpu(const char *cpu); void setAssemblerPath(const char* path); + void setAssemblerArgs(const char** args, int nargs); void addMustPreserveSymbol(const char* sym); bool writeMergedModules(const char* path, std::string& errMsg); const void* compile(size_t* length, std::string& errMsg); void setCodeGenDebugOptions(const char *opts); private: - bool generateAssemblyCode(llvm::formatted_raw_ostream& out, + bool generateAssemblyCode(llvm::raw_ostream& out, std::string& errMsg); bool assemble(const std::string& asmPath, const std::string& objPath, std::string& errMsg); @@ -62,6 +64,8 @@ private: llvm::MemoryBuffer* _nativeObjectFile; std::vector<const char*> _codegenOptions; llvm::sys::Path* _assemblerPath; + std::string _mCpu; + std::vector<std::string> _assemblerArgs; }; #endif // LTO_CODE_GENERATOR_H diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 0870205..c7cd585 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -4,10 +4,10 @@ // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. -// +// //===----------------------------------------------------------------------===// // -// This file implements the Link Time Optimization library. This library is +// This file implements the Link Time Optimization library. This library is // intended to be used by linker to optimize code at link time. // //===----------------------------------------------------------------------===// @@ -36,490 +36,473 @@ using namespace llvm; -bool LTOModule::isBitcodeFile(const void* mem, size_t length) -{ - return llvm::sys::IdentifyFileType((char*)mem, length) - == llvm::sys::Bitcode_FileType; +bool LTOModule::isBitcodeFile(const void *mem, size_t length) { + return llvm::sys::IdentifyFileType((char*)mem, length) + == llvm::sys::Bitcode_FileType; } -bool LTOModule::isBitcodeFile(const char* path) -{ - return llvm::sys::Path(path).isBitcodeFile(); +bool LTOModule::isBitcodeFile(const char *path) { + return llvm::sys::Path(path).isBitcodeFile(); } -bool LTOModule::isBitcodeFileForTarget(const void* mem, size_t length, - const char* triplePrefix) -{ - MemoryBuffer* buffer = makeBuffer(mem, length); - if (!buffer) - return false; - return isTargetMatch(buffer, triplePrefix); +bool LTOModule::isBitcodeFileForTarget(const void *mem, size_t length, + const char *triplePrefix) { + MemoryBuffer *buffer = makeBuffer(mem, length); + if (!buffer) + return false; + return isTargetMatch(buffer, triplePrefix); } -bool LTOModule::isBitcodeFileForTarget(const char* path, - const char* triplePrefix) -{ - MemoryBuffer *buffer = MemoryBuffer::getFile(path); - if (buffer == NULL) - return false; - return isTargetMatch(buffer, triplePrefix); +bool LTOModule::isBitcodeFileForTarget(const char *path, + const char *triplePrefix) { + MemoryBuffer *buffer = MemoryBuffer::getFile(path); + if (buffer == NULL) + return false; + return isTargetMatch(buffer, triplePrefix); } -// takes ownership of buffer -bool LTOModule::isTargetMatch(MemoryBuffer* buffer, const char* triplePrefix) -{ - OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext())); - // on success, m owns buffer and both are deleted at end of this method - if (!m) { - delete buffer; - return false; - } - std::string actualTarget = m->getTargetTriple(); - return (strncmp(actualTarget.c_str(), triplePrefix, - strlen(triplePrefix)) == 0); +// Takes ownership of buffer. +bool LTOModule::isTargetMatch(MemoryBuffer *buffer, const char *triplePrefix) { + OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext())); + // On success, m owns buffer and both are deleted at end of this method. + if (!m) { + delete buffer; + return false; + } + std::string actualTarget = m->getTargetTriple(); + return (strncmp(actualTarget.c_str(), triplePrefix, + strlen(triplePrefix)) == 0); } -LTOModule::LTOModule(Module* m, TargetMachine* t) - : _module(m), _target(t), _symbolsParsed(false) +LTOModule::LTOModule(Module *m, TargetMachine *t) + : _module(m), _target(t), _symbolsParsed(false) { } -LTOModule* LTOModule::makeLTOModule(const char* path, - std::string& errMsg) -{ - OwningPtr<MemoryBuffer> buffer(MemoryBuffer::getFile(path, &errMsg)); - if (!buffer) - return NULL; - return makeLTOModule(buffer.get(), errMsg); +LTOModule *LTOModule::makeLTOModule(const char *path, + std::string &errMsg) { + OwningPtr<MemoryBuffer> buffer(MemoryBuffer::getFile(path, &errMsg)); + if (!buffer) + return NULL; + return makeLTOModule(buffer.get(), errMsg); } -/// makeBuffer - create a MemoryBuffer from a memory range. -/// MemoryBuffer requires the byte past end of the buffer to be a zero. -/// We might get lucky and already be that way, otherwise make a copy. -/// Also if next byte is on a different page, don't assume it is readable. -MemoryBuffer* LTOModule::makeBuffer(const void* mem, size_t length) -{ - const char *startPtr = (char*)mem; - const char *endPtr = startPtr+length; - if (((uintptr_t)endPtr & (sys::Process::GetPageSize()-1)) == 0 || - *endPtr != 0) - return MemoryBuffer::getMemBufferCopy(StringRef(startPtr, length)); - - return MemoryBuffer::getMemBuffer(StringRef(startPtr, length)); +/// makeBuffer - Create a MemoryBuffer from a memory range. MemoryBuffer +/// requires the byte past end of the buffer to be a zero. We might get lucky +/// and already be that way, otherwise make a copy. Also if next byte is on a +/// different page, don't assume it is readable. +MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) { + const char *startPtr = (char*)mem; + const char *endPtr = startPtr+length; + if (((uintptr_t)endPtr & (sys::Process::GetPageSize()-1)) == 0 || + *endPtr != 0) + return MemoryBuffer::getMemBufferCopy(StringRef(startPtr, length)); + + return MemoryBuffer::getMemBuffer(StringRef(startPtr, length)); } -LTOModule* LTOModule::makeLTOModule(const void* mem, size_t length, - std::string& errMsg) -{ - OwningPtr<MemoryBuffer> buffer(makeBuffer(mem, length)); - if (!buffer) - return NULL; - return makeLTOModule(buffer.get(), errMsg); +LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, + std::string &errMsg) { + OwningPtr<MemoryBuffer> buffer(makeBuffer(mem, length)); + if (!buffer) + return NULL; + return makeLTOModule(buffer.get(), errMsg); } -LTOModule* LTOModule::makeLTOModule(MemoryBuffer* buffer, - std::string& errMsg) -{ - InitializeAllTargets(); - - // parse bitcode buffer - OwningPtr<Module> m(ParseBitcodeFile(buffer, getGlobalContext(), &errMsg)); - if (!m) - return NULL; - - std::string Triple = m->getTargetTriple(); - if (Triple.empty()) - Triple = sys::getHostTriple(); - - // find machine architecture for this module - const Target* march = TargetRegistry::lookupTarget(Triple, errMsg); - if (!march) - return NULL; - - // construct LTModule, hand over ownership of module and target - SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures("" /* cpu */, llvm::Triple(Triple)); - std::string FeatureStr = Features.getString(); - TargetMachine* target = march->createTargetMachine(Triple, FeatureStr); - return new LTOModule(m.take(), target); +LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, + std::string &errMsg) { + InitializeAllTargets(); + + // parse bitcode buffer + OwningPtr<Module> m(ParseBitcodeFile(buffer, getGlobalContext(), &errMsg)); + if (!m) + return NULL; + + std::string Triple = m->getTargetTriple(); + if (Triple.empty()) + Triple = sys::getHostTriple(); + + // find machine architecture for this module + const Target *march = TargetRegistry::lookupTarget(Triple, errMsg); + if (!march) + return NULL; + + // construct LTModule, hand over ownership of module and target + SubtargetFeatures Features; + Features.getDefaultSubtargetFeatures("" /* cpu */, llvm::Triple(Triple)); + std::string FeatureStr = Features.getString(); + TargetMachine *target = march->createTargetMachine(Triple, FeatureStr); + return new LTOModule(m.take(), target); } -const char* LTOModule::getTargetTriple() -{ - return _module->getTargetTriple().c_str(); +const char *LTOModule::getTargetTriple() { + return _module->getTargetTriple().c_str(); } -void LTOModule::addDefinedFunctionSymbol(Function* f, Mangler &mangler) -{ - // add to list of defined symbols - addDefinedSymbol(f, mangler, true); - - // add external symbols referenced by this function. - for (Function::iterator b = f->begin(); b != f->end(); ++b) { - for (BasicBlock::iterator i = b->begin(); i != b->end(); ++i) { - for (unsigned count = 0, total = i->getNumOperands(); - count != total; ++count) { - findExternalRefs(i->getOperand(count), mangler); - } - } - } +void LTOModule::setTargetTriple(const char *triple) { + _module->setTargetTriple(triple); } -// get string that data pointer points to -bool LTOModule::objcClassNameFromExpression(Constant* c, std::string& name) -{ - if (ConstantExpr* ce = dyn_cast<ConstantExpr>(c)) { - Constant* op = ce->getOperand(0); - if (GlobalVariable* gvn = dyn_cast<GlobalVariable>(op)) { - Constant* cn = gvn->getInitializer(); - if (ConstantArray* ca = dyn_cast<ConstantArray>(cn)) { - if (ca->isCString()) { - name = ".objc_class_name_" + ca->getAsString(); - return true; - } - } - } +void LTOModule::addDefinedFunctionSymbol(Function *f, Mangler &mangler) { + // add to list of defined symbols + addDefinedSymbol(f, mangler, true); + + // add external symbols referenced by this function. + for (Function::iterator b = f->begin(); b != f->end(); ++b) { + for (BasicBlock::iterator i = b->begin(); i != b->end(); ++i) { + for (unsigned count = 0, total = i->getNumOperands(); + count != total; ++count) { + findExternalRefs(i->getOperand(count), mangler); + } } - return false; + } } -// parse i386/ppc ObjC class data structure -void LTOModule::addObjCClass(GlobalVariable* clgv) -{ - if (ConstantStruct* c = dyn_cast<ConstantStruct>(clgv->getInitializer())) { - // second slot in __OBJC,__class is pointer to superclass name - std::string superclassName; - if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { - NameAndAttributes info; - if (_undefines.find(superclassName.c_str()) == _undefines.end()) { - const char* symbolName = ::strdup(superclassName.c_str()); - info.name = ::strdup(symbolName); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - // string is owned by _undefines - _undefines[info.name] = info; - } +// Get string that data pointer points to. +bool LTOModule::objcClassNameFromExpression(Constant *c, std::string &name) { + if (ConstantExpr *ce = dyn_cast<ConstantExpr>(c)) { + Constant *op = ce->getOperand(0); + if (GlobalVariable *gvn = dyn_cast<GlobalVariable>(op)) { + Constant *cn = gvn->getInitializer(); + if (ConstantArray *ca = dyn_cast<ConstantArray>(cn)) { + if (ca->isCString()) { + name = ".objc_class_name_" + ca->getAsString(); + return true; } - // third slot in __OBJC,__class is pointer to class name - std::string className; - if (objcClassNameFromExpression(c->getOperand(2), className)) { - const char* symbolName = ::strdup(className.c_str()); - NameAndAttributes info; - info.name = symbolName; - info.attributes = (lto_symbol_attributes) - (LTO_SYMBOL_PERMISSIONS_DATA | - LTO_SYMBOL_DEFINITION_REGULAR | - LTO_SYMBOL_SCOPE_DEFAULT); - _symbols.push_back(info); - _defines[info.name] = 1; - } + } } + } + return false; } - -// parse i386/ppc ObjC category data structure -void LTOModule::addObjCCategory(GlobalVariable* clgv) -{ - if (ConstantStruct* c = dyn_cast<ConstantStruct>(clgv->getInitializer())) { - // second slot in __OBJC,__category is pointer to target class name - std::string targetclassName; - if (objcClassNameFromExpression(c->getOperand(1), targetclassName)) { - NameAndAttributes info; - if (_undefines.find(targetclassName.c_str()) == _undefines.end()) { - const char* symbolName = ::strdup(targetclassName.c_str()); - info.name = ::strdup(symbolName); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - // string is owned by _undefines - _undefines[info.name] = info; - } - } +// Parse i386/ppc ObjC class data structure. +void LTOModule::addObjCClass(GlobalVariable *clgv) { + if (ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer())) { + // second slot in __OBJC,__class is pointer to superclass name + std::string superclassName; + if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { + NameAndAttributes info; + if (_undefines.find(superclassName.c_str()) == _undefines.end()) { + const char *symbolName = ::strdup(superclassName.c_str()); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + // string is owned by _undefines + _undefines[info.name] = info; + } + } + // third slot in __OBJC,__class is pointer to class name + std::string className; + if (objcClassNameFromExpression(c->getOperand(2), className)) { + const char *symbolName = ::strdup(className.c_str()); + NameAndAttributes info; + info.name = symbolName; + info.attributes = (lto_symbol_attributes) + (LTO_SYMBOL_PERMISSIONS_DATA | + LTO_SYMBOL_DEFINITION_REGULAR | + LTO_SYMBOL_SCOPE_DEFAULT); + _symbols.push_back(info); + _defines[info.name] = 1; } + } } -// parse i386/ppc ObjC class list data structure -void LTOModule::addObjCClassRef(GlobalVariable* clgv) -{ +// Parse i386/ppc ObjC category data structure. +void LTOModule::addObjCCategory(GlobalVariable *clgv) { + if (ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer())) { + // second slot in __OBJC,__category is pointer to target class name std::string targetclassName; - if (objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) { - NameAndAttributes info; - if (_undefines.find(targetclassName.c_str()) == _undefines.end()) { - const char* symbolName = ::strdup(targetclassName.c_str()); - info.name = ::strdup(symbolName); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - // string is owned by _undefines - _undefines[info.name] = info; - } + if (objcClassNameFromExpression(c->getOperand(1), targetclassName)) { + NameAndAttributes info; + if (_undefines.find(targetclassName.c_str()) == _undefines.end()) { + const char *symbolName = ::strdup(targetclassName.c_str()); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + // string is owned by _undefines + _undefines[info.name] = info; + } } + } } -void LTOModule::addDefinedDataSymbol(GlobalValue* v, Mangler& mangler) -{ - // add to list of defined symbols - addDefinedSymbol(v, mangler, false); - - // Special case i386/ppc ObjC data structures in magic sections: - // The issue is that the old ObjC object format did some strange - // contortions to avoid real linker symbols. For instance, the - // ObjC class data structure is allocated statically in the executable - // that defines that class. That data structures contains a pointer to - // its superclass. But instead of just initializing that part of the - // struct to the address of its superclass, and letting the static and - // dynamic linkers do the rest, the runtime works by having that field - // instead point to a C-string that is the name of the superclass. - // At runtime the objc initialization updates that pointer and sets - // it to point to the actual super class. As far as the linker - // knows it is just a pointer to a string. But then someone wanted the - // linker to issue errors at build time if the superclass was not found. - // So they figured out a way in mach-o object format to use an absolute - // symbols (.objc_class_name_Foo = 0) and a floating reference - // (.reference .objc_class_name_Bar) to cause the linker into erroring when - // a class was missing. - // The following synthesizes the implicit .objc_* symbols for the linker - // from the ObjC data structures generated by the front end. - if (v->hasSection() /* && isTargetDarwin */) { - // special case if this data blob is an ObjC class definition - if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { - if (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) { - addObjCClass(gv); - } - } - - // special case if this data blob is an ObjC category definition - else if (v->getSection().compare(0, 18, "__OBJC,__category,") == 0) { - if (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) { - addObjCCategory(gv); - } - } - - // special case if this data blob is the list of referenced classes - else if (v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0) { - if (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) { - addObjCClassRef(gv); - } - } - } - - // add external symbols referenced by this data. - for (unsigned count = 0, total = v->getNumOperands(); - count != total; ++count) { - findExternalRefs(v->getOperand(count), mangler); +// Parse i386/ppc ObjC class list data structure. +void LTOModule::addObjCClassRef(GlobalVariable *clgv) { + std::string targetclassName; + if (objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) { + NameAndAttributes info; + if (_undefines.find(targetclassName.c_str()) == _undefines.end()) { + const char *symbolName = ::strdup(targetclassName.c_str()); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + // string is owned by _undefines + _undefines[info.name] = info; } + } } -void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler, - bool isFunction) -{ - // ignore all llvm.* symbols - if (def->getName().startswith("llvm.")) - return; - - // string is owned by _defines - const char* symbolName = ::strdup(mangler.getNameWithPrefix(def).c_str()); - - // set alignment part log2() can have rounding errors - uint32_t align = def->getAlignment(); - uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0; - - // set permissions part - if (isFunction) - attr |= LTO_SYMBOL_PERMISSIONS_CODE; - else { - GlobalVariable* gv = dyn_cast<GlobalVariable>(def); - if (gv && gv->isConstant()) - attr |= LTO_SYMBOL_PERMISSIONS_RODATA; - else - attr |= LTO_SYMBOL_PERMISSIONS_DATA; - } - - // set definition part - if (def->hasWeakLinkage() || def->hasLinkOnceLinkage()) { - attr |= LTO_SYMBOL_DEFINITION_WEAK; - } - else if (def->hasCommonLinkage()) { - attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; +void LTOModule::addDefinedDataSymbol(GlobalValue *v, Mangler &mangler) { + // Add to list of defined symbols. + addDefinedSymbol(v, mangler, false); + + // Special case i386/ppc ObjC data structures in magic sections: + // The issue is that the old ObjC object format did some strange + // contortions to avoid real linker symbols. For instance, the + // ObjC class data structure is allocated statically in the executable + // that defines that class. That data structures contains a pointer to + // its superclass. But instead of just initializing that part of the + // struct to the address of its superclass, and letting the static and + // dynamic linkers do the rest, the runtime works by having that field + // instead point to a C-string that is the name of the superclass. + // At runtime the objc initialization updates that pointer and sets + // it to point to the actual super class. As far as the linker + // knows it is just a pointer to a string. But then someone wanted the + // linker to issue errors at build time if the superclass was not found. + // So they figured out a way in mach-o object format to use an absolute + // symbols (.objc_class_name_Foo = 0) and a floating reference + // (.reference .objc_class_name_Bar) to cause the linker into erroring when + // a class was missing. + // The following synthesizes the implicit .objc_* symbols for the linker + // from the ObjC data structures generated by the front end. + if (v->hasSection() /* && isTargetDarwin */) { + // special case if this data blob is an ObjC class definition + if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { + if (GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { + addObjCClass(gv); + } } - else { - attr |= LTO_SYMBOL_DEFINITION_REGULAR; + + // special case if this data blob is an ObjC category definition + else if (v->getSection().compare(0, 18, "__OBJC,__category,") == 0) { + if (GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { + addObjCCategory(gv); + } } - - // set scope part - if (def->hasHiddenVisibility()) - attr |= LTO_SYMBOL_SCOPE_HIDDEN; - else if (def->hasProtectedVisibility()) - attr |= LTO_SYMBOL_SCOPE_PROTECTED; - else if (def->hasExternalLinkage() || def->hasWeakLinkage() - || def->hasLinkOnceLinkage() || def->hasCommonLinkage()) - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - else - attr |= LTO_SYMBOL_SCOPE_INTERNAL; - // add to table of symbols - NameAndAttributes info; - info.name = symbolName; - info.attributes = (lto_symbol_attributes)attr; - _symbols.push_back(info); - _defines[info.name] = 1; -} + // special case if this data blob is the list of referenced classes + else if (v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0) { + if (GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { + addObjCClassRef(gv); + } + } + } -void LTOModule::addAsmGlobalSymbol(const char *name) { - // only add new define if not already defined - if (_defines.count(name) == 0) - return; - - // string is owned by _defines - const char *symbolName = ::strdup(name); - uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR; - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - NameAndAttributes info; - info.name = symbolName; - info.attributes = (lto_symbol_attributes)attr; - _symbols.push_back(info); - _defines[info.name] = 1; + // add external symbols referenced by this data. + for (unsigned count = 0, total = v->getNumOperands(); + count != total; ++count) { + findExternalRefs(v->getOperand(count), mangler); + } } -void LTOModule::addPotentialUndefinedSymbol(GlobalValue* decl, Mangler &mangler) -{ - // ignore all llvm.* symbols - if (decl->getName().startswith("llvm.")) - return; - // ignore all aliases - if (isa<GlobalAlias>(decl)) - return; +void LTOModule::addDefinedSymbol(GlobalValue *def, Mangler &mangler, + bool isFunction) { + // ignore all llvm.* symbols + if (def->getName().startswith("llvm.")) + return; - std::string name = mangler.getNameWithPrefix(decl); + // string is owned by _defines + const char *symbolName = ::strdup(mangler.getNameWithPrefix(def).c_str()); - // we already have the symbol - if (_undefines.find(name) != _undefines.end()) - return; + // set alignment part log2() can have rounding errors + uint32_t align = def->getAlignment(); + uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0; - NameAndAttributes info; - // string is owned by _undefines - info.name = ::strdup(name.c_str()); - if (decl->hasExternalWeakLinkage()) - info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; + // set permissions part + if (isFunction) + attr |= LTO_SYMBOL_PERMISSIONS_CODE; + else { + GlobalVariable *gv = dyn_cast<GlobalVariable>(def); + if (gv && gv->isConstant()) + attr |= LTO_SYMBOL_PERMISSIONS_RODATA; else - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - _undefines[name] = info; + attr |= LTO_SYMBOL_PERMISSIONS_DATA; + } + + // set definition part + if (def->hasWeakLinkage() || def->hasLinkOnceLinkage()) { + attr |= LTO_SYMBOL_DEFINITION_WEAK; + } + else if (def->hasCommonLinkage()) { + attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; + } + else { + attr |= LTO_SYMBOL_DEFINITION_REGULAR; + } + + // set scope part + if (def->hasHiddenVisibility()) + attr |= LTO_SYMBOL_SCOPE_HIDDEN; + else if (def->hasProtectedVisibility()) + attr |= LTO_SYMBOL_SCOPE_PROTECTED; + else if (def->hasExternalLinkage() || def->hasWeakLinkage() + || def->hasLinkOnceLinkage() || def->hasCommonLinkage()) + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + else + attr |= LTO_SYMBOL_SCOPE_INTERNAL; + + // add to table of symbols + NameAndAttributes info; + info.name = symbolName; + info.attributes = (lto_symbol_attributes)attr; + _symbols.push_back(info); + _defines[info.name] = 1; } +void LTOModule::addAsmGlobalSymbol(const char *name) { + // only add new define if not already defined + if (_defines.count(name)) + return; + + // string is owned by _defines + const char *symbolName = ::strdup(name); + uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR; + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + NameAndAttributes info; + info.name = symbolName; + info.attributes = (lto_symbol_attributes)attr; + _symbols.push_back(info); + _defines[info.name] = 1; +} +void LTOModule::addPotentialUndefinedSymbol(GlobalValue *decl, + Mangler &mangler) { + // ignore all llvm.* symbols + if (decl->getName().startswith("llvm.")) + return; + + // ignore all aliases + if (isa<GlobalAlias>(decl)) + return; + + std::string name = mangler.getNameWithPrefix(decl); + + // we already have the symbol + if (_undefines.find(name) != _undefines.end()) + return; + + NameAndAttributes info; + // string is owned by _undefines + info.name = ::strdup(name.c_str()); + if (decl->hasExternalWeakLinkage()) + info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; + else + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + _undefines[name] = info; +} -// Find external symbols referenced by VALUE. This is a recursive function. -void LTOModule::findExternalRefs(Value* value, Mangler &mangler) { - - if (GlobalValue* gv = dyn_cast<GlobalValue>(value)) { - if (!gv->hasExternalLinkage()) - addPotentialUndefinedSymbol(gv, mangler); - // If this is a variable definition, do not recursively process - // initializer. It might contain a reference to this variable - // and cause an infinite loop. The initializer will be - // processed in addDefinedDataSymbol(). - return; - } - // GlobalValue, even with InternalLinkage type, may have operands with - // ExternalLinkage type. Do not ignore these operands. - if (Constant* c = dyn_cast<Constant>(value)) { - // Handle ConstantExpr, ConstantStruct, ConstantArry etc. - for (unsigned i = 0, e = c->getNumOperands(); i != e; ++i) - findExternalRefs(c->getOperand(i), mangler); - } + +// Find external symbols referenced by VALUE. This is a recursive function. +void LTOModule::findExternalRefs(Value *value, Mangler &mangler) { + if (GlobalValue *gv = dyn_cast<GlobalValue>(value)) { + if (!gv->hasExternalLinkage()) + addPotentialUndefinedSymbol(gv, mangler); + // If this is a variable definition, do not recursively process + // initializer. It might contain a reference to this variable + // and cause an infinite loop. The initializer will be + // processed in addDefinedDataSymbol(). + return; + } + + // GlobalValue, even with InternalLinkage type, may have operands with + // ExternalLinkage type. Do not ignore these operands. + if (Constant *c = dyn_cast<Constant>(value)) { + // Handle ConstantExpr, ConstantStruct, ConstantArry etc. + for (unsigned i = 0, e = c->getNumOperands(); i != e; ++i) + findExternalRefs(c->getOperand(i), mangler); + } } -void LTOModule::lazyParseSymbols() -{ - if (!_symbolsParsed) { - _symbolsParsed = true; - - // Use mangler to add GlobalPrefix to names to match linker names. - MCContext Context(*_target->getMCAsmInfo()); - Mangler mangler(Context, *_target->getTargetData()); - - // add functions - for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { - if (f->isDeclaration()) - addPotentialUndefinedSymbol(f, mangler); - else - addDefinedFunctionSymbol(f, mangler); - } - - // add data - for (Module::global_iterator v = _module->global_begin(), - e = _module->global_end(); v != e; ++v) { - if (v->isDeclaration()) - addPotentialUndefinedSymbol(v, mangler); - else - addDefinedDataSymbol(v, mangler); - } +void LTOModule::lazyParseSymbols() { + if (_symbolsParsed) + return; - // add asm globals - const std::string &inlineAsm = _module->getModuleInlineAsm(); - const std::string glbl = ".globl"; - std::string asmSymbolName; - std::string::size_type pos = inlineAsm.find(glbl, 0); - while (pos != std::string::npos) { - // eat .globl - pos = pos + 6; - - // skip white space between .globl and symbol name - std::string::size_type pbegin = inlineAsm.find_first_not_of(' ', pos); - if (pbegin == std::string::npos) - break; - - // find end-of-line - std::string::size_type pend = inlineAsm.find_first_of('\n', pbegin); - if (pend == std::string::npos) - break; - - asmSymbolName.assign(inlineAsm, pbegin, pend - pbegin); - addAsmGlobalSymbol(asmSymbolName.c_str()); - - // search next .globl - pos = inlineAsm.find(glbl, pend); - } + _symbolsParsed = true; - // make symbols for all undefines - for (StringMap<NameAndAttributes>::iterator it=_undefines.begin(); - it != _undefines.end(); ++it) { - // if this symbol also has a definition, then don't make an undefine - // because it is a tentative definition - if (_defines.count(it->getKey()) == 0) { - NameAndAttributes info = it->getValue(); - _symbols.push_back(info); - } - } - } + // Use mangler to add GlobalPrefix to names to match linker names. + MCContext Context(*_target->getMCAsmInfo()); + Mangler mangler(Context, *_target->getTargetData()); + + // add functions + for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { + if (f->isDeclaration()) + addPotentialUndefinedSymbol(f, mangler); + else + addDefinedFunctionSymbol(f, mangler); + } + + // add data + for (Module::global_iterator v = _module->global_begin(), + e = _module->global_end(); v != e; ++v) { + if (v->isDeclaration()) + addPotentialUndefinedSymbol(v, mangler); + else + addDefinedDataSymbol(v, mangler); + } + + // add asm globals + const std::string &inlineAsm = _module->getModuleInlineAsm(); + const std::string glbl = ".globl"; + std::string asmSymbolName; + std::string::size_type pos = inlineAsm.find(glbl, 0); + while (pos != std::string::npos) { + // eat .globl + pos = pos + 6; + + // skip white space between .globl and symbol name + std::string::size_type pbegin = inlineAsm.find_first_not_of(' ', pos); + if (pbegin == std::string::npos) + break; + + // find end-of-line + std::string::size_type pend = inlineAsm.find_first_of('\n', pbegin); + if (pend == std::string::npos) + break; + + asmSymbolName.assign(inlineAsm, pbegin, pend - pbegin); + addAsmGlobalSymbol(asmSymbolName.c_str()); + + // search next .globl + pos = inlineAsm.find(glbl, pend); + } + + // make symbols for all undefines + for (StringMap<NameAndAttributes>::iterator it=_undefines.begin(); + it != _undefines.end(); ++it) { + // if this symbol also has a definition, then don't make an undefine + // because it is a tentative definition + if (_defines.count(it->getKey()) == 0) { + NameAndAttributes info = it->getValue(); + _symbols.push_back(info); + } + } } -uint32_t LTOModule::getSymbolCount() -{ - lazyParseSymbols(); - return _symbols.size(); +uint32_t LTOModule::getSymbolCount() { + lazyParseSymbols(); + return _symbols.size(); } -lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) -{ - lazyParseSymbols(); - if (index < _symbols.size()) - return _symbols[index].attributes; - else - return lto_symbol_attributes(0); +lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) { + lazyParseSymbols(); + if (index < _symbols.size()) + return _symbols[index].attributes; + else + return lto_symbol_attributes(0); } -const char* LTOModule::getSymbolName(uint32_t index) -{ - lazyParseSymbols(); - if (index < _symbols.size()) - return _symbols[index].name; - else - return NULL; +const char *LTOModule::getSymbolName(uint32_t index) { + lazyParseSymbols(); + if (index < _symbols.size()) + return _symbols[index].name; + else + return NULL; } diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h index 7f475d4..a19acc0 100644 --- a/tools/lto/LTOModule.h +++ b/tools/lto/LTOModule.h @@ -55,6 +55,7 @@ struct LTOModule { std::string& errMsg); const char* getTargetTriple(); + void setTargetTriple(const char*); uint32_t getSymbolCount(); lto_symbol_attributes getSymbolAttributes(uint32_t index); const char* getSymbolName(uint32_t index); diff --git a/tools/lto/Makefile b/tools/lto/Makefile index 8d57333..e157a4c 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -25,15 +25,22 @@ LINK_COMPONENTS := $(TARGETS_TO_BUILD) ipo scalaropts linker bitreader bitwriter include $(LEVEL)/Makefile.common ifeq ($(HOST_OS),Darwin) + # Special hack to allow libLTO to have an offset version number. + ifdef LLVM_LTO_VERSION_OFFSET + LTO_LIBRARY_VERSION := $(shell expr $(LLVM_SUBMIT_VERSION) + \ + $(LLVM_LTO_VERSION_OFFSET)) + else + LTO_LIBRARY_VERSION := $(LLVM_SUBMIT_VERSION) + endif + # set dylib internal version number to llvmCore submission number ifdef LLVM_SUBMIT_VERSION LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \ - -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) \ + -Wl,$(LTO_LIBRARY_VERSION).$(LLVM_SUBMIT_SUBVERSION) \ -Wl,-compatibility_version -Wl,1 endif # extra options to override libtool defaults LLVMLibsOptions := $(LLVMLibsOptions) \ - -avoid-version \ -Wl,-dead_strip \ -Wl,-seg1addr -Wl,0xE0000000 @@ -41,7 +48,7 @@ ifeq ($(HOST_OS),Darwin) DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ - -no-undefined -Wl,-install_name \ + -Wl,-install_name \ -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index cc841bd..3d7ef0a 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -120,6 +120,14 @@ const char* lto_module_get_target_triple(lto_module_t mod) return mod->getTargetTriple(); } +// +// sets triple string with which the object will be codegened. +// +void lto_module_set_target_triple(lto_module_t mod, const char *triple) +{ + return mod->setTargetTriple(triple); +} + // // returns the number of symbols in the object module @@ -142,7 +150,7 @@ const char* lto_module_get_symbol_name(lto_module_t mod, uint32_t index) // returns the attributes of the ith symbol in the object module // lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod, - uint32_t index) + uint32_t index) { return mod->getSymbolAttributes(index); } @@ -203,6 +211,14 @@ bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) } // +// sets the cpu to generate code for +// +void lto_codegen_set_cpu(lto_code_gen_t cg, const char* cpu) +{ + return cg->setCpu(cpu); +} + +// // sets the path to the assembler tool // void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path) @@ -210,6 +226,16 @@ void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path) cg->setAssemblerPath(path); } + +// +// sets extra arguments that libLTO should pass to the assembler +// +void lto_codegen_set_assembler_args(lto_code_gen_t cg, const char** args, + int nargs) +{ + cg->setAssemblerArgs(args, nargs); +} + // // adds to a list of all global symbols that must exist in the final // generated code. If a function is not listed there, it might be diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports index 9011cf6..4dbf760 100644 --- a/tools/lto/lto.exports +++ b/tools/lto/lto.exports @@ -6,6 +6,7 @@ lto_module_get_num_symbols lto_module_get_symbol_attribute lto_module_get_symbol_name lto_module_get_target_triple +lto_module_set_target_triple lto_module_is_object_file lto_module_is_object_file_for_target lto_module_is_object_file_in_memory @@ -20,4 +21,6 @@ lto_codegen_set_debug_model lto_codegen_set_pic_model lto_codegen_write_merged_modules lto_codegen_debug_options +lto_codegen_set_assembler_args lto_codegen_set_assembler_path +lto_codegen_set_cpu diff --git a/tools/opt/AnalysisWrappers.cpp b/tools/opt/AnalysisWrappers.cpp index f548d00..a2b57bb 100644 --- a/tools/opt/AnalysisWrappers.cpp +++ b/tools/opt/AnalysisWrappers.cpp @@ -31,7 +31,7 @@ namespace { /// or handle in alias analyses. struct ExternalFunctionsPassedConstants : public ModulePass { static char ID; // Pass ID, replacement for typeid - ExternalFunctionsPassedConstants() : ModulePass(&ID) {} + ExternalFunctionsPassedConstants() : ModulePass(ID) {} virtual bool runOnModule(Module &M) { for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { if (!I->isDeclaration()) continue; @@ -42,8 +42,8 @@ namespace { Instruction *User = dyn_cast<Instruction>(*UI); if (!User) continue; - CallSite CS = CallSite::get(User); - if (!CS.getInstruction()) continue; + CallSite CS(cast<Value>(User)); + if (!CS) continue; for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); AI != E; ++AI) { @@ -66,15 +66,17 @@ namespace { AU.setPreservesAll(); } }; +} - char ExternalFunctionsPassedConstants::ID = 0; - RegisterPass<ExternalFunctionsPassedConstants> +char ExternalFunctionsPassedConstants::ID = 0; +static RegisterPass<ExternalFunctionsPassedConstants> P1("print-externalfnconstants", "Print external fn callsites passed constants"); +namespace { struct CallGraphPrinter : public ModulePass { static char ID; // Pass ID, replacement for typeid - CallGraphPrinter() : ModulePass(&ID) {} + CallGraphPrinter() : ModulePass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -85,8 +87,8 @@ namespace { return false; } }; - - char CallGraphPrinter::ID = 0; - RegisterPass<CallGraphPrinter> - P2("print-callgraph", "Print a call graph"); } + +char CallGraphPrinter::ID = 0; +static RegisterPass<CallGraphPrinter> + P2("print-callgraph", "Print a call graph"); diff --git a/tools/opt/GraphPrinters.cpp b/tools/opt/GraphPrinters.cpp index e7c6d1e..9de7d6a 100644 --- a/tools/opt/GraphPrinters.cpp +++ b/tools/opt/GraphPrinters.cpp @@ -28,13 +28,19 @@ static void WriteGraphToFile(raw_ostream &O, const std::string &GraphName, std::string Filename = GraphName + ".dot"; O << "Writing '" << Filename << "'..."; std::string ErrInfo; - raw_fd_ostream F(Filename.c_str(), ErrInfo); - - if (ErrInfo.empty()) - WriteGraph(F, GT); - else - O << " error opening file for writing!"; - O << "\n"; + tool_output_file F(Filename.c_str(), ErrInfo); + + if (ErrInfo.empty()) { + WriteGraph(F.os(), GT); + F.os().close(); + if (!F.os().has_error()) { + O << "\n"; + F.keep(); + return; + } + } + O << " error opening file for writing!\n"; + F.os().clear_error(); } @@ -65,7 +71,7 @@ namespace llvm { namespace { struct CallGraphPrinter : public ModulePass { static char ID; // Pass ID, replacement for typeid - CallGraphPrinter() : ModulePass(&ID) {} + CallGraphPrinter() : ModulePass(ID) {} virtual bool runOnModule(Module &M) { WriteGraphToFile(llvm::errs(), "callgraph", &getAnalysis<CallGraph>()); @@ -79,12 +85,12 @@ namespace { AU.setPreservesAll(); } }; - - char CallGraphPrinter::ID = 0; - RegisterPass<CallGraphPrinter> P2("dot-callgraph", - "Print Call Graph to 'dot' file"); } +char CallGraphPrinter::ID = 0; +static RegisterPass<CallGraphPrinter> P2("dot-callgraph", + "Print Call Graph to 'dot' file"); + //===----------------------------------------------------------------------===// // DomInfoPrinter Pass //===----------------------------------------------------------------------===// @@ -93,7 +99,7 @@ namespace { class DomInfoPrinter : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid - DomInfoPrinter() : FunctionPass(&ID) {} + DomInfoPrinter() : FunctionPass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -110,8 +116,8 @@ namespace { return false; } }; - - char DomInfoPrinter::ID = 0; - static RegisterPass<DomInfoPrinter> - DIP("print-dom-info", "Dominator Info Printer", true, true); } + +char DomInfoPrinter::ID = 0; +static RegisterPass<DomInfoPrinter> +DIP("print-dom-info", "Dominator Info Printer", true, true); diff --git a/tools/opt/PrintSCC.cpp b/tools/opt/PrintSCC.cpp index ea486ca..533f49e 100644 --- a/tools/opt/PrintSCC.cpp +++ b/tools/opt/PrintSCC.cpp @@ -36,7 +36,7 @@ using namespace llvm; namespace { struct CFGSCC : public FunctionPass { static char ID; // Pass identification, replacement for typeid - CFGSCC() : FunctionPass(&ID) {} + CFGSCC() : FunctionPass(ID) {} bool runOnFunction(Function& func); void print(raw_ostream &O, const Module* = 0) const { } @@ -48,7 +48,7 @@ namespace { struct CallGraphSCC : public ModulePass { static char ID; // Pass identification, replacement for typeid - CallGraphSCC() : ModulePass(&ID) {} + CallGraphSCC() : ModulePass(ID) {} // run - Print out SCCs in the call graph for the specified module. bool runOnModule(Module &M); @@ -61,30 +61,30 @@ namespace { AU.addRequired<CallGraph>(); } }; +} - char CFGSCC::ID = 0; - RegisterPass<CFGSCC> - Y("print-cfg-sccs", "Print SCCs of each function CFG"); +char CFGSCC::ID = 0; +static RegisterPass<CFGSCC> +Y("print-cfg-sccs", "Print SCCs of each function CFG"); - char CallGraphSCC::ID = 0; - RegisterPass<CallGraphSCC> - Z("print-callgraph-sccs", "Print SCCs of the Call Graph"); -} +char CallGraphSCC::ID = 0; +static RegisterPass<CallGraphSCC> +Z("print-callgraph-sccs", "Print SCCs of the Call Graph"); bool CFGSCC::runOnFunction(Function &F) { unsigned sccNum = 0; - outs() << "SCCs for Function " << F.getName() << " in PostOrder:"; + errs() << "SCCs for Function " << F.getName() << " in PostOrder:"; for (scc_iterator<Function*> SCCI = scc_begin(&F), E = scc_end(&F); SCCI != E; ++SCCI) { std::vector<BasicBlock*> &nextSCC = *SCCI; - outs() << "\nSCC #" << ++sccNum << " : "; + errs() << "\nSCC #" << ++sccNum << " : "; for (std::vector<BasicBlock*>::const_iterator I = nextSCC.begin(), E = nextSCC.end(); I != E; ++I) - outs() << (*I)->getName() << ", "; + errs() << (*I)->getName() << ", "; if (nextSCC.size() == 1 && SCCI.hasLoop()) - outs() << " (Has self-loop)."; + errs() << " (Has self-loop)."; } - outs() << "\n"; + errs() << "\n"; return true; } @@ -94,19 +94,19 @@ bool CFGSCC::runOnFunction(Function &F) { bool CallGraphSCC::runOnModule(Module &M) { CallGraphNode* rootNode = getAnalysis<CallGraph>().getRoot(); unsigned sccNum = 0; - outs() << "SCCs for the program in PostOrder:"; + errs() << "SCCs for the program in PostOrder:"; for (scc_iterator<CallGraphNode*> SCCI = scc_begin(rootNode), E = scc_end(rootNode); SCCI != E; ++SCCI) { const std::vector<CallGraphNode*> &nextSCC = *SCCI; - outs() << "\nSCC #" << ++sccNum << " : "; + errs() << "\nSCC #" << ++sccNum << " : "; for (std::vector<CallGraphNode*>::const_iterator I = nextSCC.begin(), E = nextSCC.end(); I != E; ++I) - outs() << ((*I)->getFunction() ? (*I)->getFunction()->getNameStr() + errs() << ((*I)->getFunction() ? (*I)->getFunction()->getNameStr() : std::string("external node")) << ", "; if (nextSCC.size() == 1 && SCCI.hasLoop()) - outs() << " (Has self-loop)."; + errs() << " (Has self-loop)."; } - outs() << "\n"; + errs() << "\n"; return true; } diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 0878737..d837185 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -53,7 +53,7 @@ InputFilename(cl::Positional, cl::desc("<input bitcode file>"), static cl::opt<std::string> OutputFilename("o", cl::desc("Override output filename"), - cl::value_desc("filename"), cl::init("-")); + cl::value_desc("filename")); static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals")); @@ -138,17 +138,19 @@ namespace { struct CallGraphSCCPassPrinter : public CallGraphSCCPass { static char ID; const PassInfo *PassToPrint; - CallGraphSCCPassPrinter(const PassInfo *PI) : - CallGraphSCCPass(&ID), PassToPrint(PI) {} + raw_ostream &Out; + CallGraphSCCPassPrinter(const PassInfo *PI, raw_ostream &out) : + CallGraphSCCPass(ID), PassToPrint(PI), Out(out) {} virtual bool runOnSCC(CallGraphSCC &SCC) { if (!Quiet) { - outs() << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; 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()); + getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, + F->getParent()); } } // Get and print pass... @@ -158,7 +160,7 @@ struct CallGraphSCCPassPrinter : public CallGraphSCCPass { virtual const char *getPassName() const { return "'Pass' Printer"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint); + AU.addRequiredID(PassToPrint->getTypeInfo()); AU.setPreservesAll(); } }; @@ -168,13 +170,14 @@ char CallGraphSCCPassPrinter::ID = 0; struct ModulePassPrinter : public ModulePass { static char ID; const PassInfo *PassToPrint; - ModulePassPrinter(const PassInfo *PI) : ModulePass(&ID), - PassToPrint(PI) {} + raw_ostream &Out; + ModulePassPrinter(const PassInfo *PI, raw_ostream &out) + : ModulePass(ID), PassToPrint(PI), Out(out) {} virtual bool runOnModule(Module &M) { if (!Quiet) { - outs() << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; - getAnalysisID<Pass>(PassToPrint).print(outs(), &M); + Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, &M); } // Get and print pass... @@ -184,7 +187,7 @@ struct ModulePassPrinter : public ModulePass { virtual const char *getPassName() const { return "'Pass' Printer"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint); + AU.addRequiredID(PassToPrint->getTypeInfo()); AU.setPreservesAll(); } }; @@ -192,24 +195,26 @@ struct ModulePassPrinter : public ModulePass { char ModulePassPrinter::ID = 0; struct FunctionPassPrinter : public FunctionPass { const PassInfo *PassToPrint; + raw_ostream &Out; static char ID; - FunctionPassPrinter(const PassInfo *PI) : FunctionPass(&ID), - PassToPrint(PI) {} + FunctionPassPrinter(const PassInfo *PI, raw_ostream &out) + : FunctionPass(ID), PassToPrint(PI), Out(out) {} virtual bool runOnFunction(Function &F) { if (!Quiet) { - outs() << "Printing analysis '" << PassToPrint->getPassName() - << "' for function '" << F.getName() << "':\n"; + Out << "Printing analysis '" << PassToPrint->getPassName() + << "' for function '" << F.getName() << "':\n"; } // Get and print pass... - getAnalysisID<Pass>(PassToPrint).print(outs(), F.getParent()); + getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, + F.getParent()); return false; } virtual const char *getPassName() const { return "FunctionPass Printer"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint); + AU.addRequiredID(PassToPrint->getTypeInfo()); AU.setPreservesAll(); } }; @@ -219,13 +224,14 @@ char FunctionPassPrinter::ID = 0; struct LoopPassPrinter : public LoopPass { static char ID; const PassInfo *PassToPrint; - LoopPassPrinter(const PassInfo *PI) : - LoopPass(&ID), PassToPrint(PI) {} + raw_ostream &Out; + LoopPassPrinter(const PassInfo *PI, raw_ostream &out) : + LoopPass(ID), PassToPrint(PI), Out(out) {} virtual bool runOnLoop(Loop *L, LPPassManager &LPM) { if (!Quiet) { - outs() << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; - getAnalysisID<Pass>(PassToPrint).print(outs(), + Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, L->getHeader()->getParent()->getParent()); } // Get and print pass... @@ -235,7 +241,7 @@ struct LoopPassPrinter : public LoopPass { virtual const char *getPassName() const { return "'Pass' Printer"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint); + AU.addRequiredID(PassToPrint->getTypeInfo()); AU.setPreservesAll(); } }; @@ -244,25 +250,27 @@ char LoopPassPrinter::ID = 0; struct BasicBlockPassPrinter : public BasicBlockPass { const PassInfo *PassToPrint; + raw_ostream &Out; static char ID; - BasicBlockPassPrinter(const PassInfo *PI) - : BasicBlockPass(&ID), PassToPrint(PI) {} + BasicBlockPassPrinter(const PassInfo *PI, raw_ostream &out) + : BasicBlockPass(ID), PassToPrint(PI), Out(out) {} virtual bool runOnBasicBlock(BasicBlock &BB) { if (!Quiet) { - outs() << "Printing Analysis info for BasicBlock '" << BB.getName() - << "': Pass " << PassToPrint->getPassName() << ":\n"; + Out << "Printing Analysis info for BasicBlock '" << BB.getName() + << "': Pass " << PassToPrint->getPassName() << ":\n"; } // Get and print pass... - getAnalysisID<Pass>(PassToPrint).print(outs(), BB.getParent()->getParent()); + getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, + BB.getParent()->getParent()); return false; } virtual const char *getPassName() const { return "BasicBlockPass Printer"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredID(PassToPrint); + AU.addRequiredID(PassToPrint->getTypeInfo()); AU.setPreservesAll(); } }; @@ -351,6 +359,11 @@ void AddStandardLinkPasses(PassManagerBase &PM) { int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc, argv); + + if (AnalyzeOnly && NoOutput) { + errs() << argv[0] << ": analyze mode conflicts with no-output mode.\n"; + return 1; + } // Enable debug stream buffering. EnableDebugBuffering = true; @@ -377,35 +390,22 @@ int main(int argc, char **argv) { } // Figure out what stream we are supposed to write to... - raw_ostream *Out = 0; - bool DeleteStream = false; - if (!NoOutput && !AnalyzeOnly) { - if (OutputFilename == "-") { - // Print to stdout. - Out = &outs(); - // If we're printing a bitcode file, switch stdout to binary mode. - // FIXME: This switches outs() globally, not just for the bitcode output. - if (!OutputAssembly) - sys::Program::ChangeStdoutToBinary(); - } else { - if (NoOutput || AnalyzeOnly) { - errs() << "WARNING: The -o (output filename) option is ignored when\n" - "the --disable-output or --analyze options are used.\n"; - } else { - // Make sure that the Output file gets unlinked from the disk if we get - // a SIGINT. - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - - std::string ErrorInfo; - Out = new raw_fd_ostream(OutputFilename.c_str(), ErrorInfo, - raw_fd_ostream::F_Binary); - if (!ErrorInfo.empty()) { - errs() << ErrorInfo << '\n'; - delete Out; - return 1; - } - DeleteStream = true; - } + OwningPtr<tool_output_file> Out; + if (NoOutput) { + if (!OutputFilename.empty()) + errs() << "WARNING: The -o (output filename) option is ignored when\n" + "the --disable-output option is used.\n"; + } else { + // Default to standard output. + if (OutputFilename.empty()) + OutputFilename = "-"; + + std::string ErrorInfo; + Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary)); + if (!ErrorInfo.empty()) { + errs() << ErrorInfo << '\n'; + return 1; } } @@ -413,7 +413,7 @@ int main(int argc, char **argv) { // console, print out a warning message and refuse to do it. We don't // impress anyone by spewing tons of binary goo to a terminal. if (!Force && !NoOutput && !AnalyzeOnly && !OutputAssembly) - if (CheckBitcodeOutputToConsole(*Out, !Quiet)) + if (CheckBitcodeOutputToConsole(Out->os(), !Quiet)) NoOutput = true; // Create a PassManager to hold and optimize the collection of passes we are @@ -489,19 +489,19 @@ int main(int argc, char **argv) { if (AnalyzeOnly) { switch (Kind) { case PT_BasicBlock: - Passes.add(new BasicBlockPassPrinter(PassInf)); + Passes.add(new BasicBlockPassPrinter(PassInf, Out->os())); break; case PT_Loop: - Passes.add(new LoopPassPrinter(PassInf)); + Passes.add(new LoopPassPrinter(PassInf, Out->os())); break; case PT_Function: - Passes.add(new FunctionPassPrinter(PassInf)); + Passes.add(new FunctionPassPrinter(PassInf, Out->os())); break; case PT_CallGraphSCC: - Passes.add(new CallGraphSCCPassPrinter(PassInf)); + Passes.add(new CallGraphSCCPassPrinter(PassInf, Out->os())); break; default: - Passes.add(new ModulePassPrinter(PassInf)); + Passes.add(new ModulePassPrinter(PassInf, Out->os())); break; } } @@ -538,19 +538,20 @@ int main(int argc, char **argv) { if (!NoVerify && !VerifyEach) Passes.add(createVerifierPass()); - // Write bitcode or assembly out to disk or outs() as the last step... + // Write bitcode or assembly to the output as the last step... if (!NoOutput && !AnalyzeOnly) { if (OutputAssembly) - Passes.add(createPrintModulePass(Out)); + Passes.add(createPrintModulePass(&Out->os())); else - Passes.add(createBitcodeWriterPass(*Out)); + Passes.add(createBitcodeWriterPass(Out->os())); } // Now that we have all of the passes ready, run them. Passes.run(*M.get()); - // Delete the raw_fd_ostream. - if (DeleteStream) - delete Out; + // Declare success. + if (!NoOutput) + Out->keep(); + return 0; } |