diff options
Diffstat (limited to 'tools')
63 files changed, 3606 insertions, 2263 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 1273c25..8b5d77e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -2,10 +2,13 @@ # large and three small executables. This is done to minimize memory load # in parallel builds. Please retain this ordering. -# FIXME: We don't yet have the ability to build llvm-config with CMake -# based on explicit dependencies. -if (FALSE) - add_subdirectory(llvm-config) +if( NOT WIN32 OR MSYS OR CYGWIN ) + # It is useful to build llvm-config before the other tools, so we + # have a fresh LibDeps.txt for regenerating the hard-coded library + # dependencies. llvm-config/CMakeLists.txt takes care of this but we + # must keep llvm-config as the first entry on the list of tools to + # be built. + add_subdirectory(llvm-config) endif() add_subdirectory(opt) @@ -23,11 +26,7 @@ add_subdirectory(llvm-prof) add_subdirectory(llvm-link) add_subdirectory(lli) -# gccas and gccld are deprecated: -# add_subdirectory(gccas) -# add_subdirectory(gccld) add_subdirectory(llvm-extract) -add_subdirectory(llvm-db) add_subdirectory(bugpoint) add_subdirectory(llvm-bcanalyzer) @@ -37,3 +36,5 @@ add_subdirectory(llvmc) if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/clang/CMakeLists.txt ) add_subdirectory( ${CMAKE_CURRENT_SOURCE_DIR}/clang ) endif( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/clang/CMakeLists.txt ) + +set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE) diff --git a/tools/Makefile b/tools/Makefile index 4f0f54b..0340c7f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -19,7 +19,7 @@ DIRS := llvm-config PARALLEL_DIRS := opt llvm-as llvm-dis \ llc llvm-ranlib llvm-ar llvm-nm \ llvm-ld llvm-prof llvm-link \ - lli gccas gccld llvm-extract llvm-db \ + lli llvm-extract \ bugpoint llvm-bcanalyzer llvm-stub \ llvm-mc llvmc @@ -39,7 +39,7 @@ ifeq ($(ENABLE_PIC),1) endif # No support for lto / gold on windows targets -ifeq ($(OS), $(filter $(OS), Cygwin MingW)) +ifeq ($(TARGET_OS), $(filter $(TARGET_OS), Cygwin MingW)) DIRS := $(filter-out lto gold, $(DIRS)) endif diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index aab5072..abf5d8e 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -18,17 +18,20 @@ #include "llvm/Linker.h" #include "llvm/Module.h" #include "llvm/Pass.h" -#include "llvm/Assembly/Parser.h" -#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" -#include <iostream> +#include "llvm/System/Host.h" #include <memory> using namespace llvm; +namespace llvm { + Triple TargetTriple; +} + // Anonymous namespace to define command line options for debugging. // namespace { @@ -78,17 +81,25 @@ BugDriver::BugDriver(const char *toolname, bool as_child, bool find_bugs, /// Module *llvm::ParseInputFile(const std::string &Filename, LLVMContext& Ctxt) { - std::auto_ptr<MemoryBuffer> Buffer(MemoryBuffer::getFileOrSTDIN(Filename)); - Module *Result = 0; - if (Buffer.get()) - Result = ParseBitcodeFile(Buffer.get(), Ctxt); - SMDiagnostic Err; - if (!Result && !(Result = ParseAssemblyFile(Filename, Err, Ctxt))) { - Err.Print("bugpoint", errs()); - Result = 0; + Module *Result = ParseIRFile(Filename, Err, Ctxt); + if (!Result) + Err.Print("bugpoint", errs()); + + // If we don't have an override triple, use the first one to configure + // bugpoint, or use the host triple if none provided. + if (Result) { + if (TargetTriple.getTriple().empty()) { + Triple TheTriple(Result->getTargetTriple()); + + if (TheTriple.getTriple().empty()) + TheTriple.setTriple(sys::getHostTriple()); + + TargetTriple.setTriple(TheTriple.getTriple()); + } + + Result->setTargetTriple(TargetTriple.getTriple()); // override the triple } - return Result; } @@ -107,28 +118,28 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { if (Program == 0) return true; if (!run_as_child) - std::cout << "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) - std::cout << "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)) { - std::cerr << ToolName << ": error linking in '" << Filenames[i] << "': " - << ErrorMessage << '\n'; + errs() << ToolName << ": error linking in '" << Filenames[i] << "': " + << ErrorMessage << '\n'; return true; } } } catch (const std::string &Error) { - std::cerr << ToolName << ": error reading input '" << Error << "'\n"; + errs() << ToolName << ": error reading input '" << Error << "'\n"; return true; } if (!run_as_child) - std::cout << "*** All input ok\n"; + outs() << "*** All input ok\n"; // All input files read successfully! return false; @@ -162,7 +173,7 @@ bool BugDriver::run() { // file, then we know the compiler didn't crash, so try to diagnose a // miscompilation. if (!PassesToRun.empty()) { - std::cout << "Running selected passes on program to test for crash: "; + outs() << "Running selected passes on program to test for crash: "; if (runPasses(PassesToRun)) return debugOptimizerCrash(); } @@ -171,12 +182,12 @@ bool BugDriver::run() { if (initializeExecutionEnvironment()) return true; // Test to see if we have a code generator crash. - std::cout << "Running the code generator to test for a crash: "; + outs() << "Running the code generator to test for a crash: "; try { compileProgram(Program); - std::cout << '\n'; + outs() << '\n'; } catch (ToolExecutionError &TEE) { - std::cout << TEE.what(); + outs() << TEE.what(); return debugCodeGeneratorCrash(); } @@ -187,7 +198,7 @@ bool BugDriver::run() { // bool CreatedOutput = false; if (ReferenceOutputFile.empty()) { - std::cout << "Generating reference output from raw program: "; + outs() << "Generating reference output from raw program: "; if(!createReferenceFile(Program)){ return debugCodeGeneratorCrash(); } @@ -197,28 +208,28 @@ bool BugDriver::run() { // Make sure the reference output file gets deleted on exit from this // function, if appropriate. sys::Path ROF(ReferenceOutputFile); - FileRemover RemoverInstance(ROF, CreatedOutput); + FileRemover RemoverInstance(ROF, CreatedOutput && !SaveTemps); // Diff the output of the raw program against the reference output. If it // matches, then we assume there is a miscompilation bug and try to // diagnose it. - std::cout << "*** Checking the code generator...\n"; + outs() << "*** Checking the code generator...\n"; try { if (!diffProgram()) { - std::cout << "\n*** Debugging miscompilation!\n"; + outs() << "\n*** Output matches: Debugging miscompilation!\n"; return debugMiscompilation(); } } catch (ToolExecutionError &TEE) { - std::cerr << TEE.what(); + errs() << TEE.what(); return debugCodeGeneratorCrash(); } - std::cout << "\n*** Input program does not match reference diff!\n"; - std::cout << "Debugging code generator problem!\n"; + outs() << "\n*** Input program does not match reference diff!\n"; + outs() << "Debugging code generator problem!\n"; try { return debugCodeGenerator(); } catch (ToolExecutionError &TEE) { - std::cerr << TEE.what(); + errs() << TEE.what(); return debugCodeGeneratorCrash(); } } @@ -227,18 +238,18 @@ void llvm::PrintFunctionList(const std::vector<Function*> &Funcs) { unsigned NumPrint = Funcs.size(); if (NumPrint > 10) NumPrint = 10; for (unsigned i = 0; i != NumPrint; ++i) - std::cout << " " << Funcs[i]->getName(); + outs() << " " << Funcs[i]->getName(); if (NumPrint < Funcs.size()) - std::cout << "... <" << Funcs.size() << " total>"; - std::cout << std::flush; + outs() << "... <" << Funcs.size() << " total>"; + outs().flush(); } void llvm::PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs) { unsigned NumPrint = GVs.size(); if (NumPrint > 10) NumPrint = 10; for (unsigned i = 0; i != NumPrint; ++i) - std::cout << " " << GVs[i]->getName(); + outs() << " " << GVs[i]->getName(); if (NumPrint < GVs.size()) - std::cout << "... <" << GVs.size() << " total>"; - std::cout << std::flush; + outs() << "... <" << GVs.size() << " total>"; + outs().flush(); } diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index d637c24..db35c85 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -44,7 +44,7 @@ extern bool BugpointIsInterrupted; class BugDriver { LLVMContext& Context; - const std::string ToolName; // Name of bugpoint + 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; @@ -64,7 +64,7 @@ public: BugDriver(const char *toolname, bool as_child, bool find_bugs, unsigned timeout, unsigned memlimit, LLVMContext& ctxt); - const std::string &getToolName() const { return ToolName; } + const char *getToolName() const { return ToolName; } LLVMContext& getContext() { return Context; } @@ -248,7 +248,7 @@ public: /// optimizations fail for some reason (optimizer crashes), return true, /// otherwise return false. If DeleteOutput is set to true, the bitcode is /// deleted on success, and the filename string is undefined. This prints to - /// cout a single line message indicating whether compilation was successful + /// outs() a single line message indicating whether compilation was successful /// or failed, unless Quiet is set. ExtraArgs specifies additional arguments /// to pass to the child bugpoint instance. /// diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index 9697b34..b348a08 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -28,7 +28,6 @@ #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/CommandLine.h" -#include <fstream> #include <set> using namespace llvm; @@ -64,8 +63,8 @@ ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, sys::Path PrefixOutput; Module *OrigProgram = 0; if (!Prefix.empty()) { - std::cout << "Checking to see if these passes crash: " - << getPassesString(Prefix) << ": "; + outs() << "Checking to see if these passes crash: " + << getPassesString(Prefix) << ": "; std::string PfxOutput; if (BD.runPasses(Prefix, PfxOutput)) return KeepPrefix; @@ -73,17 +72,17 @@ ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, PrefixOutput.set(PfxOutput); OrigProgram = BD.Program; - BD.Program = ParseInputFile(PrefixOutput.toString(), BD.getContext()); + BD.Program = ParseInputFile(PrefixOutput.str(), BD.getContext()); if (BD.Program == 0) { - std::cerr << BD.getToolName() << ": Error reading bitcode file '" - << PrefixOutput << "'!\n"; + errs() << BD.getToolName() << ": Error reading bitcode file '" + << PrefixOutput.str() << "'!\n"; exit(1); } PrefixOutput.eraseFromDisk(); } - std::cout << "Checking to see if these passes crash: " - << getPassesString(Suffix) << ": "; + outs() << "Checking to see if these passes crash: " + << getPassesString(Suffix) << ": "; if (BD.runPasses(Suffix)) { delete OrigProgram; // The suffix crashes alone... @@ -142,9 +141,9 @@ ReduceCrashingGlobalVariables::TestGlobalVariables( GVSet.insert(CMGV); } - std::cout << "Checking for crash with only these global variables: "; + outs() << "Checking for crash with only these global variables: "; PrintGlobalVariableList(GVs); - std::cout << ": "; + outs() << ": "; // Loop over and delete any global variables which we aren't supposed to be // playing with... @@ -216,9 +215,9 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { Functions.insert(CMF); } - std::cout << "Checking for crash with only these functions: "; + outs() << "Checking for crash with only these functions: "; PrintFunctionList(Funcs); - std::cout << ": "; + outs() << ": "; // Loop over and delete any functions which we aren't supposed to be playing // with... @@ -276,14 +275,14 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { for (unsigned i = 0, e = BBs.size(); i != e; ++i) Blocks.insert(cast<BasicBlock>(ValueMap[BBs[i]])); - std::cout << "Checking for crash with only these blocks:"; + outs() << "Checking for crash with only these blocks:"; unsigned NumPrint = Blocks.size(); if (NumPrint > 10) NumPrint = 10; for (unsigned i = 0, e = NumPrint; i != e; ++i) - std::cout << " " << BBs[i]->getName(); + outs() << " " << BBs[i]->getName(); if (NumPrint < Blocks.size()) - std::cout << "... <" << Blocks.size() << " total>"; - std::cout << ": "; + outs() << "... <" << Blocks.size() << " total>"; + outs() << ": "; // Loop over and delete any hack up any blocks that are not listed... for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) @@ -298,12 +297,13 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { if (isa<StructType>(BBTerm->getType())) BBTerm->replaceAllUsesWith(UndefValue::get(BBTerm->getType())); - else if (BB->getTerminator()->getType() != Type::VoidTy) + else if (BB->getTerminator()->getType() != + Type::getVoidTy(BB->getContext())) BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType())); // Replace the old terminator instruction. BB->getInstList().pop_back(); - new UnreachableInst(BB); + new UnreachableInst(BB->getContext(), BB); } // The CFG Simplifier pass may delete one of the basic blocks we are @@ -333,7 +333,7 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) { ValueSymbolTable &ST = BlockInfo[i].first->getValueSymbolTable(); Value* V = ST.lookup(BlockInfo[i].second); - if (V && V->getType() == Type::LabelTy) + if (V && V->getType() == Type::getLabelTy(V->getContext())) BBs.push_back(cast<BasicBlock>(V)); } return true; @@ -380,18 +380,18 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> Instructions.insert(cast<Instruction>(ValueMap[Insts[i]])); } - std::cout << "Checking for crash with only " << Instructions.size(); + outs() << "Checking for crash with only " << Instructions.size(); if (Instructions.size() == 1) - std::cout << " instruction: "; + outs() << " instruction: "; else - std::cout << " instructions: "; + outs() << " instructions: "; for (Module::iterator MI = M->begin(), ME = M->end(); MI != ME; ++MI) for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI) for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) { Instruction *Inst = I++; if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst)) { - if (Inst->getType() != Type::VoidTy) + if (Inst->getType() != Type::getVoidTy(Inst->getContext())) Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); Inst->eraseFromParent(); } @@ -443,13 +443,13 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { delete M; // No change made... } else { // See if the program still causes a crash... - std::cout << "\nChecking to see if we can delete global inits: "; + outs() << "\nChecking to see if we can delete global inits: "; if (TestFn(BD, M)) { // Still crashes? BD.setNewProgram(M); - std::cout << "\n*** Able to remove all global initializers!\n"; + outs() << "\n*** Able to remove all global initializers!\n"; } else { // No longer crashes? - std::cout << " - Removing all global inits hides problem!\n"; + outs() << " - Removing all global inits hides problem!\n"; delete M; std::vector<GlobalVariable*> GVs; @@ -460,7 +460,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { GVs.push_back(I); if (GVs.size() > 1 && !BugpointIsInterrupted) { - std::cout << "\n*** Attempting to reduce the number of global " + outs() << "\n*** Attempting to reduce the number of global " << "variables in the testcase\n"; unsigned OldSize = GVs.size(); @@ -481,7 +481,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { Functions.push_back(I); if (Functions.size() > 1 && !BugpointIsInterrupted) { - std::cout << "\n*** Attempting to reduce the number of functions " + outs() << "\n*** Attempting to reduce the number of functions " "in the testcase\n"; unsigned OldSize = Functions.size(); @@ -530,8 +530,8 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { do { if (BugpointIsInterrupted) break; --Simplification; - std::cout << "\n*** Attempting to reduce testcase by deleting instruc" - << "tions: Simplification Level #" << Simplification << '\n'; + outs() << "\n*** Attempting to reduce testcase by deleting instruc" + << "tions: Simplification Level #" << Simplification << '\n'; // Now that we have deleted the functions that are unnecessary for the // program, try to remove instructions that are not necessary to cause the @@ -559,7 +559,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { } else { if (BugpointIsInterrupted) goto ExitLoops; - std::cout << "Checking instruction: " << *I; + outs() << "Checking instruction: " << *I; Module *M = BD.deleteInstructionFromProgram(I, Simplification); // Find out if the pass still crashes on this pass... @@ -586,7 +586,7 @@ ExitLoops: // Try to clean up the testcase by running funcresolve and globaldce... if (!BugpointIsInterrupted) { - std::cout << "\n*** Attempting to perform final cleanups: "; + outs() << "\n*** Attempting to perform final cleanups: "; Module *M = CloneModule(BD.getProgram()); M = BD.performFinalCleanups(M, true); @@ -612,15 +612,15 @@ static bool TestForOptimizerCrash(BugDriver &BD, Module *M) { /// out exactly which pass is crashing. /// bool BugDriver::debugOptimizerCrash(const std::string &ID) { - std::cout << "\n*** Debugging optimizer crash!\n"; + outs() << "\n*** Debugging optimizer crash!\n"; // Reduce the list of passes which causes the optimizer to crash... if (!BugpointIsInterrupted) ReducePassList(*this).reduceList(PassesToRun); - std::cout << "\n*** Found crashing pass" - << (PassesToRun.size() == 1 ? ": " : "es: ") - << getPassesString(PassesToRun) << '\n'; + outs() << "\n*** Found crashing pass" + << (PassesToRun.size() == 1 ? ": " : "es: ") + << getPassesString(PassesToRun) << '\n'; EmitProgressBitcode(ID); @@ -630,10 +630,10 @@ bool BugDriver::debugOptimizerCrash(const std::string &ID) { static bool TestForCodeGenCrash(BugDriver &BD, Module *M) { try { BD.compileProgram(M); - std::cerr << '\n'; + errs() << '\n'; return false; } catch (ToolExecutionError &) { - std::cerr << "<crash>\n"; + errs() << "<crash>\n"; return true; // Tool is still crashing. } } @@ -642,7 +642,7 @@ static bool TestForCodeGenCrash(BugDriver &BD, Module *M) { /// crashes on an input. It attempts to reduce the input as much as possible /// while still causing the code generator to crash. bool BugDriver::debugCodeGeneratorCrash() { - std::cerr << "*** Debugging code generator crash!\n"; + errs() << "*** Debugging code generator crash!\n"; return DebugACrash(*this, TestForCodeGenCrash); } diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index 640fe28..feda331 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -18,8 +18,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/SystemUtils.h" +#include "llvm/Support/raw_ostream.h" #include <fstream> -#include <iostream> using namespace llvm; @@ -56,19 +56,19 @@ namespace { cl::opt<OutputType> SafeInterpreterSel(cl::desc("Specify \"safe\" i.e. known-good backend:"), - cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"), - clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"), - clEnumValN(RunCBE, "safe-run-cbe", "Compile with CBE"), - clEnumValN(Custom, "safe-run-custom", - "Use -exec-command to define a command to execute " - "the bitcode. Useful for cross-compilation."), - clEnumValEnd), + cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"), + clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"), + clEnumValN(RunCBE, "safe-run-cbe", "Compile with CBE"), + clEnumValN(Custom, "safe-run-custom", + "Use -exec-command to define a command to execute " + "the bitcode. Useful for cross-compilation."), + clEnumValEnd), cl::init(AutoPick)); cl::opt<std::string> SafeInterpreterPath("safe-path", - cl::desc("Specify the path to the \"safe\" backend program"), - cl::init("")); + cl::desc("Specify the path to the \"safe\" backend program"), + cl::init("")); cl::opt<bool> AppendProgramExitCode("append-exit-code", @@ -100,6 +100,10 @@ namespace llvm { cl::list<std::string> InputArgv("args", cl::Positional, cl::desc("<program arguments>..."), cl::ZeroOrMore, cl::PositionalEatsArgs); + + cl::opt<std::string> + OutputPrefix("output-prefix", cl::init("bugpoint"), + cl::desc("Prefix to use for outputs (default: 'bugpoint')")); } namespace { @@ -126,7 +130,7 @@ namespace { /// environment for executing LLVM programs. /// bool BugDriver::initializeExecutionEnvironment() { - std::cout << "Initializing execution environment: "; + outs() << "Initializing execution environment: "; // Create an instance of the AbstractInterpreter interface as specified on // the command line @@ -178,17 +182,16 @@ bool BugDriver::initializeExecutionEnvironment() { &ToolArgv, &GCCToolArgv); break; case Custom: - Interpreter = AbstractInterpreter::createCustom(getToolName(), Message, - CustomExecCommand); + Interpreter = AbstractInterpreter::createCustom(Message, CustomExecCommand); break; default: Message = "Sorry, this back-end is not supported by bugpoint right now!\n"; break; } if (!Interpreter) - std::cerr << Message; + errs() << Message; else // Display informational messages on stdout instead of stderr - std::cout << Message; + outs() << Message; std::string Path = SafeInterpreterPath; if (Path.empty()) @@ -201,7 +204,7 @@ bool BugDriver::initializeExecutionEnvironment() { InterpreterSel == CBE_bug) { SafeInterpreterSel = RunLLC; SafeToolArgs.push_back("--relocation-model=pic"); - SafeInterpreter = AbstractInterpreter::createLLC(Path, Message, + SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, &SafeToolArgs, &GCCToolArgv); } @@ -211,7 +214,7 @@ bool BugDriver::initializeExecutionEnvironment() { InterpreterSel == LLC_Safe) { SafeInterpreterSel = RunLLC; SafeToolArgs.push_back("--relocation-model=pic"); - SafeInterpreter = AbstractInterpreter::createLLC(Path, Message, + SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, &SafeToolArgs, &GCCToolArgv); } @@ -222,7 +225,7 @@ bool BugDriver::initializeExecutionEnvironment() { if (!SafeInterpreter && InterpreterSel != RunCBE) { SafeInterpreterSel = RunCBE; - SafeInterpreter = AbstractInterpreter::createCBE(Path, Message, + SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message, &SafeToolArgs, &GCCToolArgv); } @@ -231,7 +234,7 @@ bool BugDriver::initializeExecutionEnvironment() { InterpreterSel != RunJIT) { SafeInterpreterSel = RunLLC; SafeToolArgs.push_back("--relocation-model=pic"); - SafeInterpreter = AbstractInterpreter::createLLC(Path, Message, + SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, &SafeToolArgs, &GCCToolArgv); } @@ -242,17 +245,17 @@ bool BugDriver::initializeExecutionEnvironment() { break; case RunLLC: SafeToolArgs.push_back("--relocation-model=pic"); - SafeInterpreter = AbstractInterpreter::createLLC(Path, Message, + SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, &SafeToolArgs, &GCCToolArgv); break; case RunCBE: - SafeInterpreter = AbstractInterpreter::createCBE(Path, Message, + SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message, &SafeToolArgs, &GCCToolArgv); break; case Custom: - SafeInterpreter = AbstractInterpreter::createCustom(Path, Message, + SafeInterpreter = AbstractInterpreter::createCustom(Message, CustomExecCommand); break; default: @@ -260,10 +263,10 @@ bool BugDriver::initializeExecutionEnvironment() { "\"safe\" backend right now!\n"; break; } - if (!SafeInterpreter) { std::cout << Message << "\nExiting.\n"; exit(1); } + if (!SafeInterpreter) { outs() << Message << "\nExiting.\n"; exit(1); } - gcc = GCC::create(getToolName(), Message, &GCCToolArgv); - if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); } + gcc = GCC::create(Message, &GCCToolArgv); + if (!gcc) { outs() << Message << "\nExiting.\n"; exit(1); } // If there was an error creating the selected interpreter, quit with error. return Interpreter == 0; @@ -275,24 +278,24 @@ bool BugDriver::initializeExecutionEnvironment() { /// void BugDriver::compileProgram(Module *M) { // Emit the program to a bitcode file... - sys::Path BitcodeFile ("bugpoint-test-program.bc"); + sys::Path BitcodeFile (OutputPrefix + "-test-program.bc"); std::string ErrMsg; if (BitcodeFile.makeUnique(true,&ErrMsg)) { - std::cerr << ToolName << ": Error making unique filename: " << ErrMsg - << "\n"; + errs() << ToolName << ": Error making unique filename: " << ErrMsg + << "\n"; exit(1); } - if (writeProgramToFile(BitcodeFile.toString(), M)) { - std::cerr << ToolName << ": Error emitting bitcode to file '" - << BitcodeFile << "'!\n"; + if (writeProgramToFile(BitcodeFile.str(), M)) { + errs() << ToolName << ": Error emitting bitcode to file '" + << BitcodeFile.str() << "'!\n"; exit(1); } // Remove the temporary bitcode file when we are done. - FileRemover BitcodeFileRemover(BitcodeFile); + FileRemover BitcodeFileRemover(BitcodeFile, !SaveTemps); // Actually compile the program! - Interpreter->compileProgram(BitcodeFile.toString()); + Interpreter->compileProgram(BitcodeFile.str()); } @@ -311,17 +314,17 @@ std::string BugDriver::executeProgram(std::string OutputFile, std::string ErrMsg; if (BitcodeFile.empty()) { // Emit the program to a bitcode file... - sys::Path uniqueFilename("bugpoint-test-program.bc"); + sys::Path uniqueFilename(OutputPrefix + "-test-program.bc"); if (uniqueFilename.makeUnique(true, &ErrMsg)) { - std::cerr << ToolName << ": Error making unique filename: " - << ErrMsg << "!\n"; + errs() << ToolName << ": Error making unique filename: " + << ErrMsg << "!\n"; exit(1); } - BitcodeFile = uniqueFilename.toString(); + BitcodeFile = uniqueFilename.str(); if (writeProgramToFile(BitcodeFile, Program)) { - std::cerr << ToolName << ": Error emitting bitcode to file '" - << BitcodeFile << "'!\n"; + errs() << ToolName << ": Error emitting bitcode to file '" + << BitcodeFile << "'!\n"; exit(1); } CreatedBitcode = true; @@ -329,18 +332,18 @@ std::string BugDriver::executeProgram(std::string OutputFile, // Remove the temporary bitcode file when we are done. sys::Path BitcodePath (BitcodeFile); - FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode); + FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps); - if (OutputFile.empty()) OutputFile = "bugpoint-execution-output"; + if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output"; // Check to see if this is a valid output filename... sys::Path uniqueFile(OutputFile); if (uniqueFile.makeUnique(true, &ErrMsg)) { - std::cerr << ToolName << ": Error making unique filename: " - << ErrMsg << "\n"; + errs() << ToolName << ": Error making unique filename: " + << ErrMsg << "\n"; exit(1); } - OutputFile = uniqueFile.toString(); + OutputFile = uniqueFile.str(); // Figure out which shared objects to run, if any. std::vector<std::string> SharedObjs(AdditionalSOs); @@ -352,10 +355,10 @@ std::string BugDriver::executeProgram(std::string OutputFile, Timeout, MemoryLimit); if (RetVal == -1) { - std::cerr << "<timeout>"; + errs() << "<timeout>"; static bool FirstTimeout = true; if (FirstTimeout) { - std::cout << "\n" + outs() << "\n" "*** Program execution timed out! This mechanism is designed to handle\n" " programs stuck in infinite loops gracefully. The -timeout option\n" " can be used to change the timeout threshold or disable it completely\n" @@ -395,7 +398,7 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile) { GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile); std::string SharedObjectFile; - if (gcc->MakeSharedObject(OutputFile.toString(), FT, + if (gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile, AdditionalLinkerArgs)) exit(1); @@ -418,14 +421,14 @@ bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { } try { ReferenceOutputFile = executeProgramSafely(Filename); - std::cout << "\nReference output is: " << ReferenceOutputFile << "\n\n"; + outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n"; } catch (ToolExecutionError &TEE) { - std::cerr << TEE.what(); + errs() << TEE.what(); if (Interpreter != SafeInterpreter) { - std::cerr << "*** There is a bug running the \"safe\" backend. Either" - << " debug it (for example with the -run-cbe bugpoint option," - << " if CBE is being used as the \"safe\" backend), or fix the" - << " error some other way.\n"; + errs() << "*** There is a bug running the \"safe\" backend. Either" + << " debug it (for example with the -run-cbe bugpoint option," + << " if CBE is being used as the \"safe\" backend), or fix the" + << " error some other way.\n"; } return false; } @@ -449,17 +452,18 @@ bool BugDriver::diffProgram(const std::string &BitcodeFile, std::string Error; bool FilesDifferent = false; if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile), - sys::Path(Output.toString()), + sys::Path(Output.str()), AbsTolerance, RelTolerance, &Error)) { if (Diff == 2) { - std::cerr << "While diffing output: " << Error << '\n'; + errs() << "While diffing output: " << Error << '\n'; exit(1); } FilesDifferent = true; } - - // Remove the generated output. - Output.eraseFromDisk(); + else { + // Remove the generated output if there are no differences. + Output.eraseFromDisk(); + } // Remove the bitcode file if we are supposed to. if (RemoveBitcode) diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index e4affbb..918d6a6a 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -15,10 +15,12 @@ #include "BugDriver.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" +#include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Pass.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Assembly/Writer.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/Cloning.h" @@ -27,15 +29,15 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/System/Signals.h" #include <set> -#include <fstream> -#include <iostream> using namespace llvm; namespace llvm { bool DisableSimplifyCFG = false; + extern cl::opt<std::string> OutputPrefix; } // End llvm namespace namespace { @@ -73,7 +75,7 @@ Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, // If this instruction produces a value, replace any users with null values if (isa<StructType>(TheInst->getType())) TheInst->replaceAllUsesWith(UndefValue::get(TheInst->getType())); - else if (TheInst->getType() != Type::VoidTy) + else if (TheInst->getType() != Type::getVoidTy(I->getContext())) TheInst->replaceAllUsesWith(Constant::getNullValue(TheInst->getType())); // Remove the instruction from the program. @@ -125,7 +127,7 @@ Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) { Module *New = runPassesOn(M, CleanupPasses); if (New == 0) { - std::cerr << "Final cleanups failed. Sorry. :( Please report a bug!\n"; + errs() << "Final cleanups failed. Sorry. :( Please report a bug!\n"; return M; } delete M; @@ -143,9 +145,9 @@ Module *BugDriver::ExtractLoop(Module *M) { Module *NewM = runPassesOn(M, LoopExtractPasses); if (NewM == 0) { Module *Old = swapProgramIn(M); - std::cout << "*** Loop extraction failed: "; + outs() << "*** Loop extraction failed: "; EmitProgressBitcode("loopextraction", true); - std::cout << "*** Sorry. :( Please report a bug!\n"; + outs() << "*** Sorry. :( Please report a bug!\n"; swapProgramIn(Old); return 0; } @@ -184,9 +186,11 @@ static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) { std::vector<Constant*> ArrayElts; for (unsigned i = 0, e = TorList.size(); i != e; ++i) { std::vector<Constant*> Elts; - Elts.push_back(ConstantInt::get(Type::Int32Ty, TorList[i].second)); + Elts.push_back(ConstantInt::get( + Type::getInt32Ty(TorList[i].first->getContext()), TorList[i].second)); Elts.push_back(TorList[i].first); - ArrayElts.push_back(ConstantStruct::get(Elts)); + ArrayElts.push_back(ConstantStruct::get(TorList[i].first->getContext(), + Elts, false)); } return ConstantArray::get(ArrayType::get(ArrayElts[0]->getType(), ArrayElts.size()), @@ -236,8 +240,9 @@ static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2, GV->eraseFromParent(); if (!M1Tors.empty()) { Constant *M1Init = GetTorInit(M1Tors); - new GlobalVariable(M1Init->getType(), false, GlobalValue::AppendingLinkage, - M1Init, GlobalName, M1); + new GlobalVariable(*M1, M1Init->getType(), false, + GlobalValue::AppendingLinkage, + M1Init, GlobalName); } GV = M2->getNamedGlobal(GlobalName); @@ -247,8 +252,9 @@ static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2, GV->eraseFromParent(); if (!M2Tors.empty()) { Constant *M2Init = GetTorInit(M2Tors); - new GlobalVariable(M2Init->getType(), false, GlobalValue::AppendingLinkage, - M2Init, GlobalName, M2); + new GlobalVariable(*M2, M2Init->getType(), false, + GlobalValue::AppendingLinkage, + M2Init, GlobalName); } } @@ -266,8 +272,8 @@ llvm::SplitFunctionsOutOfModule(Module *M, I->setLinkage(GlobalValue::ExternalLinkage); for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) { - if (I->hasName() && *I->getNameStart() == '\01') - I->setName(I->getNameStart()+1, I->getNameLen()-1); + if (I->hasName() && I->getName()[0] == '\01') + I->setName(I->getName().substr(1)); I->setLinkage(GlobalValue::ExternalLinkage); } @@ -283,9 +289,9 @@ llvm::SplitFunctionsOutOfModule(Module *M, std::set<Function *> TestFunctions; for (unsigned i = 0, e = F.size(); i != e; ++i) { Function *TNOF = cast<Function>(ValueMap[F[i]]); - DEBUG(std::cerr << "Removing function "); - DEBUG(WriteAsOperand(std::cerr, TNOF, false)); - DEBUG(std::cerr << "\n"); + DEBUG(errs() << "Removing function "); + DEBUG(WriteAsOperand(errs(), TNOF, false)); + DEBUG(errs() << "\n"); TestFunctions.insert(cast<Function>(NewValueMap[TNOF])); DeleteFunctionBody(TNOF); // Function is now external in this module! } @@ -319,11 +325,11 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const Module *M) { char *ExtraArg = NULL; - sys::Path uniqueFilename("bugpoint-extractblocks"); + sys::Path uniqueFilename(OutputPrefix + "-extractblocks"); std::string ErrMsg; if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) { - std::cout << "*** Basic Block extraction failed!\n"; - std::cerr << "Error creating temporary file: " << ErrMsg << "\n"; + outs() << "*** Basic Block extraction failed!\n"; + errs() << "Error creating temporary file: " << ErrMsg << "\n"; M = swapProgramIn(M); EmitProgressBitcode("basicblockextractfail", true); swapProgramIn(M); @@ -331,11 +337,12 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const } sys::RemoveFileOnSignal(uniqueFilename); - std::ofstream BlocksToNotExtractFile(uniqueFilename.c_str()); - if (!BlocksToNotExtractFile) { - std::cout << "*** Basic Block extraction failed!\n"; - std::cerr << "Error writing list of blocks to not extract: " << ErrMsg - << "\n"; + std::string ErrorInfo; + raw_fd_ostream BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) { + outs() << "*** Basic Block extraction failed!\n"; + errs() << "Error writing list of blocks to not extract: " << ErrorInfo + << "\n"; M = swapProgramIn(M); EmitProgressBitcode("basicblockextractfail", true); swapProgramIn(M); @@ -347,7 +354,7 @@ 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()->getName() << " " + BlocksToNotExtractFile << BB->getParent()->getNameStr() << " " << BB->getName() << "\n"; } BlocksToNotExtractFile.close(); @@ -366,7 +373,7 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const free(ExtraArg); if (Ret == 0) { - std::cout << "*** Basic Block extraction failed, please report a bug!\n"; + outs() << "*** Basic Block extraction failed, please report a bug!\n"; M = swapProgramIn(M); EmitProgressBitcode("basicblockextractfail", true); swapProgramIn(M); diff --git a/tools/bugpoint/FindBugs.cpp b/tools/bugpoint/FindBugs.cpp index e42cce4..2c11d29 100644 --- a/tools/bugpoint/FindBugs.cpp +++ b/tools/bugpoint/FindBugs.cpp @@ -17,9 +17,9 @@ #include "BugDriver.h" #include "ToolRunner.h" #include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <ctime> -#include <iostream> using namespace llvm; /// runManyPasses - Take the specified pass list and create different @@ -31,14 +31,14 @@ using namespace llvm; /// bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses) { setPassesToRun(AllPasses); - std::cout << "Starting bug finding procedure...\n\n"; + outs() << "Starting bug finding procedure...\n\n"; // Creating a reference output if necessary if (initializeExecutionEnvironment()) return false; - std::cout << "\n"; + outs() << "\n"; if (ReferenceOutputFile.empty()) { - std::cout << "Generating reference output from raw program: \n"; + outs() << "Generating reference output from raw program: \n"; if (!createReferenceFile(Program)) return false; } @@ -55,31 +55,31 @@ bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses) { // // Step 2: Run optimizer passes on the program and check for success. // - std::cout << "Running selected passes on program to test for crash: "; + outs() << "Running selected passes on program to test for crash: "; for(int i = 0, e = PassesToRun.size(); i != e; i++) { - std::cout << "-" << PassesToRun[i]->getPassArgument( )<< " "; + outs() << "-" << PassesToRun[i]->getPassArgument( )<< " "; } std::string Filename; if(runPasses(PassesToRun, Filename, false)) { - std::cout << "\n"; - std::cout << "Optimizer passes caused failure!\n\n"; + outs() << "\n"; + outs() << "Optimizer passes caused failure!\n\n"; debugOptimizerCrash(); return true; } else { - std::cout << "Combination " << num << " optimized successfully!\n"; + outs() << "Combination " << num << " optimized successfully!\n"; } // // Step 3: Compile the optimized code. // - std::cout << "Running the code generator to test for a crash: "; + outs() << "Running the code generator to test for a crash: "; try { compileProgram(Program); - std::cout << '\n'; + outs() << '\n'; } catch (ToolExecutionError &TEE) { - std::cout << "\n*** compileProgram threw an exception: "; - std::cout << TEE.what(); + outs() << "\n*** compileProgram threw an exception: "; + outs() << TEE.what(); return debugCodeGeneratorCrash(); } @@ -87,24 +87,24 @@ bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses) { // Step 4: Run the program and compare its output to the reference // output (created above). // - std::cout << "*** Checking if passes caused miscompliation:\n"; + outs() << "*** Checking if passes caused miscompliation:\n"; try { if (diffProgram(Filename, "", false)) { - std::cout << "\n*** diffProgram returned true!\n"; + outs() << "\n*** diffProgram returned true!\n"; debugMiscompilation(); return true; } else { - std::cout << "\n*** diff'd output matches!\n"; + outs() << "\n*** diff'd output matches!\n"; } } catch (ToolExecutionError &TEE) { - std::cerr << TEE.what(); + errs() << TEE.what(); debugCodeGeneratorCrash(); return true; } sys::Path(Filename).eraseFromDisk(); - std::cout << "\n\n"; + outs() << "\n\n"; num++; } //end while diff --git a/tools/bugpoint/ListReducer.h b/tools/bugpoint/ListReducer.h index de3f389..8036d1f 100644 --- a/tools/bugpoint/ListReducer.h +++ b/tools/bugpoint/ListReducer.h @@ -15,8 +15,8 @@ #ifndef BUGPOINT_LIST_REDUCER_H #define BUGPOINT_LIST_REDUCER_H +#include "llvm/Support/raw_ostream.h" #include <vector> -#include <iostream> #include <cstdlib> #include <algorithm> @@ -58,7 +58,7 @@ struct ListReducer { case KeepSuffix: // cannot be reached! - std::cerr << "bugpoint ListReducer internal error: selected empty set.\n"; + errs() << "bugpoint ListReducer internal error: selected empty set.\n"; abort(); case NoFailure: @@ -77,7 +77,7 @@ Backjump: while (MidTop > 1) { // Binary split reduction loop // Halt if the user presses ctrl-c. if (BugpointIsInterrupted) { - std::cerr << "\n\n*** Reduction Interrupted, cleaning up...\n\n"; + errs() << "\n\n*** Reduction Interrupted, cleaning up...\n\n"; return true; } @@ -88,7 +88,7 @@ Backjump: NumOfIterationsWithoutProgress > MaxIterations) { std::vector<ElTy> ShuffledList(TheList); std::random_shuffle(ShuffledList.begin(), ShuffledList.end()); - std::cerr << "\n\n*** Testing shuffled set...\n\n"; + errs() << "\n\n*** Testing shuffled set...\n\n"; // Check that random shuffle doesn't loose the bug if (doTest(ShuffledList, empty) == KeepPrefix) { // If the bug is still here, use the shuffled list. @@ -97,10 +97,10 @@ Backjump: // Must increase the shuffling treshold to avoid the small // probability of inifinite looping without making progress. MaxIterations += 2; - std::cerr << "\n\n*** Shuffling does not hide the bug...\n\n"; + errs() << "\n\n*** Shuffling does not hide the bug...\n\n"; } else { ShufflingEnabled = false; // Disable shuffling further on - std::cerr << "\n\n*** Shuffling hides the bug...\n\n"; + errs() << "\n\n*** Shuffling hides the bug...\n\n"; } NumOfIterationsWithoutProgress = 0; } @@ -160,7 +160,7 @@ Backjump: for (unsigned i = 1; i < TheList.size()-1; ++i) { // Check interior elts if (BugpointIsInterrupted) { - std::cerr << "\n\n*** Reduction Interrupted, cleaning up...\n\n"; + errs() << "\n\n*** Reduction Interrupted, cleaning up...\n\n"; return true; } diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index b3260e1..a591417 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -14,6 +14,7 @@ #include "BugDriver.h" #include "ListReducer.h" +#include "ToolRunner.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Instructions.h" @@ -29,6 +30,7 @@ using namespace llvm; namespace llvm { + extern cl::opt<std::string> OutputPrefix; extern cl::list<std::string> InputArgv; } @@ -37,6 +39,10 @@ namespace { DisableLoopExtraction("disable-loop-extraction", cl::desc("Don't extract loops when searching for miscompilations"), cl::init(false)); + static llvm::cl::opt<bool> + DisableBlockExtraction("disable-block-extraction", + cl::desc("Don't extract blocks when searching for miscompilations"), + cl::init(false)); class ReduceMiscompilingPasses : public ListReducer<const PassInfo*> { BugDriver &BD; @@ -56,36 +62,36 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, std::vector<const PassInfo*> &Suffix) { // First, run the program with just the Suffix passes. If it is still broken // with JUST the kept passes, discard the prefix passes. - std::cout << "Checking to see if '" << getPassesString(Suffix) - << "' compile correctly: "; + outs() << "Checking to see if '" << getPassesString(Suffix) + << "' compiles correctly: "; std::string BitcodeResult; if (BD.runPasses(Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { - std::cerr << " Error running this sequence of passes" - << " on the input program!\n"; + errs() << " Error running this sequence of passes" + << " on the input program!\n"; BD.setPassesToRun(Suffix); BD.EmitProgressBitcode("pass-error", false); exit(BD.debugOptimizerCrash()); } - + // Check to see if the finished program matches the reference output... if (BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/)) { - std::cout << " nope.\n"; + outs() << " nope.\n"; if (Suffix.empty()) { - std::cerr << BD.getToolName() << ": I'm confused: the test fails when " - << "no passes are run, nondeterministic program?\n"; + errs() << BD.getToolName() << ": I'm confused: the test fails when " + << "no passes are run, nondeterministic program?\n"; exit(1); } return KeepSuffix; // Miscompilation detected! } - std::cout << " yup.\n"; // No miscompilation! + outs() << " yup.\n"; // No miscompilation! if (Prefix.empty()) return NoFailure; // Next, see if the program is broken if we run the "prefix" passes first, // then separately run the "kept" passes. - std::cout << "Checking to see if '" << getPassesString(Prefix) - << "' compile correctly: "; + outs() << "Checking to see if '" << getPassesString(Prefix) + << "' compiles correctly: "; // If it is not broken with the kept passes, it's possible that the prefix // passes must be run before the kept passes to break it. If the program @@ -94,8 +100,8 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, // prefix passes, then discard the prefix passes. // if (BD.runPasses(Prefix, BitcodeResult, false/*delete*/, true/*quiet*/)) { - std::cerr << " Error running this sequence of passes" - << " on the input program!\n"; + errs() << " Error running this sequence of passes" + << " on the input program!\n"; BD.setPassesToRun(Prefix); BD.EmitProgressBitcode("pass-error", false); exit(BD.debugOptimizerCrash()); @@ -103,19 +109,19 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, // If the prefix maintains the predicate by itself, only keep the prefix! if (BD.diffProgram(BitcodeResult)) { - std::cout << " nope.\n"; + outs() << " nope.\n"; sys::Path(BitcodeResult).eraseFromDisk(); return KeepPrefix; } - std::cout << " yup.\n"; // No miscompilation! + outs() << " yup.\n"; // No miscompilation! // Ok, so now we know that the prefix passes work, try running the suffix // passes on the result of the prefix passes. // Module *PrefixOutput = ParseInputFile(BitcodeResult, BD.getContext()); if (PrefixOutput == 0) { - std::cerr << BD.getToolName() << ": Error reading bitcode file '" - << BitcodeResult << "'!\n"; + errs() << BD.getToolName() << ": Error reading bitcode file '" + << BitcodeResult << "'!\n"; exit(1); } sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk @@ -124,14 +130,14 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, if (Suffix.empty()) return NoFailure; - std::cout << "Checking to see if '" << getPassesString(Suffix) + outs() << "Checking to see if '" << getPassesString(Suffix) << "' passes compile correctly after the '" << getPassesString(Prefix) << "' passes: "; Module *OriginalInput = BD.swapProgramIn(PrefixOutput); if (BD.runPasses(Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { - std::cerr << " Error running this sequence of passes" - << " on the input program!\n"; + errs() << " Error running this sequence of passes" + << " on the input program!\n"; BD.setPassesToRun(Suffix); BD.EmitProgressBitcode("pass-error", false); exit(BD.debugOptimizerCrash()); @@ -139,13 +145,13 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, // Run the result... if (BD.diffProgram(BitcodeResult, "", true/*delete bitcode*/)) { - std::cout << " nope.\n"; + outs() << " nope.\n"; delete OriginalInput; // We pruned down the original input... return KeepSuffix; } // Otherwise, we must not be running the bad pass anymore. - std::cout << " yup.\n"; // No miscompilation! + outs() << " yup.\n"; // No miscompilation! delete BD.swapProgramIn(OriginalInput); // Restore orig program & free test return NoFailure; } @@ -187,8 +193,8 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, M2 = CloneModule(M2); } if (Linker::LinkModules(M1, M2, &ErrorMsg)) { - std::cerr << BD.getToolName() << ": Error linking modules together:" - << ErrorMsg << '\n'; + errs() << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << '\n'; exit(1); } delete M2; // We are done with this module. @@ -212,12 +218,12 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*>&Funcs){ // Test to see if the function is misoptimized if we ONLY run it on the // functions listed in Funcs. - std::cout << "Checking to see if the program is misoptimized when " - << (Funcs.size()==1 ? "this function is" : "these functions are") - << " run through the pass" - << (BD.getPassesToRun().size() == 1 ? "" : "es") << ":"; + outs() << "Checking to see if the program is misoptimized when " + << (Funcs.size()==1 ? "this function is" : "these functions are") + << " run through the pass" + << (BD.getPassesToRun().size() == 1 ? "" : "es") << ":"; PrintFunctionList(Funcs); - std::cout << '\n'; + outs() << '\n'; // Split the module into the two halves of the program we want. DenseMap<const Value*, Value*> ValueMap; @@ -241,12 +247,18 @@ static void DisambiguateGlobalSymbols(Module *M) { Mangler Mang(*M); // Agree with the CBE on symbol naming Mang.markCharUnacceptable('.'); - Mang.setPreserveAsmNames(true); for (Module::global_iterator I = M->global_begin(), E = M->global_end(); - I != E; ++I) - I->setName(Mang.getValueName(I)); - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) - I->setName(Mang.getValueName(I)); + I != E; ++I) { + // Don't mangle asm names. + if (!I->hasName() || I->getName()[0] != 1) + I->setName(Mang.getMangledName(I)); + } + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { + // Don't mangle asm names or intrinsics. + if ((!I->hasName() || I->getName()[0] != 1) && + I->getIntrinsicID() == 0) + I->setName(Mang.getMangledName(I)); + } } /// ExtractLoops - Given a reduced list of functions that still exposed the bug, @@ -274,7 +286,7 @@ static bool ExtractLoops(BugDriver &BD, return MadeChange; } - std::cerr << "Extracted a loop from the breaking portion of the program.\n"; + errs() << "Extracted a loop from the breaking portion of the program.\n"; // Bugpoint is intentionally not very trusting of LLVM transformations. In // particular, we're not going to assume that the loop extractor works, so @@ -286,16 +298,19 @@ static bool ExtractLoops(BugDriver &BD, BD.switchToInterpreter(AI); // Merged program doesn't work anymore! - std::cerr << " *** ERROR: Loop extraction broke the program. :(" - << " Please report a bug!\n"; - std::cerr << " Continuing on with un-loop-extracted version.\n"; - - BD.writeProgramToFile("bugpoint-loop-extract-fail-tno.bc", ToNotOptimize); - BD.writeProgramToFile("bugpoint-loop-extract-fail-to.bc", ToOptimize); - BD.writeProgramToFile("bugpoint-loop-extract-fail-to-le.bc", + errs() << " *** ERROR: Loop extraction broke the program. :(" + << " Please report a bug!\n"; + errs() << " Continuing on with un-loop-extracted version.\n"; + + BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-tno.bc", + ToNotOptimize); + BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to.bc", + ToOptimize); + BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc", ToOptimizeLoopExtracted); - std::cerr << "Please submit the bugpoint-loop-extract-fail-*.bc files.\n"; + errs() << "Please submit the " + << OutputPrefix << "-loop-extract-fail-*.bc files.\n"; delete ToOptimize; delete ToNotOptimize; delete ToOptimizeLoopExtracted; @@ -304,12 +319,12 @@ static bool ExtractLoops(BugDriver &BD, delete ToOptimize; BD.switchToInterpreter(AI); - std::cout << " Testing after loop extraction:\n"; + outs() << " Testing after loop extraction:\n"; // Clone modules, the tester function will free them. Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); Module *TNOBackup = CloneModule(ToNotOptimize); if (!TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize)) { - std::cout << "*** Loop extraction masked the problem. Undoing.\n"; + outs() << "*** Loop extraction masked the problem. Undoing.\n"; // If the program is not still broken, then loop extraction did something // that masked the error. Stop loop extraction now. delete TOLEBackup; @@ -319,7 +334,7 @@ static bool ExtractLoops(BugDriver &BD, ToOptimizeLoopExtracted = TOLEBackup; ToNotOptimize = TNOBackup; - std::cout << "*** Loop extraction successful!\n"; + outs() << "*** Loop extraction successful!\n"; std::vector<std::pair<std::string, const FunctionType*> > MisCompFunctions; for (Module::iterator I = ToOptimizeLoopExtracted->begin(), @@ -334,8 +349,8 @@ static bool ExtractLoops(BugDriver &BD, // extract another loop. std::string ErrorMsg; if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, &ErrorMsg)){ - std::cerr << BD.getToolName() << ": Error linking modules together:" - << ErrorMsg << '\n'; + errs() << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << '\n'; exit(1); } delete ToOptimizeLoopExtracted; @@ -388,16 +403,16 @@ namespace { bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs) { // Test to see if the function is misoptimized if we ONLY run it on the // functions listed in Funcs. - std::cout << "Checking to see if the program is misoptimized when all "; + outs() << "Checking to see if the program is misoptimized when all "; if (!BBs.empty()) { - std::cout << "but these " << BBs.size() << " blocks are extracted: "; + outs() << "but these " << BBs.size() << " blocks are extracted: "; for (unsigned i = 0, e = BBs.size() < 10 ? BBs.size() : 10; i != e; ++i) - std::cout << BBs[i]->getName() << " "; - if (BBs.size() > 10) std::cout << "..."; + outs() << BBs[i]->getName() << " "; + if (BBs.size() > 10) outs() << "..."; } else { - std::cout << "blocks are extracted."; + outs() << "blocks are extracted."; } - std::cout << '\n'; + outs() << '\n'; // Split the module into the two halves of the program we want. DenseMap<const Value*, Value*> ValueMap; @@ -457,7 +472,7 @@ static bool ExtractBlocks(BugDriver &BD, Module *Extracted = BD.ExtractMappedBlocksFromModule(Blocks, ToExtract); if (Extracted == 0) { // Weird, extraction should have worked. - std::cerr << "Nondeterministic problem extracting blocks??\n"; + errs() << "Nondeterministic problem extracting blocks??\n"; delete ProgClone; delete ToExtract; return false; @@ -476,8 +491,8 @@ static bool ExtractBlocks(BugDriver &BD, std::string ErrorMsg; if (Linker::LinkModules(ProgClone, Extracted, &ErrorMsg)) { - std::cerr << BD.getToolName() << ": Error linking modules together:" - << ErrorMsg << '\n'; + errs() << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << '\n'; exit(1); } delete Extracted; @@ -520,11 +535,11 @@ DebugAMiscompilation(BugDriver &BD, if (!BugpointIsInterrupted) ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); - std::cout << "\n*** The following function" - << (MiscompiledFunctions.size() == 1 ? " is" : "s are") - << " being miscompiled: "; + outs() << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); - std::cout << '\n'; + outs() << '\n'; // See if we can rip any loops out of the miscompiled functions and still // trigger the problem. @@ -543,14 +558,14 @@ DebugAMiscompilation(BugDriver &BD, if (!BugpointIsInterrupted) ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); - std::cout << "\n*** The following function" - << (MiscompiledFunctions.size() == 1 ? " is" : "s are") - << " being miscompiled: "; + outs() << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); - std::cout << '\n'; + outs() << '\n'; } - if (!BugpointIsInterrupted && + if (!BugpointIsInterrupted && !DisableBlockExtraction && ExtractBlocks(BD, TestFn, MiscompiledFunctions)) { // Okay, we extracted some blocks and the problem still appears. See if we // can eliminate some of the created functions from being candidates. @@ -563,11 +578,11 @@ DebugAMiscompilation(BugDriver &BD, // Do the reduction... ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); - std::cout << "\n*** The following function" - << (MiscompiledFunctions.size() == 1 ? " is" : "s are") - << " being miscompiled: "; + outs() << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; PrintFunctionList(MiscompiledFunctions); - std::cout << '\n'; + outs() << '\n'; } return MiscompiledFunctions; @@ -580,15 +595,15 @@ DebugAMiscompilation(BugDriver &BD, static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe) { // Run the optimization passes on ToOptimize, producing a transformed version // of the functions being tested. - std::cout << " Optimizing functions being tested: "; + outs() << " Optimizing functions being tested: "; Module *Optimized = BD.runPassesOn(Test, BD.getPassesToRun(), /*AutoDebugCrashes*/true); - std::cout << "done.\n"; + outs() << "done.\n"; delete Test; - std::cout << " Checking to see if the merged program executes correctly: "; + outs() << " Checking to see if the merged program executes correctly: "; bool Broken = TestMergedProgram(BD, Optimized, Safe, true); - std::cout << (Broken ? " nope.\n" : " yup.\n"); + outs() << (Broken ? " nope.\n" : " yup.\n"); return Broken; } @@ -601,33 +616,33 @@ bool BugDriver::debugMiscompilation() { // Make sure something was miscompiled... if (!BugpointIsInterrupted) if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) { - std::cerr << "*** Optimized program matches reference output! No problem" - << " detected...\nbugpoint can't help you with your problem!\n"; + errs() << "*** Optimized program matches reference output! No problem" + << " detected...\nbugpoint can't help you with your problem!\n"; return false; } - std::cout << "\n*** Found miscompiling pass" - << (getPassesToRun().size() == 1 ? "" : "es") << ": " - << getPassesString(getPassesToRun()) << '\n'; + outs() << "\n*** Found miscompiling pass" + << (getPassesToRun().size() == 1 ? "" : "es") << ": " + << getPassesString(getPassesToRun()) << '\n'; EmitProgressBitcode("passinput"); std::vector<Function*> MiscompiledFunctions = DebugAMiscompilation(*this, TestOptimizer); // Output a bunch of bitcode files for the user... - std::cout << "Outputting reduced bitcode files which expose the problem:\n"; + outs() << "Outputting reduced bitcode files which expose the problem:\n"; DenseMap<const Value*, Value*> ValueMap; Module *ToNotOptimize = CloneModule(getProgram(), ValueMap); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, MiscompiledFunctions, ValueMap); - std::cout << " Non-optimized portion: "; + outs() << " Non-optimized portion: "; ToNotOptimize = swapProgramIn(ToNotOptimize); EmitProgressBitcode("tonotoptimize", true); setNewProgram(ToNotOptimize); // Delete hacked module. - std::cout << " Portion that is input to optimizer: "; + outs() << " Portion that is input to optimizer: "; ToOptimize = swapProgramIn(ToOptimize); EmitProgressBitcode("tooptimize"); setNewProgram(ToOptimize); // Delete hacked module. @@ -672,12 +687,12 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, } // Call the old main function and return its result - BasicBlock *BB = BasicBlock::Create("entry", newMain); + BasicBlock *BB = BasicBlock::Create(Safe->getContext(), "entry", newMain); CallInst *call = CallInst::Create(oldMainProto, args.begin(), args.end(), "", BB); // If the type of old function wasn't void, return value of call - ReturnInst::Create(call, BB); + ReturnInst::Create(Safe->getContext(), call, BB); } // The second nasty issue we must deal with in the JIT is that the Safe @@ -689,8 +704,9 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, // Prototype: void *getPointerToNamedFunction(const char* Name) Constant *resolverFunc = Safe->getOrInsertFunction("getPointerToNamedFunction", - PointerType::getUnqual(Type::Int8Ty), - PointerType::getUnqual(Type::Int8Ty), (Type *)0); + Type::getInt8PtrTy(Safe->getContext()), + Type::getInt8PtrTy(Safe->getContext()), + (Type *)0); // Use the function we just added to get addresses of functions we need. for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) { @@ -701,18 +717,20 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, // Don't forward functions which are external in the test module too. if (TestFn && !TestFn->isDeclaration()) { // 1. Add a string constant with its name to the global file - Constant *InitArray = ConstantArray::get(F->getName()); + Constant *InitArray = ConstantArray::get(F->getContext(), F->getName()); GlobalVariable *funcName = - new GlobalVariable(InitArray->getType(), true /*isConstant*/, + new GlobalVariable(*Safe, InitArray->getType(), true /*isConstant*/, GlobalValue::InternalLinkage, InitArray, - F->getName() + "_name", Safe); + F->getName() + "_name"); // 2. Use `GetElementPtr *funcName, 0, 0' to convert the string to an // sbyte* so it matches the signature of the resolver function. // GetElementPtr *funcName, ulong 0, ulong 0 - std::vector<Constant*> GEPargs(2,Constant::getNullValue(Type::Int32Ty)); - Value *GEP = ConstantExpr::getGetElementPtr(funcName, &GEPargs[0], 2); + std::vector<Constant*> GEPargs(2, + Constant::getNullValue(Type::getInt32Ty(F->getContext()))); + Value *GEP = + ConstantExpr::getGetElementPtr(funcName, &GEPargs[0], 2); std::vector<Value*> ResolverArgs; ResolverArgs.push_back(GEP); @@ -722,8 +740,9 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, // Create a new global to hold the cached function pointer. Constant *NullPtr = ConstantPointerNull::get(F->getType()); GlobalVariable *Cache = - new GlobalVariable(F->getType(), false,GlobalValue::InternalLinkage, - NullPtr,F->getName()+".fpcache", F->getParent()); + new GlobalVariable(*F->getParent(), F->getType(), + false, GlobalValue::InternalLinkage, + NullPtr,F->getName()+".fpcache"); // Construct a new stub function that will re-route calls to F const FunctionType *FuncTy = F->getFunctionType(); @@ -731,14 +750,17 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, GlobalValue::InternalLinkage, F->getName() + "_wrapper", F->getParent()); - BasicBlock *EntryBB = BasicBlock::Create("entry", FuncWrapper); - BasicBlock *DoCallBB = BasicBlock::Create("usecache", FuncWrapper); - BasicBlock *LookupBB = BasicBlock::Create("lookupfp", FuncWrapper); + BasicBlock *EntryBB = BasicBlock::Create(F->getContext(), + "entry", FuncWrapper); + BasicBlock *DoCallBB = BasicBlock::Create(F->getContext(), + "usecache", FuncWrapper); + BasicBlock *LookupBB = BasicBlock::Create(F->getContext(), + "lookupfp", FuncWrapper); // Check to see if we already looked up the value. Value *CachedVal = new LoadInst(Cache, "fpcache", EntryBB); - Value *IsNull = new ICmpInst(ICmpInst::ICMP_EQ, CachedVal, - NullPtr, "isNull", EntryBB); + Value *IsNull = new ICmpInst(*EntryBB, ICmpInst::ICMP_EQ, CachedVal, + NullPtr, "isNull"); BranchInst::Create(LookupBB, DoCallBB, IsNull, EntryBB); // Resolve the call to function F via the JIT API: @@ -770,13 +792,13 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, Args.push_back(i); // Pass on the arguments to the real function, return its result - if (F->getReturnType() == Type::VoidTy) { + if (F->getReturnType() == Type::getVoidTy(F->getContext())) { CallInst::Create(FuncPtr, Args.begin(), Args.end(), "", DoCallBB); - ReturnInst::Create(DoCallBB); + ReturnInst::Create(F->getContext(), DoCallBB); } else { CallInst *Call = CallInst::Create(FuncPtr, Args.begin(), Args.end(), "retval", DoCallBB); - ReturnInst::Create(Call, DoCallBB); + ReturnInst::Create(F->getContext(),Call, DoCallBB); } // Use the wrapper function instead of the old function @@ -787,7 +809,7 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, } if (verifyModule(*Test) || verifyModule(*Safe)) { - std::cerr << "Bugpoint has a bug, which corrupted a module!!\n"; + errs() << "Bugpoint has a bug, which corrupted a module!!\n"; abort(); } } @@ -804,12 +826,13 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { sys::Path TestModuleBC("bugpoint.test.bc"); std::string ErrMsg; if (TestModuleBC.makeUnique(true, &ErrMsg)) { - std::cerr << BD.getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + errs() << BD.getToolName() << "Error making unique filename: " + << ErrMsg << "\n"; exit(1); } - if (BD.writeProgramToFile(TestModuleBC.toString(), Test)) { - std::cerr << "Error writing bitcode to `" << TestModuleBC << "'\nExiting."; + if (BD.writeProgramToFile(TestModuleBC.str(), Test)) { + errs() << "Error writing bitcode to `" << TestModuleBC.str() + << "'\nExiting."; exit(1); } delete Test; @@ -817,26 +840,27 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { // Make the shared library sys::Path SafeModuleBC("bugpoint.safe.bc"); if (SafeModuleBC.makeUnique(true, &ErrMsg)) { - std::cerr << BD.getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + errs() << BD.getToolName() << "Error making unique filename: " + << ErrMsg << "\n"; exit(1); } - if (BD.writeProgramToFile(SafeModuleBC.toString(), Safe)) { - std::cerr << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting."; + if (BD.writeProgramToFile(SafeModuleBC.str(), Safe)) { + errs() << "Error writing bitcode to `" << SafeModuleBC.str() + << "'\nExiting."; exit(1); } - std::string SharedObject = BD.compileSharedObject(SafeModuleBC.toString()); + std::string SharedObject = BD.compileSharedObject(SafeModuleBC.str()); delete Safe; // Run the code generator on the `Test' code, loading the shared library. // The function returns whether or not the new output differs from reference. - int Result = BD.diffProgram(TestModuleBC.toString(), SharedObject, false); + int Result = BD.diffProgram(TestModuleBC.str(), SharedObject, false); if (Result) - std::cerr << ": still failing!\n"; + errs() << ": still failing!\n"; else - std::cerr << ": didn't fail.\n"; + errs() << ": didn't fail.\n"; TestModuleBC.eraseFromDisk(); SafeModuleBC.eraseFromDisk(); sys::Path(SharedObject).eraseFromDisk(); @@ -850,14 +874,14 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { bool BugDriver::debugCodeGenerator() { if ((void*)SafeInterpreter == (void*)Interpreter) { std::string Result = executeProgramSafely("bugpoint.safe.out"); - std::cout << "\n*** The \"safe\" i.e. 'known good' backend cannot match " - << "the reference diff. This may be due to a\n front-end " - << "bug or a bug in the original program, but this can also " - << "happen if bugpoint isn't running the program with the " - << "right flags or input.\n I left the result of executing " - << "the program with the \"safe\" backend in this file for " - << "you: '" - << Result << "'.\n"; + outs() << "\n*** The \"safe\" i.e. 'known good' backend cannot match " + << "the reference diff. This may be due to a\n front-end " + << "bug or a bug in the original program, but this can also " + << "happen if bugpoint isn't running the program with the " + << "right flags or input.\n I left the result of executing " + << "the program with the \"safe\" backend in this file for " + << "you: '" + << Result << "'.\n"; return true; } @@ -876,13 +900,14 @@ bool BugDriver::debugCodeGenerator() { sys::Path TestModuleBC("bugpoint.test.bc"); std::string ErrMsg; if (TestModuleBC.makeUnique(true, &ErrMsg)) { - std::cerr << getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + errs() << getToolName() << "Error making unique filename: " + << ErrMsg << "\n"; exit(1); } - if (writeProgramToFile(TestModuleBC.toString(), ToCodeGen)) { - std::cerr << "Error writing bitcode to `" << TestModuleBC << "'\nExiting."; + if (writeProgramToFile(TestModuleBC.str(), ToCodeGen)) { + errs() << "Error writing bitcode to `" << TestModuleBC.str() + << "'\nExiting."; exit(1); } delete ToCodeGen; @@ -890,43 +915,45 @@ bool BugDriver::debugCodeGenerator() { // Make the shared library sys::Path SafeModuleBC("bugpoint.safe.bc"); if (SafeModuleBC.makeUnique(true, &ErrMsg)) { - std::cerr << getToolName() << "Error making unique filename: " - << ErrMsg << "\n"; + errs() << getToolName() << "Error making unique filename: " + << ErrMsg << "\n"; exit(1); } - if (writeProgramToFile(SafeModuleBC.toString(), ToNotCodeGen)) { - std::cerr << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting."; + if (writeProgramToFile(SafeModuleBC.str(), ToNotCodeGen)) { + errs() << "Error writing bitcode to `" << SafeModuleBC.str() + << "'\nExiting."; exit(1); } - std::string SharedObject = compileSharedObject(SafeModuleBC.toString()); + std::string SharedObject = compileSharedObject(SafeModuleBC.str()); delete ToNotCodeGen; - std::cout << "You can reproduce the problem with the command line: \n"; + outs() << "You can reproduce the problem with the command line: \n"; if (isExecutingJIT()) { - std::cout << " lli -load " << SharedObject << " " << TestModuleBC; + outs() << " lli -load " << SharedObject << " " << TestModuleBC.str(); } else { - std::cout << " llc -f " << TestModuleBC << " -o " << TestModuleBC<< ".s\n"; - std::cout << " gcc " << SharedObject << " " << TestModuleBC - << ".s -o " << TestModuleBC << ".exe"; + outs() << " llc -f " << TestModuleBC.str() << " -o " << TestModuleBC.str() + << ".s\n"; + outs() << " gcc " << SharedObject << " " << TestModuleBC.str() + << ".s -o " << TestModuleBC.str() << ".exe"; #if defined (HAVE_LINK_R) - std::cout << " -Wl,-R."; + outs() << " -Wl,-R."; #endif - std::cout << "\n"; - std::cout << " " << TestModuleBC << ".exe"; + outs() << "\n"; + outs() << " " << TestModuleBC.str() << ".exe"; } for (unsigned i=0, e = InputArgv.size(); i != e; ++i) - std::cout << " " << InputArgv[i]; - std::cout << '\n'; - std::cout << "The shared object was created with:\n llc -march=c " - << SafeModuleBC << " -o temporary.c\n" - << " gcc -xc temporary.c -O2 -o " << SharedObject -#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) - << " -G" // Compile a shared library, `-G' for Sparc -#else - << " -fPIC -shared" // `-shared' for Linux/X86, maybe others -#endif - << " -fno-strict-aliasing\n"; + outs() << " " << InputArgv[i]; + outs() << '\n'; + outs() << "The shared object was created with:\n llc -march=c " + << SafeModuleBC.str() << " -o temporary.c\n" + << " gcc -xc temporary.c -O2 -o " << SharedObject; + if (TargetTriple.getArch() == Triple::sparc) + outs() << " -G"; // Compile a shared library, `-G' for Sparc + else + outs() << " -fPIC -shared"; // `-shared' for Linux/X86, maybe others + + outs() << " -fno-strict-aliasing\n"; return false; } diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index 741be24..9f712e0 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -27,10 +27,9 @@ #include "llvm/Target/TargetData.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Streams.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/System/Program.h" -#include "llvm/Config/alloca.h" #define DONT_GET_PLUGIN_LOADER_OPTION #include "llvm/Support/PluginLoader.h" @@ -38,6 +37,9 @@ #include <fstream> using namespace llvm; +namespace llvm { + extern cl::opt<std::string> OutputPrefix; +} namespace { // ChildOutput - This option captures the name of the child output file that @@ -52,10 +54,10 @@ namespace { /// bool BugDriver::writeProgramToFile(const std::string &Filename, Module *M) const { - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - std::ofstream Out(Filename.c_str(), io_mode); - if (!Out.good()) return true; + 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; @@ -69,26 +71,26 @@ void BugDriver::EmitProgressBitcode(const std::string &ID, bool NoFlyer) { // Output the input to the current pass to a bitcode file, emit a message // telling the user how to reproduce it: opt -foo blah.bc // - std::string Filename = "bugpoint-" + ID + ".bc"; + std::string Filename = OutputPrefix + "-" + ID + ".bc"; if (writeProgramToFile(Filename)) { - cerr << "Error opening file '" << Filename << "' for writing!\n"; + errs() << "Error opening file '" << Filename << "' for writing!\n"; return; } - cout << "Emitted bitcode to '" << Filename << "'\n"; + outs() << "Emitted bitcode to '" << Filename << "'\n"; if (NoFlyer || PassesToRun.empty()) return; - cout << "\n*** You can reproduce the problem with: "; - cout << "opt " << Filename << " "; - cout << getPassesString(PassesToRun) << "\n"; + outs() << "\n*** You can reproduce the problem with: "; + if (UseValgrind) outs() << "valgrind "; + outs() << "opt " << Filename << " "; + outs() << getPassesString(PassesToRun) << "\n"; } int BugDriver::runPassesAsChild(const std::vector<const PassInfo*> &Passes) { - - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - std::ofstream OutFile(ChildOutput.c_str(), io_mode); - if (!OutFile.good()) { - cerr << "Error opening bitcode file: " << ChildOutput << "\n"; + 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; } @@ -100,13 +102,13 @@ int BugDriver::runPassesAsChild(const std::vector<const PassInfo*> &Passes) { if (Passes[i]->getNormalCtor()) PM.add(Passes[i]->getNormalCtor()()); else - cerr << "Cannot create pass yet: " << Passes[i]->getPassName() << "\n"; + 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)); + PM.add(createBitcodeWriterPass(OutFile)); // Run all queued passes. PM.run(*Program); @@ -121,58 +123,58 @@ cl::opt<bool> SilencePasses("silence-passes", cl::desc("Suppress output of runni /// optimizations fail for some reason (optimizer crashes), return true, /// otherwise return false. If DeleteOutput is set to true, the bitcode is /// deleted on success, and the filename string is undefined. This prints to -/// cout a single line message indicating whether compilation was successful or -/// failed. +/// outs() a single line message indicating whether compilation was successful +/// or failed. /// bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, std::string &OutputFilename, bool DeleteOutput, bool Quiet, unsigned NumExtraArgs, const char * const *ExtraArgs) const { // setup the output file name - cout << std::flush; - sys::Path uniqueFilename("bugpoint-output.bc"); + outs().flush(); + sys::Path uniqueFilename(OutputPrefix + "-output.bc"); std::string ErrMsg; if (uniqueFilename.makeUnique(true, &ErrMsg)) { - cerr << getToolName() << ": Error making unique filename: " - << ErrMsg << "\n"; + errs() << getToolName() << ": Error making unique filename: " + << ErrMsg << "\n"; return(1); } - OutputFilename = uniqueFilename.toString(); + OutputFilename = uniqueFilename.str(); // set up the input file name - sys::Path inputFilename("bugpoint-input.bc"); + sys::Path inputFilename(OutputPrefix + "-input.bc"); if (inputFilename.makeUnique(true, &ErrMsg)) { - cerr << getToolName() << ": Error making unique filename: " - << ErrMsg << "\n"; + errs() << getToolName() << ": Error making unique filename: " + << ErrMsg << "\n"; return(1); } - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - std::ofstream InFile(inputFilename.c_str(), io_mode); - if (!InFile.good()) { - cerr << "Error opening bitcode file: " << inputFilename << "\n"; - return(1); + + std::string ErrInfo; + raw_fd_ostream InFile(inputFilename.c_str(), ErrInfo, + raw_fd_ostream::F_Binary); + + + if (!ErrInfo.empty()) { + errs() << "Error opening bitcode file: " << inputFilename.str() << "\n"; + return 1; } WriteBitcodeToFile(Program, InFile); InFile.close(); // setup the child process' arguments - const char** args = (const char**) - alloca(sizeof(const char*) * - (Passes.size()+13+2*PluginLoader::getNumPlugins()+NumExtraArgs)); - int n = 0; + SmallVector<const char*, 8> Args; sys::Path tool = sys::Program::FindProgramByName(ToolName); if (UseValgrind) { - args[n++] = "valgrind"; - args[n++] = "--error-exitcode=1"; - args[n++] = "-q"; - args[n++] = tool.c_str(); + Args.push_back("valgrind"); + Args.push_back("--error-exitcode=1"); + Args.push_back("-q"); + Args.push_back(tool.c_str()); } else - args[n++] = ToolName.c_str(); + Args.push_back(ToolName); - args[n++] = "-as-child"; - args[n++] = "-child-output"; - args[n++] = OutputFilename.c_str(); + Args.push_back("-as-child"); + Args.push_back("-child-output"); + Args.push_back(OutputFilename.c_str()); std::vector<std::string> pass_args; for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) { pass_args.push_back( std::string("-load")); @@ -183,11 +185,11 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, pass_args.push_back( std::string("-") + (*I)->getPassArgument() ); for (std::vector<std::string>::const_iterator I = pass_args.begin(), E = pass_args.end(); I != E; ++I ) - args[n++] = I->c_str(); - args[n++] = inputFilename.c_str(); + Args.push_back(I->c_str()); + Args.push_back(inputFilename.c_str()); for (unsigned i = 0; i < NumExtraArgs; ++i) - args[n++] = *ExtraArgs; - args[n++] = 0; + Args.push_back(*ExtraArgs); + Args.push_back(0); sys::Path prog; if (UseValgrind) @@ -199,7 +201,8 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, sys::Path Nowhere; const sys::Path *Redirects[3] = {0, &Nowhere, &Nowhere}; - int result = sys::Program::ExecuteAndWait(prog, args, 0, (SilencePasses ? Redirects : 0), + int result = sys::Program::ExecuteAndWait(prog, Args.data(), 0, + (SilencePasses ? Redirects : 0), Timeout, MemoryLimit, &ErrMsg); // If we are supposed to delete the bitcode file or if the passes crashed, @@ -212,17 +215,17 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, if (!Quiet) { if (result == 0) - cout << "Success!\n"; + outs() << "Success!\n"; else if (result > 0) - cout << "Exited with error code '" << result << "'\n"; + outs() << "Exited with error code '" << result << "'\n"; else if (result < 0) { if (result == -1) - cout << "Execute failed: " << ErrMsg << "\n"; + outs() << "Execute failed: " << ErrMsg << "\n"; else - cout << "Crashed with signal #" << abs(result) << "\n"; + outs() << "Crashed with signal #" << abs(result) << "\n"; } if (result & 0x01000000) - cout << "Dumped core\n"; + outs() << "Dumped core\n"; } // Was the child successful? @@ -242,8 +245,8 @@ Module *BugDriver::runPassesOn(Module *M, if (runPasses(Passes, BitcodeResult, false/*delete*/, true/*quiet*/, NumExtraArgs, ExtraArgs)) { if (AutoDebugCrashes) { - cerr << " Error running this sequence of passes" - << " on the input program!\n"; + errs() << " Error running this sequence of passes" + << " on the input program!\n"; delete OldProgram; EmitProgressBitcode("pass-error", false); exit(debugOptimizerCrash()); @@ -257,8 +260,8 @@ Module *BugDriver::runPassesOn(Module *M, Module *Ret = ParseInputFile(BitcodeResult, Context); if (Ret == 0) { - cerr << getToolName() << ": Error reading bitcode file '" - << BitcodeResult << "'!\n"; + errs() << getToolName() << ": Error reading bitcode file '" + << BitcodeResult << "'!\n"; exit(1); } sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 978e60b..4551d41 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -13,16 +13,22 @@ #define DEBUG_TYPE "toolrunner" #include "ToolRunner.h" -#include "llvm/Config/config.h" // for HAVE_LINK_R #include "llvm/System/Program.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/config.h" // for HAVE_LINK_R #include <fstream> #include <sstream> -#include <iostream> using namespace llvm; +namespace llvm { + cl::opt<bool> + SaveTemps("save-temps", cl::init(false), cl::desc("Save temporary files")); +} + namespace { cl::opt<std::string> RemoteClient("remote-client", @@ -33,6 +39,10 @@ namespace { cl::desc("Remote execution (rsh/ssh) host")); cl::opt<std::string> + RemotePort("remote-port", + cl::desc("Remote execution (rsh/ssh) port")); + + cl::opt<std::string> RemoteUser("remote-user", cl::desc("Remote execution (rsh/ssh) user id")); @@ -43,8 +53,8 @@ namespace { ToolExecutionError::~ToolExecutionError() throw() { } -/// RunProgramWithTimeout - This function provides an alternate interface to the -/// sys::Program::ExecuteAndWait interface. +/// RunProgramWithTimeout - This function provides an alternate interface +/// to the sys::Program::ExecuteAndWait interface. /// @see sys:Program::ExecuteAndWait static int RunProgramWithTimeout(const sys::Path &ProgramPath, const char **Args, @@ -57,20 +67,74 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, redirects[0] = &StdInFile; redirects[1] = &StdOutFile; redirects[2] = &StdErrFile; - - if (0) { - std::cerr << "RUN:"; + +#if 0 // For debug purposes + { + errs() << "RUN:"; for (unsigned i = 0; Args[i]; ++i) - std::cerr << " " << Args[i]; - std::cerr << "\n"; + errs() << " " << Args[i]; + errs() << "\n"; } +#endif return sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, NumSeconds, MemoryLimit); } +/// RunProgramRemotelyWithTimeout - This function runs the given program +/// remotely using the given remote client and the sys::Program::ExecuteAndWait. +/// Returns the remote program exit code or reports a remote client error if it +/// fails. Remote client is required to return 255 if it failed or program exit +/// code otherwise. +/// @see sys:Program::ExecuteAndWait +static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, + const char **Args, + const sys::Path &StdInFile, + const sys::Path &StdOutFile, + const sys::Path &StdErrFile, + unsigned NumSeconds = 0, + unsigned MemoryLimit = 0) { + const sys::Path* redirects[3]; + redirects[0] = &StdInFile; + redirects[1] = &StdOutFile; + redirects[2] = &StdErrFile; + +#if 0 // For debug purposes + { + errs() << "RUN:"; + for (unsigned i = 0; Args[i]; ++i) + errs() << " " << Args[i]; + errs() << "\n"; + } +#endif + // Run the program remotely with the remote client + int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args, + 0, redirects, NumSeconds, MemoryLimit); + + // Has the remote client fail? + if (255 == ReturnCode) { + std::ostringstream OS; + OS << "\nError running remote client:\n "; + for (const char **Arg = Args; *Arg; ++Arg) + OS << " " << *Arg; + OS << "\n"; + + // The error message is in the output file, let's print it out from there. + std::ifstream ErrorFile(StdOutFile.c_str()); + if (ErrorFile) { + std::copy(std::istreambuf_iterator<char>(ErrorFile), + std::istreambuf_iterator<char>(), + std::ostreambuf_iterator<char>(OS)); + ErrorFile.close(); + } + + throw ToolExecutionError(OS.str()); + } + + return ReturnCode; +} static void ProcessFailure(sys::Path ProgPath, const char** Args) { std::ostringstream OS; @@ -83,7 +147,7 @@ static void ProcessFailure(sys::Path ProgPath, const char** Args) { sys::Path ErrorFilename("bugpoint.program_error_messages"); std::string ErrMsg; if (ErrorFilename.makeUnique(true, &ErrMsg)) { - std::cerr << "Error making unique filename: " << ErrMsg << "\n"; + errs() << "Error making unique filename: " << ErrMsg << "\n"; exit(1); } RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename, @@ -154,11 +218,11 @@ int LLI::ExecuteProgram(const std::string &Bitcode, LLIArgs.push_back(Args[i].c_str()); LLIArgs.push_back(0); - std::cout << "<lli>" << std::flush; - DEBUG(std::cerr << "\nAbout to run:\t"; + outs() << "<lli>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i) - std::cerr << " " << LLIArgs[i]; - std::cerr << "\n"; + errs() << " " << LLIArgs[i]; + errs() << "\n"; ); return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0], sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), @@ -166,10 +230,11 @@ int LLI::ExecuteProgram(const std::string &Bitcode, } // LLI create method - Try to find the LLI executable -AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath, +AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0, std::string &Message, const std::vector<std::string> *ToolArgs) { - std::string LLIPath = FindExecutable("lli", ProgPath).toString(); + std::string LLIPath = + FindExecutable("lli", Argv0, (void *)(intptr_t)&createLLI).str(); if (!LLIPath.empty()) { Message = "Found lli: " + LLIPath + "\n"; return new LLI(LLIPath, ToolArgs); @@ -236,7 +301,6 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode, // Custom execution environment create method, takes the execution command // as arguments AbstractInterpreter *AbstractInterpreter::createCustom( - const std::string &ProgramPath, std::string &Message, const std::string &ExecCommandLine) { @@ -270,7 +334,7 @@ AbstractInterpreter *AbstractInterpreter::createCustom( pos = ExecCommandLine.find_first_of(delimiters, lastPos); } - std::string CmdPath = FindExecutable(Command, ProgramPath).toString(); + std::string CmdPath = sys::Program::FindProgramByName(Command).str(); if (CmdPath.empty()) { Message = std::string("Cannot find '") + Command + @@ -291,7 +355,7 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, sys::Path uniqueFile(Bitcode+".llc.s"); std::string ErrMsg; if (uniqueFile.makeUnique(true, &ErrMsg)) { - std::cerr << "Error making unique filename: " << ErrMsg << "\n"; + errs() << "Error making unique filename: " << ErrMsg << "\n"; exit(1); } OutputAsmFile = uniqueFile; @@ -304,15 +368,14 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, LLCArgs.push_back ("-o"); LLCArgs.push_back (OutputAsmFile.c_str()); // Output to the Asm file - LLCArgs.push_back ("-f"); // Overwrite as necessary... LLCArgs.push_back (Bitcode.c_str()); // This is the input bitcode LLCArgs.push_back (0); - std::cout << "<llc>" << std::flush; - DEBUG(std::cerr << "\nAbout to run:\t"; + outs() << "<llc>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) - std::cerr << " " << LLCArgs[i]; - std::cerr << "\n"; + errs() << " " << LLCArgs[i]; + errs() << "\n"; ); if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0], sys::Path(), sys::Path(), sys::Path())) @@ -338,34 +401,35 @@ int LLC::ExecuteProgram(const std::string &Bitcode, sys::Path OutputAsmFile; OutputCode(Bitcode, OutputAsmFile); - FileRemover OutFileRemover(OutputAsmFile); + FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); std::vector<std::string> GCCArgs(ArgsForGCC); GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); GCCArgs.insert(GCCArgs.end(), gccArgs.begin(), gccArgs.end()); // Assuming LLC worked, compile the result with GCC and run it. - return gcc->ExecuteProgram(OutputAsmFile.toString(), Args, GCC::AsmFile, + return gcc->ExecuteProgram(OutputAsmFile.str(), Args, GCC::AsmFile, InputFile, OutputFile, GCCArgs, Timeout, MemoryLimit); } /// createLLC - Try to find the LLC executable /// -LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath, +LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message, const std::vector<std::string> *Args, const std::vector<std::string> *GCCArgs) { - std::string LLCPath = FindExecutable("llc", ProgramPath).toString(); + std::string LLCPath = + FindExecutable("llc", Argv0, (void *)(intptr_t)&createLLC).str(); if (LLCPath.empty()) { Message = "Cannot find `llc' in executable directory or PATH!\n"; return 0; } Message = "Found llc: " + LLCPath + "\n"; - GCC *gcc = GCC::create(ProgramPath, Message, GCCArgs); + GCC *gcc = GCC::create(Message, GCCArgs); if (!gcc) { - std::cerr << Message << "\n"; + errs() << Message << "\n"; exit(1); } return new LLC(LLCPath, gcc, Args, GCCArgs); @@ -425,13 +489,13 @@ int JIT::ExecuteProgram(const std::string &Bitcode, JITArgs.push_back(Args[i].c_str()); JITArgs.push_back(0); - std::cout << "<jit>" << std::flush; - DEBUG(std::cerr << "\nAbout to run:\t"; + outs() << "<jit>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i) - std::cerr << " " << JITArgs[i]; - std::cerr << "\n"; + errs() << " " << JITArgs[i]; + errs() << "\n"; ); - DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n"); + DEBUG(errs() << "\nSending output to " << OutputFile << "\n"); return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0], sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), Timeout, MemoryLimit); @@ -439,9 +503,10 @@ int JIT::ExecuteProgram(const std::string &Bitcode, /// createJIT - Try to find the LLI executable /// -AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath, +AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0, std::string &Message, const std::vector<std::string> *Args) { - std::string LLIPath = FindExecutable("lli", ProgPath).toString(); + std::string LLIPath = + FindExecutable("lli", Argv0, (void *)(intptr_t)&createJIT).str(); if (!LLIPath.empty()) { Message = "Found lli: " + LLIPath + "\n"; return new JIT(LLIPath, Args); @@ -456,7 +521,7 @@ GCC::FileType CBE::OutputCode(const std::string &Bitcode, sys::Path uniqueFile(Bitcode+".cbe.c"); std::string ErrMsg; if (uniqueFile.makeUnique(true, &ErrMsg)) { - std::cerr << "Error making unique filename: " << ErrMsg << "\n"; + errs() << "Error making unique filename: " << ErrMsg << "\n"; exit(1); } OutputCFile = uniqueFile; @@ -474,11 +539,11 @@ GCC::FileType CBE::OutputCode(const std::string &Bitcode, LLCArgs.push_back (Bitcode.c_str()); // This is the input bitcode LLCArgs.push_back (0); - std::cout << "<cbe>" << std::flush; - DEBUG(std::cerr << "\nAbout to run:\t"; + outs() << "<cbe>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) - std::cerr << " " << LLCArgs[i]; - std::cerr << "\n"; + errs() << " " << LLCArgs[i]; + errs() << "\n"; ); if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(), sys::Path())) @@ -503,33 +568,34 @@ int CBE::ExecuteProgram(const std::string &Bitcode, sys::Path OutputCFile; OutputCode(Bitcode, OutputCFile); - FileRemover CFileRemove(OutputCFile); + FileRemover CFileRemove(OutputCFile, !SaveTemps); std::vector<std::string> GCCArgs(ArgsForGCC); GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); - return gcc->ExecuteProgram(OutputCFile.toString(), Args, GCC::CFile, + return gcc->ExecuteProgram(OutputCFile.str(), Args, GCC::CFile, InputFile, OutputFile, GCCArgs, Timeout, MemoryLimit); } /// createCBE - Try to find the 'llc' executable /// -CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath, +CBE *AbstractInterpreter::createCBE(const char *Argv0, std::string &Message, const std::vector<std::string> *Args, const std::vector<std::string> *GCCArgs) { - sys::Path LLCPath = FindExecutable("llc", ProgramPath); + sys::Path LLCPath = + FindExecutable("llc", Argv0, (void *)(intptr_t)&createCBE); if (LLCPath.isEmpty()) { Message = "Cannot find `llc' in executable directory or PATH!\n"; return 0; } - Message = "Found llc: " + LLCPath.toString() + "\n"; - GCC *gcc = GCC::create(ProgramPath, Message, GCCArgs); + Message = "Found llc: " + LLCPath.str() + "\n"; + GCC *gcc = GCC::create(Message, GCCArgs); if (!gcc) { - std::cerr << Message << "\n"; + errs() << Message << "\n"; exit(1); } return new CBE(LLCPath, gcc, Args); @@ -538,6 +604,23 @@ CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath, //===---------------------------------------------------------------------===// // GCC abstraction // + +static bool +IsARMArchitecture(std::vector<std::string> Args) +{ + for (std::vector<std::string>::const_iterator + I = Args.begin(), E = Args.end(); I != E; ++I) { + if (!StringsEqualNoCase(*I, "-arch")) { + ++I; + if ((I != E) && !StringsEqualNoCase(I->c_str(), "arm", strlen("arm"))) { + return true; + } + } + } + + return false; +} + int GCC::ExecuteProgram(const std::string &ProgramFile, const std::vector<std::string> &Args, FileType fileType, @@ -561,9 +644,13 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, GCCArgs.push_back("-fno-strict-aliasing"); } else { GCCArgs.push_back("assembler"); -#ifdef __APPLE__ - GCCArgs.push_back("-force_cpusubtype_ALL"); -#endif + + // For ARM architectures we don't want this flag. bugpoint isn't + // explicitly told what architecture it is working on, so we get + // it from gcc flags + if ((TargetTriple.getOS() == Triple::Darwin) && + !IsARMArchitecture(ArgsForGCC)) + GCCArgs.push_back("-force_cpusubtype_ALL"); } GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename... GCCArgs.push_back("-x"); @@ -572,7 +659,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, sys::Path OutputBinary (ProgramFile+".gcc.exe"); std::string ErrMsg; if (OutputBinary.makeUnique(true, &ErrMsg)) { - std::cerr << "Error making unique filename: " << ErrMsg << "\n"; + errs() << "Error making unique filename: " << ErrMsg << "\n"; exit(1); } GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file... @@ -589,16 +676,15 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, #if defined (HAVE_LINK_R) GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files #endif -#ifdef __sparc__ - GCCArgs.push_back("-mcpu=v9"); -#endif + if (TargetTriple.getArch() == Triple::sparc) + GCCArgs.push_back("-mcpu=v9"); GCCArgs.push_back(0); // NULL terminator - std::cout << "<gcc>" << std::flush; - DEBUG(std::cerr << "\nAbout to run:\t"; + outs() << "<gcc>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = GCCArgs.size()-1; i != e; ++i) - std::cerr << " " << GCCArgs[i]; - std::cerr << "\n"; + errs() << " " << GCCArgs[i]; + errs() << "\n"; ); if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), sys::Path())) { @@ -613,12 +699,20 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, else { ProgramArgs.push_back(RemoteClientPath.c_str()); ProgramArgs.push_back(RemoteHost.c_str()); - ProgramArgs.push_back("-l"); - ProgramArgs.push_back(RemoteUser.c_str()); + if (!RemoteUser.empty()) { + ProgramArgs.push_back("-l"); + ProgramArgs.push_back(RemoteUser.c_str()); + } + if (!RemotePort.empty()) { + ProgramArgs.push_back("-p"); + ProgramArgs.push_back(RemotePort.c_str()); + } if (!RemoteExtra.empty()) { ProgramArgs.push_back(RemoteExtra.c_str()); } + // Full path to the binary. We need to cd to the exec directory because + // there is a dylib there that the exec expects to find in the CWD char* env_pwd = getenv("PWD"); std::string Exec = "cd "; Exec += env_pwd; @@ -633,23 +727,26 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, ProgramArgs.push_back(0); // NULL terminator // Now that we have a binary, run it! - std::cout << "<program>" << std::flush; - DEBUG(std::cerr << "\nAbout to run:\t"; + outs() << "<program>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i) - std::cerr << " " << ProgramArgs[i]; - std::cerr << "\n"; + errs() << " " << ProgramArgs[i]; + errs() << "\n"; ); - FileRemover OutputBinaryRemover(OutputBinary); + FileRemover OutputBinaryRemover(OutputBinary, !SaveTemps); - if (RemoteClientPath.isEmpty()) + if (RemoteClientPath.isEmpty()) { + DEBUG(errs() << "<run locally>";); return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), Timeout, MemoryLimit); - else - return RunProgramWithTimeout(sys::Path(RemoteClientPath), &ProgramArgs[0], - sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), - Timeout, MemoryLimit); + } else { + outs() << "<run remotely>"; outs().flush(); + return RunProgramRemotelyWithTimeout(sys::Path(RemoteClientPath), + &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), + sys::Path(OutputFile), Timeout, MemoryLimit); + } } int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, @@ -658,10 +755,10 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT); std::string ErrMsg; if (uniqueFilename.makeUnique(true, &ErrMsg)) { - std::cerr << "Error making unique filename: " << ErrMsg << "\n"; + errs() << "Error making unique filename: " << ErrMsg << "\n"; exit(1); } - OutputFile = uniqueFilename.toString(); + OutputFile = uniqueFilename.str(); std::vector<const char*> GCCArgs; @@ -678,27 +775,27 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCCArgs.push_back(InputFile.c_str()); // Specify the input filename. GCCArgs.push_back("-x"); GCCArgs.push_back("none"); -#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) - GCCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc -#elif defined(__APPLE__) - // link all source files into a single module in data segment, rather than - // generating blocks. dynamic_lookup requires that you set - // MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for - // bugpoint to just pass that in the environment of GCC. - GCCArgs.push_back("-single_module"); - GCCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC - GCCArgs.push_back("-undefined"); - GCCArgs.push_back("dynamic_lookup"); -#else - GCCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others -#endif + if (TargetTriple.getArch() == Triple::sparc) + GCCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc + else if (TargetTriple.getOS() == Triple::Darwin) { + // link all source files into a single module in data segment, rather than + // generating blocks. dynamic_lookup requires that you set + // MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for + // bugpoint to just pass that in the environment of GCC. + GCCArgs.push_back("-single_module"); + GCCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC + GCCArgs.push_back("-undefined"); + GCCArgs.push_back("dynamic_lookup"); + } else + GCCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others + + if ((TargetTriple.getArch() == Triple::alpha) || + (TargetTriple.getArch() == Triple::x86_64)) + GCCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC + + if (TargetTriple.getArch() == Triple::sparc) + GCCArgs.push_back("-mcpu=v9"); -#if defined(__ia64__) || defined(__alpha__) || defined(__amd64__) - GCCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC -#endif -#ifdef __sparc__ - GCCArgs.push_back("-mcpu=v9"); -#endif GCCArgs.push_back("-o"); GCCArgs.push_back(OutputFile.c_str()); // Output to the right filename. GCCArgs.push_back("-O2"); // Optimize the program a bit. @@ -715,11 +812,11 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, - std::cout << "<gcc>" << std::flush; - DEBUG(std::cerr << "\nAbout to run:\t"; + outs() << "<gcc>"; outs().flush(); + DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = GCCArgs.size()-1; i != e; ++i) - std::cerr << " " << GCCArgs[i]; - std::cerr << "\n"; + errs() << " " << GCCArgs[i]; + errs() << "\n"; ); if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), sys::Path())) { @@ -731,9 +828,9 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, /// create - Try to find the `gcc' executable /// -GCC *GCC::create(const std::string &ProgramPath, std::string &Message, +GCC *GCC::create(std::string &Message, const std::vector<std::string> *Args) { - sys::Path GCCPath = FindExecutable("gcc", ProgramPath); + sys::Path GCCPath = sys::Program::FindProgramByName("gcc"); if (GCCPath.isEmpty()) { Message = "Cannot find `gcc' in executable directory or PATH!\n"; return 0; @@ -741,8 +838,8 @@ GCC *GCC::create(const std::string &ProgramPath, std::string &Message, sys::Path RemoteClientPath; if (!RemoteClient.empty()) - RemoteClientPath = FindExecutable(RemoteClient.c_str(), ProgramPath); + RemoteClientPath = sys::Program::FindProgramByName(RemoteClient); - Message = "Found gcc: " + GCCPath.toString() + "\n"; + Message = "Found gcc: " + GCCPath.str() + "\n"; return new GCC(GCCPath, RemoteClientPath, Args); } diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h index 721f66c..39b0bbf 100644 --- a/tools/bugpoint/ToolRunner.h +++ b/tools/bugpoint/ToolRunner.h @@ -17,12 +17,18 @@ #ifndef BUGPOINT_TOOLRUNNER_H #define BUGPOINT_TOOLRUNNER_H +#include "llvm/ADT/Triple.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/SystemUtils.h" +#include "llvm/System/Path.h" #include <exception> #include <vector> namespace llvm { +extern cl::opt<bool> SaveTemps; +extern Triple TargetTriple; + class CBE; class LLC; @@ -54,7 +60,7 @@ class GCC { public: enum FileType { AsmFile, CFile }; - static GCC *create(const std::string &ProgramPath, std::string &Message, + static GCC *create(std::string &Message, const std::vector<std::string> *Args); /// ExecuteProgram - Execute the program specified by "ProgramFile" (which is @@ -90,23 +96,20 @@ public: /// class AbstractInterpreter { public: - static CBE *createCBE(const std::string &ProgramPath, std::string &Message, + static CBE *createCBE(const char *Argv0, std::string &Message, const std::vector<std::string> *Args = 0, const std::vector<std::string> *GCCArgs = 0); - static LLC *createLLC(const std::string &ProgramPath, std::string &Message, + static LLC *createLLC(const char *Argv0, std::string &Message, const std::vector<std::string> *Args = 0, const std::vector<std::string> *GCCArgs = 0); - static AbstractInterpreter* createLLI(const std::string &ProgramPath, - std::string &Message, + static AbstractInterpreter* createLLI(const char *Argv0, std::string &Message, const std::vector<std::string> *Args=0); - static AbstractInterpreter* createJIT(const std::string &ProgramPath, - std::string &Message, + static AbstractInterpreter* createJIT(const char *Argv0, std::string &Message, const std::vector<std::string> *Args=0); - static AbstractInterpreter* createCustom(const std::string &ProgramPath, - std::string &Message, + static AbstractInterpreter* createCustom(std::string &Message, const std::string &ExecCommandLine); diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index 3365b22..565f3f9 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -22,10 +22,10 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/StandardPasses.h" #include "llvm/System/Process.h" #include "llvm/System/Signals.h" #include "llvm/LinkAllVMCore.h" -#include <iostream> using namespace llvm; // AsChild - Specifies that this invocation of bugpoint is being generated @@ -58,6 +58,17 @@ MemoryLimit("mlimit", cl::init(100), cl::value_desc("MBytes"), static cl::list<const PassInfo*, bool, PassNameParser> PassList(cl::desc("Passes available:"), cl::ZeroOrMore); +static cl::opt<bool> +StandardCompileOpts("std-compile-opts", + cl::desc("Include the standard compile time optimizations")); + +static cl::opt<bool> +StandardLinkOpts("std-link-opts", + cl::desc("Include the standard link time optimizations")); + +static cl::opt<std::string> +OverrideTriple("mtriple", cl::desc("Override target triple for module")); + /// BugpointIsInterrupted - Set to true when the user presses ctrl-c. bool llvm::BugpointIsInterrupted = false; @@ -65,6 +76,20 @@ static void BugpointInterruptFunction() { BugpointIsInterrupted = true; } +// Hack to capture a pass list. +namespace { + class AddToDriver : public PassManager { + BugDriver &D; + public: + AddToDriver(BugDriver &_D) : D(_D) {} + + virtual void add(Pass *P) { + const PassInfo *PI = P->getPassInfo(); + D.addPasses(&PI, &PI + 1); + } + }; +} + int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc, argv); @@ -75,9 +100,33 @@ int main(int argc, char **argv) { " for more information.\n"); sys::SetInterruptFunction(BugpointInterruptFunction); - LLVMContext Context; + LLVMContext& Context = getGlobalContext(); + // If we have an override, set it and then track the triple we want Modules + // to use. + if (!OverrideTriple.empty()) { + TargetTriple.setTriple(OverrideTriple); + outs() << "Override triple set to '" << OverrideTriple << "'\n"; + } + BugDriver D(argv[0], AsChild, FindBugs, TimeoutValue, MemoryLimit, Context); if (D.addSources(InputFilenames)) return 1; + + AddToDriver PM(D); + if (StandardCompileOpts) { + createStandardModulePasses(&PM, 3, + /*OptimizeSize=*/ false, + /*UnitAtATime=*/ true, + /*UnrollLoops=*/ true, + /*SimplifyLibCalls=*/ true, + /*HaveExceptions=*/ true, + createFunctionInliningPass()); + } + + if (StandardLinkOpts) + createStandardLTOPasses(&PM, /*Internalize=*/true, + /*RunInliner=*/true, + /*VerifyEach=*/false); + D.addPasses(PassList.begin(), PassList.end()); // Bugpoint has the ability of generating a plethora of core files, so to @@ -87,20 +136,20 @@ int main(int argc, char **argv) { try { return D.run(); } catch (ToolExecutionError &TEE) { - std::cerr << "Tool execution error: " << TEE.what() << '\n'; + errs() << "Tool execution error: " << TEE.what() << '\n'; } catch (const std::string& msg) { - std::cerr << argv[0] << ": " << msg << "\n"; - } catch (const std::bad_alloc &e) { - std::cerr << "Oh no, a bugpoint process ran out of memory!\n" - "To increase the allocation limits for bugpoint child\n" - "processes, use the -mlimit option.\n"; + errs() << argv[0] << ": " << msg << "\n"; + } catch (const std::bad_alloc&) { + errs() << "Oh no, a bugpoint process ran out of memory!\n" + "To increase the allocation limits for bugpoint child\n" + "processes, use the -mlimit option.\n"; } catch (const std::exception &e) { - std::cerr << "Whoops, a std::exception leaked out of bugpoint: " - << e.what() << "\n" - << "This is a bug in bugpoint!\n"; + errs() << "Whoops, a std::exception leaked out of bugpoint: " + << e.what() << "\n" + << "This is a bug in bugpoint!\n"; } catch (...) { - std::cerr << "Whoops, an exception leaked out of bugpoint. " - << "This is a bug in bugpoint!\n"; + errs() << "Whoops, an exception leaked out of bugpoint. " + << "This is a bug in bugpoint!\n"; } return 1; } diff --git a/tools/gold/Makefile b/tools/gold/Makefile index 65e99bf..7bac4ec 100644 --- a/tools/gold/Makefile +++ b/tools/gold/Makefile @@ -8,7 +8,7 @@ ##===----------------------------------------------------------------------===## LEVEL = ../.. -LIBRARYNAME = LLVMgold +LIBRARYNAME = libLLVMgold # Include this here so we can get the configuration of the targets # that have been configured for construction. We have to do this @@ -18,8 +18,9 @@ include $(LEVEL)/Makefile.config LINK_LIBS_IN_SHARED=1 SHARED_LIBRARY = 1 BUILD_ARCHIVE = 0 +LOADABLE_MODULE = 1 -LINK_COMPONENTS := +LINK_COMPONENTS := support system LIBS += -llto # Because off_t is used in the public API, the largefile parts are required for diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 146c53f..6520617 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -362,8 +362,9 @@ ld_plugin_status all_symbols_read_hook(void) { (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); return LDPS_ERR; } - raw_fd_ostream *objFile = new raw_fd_ostream(uniqueObjPath.c_str(), true, - ErrMsg); + raw_fd_ostream *objFile = + new raw_fd_ostream(uniqueObjPath.c_str(), ErrMsg, + raw_fd_ostream::F_Binary); if (!ErrMsg.empty()) { delete objFile; (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt index e98b5a2..683f298 100644 --- a/tools/llc/CMakeLists.txt +++ b/tools/llc/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser) add_llvm_tool(llc llc.cpp diff --git a/tools/llc/Makefile b/tools/llc/Makefile index 8514040..7319aad 100644 --- a/tools/llc/Makefile +++ b/tools/llc/Makefile @@ -15,7 +15,7 @@ TOOLNAME = llc # early so we can set up LINK_COMPONENTS before including Makefile.rules include $(LEVEL)/Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader +LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader asmparser include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index ae03c1e..b94e5fb 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -13,35 +13,35 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/CodeGen/FileWriters.h" -#include "llvm/CodeGen/LinkAllCodegenComponents.h" -#include "llvm/CodeGen/LinkAllAsmWriterComponents.h" -#include "llvm/Target/SubtargetFeature.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetMachineRegistry.h" -#include "llvm/Transforms/Scalar.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #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/FileWriters.h" +#include "llvm/CodeGen/LinkAllAsmWriterComponents.h" +#include "llvm/CodeGen/LinkAllCodegenComponents.h" +#include "llvm/CodeGen/ObjectCodeEmitter.h" +#include "llvm/Config/config.h" +#include "llvm/LinkAllVMCore.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" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/RegistryParser.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Analysis/Verifier.h" +#include "llvm/System/Host.h" #include "llvm/System/Signals.h" -#include "llvm/Config/config.h" -#include "llvm/LinkAllVMCore.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" -#include <fstream> -#include <iostream> +#include "llvm/Transforms/Scalar.h" #include <memory> using namespace llvm; @@ -55,7 +55,8 @@ InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-")); static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); -static cl::opt<bool> Force("f", cl::desc("Overwrite output files")); +static cl::opt<bool> +Force("f", cl::desc("Enable binary output on terminals")); // Determine optimization level. static cl::opt<char> @@ -69,9 +70,8 @@ OptLevel("O", static cl::opt<std::string> TargetTriple("mtriple", cl::desc("Override target triple for module")); -static cl::opt<const TargetMachineRegistry::entry*, false, - RegistryParser<TargetMachine> > -MArch("march", cl::desc("Architecture to generate code for:")); +static cl::opt<std::string> +MArch("march", cl::desc("Architecture to generate code for (see --version)")); static cl::opt<std::string> MCPU("mcpu", @@ -119,7 +119,9 @@ GetFileNameRoot(const std::string &InputFilename) { std::string outputFilename; int Len = IFN.length(); if ((Len > 2) && - IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') { + IFN[Len-3] == '.' && + ((IFN[Len-2] == 'b' && IFN[Len-1] == 'c') || + (IFN[Len-2] == 'l' && IFN[Len-1] == 'l'))) { outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/ } else { outputFilename = IFN; @@ -127,37 +129,34 @@ GetFileNameRoot(const std::string &InputFilename) { return outputFilename; } -static raw_ostream *GetOutputStream(const char *ProgName) { +static formatted_raw_ostream *GetOutputStream(const char *TargetName, + const char *ProgName) { if (OutputFilename != "") { if (OutputFilename == "-") - return &outs(); - - // Specified an output filename? - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - std::cerr << ProgName << ": error opening '" << OutputFilename - << "': file exists!\n" - << "Use -f command line argument to force output\n"; - return 0; - } + return &fouts(); + // 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_ostream *Out = new raw_fd_ostream(OutputFilename.c_str(), true, error); + raw_fd_ostream *FDOut = + new raw_fd_ostream(OutputFilename.c_str(), error, + raw_fd_ostream::F_Binary); if (!error.empty()) { - std::cerr << error << '\n'; - delete Out; + errs() << error << '\n'; + delete FDOut; return 0; } + formatted_raw_ostream *Out = + new formatted_raw_ostream(*FDOut, formatted_raw_ostream::DELETE_STREAM); return Out; } if (InputFilename == "-") { OutputFilename = "-"; - return &outs(); + return &fouts(); } OutputFilename = GetFileNameRoot(InputFilename); @@ -165,10 +164,10 @@ static raw_ostream *GetOutputStream(const char *ProgName) { bool Binary = false; switch (FileType) { case TargetMachine::AssemblyFile: - if (MArch->Name[0] == 'c') { - if (MArch->Name[1] == 0) + if (TargetName[0] == 'c') { + if (TargetName[1] == 0) OutputFilename += ".cbe.c"; - else if (MArch->Name[1] == 'p' && MArch->Name[2] == 'p') + else if (TargetName[1] == 'p' && TargetName[2] == 'p') OutputFilename += ".cpp"; else OutputFilename += ".s"; @@ -185,26 +184,24 @@ static raw_ostream *GetOutputStream(const char *ProgName) { break; } - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - std::cerr << ProgName << ": error opening '" << OutputFilename - << "': file exists!\n" - << "Use -f command line argument to force output\n"; - return 0; - } - // 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_ostream *Out = new raw_fd_ostream(OutputFilename.c_str(), Binary, 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); if (!error.empty()) { - std::cerr << error << '\n'; - delete Out; + errs() << error << '\n'; + delete FDOut; return 0; } + formatted_raw_ostream *Out = + new formatted_raw_ostream(*FDOut, formatted_raw_ostream::DELETE_STREAM); + return Out; } @@ -213,24 +210,22 @@ static raw_ostream *GetOutputStream(const char *ProgName) { int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); + // Initialize targets first, so that --version shows registered targets. InitializeAllTargets(); InitializeAllAsmPrinters(); + + cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); // Load the module to be compiled... - std::string ErrorMessage; + SMDiagnostic Err; std::auto_ptr<Module> M; - std::auto_ptr<MemoryBuffer> Buffer( - MemoryBuffer::getFileOrSTDIN(InputFilename, &ErrorMessage)); - if (Buffer.get()) - M.reset(ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage)); + M.reset(ParseIRFile(InputFilename, Err, Context)); if (M.get() == 0) { - std::cerr << argv[0] << ": bitcode didn't read correctly.\n"; - std::cerr << "Reason: " << ErrorMessage << "\n"; + Err.Print(argv[0], errs()); return 1; } Module &mod = *M.get(); @@ -239,15 +234,40 @@ int main(int argc, char **argv) { if (!TargetTriple.empty()) mod.setTargetTriple(TargetTriple); - // Allocate target machine. First, check whether the user has - // explicitly specified an architecture to compile for. - if (MArch == 0) { + Triple TheTriple(mod.getTargetTriple()); + if (TheTriple.getTriple().empty()) + TheTriple.setTriple(sys::getHostTriple()); + + // Allocate target machine. First, check whether the user has explicitly + // specified an architecture to compile for. If so we have to look it up by + // name, because it might be a backend that has no mapping to a target triple. + const Target *TheTarget = 0; + if (!MArch.empty()) { + for (TargetRegistry::iterator it = TargetRegistry::begin(), + ie = TargetRegistry::end(); it != ie; ++it) { + if (MArch == it->getName()) { + TheTarget = &*it; + break; + } + } + + if (!TheTarget) { + errs() << argv[0] << ": error: invalid target '" << MArch << "'.\n"; + return 1; + } + + // Adjust the triple to match (if known), otherwise stick with the + // module/host triple. + Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch); + if (Type != Triple::UnknownArch) + TheTriple.setArch(Type); + } else { std::string Err; - MArch = TargetMachineRegistry::getClosestStaticTargetForModule(mod, Err); - if (MArch == 0) { - std::cerr << argv[0] << ": error auto-selecting target for module '" - << Err << "'. Please use the -march option to explicitly " - << "pick a target.\n"; + TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Err); + if (TheTarget == 0) { + errs() << argv[0] << ": error auto-selecting target for module '" + << Err << "'. Please use the -march option to explicitly " + << "pick a target.\n"; return 1; } } @@ -262,18 +282,19 @@ int main(int argc, char **argv) { FeaturesStr = Features.getString(); } - std::auto_ptr<TargetMachine> target(MArch->CtorFn(mod, FeaturesStr)); + std::auto_ptr<TargetMachine> + target(TheTarget->createTargetMachine(TheTriple.getTriple(), FeaturesStr)); assert(target.get() && "Could not allocate target machine!"); TargetMachine &Target = *target.get(); // Figure out where we are going to send the output... - raw_ostream *Out = GetOutputStream(argv[0]); + formatted_raw_ostream *Out = GetOutputStream(TheTarget->getName(), argv[0]); if (Out == 0) return 1; CodeGenOpt::Level OLvl = CodeGenOpt::Default; switch (OptLevel) { default: - std::cerr << argv[0] << ": invalid optimization level.\n"; + errs() << argv[0] << ": invalid optimization level.\n"; return 1; case ' ': break; case '0': OLvl = CodeGenOpt::None; break; @@ -286,15 +307,21 @@ int main(int argc, char **argv) { // used by strange things like the C backend. if (Target.WantsWholeFile()) { PassManager PM; - PM.add(new TargetData(*Target.getTargetData())); + + // Add the target data from the target machine, if it exists, or the module. + if (const TargetData *TD = Target.getTargetData()) + PM.add(new TargetData(*TD)); + else + PM.add(new TargetData(&mod)); + if (!NoVerify) PM.add(createVerifierPass()); // Ask the target to add backend passes as necessary. if (Target.addPassesToEmitWholeFile(PM, *Out, FileType, OLvl)) { - std::cerr << argv[0] << ": target does not support generation of this" - << " file type!\n"; - if (Out != &outs()) delete Out; + errs() << argv[0] << ": target does not support generation of this" + << " file type!\n"; + if (Out != &fouts()) delete Out; // And the Out file is empty and useless, so remove it now. sys::Path(OutputFilename).eraseFromDisk(); return 1; @@ -304,7 +331,12 @@ int main(int argc, char **argv) { // Build up all of the passes that we want to do to the module. ExistingModuleProvider Provider(M.release()); FunctionPassManager Passes(&Provider); - Passes.add(new TargetData(*Target.getTargetData())); + + // Add the target data from the target machine, if it exists, or the module. + if (const TargetData *TD = Target.getTargetData()) + Passes.add(new TargetData(*TD)); + else + Passes.add(new TargetData(&mod)); #ifndef NDEBUG if (!NoVerify) @@ -312,7 +344,7 @@ int main(int argc, char **argv) { #endif // Ask the target to add backend passes as necessary. - MachineCodeEmitter *MCE = 0; + ObjectCodeEmitter *OCE = 0; // Override default to generate verbose assembly. Target.setAsmVerbosityDefault(true); @@ -322,26 +354,26 @@ int main(int argc, char **argv) { assert(0 && "Invalid file model!"); return 1; case FileModel::Error: - std::cerr << argv[0] << ": target does not support generation of this" - << " file type!\n"; - if (Out != &outs()) delete Out; + errs() << argv[0] << ": target does not support generation of this" + << " file type!\n"; + if (Out != &fouts()) delete Out; // And the Out file is empty and useless, so remove it now. sys::Path(OutputFilename).eraseFromDisk(); return 1; case FileModel::AsmFile: break; case FileModel::MachOFile: - MCE = AddMachOWriter(Passes, *Out, Target); + OCE = AddMachOWriter(Passes, *Out, Target); break; case FileModel::ElfFile: - MCE = AddELFWriter(Passes, *Out, Target); + OCE = AddELFWriter(Passes, *Out, Target); break; } - if (Target.addPassesToEmitFileFinish(Passes, MCE, OLvl)) { - std::cerr << argv[0] << ": target does not support generation of this" - << " file type!\n"; - if (Out != &outs()) delete Out; + if (Target.addPassesToEmitFileFinish(Passes, OCE, OLvl)) { + errs() << argv[0] << ": target does not support generation of this" + << " file type!\n"; + if (Out != &fouts()) delete Out; // And the Out file is empty and useless, so remove it now. sys::Path(OutputFilename).eraseFromDisk(); return 1; @@ -364,7 +396,7 @@ int main(int argc, char **argv) { } // Delete the ostream if it's not a stdout stream - if (Out != &outs()) delete Out; + if (Out != &fouts()) delete Out; return 0; } diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index a01b0d6..e5c1070 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -28,10 +28,10 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Process.h" #include "llvm/System/Signals.h" #include "llvm/Target/TargetSelect.h" -#include <iostream> #include <cerrno> using namespace llvm; @@ -94,8 +94,13 @@ int main(int argc, char **argv, char * const *envp) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); atexit(do_shutdown); // Call llvm_shutdown() on exit. + + // If we have a native target, initialize it to ensure it is linked in and + // usable by the JIT. + InitializeNativeTarget(); + cl::ParseCommandLineOptions(argc, argv, "llvm interpreter & dynamic compiler\n"); @@ -112,8 +117,8 @@ int main(int argc, char **argv, char * const *envp) { } if (!MP) { - std::cerr << argv[0] << ": error loading program '" << InputFile << "': " - << ErrorMsg << "\n"; + errs() << argv[0] << ": error loading program '" << InputFile << "': " + << ErrorMsg << "\n"; exit(1); } @@ -121,11 +126,17 @@ int main(int argc, char **argv, char * const *envp) { Module *Mod = NoLazyCompilation ? MP->materializeModule(&ErrorMsg) : MP->getModule(); if (!Mod) { - std::cerr << argv[0] << ": bitcode didn't read correctly.\n"; - std::cerr << "Reason: " << ErrorMsg << "\n"; + errs() << argv[0] << ": bitcode didn't read correctly.\n"; + errs() << "Reason: " << ErrorMsg << "\n"; exit(1); } + EngineBuilder builder(MP); + builder.setErrorStr(&ErrorMsg); + builder.setEngineKind(ForceInterpreter + ? EngineKind::Interpreter + : EngineKind::JIT); + // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) Mod->setTargetTriple(TargetTriple); @@ -133,7 +144,7 @@ int main(int argc, char **argv, char * const *envp) { CodeGenOpt::Level OLvl = CodeGenOpt::Default; switch (OptLevel) { default: - std::cerr << argv[0] << ": invalid optimization level.\n"; + errs() << argv[0] << ": invalid optimization level.\n"; return 1; case ' ': break; case '0': OLvl = CodeGenOpt::None; break; @@ -141,18 +152,19 @@ int main(int argc, char **argv, char * const *envp) { case '2': OLvl = CodeGenOpt::Default; break; case '3': OLvl = CodeGenOpt::Aggressive; break; } - - // If we have a native target, initialize it to ensure it is linked in and - // usable by the JIT. - InitializeNativeTarget(); - - EE = ExecutionEngine::create(MP, ForceInterpreter, &ErrorMsg, OLvl); - if (!EE && !ErrorMsg.empty()) { - std::cerr << argv[0] << ":error creating EE: " << ErrorMsg << "\n"; + builder.setOptLevel(OLvl); + + EE = builder.create(); + if (!EE) { + if (!ErrorMsg.empty()) + errs() << argv[0] << ": error creating EE: " << ErrorMsg << "\n"; + else + errs() << argv[0] << ": unknown error creating EE!\n"; exit(1); } EE->RegisterJITEventListener(createMacOSJITEventListener()); + EE->RegisterJITEventListener(createOProfileJITEventListener()); if (NoLazyCompilation) EE->DisableLazyCompilation(); @@ -178,14 +190,15 @@ int main(int argc, char **argv, char * const *envp) { // Function *EntryFn = Mod->getFunction(EntryFunc); if (!EntryFn) { - std::cerr << '\'' << EntryFunc << "\' function not found in module.\n"; + errs() << '\'' << EntryFunc << "\' function not found in module.\n"; return -1; } // If the program doesn't explicitly call exit, we will need the Exit // function later on to make an explicit call, so get the function now. - Constant *Exit = Mod->getOrInsertFunction("exit", Type::VoidTy, - Type::Int32Ty, NULL); + Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), + Type::getInt32Ty(Context), + NULL); // Reset errno to zero on entry to main. errno = 0; @@ -215,10 +228,10 @@ int main(int argc, char **argv, char * const *envp) { ResultGV.IntVal = APInt(32, Result); Args.push_back(ResultGV); EE->runFunction(ExitF, Args); - std::cerr << "ERROR: exit(" << Result << ") returned!\n"; + errs() << "ERROR: exit(" << Result << ") returned!\n"; abort(); } else { - std::cerr << "ERROR: exit defined with wrong prototype!\n"; + errs() << "ERROR: exit defined with wrong prototype!\n"; abort(); } } diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index fe58db1..021a369 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -18,11 +18,13 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Signals.h" #include <iostream> #include <algorithm> #include <iomanip> #include <memory> +#include <fstream> using namespace llvm; // Option for compatibility with AIX, not used but must allow it to be present. @@ -363,7 +365,7 @@ bool doPrint(std::string* ErrMsg) { continue; if (Verbose) - std::cout << "Printing " << I->getPath().toString() << "\n"; + std::cout << "Printing " << I->getPath().str() << "\n"; unsigned len = I->getSize(); std::cout.write(data, len); @@ -421,11 +423,10 @@ doDisplayTable(std::string* ErrMsg) { std::cout << " " << std::setw(4) << I->getUser(); std::cout << "/" << std::setw(4) << I->getGroup(); std::cout << " " << std::setw(8) << I->getSize(); - std::cout << " " << std::setw(20) << - I->getModTime().toString().substr(4); - std::cout << " " << I->getPath().toString() << "\n"; + std::cout << " " << std::setw(20) << I->getModTime().str().substr(4); + std::cout << " " << I->getPath().str() << "\n"; } else { - std::cout << I->getPath().toString() << "\n"; + std::cout << I->getPath().str() << "\n"; } } } @@ -527,7 +528,7 @@ doMove(std::string* ErrMsg) { if (AddBefore || InsertBefore || AddAfter) { for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end(); I != E; ++I ) { - if (RelPos == I->getPath().toString()) { + if (RelPos == I->getPath().str()) { if (AddAfter) { moveto_spot = I; moveto_spot++; @@ -615,7 +616,7 @@ doReplaceOrInsert(std::string* ErrMsg) { std::set<sys::Path>::iterator found = remaining.end(); for (std::set<sys::Path>::iterator RI = remaining.begin(), RE = remaining.end(); RI != RE; ++RI ) { - std::string compare(RI->toString()); + std::string compare(RI->str()); if (TruncateNames && compare.length() > 15) { const char* nm = compare.c_str(); unsigned len = compare.length(); @@ -628,7 +629,7 @@ doReplaceOrInsert(std::string* ErrMsg) { len = 15; compare.assign(nm,len); } - if (compare == I->getPath().toString()) { + if (compare == I->getPath().str()) { found = RI; break; } @@ -660,9 +661,9 @@ doReplaceOrInsert(std::string* ErrMsg) { } // Determine if this is the place where we should insert - if ((AddBefore || InsertBefore) && (RelPos == I->getPath().toString())) + if ((AddBefore || InsertBefore) && RelPos == I->getPath().str()) insert_spot = I; - else if (AddAfter && (RelPos == I->getPath().toString())) { + else if (AddAfter && RelPos == I->getPath().str()) { insert_spot = I; insert_spot++; } @@ -691,7 +692,7 @@ int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Have the command line options parsed and handle things @@ -718,15 +719,15 @@ int main(int argc, char **argv) { if (!ArchivePath.exists()) { // Produce a warning if we should and we're creating the archive if (!Create) - std::cerr << argv[0] << ": creating " << ArchivePath.toString() << "\n"; + errs() << argv[0] << ": creating " << ArchivePath.str() << "\n"; TheArchive = Archive::CreateEmpty(ArchivePath, Context); TheArchive->writeToDisk(); } else { std::string Error; TheArchive = Archive::OpenAndLoad(ArchivePath, Context, &Error); if (TheArchive == 0) { - std::cerr << argv[0] << ": error loading '" << ArchivePath << "': " - << Error << "!\n"; + errs() << argv[0] << ": error loading '" << ArchivePath.str() << "': " + << Error << "!\n"; return 1; } } @@ -749,27 +750,27 @@ int main(int argc, char **argv) { case DisplayTable: haveError = doDisplayTable(&ErrMsg); break; case Extract: haveError = doExtract(&ErrMsg); break; case NoOperation: - std::cerr << argv[0] << ": No operation was selected.\n"; + errs() << argv[0] << ": No operation was selected.\n"; break; } if (haveError) { - std::cerr << argv[0] << ": " << ErrMsg << "\n"; + errs() << argv[0] << ": " << ErrMsg << "\n"; return 1; } } catch (const char*msg) { // These errors are usage errors, thrown only by the various checks in the // code above. - std::cerr << argv[0] << ": " << msg << "\n\n"; + errs() << argv[0] << ": " << msg << "\n\n"; cl::PrintHelpMessage(); exitCode = 1; } catch (const std::string& msg) { // These errors are thrown by LLVM libraries (e.g. lib System) and represent // a more serious error so we bump the exitCode and don't print the usage. - std::cerr << argv[0] << ": " << msg << "\n"; + errs() << argv[0] << ": " << msg << "\n"; exitCode = 2; } catch (...) { // This really shouldn't happen, but just in case .... - std::cerr << argv[0] << ": An unexpected unknown exception occurred.\n"; + errs() << argv[0] << ": An unexpected unknown exception occurred.\n"; exitCode = 3; } diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp index eccabd5..d510297 100644 --- a/tools/llvm-as/llvm-as.cpp +++ b/tools/llvm-as/llvm-as.cpp @@ -24,12 +24,9 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Signals.h" -#include <fstream> -#include <iostream> #include <memory> using namespace llvm; @@ -41,7 +38,7 @@ OutputFilename("o", cl::desc("Override output filename"), cl::value_desc("filename")); static cl::opt<bool> -Force("f", cl::desc("Overwrite output files")); +Force("f", cl::desc("Enable binary output on terminals")); static cl::opt<bool> DisableOutput("disable-output", cl::desc("Disable output"), cl::init(false)); @@ -57,96 +54,64 @@ int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm .ll -> .bc assembler\n"); - int exitCode = 0; - std::ostream *Out = 0; - try { - // Parse the file now... - SMDiagnostic Err; - std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context)); - if (M.get() == 0) { - Err.Print(argv[0], errs()); - return 1; - } + // Parse the file now... + SMDiagnostic Err; + std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context)); + if (M.get() == 0) { + Err.Print(argv[0], errs()); + return 1; + } - if (!DisableVerify) { - std::string Err; - if (verifyModule(*M.get(), ReturnStatusAction, &Err)) { - cerr << argv[0] + if (!DisableVerify) { + std::string Err; + if (verifyModule(*M.get(), ReturnStatusAction, &Err)) { + errs() << argv[0] << ": assembly parsed, but does not verify as correct!\n"; - cerr << Err; - return 1; - } - } + errs() << Err; + return 1; + } + } - if (DumpAsm) cerr << "Here's the assembly:\n" << *M.get(); - - if (OutputFilename != "") { // Specified an output filename? - if (OutputFilename != "-") { // Not stdout? - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - cerr << argv[0] << ": error opening '" << OutputFilename - << "': file exists!\n" - << "Use -f command line argument to force output\n"; - return 1; - } - Out = new std::ofstream(OutputFilename.c_str(), std::ios::out | - std::ios::trunc | std::ios::binary); - } else { // Specified stdout - // FIXME: cout is not binary! - Out = &std::cout; - } + if (DumpAsm) errs() << "Here's the assembly:\n" << *M.get(); + + // Infer the output filename if needed. + if (OutputFilename.empty()) { + if (InputFilename == "-") { + OutputFilename = "-"; } else { - if (InputFilename == "-") { - OutputFilename = "-"; - Out = &std::cout; + std::string IFN = InputFilename; + int Len = IFN.length(); + if (IFN[Len-3] == '.' && IFN[Len-2] == 'l' && IFN[Len-1] == 'l') { + // Source ends in .ll + OutputFilename = std::string(IFN.begin(), IFN.end()-3); } else { - std::string IFN = InputFilename; - int Len = IFN.length(); - if (IFN[Len-3] == '.' && IFN[Len-2] == 'l' && IFN[Len-1] == 'l') { - // Source ends in .ll - OutputFilename = std::string(IFN.begin(), IFN.end()-3); - } else { - OutputFilename = IFN; // Append a .bc to it - } - OutputFilename += ".bc"; - - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - cerr << argv[0] << ": error opening '" << OutputFilename - << "': file exists!\n" - << "Use -f command line argument to force output\n"; - return 1; - } - - Out = new std::ofstream(OutputFilename.c_str(), std::ios::out | - std::ios::trunc | std::ios::binary); - // Make sure that the Out file gets unlinked from the disk if we get a - // SIGINT - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); + OutputFilename = IFN; // Append a .bc to it } + OutputFilename += ".bc"; } + } - if (!Out->good()) { - cerr << argv[0] << ": error opening " << OutputFilename << "!\n"; - return 1; - } - - if (!DisableOutput) - if (Force || !CheckBitcodeOutputToConsole(Out,true)) - WriteBitcodeToFile(M.get(), *Out); - } catch (const std::string& msg) { - cerr << argv[0] << ": " << msg << "\n"; - exitCode = 1; - } catch (...) { - cerr << argv[0] << ": Unexpected unknown exception occurred.\n"; - exitCode = 1; + // 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)); + if (!ErrorInfo.empty()) { + errs() << ErrorInfo << '\n'; + return 1; } - if (Out != &std::cout) delete Out; - return exitCode; + if (!DisableOutput) + if (Force || !CheckBitcodeOutputToConsole(*Out, true)) + WriteBitcodeToFile(M.get(), *Out); + return 0; } diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index b401a21..6d5b2b51 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -20,7 +20,7 @@ // produces on std::out a summary of the bitcode file that shows various // statistics about the contents of the file. By default this information is // detailed and contains information about individual bitcode blocks and the -// functions in the module. +// functions in the module. // The tool is also able to print a bitcode file in a straight forward text // format that shows the containment and relationships of the information in // the bitcode file (-dump option). @@ -32,13 +32,14 @@ #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Format.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 <cstdio> #include <map> -#include <fstream> -#include <iostream> #include <algorithm> using namespace llvm; @@ -62,7 +63,7 @@ NonSymbolic("non-symbolic", cl::desc("Emit numberic info in dump even if" " symbolic info is available")); -/// CurStreamType - If we can sniff the flavor of this stream, we can produce +/// CurStreamType - If we can sniff the flavor of this stream, we can produce /// better dump info. static enum { UnknownBitstream, @@ -80,26 +81,28 @@ static const char *GetBlockName(unsigned BlockID, return "BLOCKINFO_BLOCK"; return 0; } - + // Check to see if we have a blockinfo record for this block, with a name. if (const BitstreamReader::BlockInfo *Info = StreamFile.getBlockInfo(BlockID)) { if (!Info->Name.empty()) return Info->Name.c_str(); } - - + + if (CurStreamType != LLVMIRBitstream) return 0; - + switch (BlockID) { - default: return 0; - case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK"; - case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK"; - case bitc::TYPE_BLOCK_ID: return "TYPE_BLOCK"; - case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK"; - case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK"; - case bitc::TYPE_SYMTAB_BLOCK_ID: return "TYPE_SYMTAB"; - case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB"; + default: return 0; + case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK"; + case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK"; + case bitc::TYPE_BLOCK_ID: return "TYPE_BLOCK"; + case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK"; + case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK"; + case bitc::TYPE_SYMTAB_BLOCK_ID: return "TYPE_SYMTAB"; + case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB"; + case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK"; + case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK"; } } @@ -119,7 +122,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, } return 0; } - + // Check to see if we have a blockinfo record for this record, with a name. if (const BitstreamReader::BlockInfo *Info = StreamFile.getBlockInfo(BlockID)) { @@ -127,10 +130,10 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, if (Info->RecordNames[i].first == CodeID) return Info->RecordNames[i].second.c_str(); } - - + + if (CurStreamType != LLVMIRBitstream) return 0; - + switch (BlockID) { default: return 0; case bitc::MODULE_BLOCK_ID: @@ -173,67 +176,67 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::TYPE_CODE_PPC_FP128: return "PPC_FP128"; case bitc::TYPE_CODE_METADATA: return "METADATA"; } - + case bitc::CONSTANTS_BLOCK_ID: switch (CodeID) { default: return 0; - case bitc::CST_CODE_SETTYPE: return "SETTYPE"; - case bitc::CST_CODE_NULL: return "NULL"; - case bitc::CST_CODE_UNDEF: return "UNDEF"; - case bitc::CST_CODE_INTEGER: return "INTEGER"; - case bitc::CST_CODE_WIDE_INTEGER: return "WIDE_INTEGER"; - case bitc::CST_CODE_FLOAT: return "FLOAT"; - case bitc::CST_CODE_AGGREGATE: return "AGGREGATE"; - case bitc::CST_CODE_STRING: return "STRING"; - case bitc::CST_CODE_CSTRING: return "CSTRING"; - case bitc::CST_CODE_CE_BINOP: return "CE_BINOP"; - case bitc::CST_CODE_CE_CAST: return "CE_CAST"; - case bitc::CST_CODE_CE_GEP: return "CE_GEP"; - case bitc::CST_CODE_CE_SELECT: return "CE_SELECT"; - case bitc::CST_CODE_CE_EXTRACTELT: return "CE_EXTRACTELT"; - case bitc::CST_CODE_CE_INSERTELT: return "CE_INSERTELT"; - case bitc::CST_CODE_CE_SHUFFLEVEC: return "CE_SHUFFLEVEC"; - case bitc::CST_CODE_CE_CMP: return "CE_CMP"; - case bitc::CST_CODE_INLINEASM: return "INLINEASM"; - case bitc::CST_CODE_CE_SHUFVEC_EX: return "CE_SHUFVEC_EX"; - case bitc::CST_CODE_MDSTRING: return "MDSTRING"; - case bitc::CST_CODE_MDNODE: return "MDNODE"; - } + case bitc::CST_CODE_SETTYPE: return "SETTYPE"; + case bitc::CST_CODE_NULL: return "NULL"; + case bitc::CST_CODE_UNDEF: return "UNDEF"; + case bitc::CST_CODE_INTEGER: return "INTEGER"; + case bitc::CST_CODE_WIDE_INTEGER: return "WIDE_INTEGER"; + case bitc::CST_CODE_FLOAT: return "FLOAT"; + case bitc::CST_CODE_AGGREGATE: return "AGGREGATE"; + case bitc::CST_CODE_STRING: return "STRING"; + case bitc::CST_CODE_CSTRING: return "CSTRING"; + case bitc::CST_CODE_CE_BINOP: return "CE_BINOP"; + case bitc::CST_CODE_CE_CAST: return "CE_CAST"; + case bitc::CST_CODE_CE_GEP: return "CE_GEP"; + case bitc::CST_CODE_CE_INBOUNDS_GEP: return "CE_INBOUNDS_GEP"; + case bitc::CST_CODE_CE_SELECT: return "CE_SELECT"; + case bitc::CST_CODE_CE_EXTRACTELT: return "CE_EXTRACTELT"; + case bitc::CST_CODE_CE_INSERTELT: return "CE_INSERTELT"; + case bitc::CST_CODE_CE_SHUFFLEVEC: return "CE_SHUFFLEVEC"; + case bitc::CST_CODE_CE_CMP: return "CE_CMP"; + case bitc::CST_CODE_INLINEASM: return "INLINEASM"; + case bitc::CST_CODE_CE_SHUFVEC_EX: return "CE_SHUFVEC_EX"; + } case bitc::FUNCTION_BLOCK_ID: switch (CodeID) { default: return 0; case bitc::FUNC_CODE_DECLAREBLOCKS: return "DECLAREBLOCKS"; - - case bitc::FUNC_CODE_INST_BINOP: return "INST_BINOP"; - case bitc::FUNC_CODE_INST_CAST: return "INST_CAST"; - case bitc::FUNC_CODE_INST_GEP: return "INST_GEP"; - case bitc::FUNC_CODE_INST_SELECT: return "INST_SELECT"; - case bitc::FUNC_CODE_INST_EXTRACTELT: return "INST_EXTRACTELT"; - case bitc::FUNC_CODE_INST_INSERTELT: return "INST_INSERTELT"; - case bitc::FUNC_CODE_INST_SHUFFLEVEC: return "INST_SHUFFLEVEC"; - case bitc::FUNC_CODE_INST_CMP: return "INST_CMP"; - - case bitc::FUNC_CODE_INST_RET: return "INST_RET"; - case bitc::FUNC_CODE_INST_BR: return "INST_BR"; - case bitc::FUNC_CODE_INST_SWITCH: return "INST_SWITCH"; - case bitc::FUNC_CODE_INST_INVOKE: return "INST_INVOKE"; - case bitc::FUNC_CODE_INST_UNWIND: return "INST_UNWIND"; - case bitc::FUNC_CODE_INST_UNREACHABLE: return "INST_UNREACHABLE"; - - case bitc::FUNC_CODE_INST_PHI: return "INST_PHI"; - case bitc::FUNC_CODE_INST_MALLOC: return "INST_MALLOC"; - case bitc::FUNC_CODE_INST_FREE: return "INST_FREE"; - case bitc::FUNC_CODE_INST_ALLOCA: return "INST_ALLOCA"; - case bitc::FUNC_CODE_INST_LOAD: return "INST_LOAD"; - case bitc::FUNC_CODE_INST_STORE: return "INST_STORE"; - case bitc::FUNC_CODE_INST_CALL: return "INST_CALL"; - case bitc::FUNC_CODE_INST_VAARG: return "INST_VAARG"; - case bitc::FUNC_CODE_INST_STORE2: return "INST_STORE2"; - case bitc::FUNC_CODE_INST_GETRESULT: return "INST_GETRESULT"; - case bitc::FUNC_CODE_INST_EXTRACTVAL: return "INST_EXTRACTVAL"; - case bitc::FUNC_CODE_INST_INSERTVAL: return "INST_INSERTVAL"; - case bitc::FUNC_CODE_INST_CMP2: return "INST_CMP2"; - case bitc::FUNC_CODE_INST_VSELECT: return "INST_VSELECT"; + + case bitc::FUNC_CODE_INST_BINOP: return "INST_BINOP"; + case bitc::FUNC_CODE_INST_CAST: return "INST_CAST"; + case bitc::FUNC_CODE_INST_GEP: return "INST_GEP"; + case bitc::FUNC_CODE_INST_INBOUNDS_GEP: return "INST_INBOUNDS_GEP"; + case bitc::FUNC_CODE_INST_SELECT: return "INST_SELECT"; + case bitc::FUNC_CODE_INST_EXTRACTELT: return "INST_EXTRACTELT"; + case bitc::FUNC_CODE_INST_INSERTELT: return "INST_INSERTELT"; + case bitc::FUNC_CODE_INST_SHUFFLEVEC: return "INST_SHUFFLEVEC"; + case bitc::FUNC_CODE_INST_CMP: return "INST_CMP"; + + case bitc::FUNC_CODE_INST_RET: return "INST_RET"; + case bitc::FUNC_CODE_INST_BR: return "INST_BR"; + case bitc::FUNC_CODE_INST_SWITCH: return "INST_SWITCH"; + case bitc::FUNC_CODE_INST_INVOKE: return "INST_INVOKE"; + case bitc::FUNC_CODE_INST_UNWIND: return "INST_UNWIND"; + case bitc::FUNC_CODE_INST_UNREACHABLE: return "INST_UNREACHABLE"; + + case bitc::FUNC_CODE_INST_PHI: return "INST_PHI"; + case bitc::FUNC_CODE_INST_MALLOC: return "INST_MALLOC"; + case bitc::FUNC_CODE_INST_FREE: return "INST_FREE"; + case bitc::FUNC_CODE_INST_ALLOCA: return "INST_ALLOCA"; + case bitc::FUNC_CODE_INST_LOAD: return "INST_LOAD"; + case bitc::FUNC_CODE_INST_STORE: return "INST_STORE"; + case bitc::FUNC_CODE_INST_CALL: return "INST_CALL"; + case bitc::FUNC_CODE_INST_VAARG: return "INST_VAARG"; + case bitc::FUNC_CODE_INST_STORE2: return "INST_STORE2"; + case bitc::FUNC_CODE_INST_GETRESULT: return "INST_GETRESULT"; + case bitc::FUNC_CODE_INST_EXTRACTVAL: return "INST_EXTRACTVAL"; + case bitc::FUNC_CODE_INST_INSERTVAL: return "INST_INSERTVAL"; + case bitc::FUNC_CODE_INST_CMP2: return "INST_CMP2"; + case bitc::FUNC_CODE_INST_VSELECT: return "INST_VSELECT"; } case bitc::TYPE_SYMTAB_BLOCK_ID: switch (CodeID) { @@ -246,6 +249,20 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::VST_CODE_ENTRY: return "ENTRY"; case bitc::VST_CODE_BBENTRY: return "BBENTRY"; } + case bitc::METADATA_ATTACHMENT_ID: + switch(CodeID) { + default:return 0; + case bitc::METADATA_ATTACHMENT: return "METADATA_ATTACHMENT"; + } + 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_NAME: return "METADATA_NAME"; + case bitc::METADATA_NAMED_NODE: return "NAMEDMDNODE"; + case bitc::METADATA_KIND: return "METADATA_KIND"; + } } } @@ -253,30 +270,30 @@ struct PerRecordStats { unsigned NumInstances; unsigned NumAbbrev; uint64_t TotalBits; - + PerRecordStats() : NumInstances(0), NumAbbrev(0), TotalBits(0) {} }; struct PerBlockIDStats { /// NumInstances - This the number of times this block ID has been seen. unsigned NumInstances; - + /// NumBits - The total size in bits of all of these blocks. uint64_t NumBits; - + /// NumSubBlocks - The total number of blocks these blocks contain. unsigned NumSubBlocks; - + /// NumAbbrevs - The total number of abbreviations. unsigned NumAbbrevs; - - /// NumRecords - The total number of records these blocks contain, and the + + /// NumRecords - The total number of records these blocks contain, and the /// number that are abbreviated. unsigned NumRecords, NumAbbreviatedRecords; - + /// CodeFreq - Keep track of the number of times we see each code. std::vector<PerRecordStats> CodeFreq; - + PerBlockIDStats() : NumInstances(0), NumBits(0), NumSubBlocks(0), NumAbbrevs(0), NumRecords(0), NumAbbreviatedRecords(0) {} @@ -289,7 +306,7 @@ static std::map<unsigned, PerBlockIDStats> BlockIDStats; /// Error - All bitcode analysis errors go through this function, making this a /// good place to breakpoint if debugging. static bool Error(const std::string &Err) { - std::cerr << Err << "\n"; + errs() << Err << "\n"; return true; } @@ -301,38 +318,38 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { // Get the statistics for this BlockID. PerBlockIDStats &BlockStats = BlockIDStats[BlockID]; - + BlockStats.NumInstances++; - + // BLOCKINFO is a special part of the stream. if (BlockID == bitc::BLOCKINFO_BLOCK_ID) { - if (Dump) std::cerr << Indent << "<BLOCKINFO_BLOCK/>\n"; + if (Dump) errs() << Indent << "<BLOCKINFO_BLOCK/>\n"; if (Stream.ReadBlockInfoBlock()) return Error("Malformed BlockInfoBlock"); uint64_t BlockBitEnd = Stream.GetCurrentBitNo(); BlockStats.NumBits += BlockBitEnd-BlockBitStart; return false; } - + unsigned NumWords = 0; if (Stream.EnterSubBlock(BlockID, &NumWords)) return Error("Malformed block record"); const char *BlockName = 0; if (Dump) { - std::cerr << Indent << "<"; + errs() << Indent << "<"; if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader()))) - std::cerr << BlockName; + errs() << BlockName; else - std::cerr << "UnknownBlock" << BlockID; - + errs() << "UnknownBlock" << BlockID; + if (NonSymbolic && BlockName) - std::cerr << " BlockID=" << BlockID; - - std::cerr << " NumWords=" << NumWords - << " BlockCodeSize=" << Stream.GetAbbrevIDWidth() << ">\n"; + errs() << " BlockID=" << BlockID; + + errs() << " NumWords=" << NumWords + << " BlockCodeSize=" << Stream.GetAbbrevIDWidth() << ">\n"; } - + SmallVector<uint64_t, 64> Record; // Read all the records for this block. @@ -341,7 +358,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { return Error("Premature end of bitstream"); uint64_t RecordStartBit = Stream.GetCurrentBitNo(); - + // Read the code for this record. unsigned AbbrevID = Stream.ReadCode(); switch (AbbrevID) { @@ -351,21 +368,21 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { uint64_t BlockBitEnd = Stream.GetCurrentBitNo(); BlockStats.NumBits += BlockBitEnd-BlockBitStart; if (Dump) { - std::cerr << Indent << "</"; + errs() << Indent << "</"; if (BlockName) - std::cerr << BlockName << ">\n"; + errs() << BlockName << ">\n"; else - std::cerr << "UnknownBlock" << BlockID << ">\n"; + errs() << "UnknownBlock" << BlockID << ">\n"; } return false; - } + } case bitc::ENTER_SUBBLOCK: { uint64_t SubBlockBitStart = Stream.GetCurrentBitNo(); if (ParseBlock(Stream, IndentLevel+1)) return true; ++BlockStats.NumSubBlocks; uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo(); - + // Don't include subblock sizes in the size of this block. BlockBitStart += SubBlockBitEnd-SubBlockBitStart; break; @@ -380,13 +397,13 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { ++BlockStats.NumRecords; if (AbbrevID != bitc::UNABBREV_RECORD) ++BlockStats.NumAbbreviatedRecords; - + const char *BlobStart = 0; unsigned BlobLen = 0; unsigned Code = Stream.ReadRecord(AbbrevID, Record, BlobStart, BlobLen); - - + + // Increment the # occurrences of this code. if (BlockStats.CodeFreq.size() <= Code) BlockStats.CodeFreq.resize(Code+1); @@ -395,43 +412,43 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { Stream.GetCurrentBitNo()-RecordStartBit; if (AbbrevID != bitc::UNABBREV_RECORD) BlockStats.CodeFreq[Code].NumAbbrev++; - + if (Dump) { - std::cerr << Indent << " <"; + errs() << Indent << " <"; if (const char *CodeName = GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) - std::cerr << CodeName; + errs() << CodeName; else - std::cerr << "UnknownCode" << Code; + errs() << "UnknownCode" << Code; if (NonSymbolic && GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) - std::cerr << " codeid=" << Code; + errs() << " codeid=" << Code; if (AbbrevID != bitc::UNABBREV_RECORD) - std::cerr << " abbrevid=" << AbbrevID; + errs() << " abbrevid=" << AbbrevID; for (unsigned i = 0, e = Record.size(); i != e; ++i) - std::cerr << " op" << i << "=" << (int64_t)Record[i]; - - std::cerr << "/>"; - + errs() << " op" << i << "=" << (int64_t)Record[i]; + + errs() << "/>"; + if (BlobStart) { - std::cerr << " blob data = "; + errs() << " blob data = "; bool BlobIsPrintable = true; for (unsigned i = 0; i != BlobLen; ++i) if (!isprint(BlobStart[i])) { BlobIsPrintable = false; break; } - + if (BlobIsPrintable) - std::cerr << "'" << std::string(BlobStart, BlobStart+BlobLen) <<"'"; + errs() << "'" << std::string(BlobStart, BlobStart+BlobLen) <<"'"; else - std::cerr << "unprintable, " << BlobLen << " bytes."; + errs() << "unprintable, " << BlobLen << " bytes."; } - - std::cerr << "\n"; + + errs() << "\n"; } - + break; } } @@ -453,23 +470,23 @@ static int AnalyzeBitcode() { if (MemBuf == 0) return Error("Error reading '" + InputFilename + "'."); - + if (MemBuf->getBufferSize() & 3) return Error("Bitcode stream should be a multiple of 4 bytes in length"); - + unsigned char *BufPtr = (unsigned char *)MemBuf->getBufferStart(); unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize(); - + // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. if (isBitcodeWrapper(BufPtr, EndBufPtr)) if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr)) return Error("Invalid bitcode wrapper header"); - + BitstreamReader StreamFile(BufPtr, EndBufPtr); BitstreamCursor Stream(StreamFile); StreamFile.CollectBlockInfoNames(); - + // Read the stream signature. char Signature[6]; Signature[0] = Stream.Read(8); @@ -478,7 +495,7 @@ static int AnalyzeBitcode() { Signature[3] = Stream.Read(4); Signature[4] = Stream.Read(4); Signature[5] = Stream.Read(4); - + // Autodetect the file contents, if it is one we know. CurStreamType = UnknownBitstream; if (Signature[0] == 'B' && Signature[1] == 'C' && @@ -487,71 +504,72 @@ static int AnalyzeBitcode() { CurStreamType = LLVMIRBitstream; unsigned NumTopBlocks = 0; - + // Parse the top-level structure. We only allow blocks at the top-level. while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code != bitc::ENTER_SUBBLOCK) return Error("Invalid record at top-level"); - + if (ParseBlock(Stream, 0)) return true; ++NumTopBlocks; } - - if (Dump) std::cerr << "\n\n"; - + + if (Dump) errs() << "\n\n"; + uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT; // Print a summary of the read file. - std::cerr << "Summary of " << InputFilename << ":\n"; - std::cerr << " Total size: "; + errs() << "Summary of " << InputFilename << ":\n"; + errs() << " Total size: "; PrintSize(BufferSizeBits); - std::cerr << "\n"; - std::cerr << " Stream type: "; + errs() << "\n"; + errs() << " Stream type: "; switch (CurStreamType) { default: assert(0 && "Unknown bitstream type"); - case UnknownBitstream: std::cerr << "unknown\n"; break; - case LLVMIRBitstream: std::cerr << "LLVM IR\n"; break; + case UnknownBitstream: errs() << "unknown\n"; break; + case LLVMIRBitstream: errs() << "LLVM IR\n"; break; } - std::cerr << " # Toplevel Blocks: " << NumTopBlocks << "\n"; - std::cerr << "\n"; + errs() << " # Toplevel Blocks: " << NumTopBlocks << "\n"; + errs() << "\n"; // Emit per-block stats. - std::cerr << "Per-block Summary:\n"; + errs() << "Per-block Summary:\n"; for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(), E = BlockIDStats.end(); I != E; ++I) { - std::cerr << " Block ID #" << I->first; + errs() << " Block ID #" << I->first; if (const char *BlockName = GetBlockName(I->first, StreamFile)) - std::cerr << " (" << BlockName << ")"; - std::cerr << ":\n"; - + errs() << " (" << BlockName << ")"; + errs() << ":\n"; + const PerBlockIDStats &Stats = I->second; - std::cerr << " Num Instances: " << Stats.NumInstances << "\n"; - std::cerr << " Total Size: "; + errs() << " Num Instances: " << Stats.NumInstances << "\n"; + errs() << " Total Size: "; PrintSize(Stats.NumBits); - std::cerr << "\n"; - std::cerr << " % of file: " - << Stats.NumBits/(double)BufferSizeBits*100 << "\n"; + errs() << "\n"; + double pct = (Stats.NumBits * 100.0) / BufferSizeBits; + errs() << " Percent of file: " << format("%2.4f%%", pct) << "\n"; if (Stats.NumInstances > 1) { - std::cerr << " Average Size: "; + errs() << " Average Size: "; PrintSize(Stats.NumBits/(double)Stats.NumInstances); - std::cerr << "\n"; - std::cerr << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/" - << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n"; - std::cerr << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/" - << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n"; - std::cerr << " Tot/Avg Records: " << Stats.NumRecords << "/" - << Stats.NumRecords/(double)Stats.NumInstances << "\n"; + errs() << "\n"; + errs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/" + << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n"; + errs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/" + << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n"; + errs() << " Tot/Avg Records: " << Stats.NumRecords << "/" + << Stats.NumRecords/(double)Stats.NumInstances << "\n"; } else { - std::cerr << " Num SubBlocks: " << Stats.NumSubBlocks << "\n"; - std::cerr << " Num Abbrevs: " << Stats.NumAbbrevs << "\n"; - std::cerr << " Num Records: " << Stats.NumRecords << "\n"; + errs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n"; + errs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n"; + errs() << " Num Records: " << Stats.NumRecords << "\n"; + } + if (Stats.NumRecords) { + double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords; + errs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n"; } - if (Stats.NumRecords) - std::cerr << " % Abbrev Recs: " << (Stats.NumAbbreviatedRecords/ - (double)Stats.NumRecords)*100 << "\n"; - std::cerr << "\n"; - + errs() << "\n"; + // Print a histogram of the codes we see. if (!NoHistogram && !Stats.CodeFreq.empty()) { std::vector<std::pair<unsigned, unsigned> > FreqPairs; // <freq,code> @@ -560,29 +578,29 @@ static int AnalyzeBitcode() { FreqPairs.push_back(std::make_pair(Freq, i)); std::stable_sort(FreqPairs.begin(), FreqPairs.end()); std::reverse(FreqPairs.begin(), FreqPairs.end()); - - std::cerr << "\tRecord Histogram:\n"; + + errs() << "\tRecord Histogram:\n"; fprintf(stderr, "\t\t Count # Bits %% Abv Record Kind\n"); for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) { const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second]; - + fprintf(stderr, "\t\t%7d %9llu ", RecStats.NumInstances, (unsigned long long)RecStats.TotalBits); - + if (RecStats.NumAbbrev) fprintf(stderr, "%7.2f ", (double)RecStats.NumAbbrev/RecStats.NumInstances*100); else fprintf(stderr, " "); - - if (const char *CodeName = + + if (const char *CodeName = GetCodeName(FreqPairs[i].second, I->first, StreamFile)) fprintf(stderr, "%s\n", CodeName); else fprintf(stderr, "UnknownCode%d\n", FreqPairs[i].second); } - std::cerr << "\n"; - + errs() << "\n"; + } } return 0; @@ -595,6 +613,6 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n"); - + return AnalyzeBitcode(); } diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index 2cfd6bb..7638f3c 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -1,5 +1,6 @@ include(TestBigEndian) +include(FindPerl) if( NOT PERL_FOUND ) message(FATAL_ERROR "Perl required but not found!") endif( NOT PERL_FOUND ) @@ -7,6 +8,8 @@ endif( NOT PERL_FOUND ) set(PERL ${PERL_EXECUTABLE}) set(VERSION PACKAGE_VERSION) set(PREFIX ${LLVM_BINARY_DIR}) # TODO: Root for `make install'. +set(abs_top_srcdir ${LLVM_MAIN_SRC_DIR}) +set(abs_top_builddir ${LLVM_BINARY_DIR}) execute_process(COMMAND date OUTPUT_VARIABLE LLVM_CONFIGTIME OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -26,7 +29,7 @@ endif( IS_BIG_ENDIAN ) set(SHLIBEXT ${LTDL_SHLIB_EXT}) #EXEEXT already set. set(OS "${CMAKE_SYSTEM}") -set(ARCH "X86") # TODO: This gives "i686" in Linux: "${CMAKE_SYSTEM_PROCESSOR}") +set(ARCH "${LLVM_NATIVE_ARCH}") get_system_libs(LLVM_SYSTEM_LIBS_LIST) foreach(l ${LLVM_SYSTEM_LIBS_LIST}) @@ -103,7 +106,6 @@ add_custom_command(OUTPUT ${LLVM_CONFIG} COMMAND ${CMAKE_COMMAND} -E remove -f temp.sed COMMAND cat ${FINAL_LIBDEPS} >> ${LLVM_CONFIG} COMMAND chmod +x ${LLVM_CONFIG} - COMMAND cd ${CMAKE_BINARY_DIR} && ${CMAKE_COMMAND} -U HAVE_LLVM_CONFIG -D LLVM_BINARY_DIR="${LLVM_BINARY_DIR}" ${CMAKE_SOURCE_DIR} DEPENDS ${FINAL_LIBDEPS} ${LLVM_CONFIG_IN} COMMENT "Building llvm-config script." ) @@ -113,7 +115,37 @@ add_custom_target(llvm-config.target ALL add_dependencies(llvm-config.target ${llvm_lib_targets}) +# Make sure that llvm-config builds before the llvm tools, so we have +# LibDeps.txt and can use it for updating the hard-coded library +# dependencies on cmake/modules/LLVMLibDeps.cmake when the tools' +# build fail due to outdated dependencies: +set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} llvm-config.target) + install(FILES ${LLVM_CONFIG} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION bin) + + +# Regeneration of library dependencies. + +# See the comments at the end of cmake/modules/LLVMConfig.cmake for +# notes and guidelines. + +set(LLVMLibDeps ${LLVM_MAIN_SRC_DIR}/cmake/modules/LLVMLibDeps.cmake) +set(LLVMLibDeps_TMP ${CMAKE_CURRENT_BINARY_DIR}/LLVMLibDeps.cmake.tmp) + +add_custom_command(OUTPUT ${LLVMLibDeps_TMP} + COMMAND sed -e s'@\\.a@@g' -e s'@\\.so@@g' -e 's@libLLVM@LLVM@g' -e 's@: @ @' -e 's@\\\(.*\\\)@set\(MSVC_LIB_DEPS_\\1\)@' ${FINAL_LIBDEPS} > ${LLVMLibDeps_TMP} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LLVMLibDeps_TMP} ${LLVMLibDeps} + DEPENDS ${FINAL_LIBDEPS} + COMMENT "Updating cmake library dependencies file ${LLVMLibDeps}" + ) + +if( LLVM_TARGETS_TO_BUILD STREQUAL LLVM_ALL_TARGETS ) + add_custom_target(llvmlibdeps.target ALL DEPENDS ${LLVMLibDeps_TMP}) + add_dependencies(llvmlibdeps.target llvm-config.target) + set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} llvmlibdeps.target) +endif() + +set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE) diff --git a/tools/llvm-config/llvm-config.in.in b/tools/llvm-config/llvm-config.in.in index 36b5112..7f93f16 100644 --- a/tools/llvm-config/llvm-config.in.in +++ b/tools/llvm-config/llvm-config.in.in @@ -26,17 +26,6 @@ my $PREFIX = q{@LLVM_PREFIX@}; my $LLVM_CONFIGTIME = q{@LLVM_CONFIGTIME@}; my $LLVM_SRC_ROOT = q{@abs_top_srcdir@}; my $LLVM_OBJ_ROOT = q{@abs_top_builddir@}; -my $LLVM_ON_WIN32 = q{@LLVM_ON_WIN32@}; -my $LLVM_ON_UNIX = q{@LLVM_ON_UNIX@}; -my $LLVMGCCDIR = q{@LLVMGCCDIR@}; -my $LLVMGCC = q{@LLVMGCC@}; -my $LLVMGXX = q{@LLVMGXX@}; -my $LLVMGCC_VERSION = q{@LLVMGCC_VERSION@}; -my $LLVMGCC_MAJVERS = q{@LLVMGCC_MAJVERS@}; -my $ENDIAN = q{@ENDIAN@}; -my $SHLIBEXT = q{@SHLIBEXT@}; -my $EXEEXT = q{@EXEEXT@}; -my $OS = q{@OS@}; my $ARCH = lc(q{@ARCH@}); my $TARGET_TRIPLE = q{@target@}; my $TARGETS_TO_BUILD = q{@TARGETS_TO_BUILD@}; @@ -81,12 +70,15 @@ $ABS_OBJ_ROOT = `cd $ABS_OBJ_ROOT; $PWD` if (-d $ABS_OBJ_ROOT); chomp($ABS_OBJ_ROOT); my $INCLUDEDIR = "$ABS_RUN_DIR/include"; +my $INCLUDEOPTION = "-I$INCLUDEDIR"; my $LIBDIR = "$ABS_RUN_DIR/lib"; my $BINDIR = "$ABS_RUN_DIR/bin"; if ($ABS_RUN_DIR eq $ABS_OBJ_ROOT) { # If we are running out of the build directory, the include dir is in the # srcdir. $INCLUDEDIR = "$LLVM_SRC_ROOT/include"; + # We need include files from both the srcdir and objdir. + $INCLUDEOPTION = "-I$INCLUDEDIR -I$LLVM_OBJ_ROOT/include" } else { # If installed, ignore the prefix the tree was configured with, use the # current prefix. @@ -120,11 +112,11 @@ foreach my $arg (@ARGV) { } elsif ($arg eq "--libdir") { $has_opt = 1; print "$LIBDIR\n"; } elsif ($arg eq "--cppflags") { - $has_opt = 1; print "-I$INCLUDEDIR $CPPFLAGS\n"; + $has_opt = 1; print "$INCLUDEOPTION $CPPFLAGS\n"; } elsif ($arg eq "--cflags") { - $has_opt = 1; print "-I$INCLUDEDIR $CFLAGS\n"; + $has_opt = 1; print "$INCLUDEOPTION $CFLAGS\n"; } elsif ($arg eq "--cxxflags") { - $has_opt = 1; print "-I$INCLUDEDIR $CXXFLAGS\n"; + $has_opt = 1; print "$INCLUDEOPTION $CXXFLAGS\n"; } elsif ($arg eq "--ldflags") { $has_opt = 1; print "-L$LIBDIR $LDFLAGS $SYSTEM_LIBS\n"; } elsif ($arg eq "--libs") { @@ -330,7 +322,16 @@ sub build_name_map { foreach my $target (@TARGETS_BUILT) { # FIXME: Temporary, until we don't switch all targets if (defined $NAME_MAP{$target.'asmprinter'}) { - $NAME_MAP{$target} = [$target.'asmprinter', $target.'codegen'] + $NAME_MAP{$target} = [$target.'info', + $target.'asmprinter', + $target.'codegen'] + } else { + $NAME_MAP{$target} = [$target.'info', + $NAME_MAP{$target}[0]] + } + + if (defined $NAME_MAP{$target.'asmparser'}) { + push @{$NAME_MAP{$target}},$target.'asmparser' } } diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index 901c8e9..b8b1a39 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -18,18 +18,13 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" -#include "llvm/PassManager.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Assembly/PrintModulePass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Signals.h" -#include <iostream> -#include <fstream> #include <memory> using namespace llvm; @@ -41,7 +36,7 @@ OutputFilename("o", cl::desc("Override output filename"), cl::value_desc("filename")); static cl::opt<bool> -Force("f", cl::desc("Overwrite output files")); +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); @@ -51,95 +46,66 @@ int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - try { - cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n"); - - std::ostream *Out = &std::cout; // Default to printing to stdout. - std::string ErrorMessage; - - std::auto_ptr<Module> M; - - if (MemoryBuffer *Buffer - = MemoryBuffer::getFileOrSTDIN(InputFilename, &ErrorMessage)) { - M.reset(ParseBitcodeFile(Buffer, Context, &ErrorMessage)); - delete Buffer; - } + + + cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n"); + + std::string ErrorMessage; + std::auto_ptr<Module> M; + + if (MemoryBuffer *Buffer + = MemoryBuffer::getFileOrSTDIN(InputFilename, &ErrorMessage)) { + M.reset(ParseBitcodeFile(Buffer, Context, &ErrorMessage)); + delete Buffer; + } - if (M.get() == 0) { - cerr << argv[0] << ": "; - if (ErrorMessage.size()) - cerr << ErrorMessage << "\n"; - else - cerr << "bitcode didn't read correctly.\n"; - return 1; - } - - if (DontPrint) { - // Just use stdout. We won't actually print anything on it. - } else if (OutputFilename != "") { // Specified an output filename? - if (OutputFilename != "-") { // Not stdout? - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - cerr << argv[0] << ": error opening '" << OutputFilename - << "': file exists! Sending to standard output.\n"; - } else { - Out = new std::ofstream(OutputFilename.c_str()); - } - } + if (M.get() == 0) { + errs() << argv[0] << ": "; + if (ErrorMessage.size()) + errs() << ErrorMessage << "\n"; + else + errs() << "bitcode didn't read correctly.\n"; + return 1; + } + + // Just use stdout. We won't actually print anything on it. + if (DontPrint) + OutputFilename = "-"; + + if (OutputFilename.empty()) { // Unspecified output, infer it. + if (InputFilename == "-") { + OutputFilename = "-"; } else { - if (InputFilename == "-") { - OutputFilename = "-"; - } else { - std::string IFN = InputFilename; - int Len = IFN.length(); - if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') { - // Source ends in .bc - OutputFilename = std::string(IFN.begin(), IFN.end()-3)+".ll"; - } else { - OutputFilename = IFN+".ll"; - } - - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - cerr << argv[0] << ": error opening '" << OutputFilename - << "': file exists! Sending to standard output.\n"; - } else { - Out = new std::ofstream(OutputFilename.c_str()); - - // Make sure that the Out file gets unlinked from the disk if we get a - // SIGINT - sys::RemoveFileOnSignal(sys::Path(OutputFilename)); - } - } - } - - if (!Out->good()) { - cerr << argv[0] << ": error opening " << OutputFilename - << ": sending to stdout instead!\n"; - Out = &std::cout; - } - - // All that llvm-dis does is write the assembly to a file. - if (!DontPrint) { - PassManager Passes; - raw_os_ostream L(*Out); - Passes.add(createPrintModulePass(&L)); - Passes.run(*M.get()); + const std::string &IFN = InputFilename; + int Len = IFN.length(); + // If the source ends in .bc, strip it off. + if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') + OutputFilename = std::string(IFN.begin(), IFN.end()-3)+".ll"; + else + OutputFilename = IFN+".ll"; } + } - if (Out != &std::cout) { - ((std::ofstream*)Out)->close(); - delete Out; - } - return 0; - } catch (const std::string& msg) { - cerr << argv[0] << ": " << msg << "\n"; - } catch (...) { - cerr << argv[0] << ": Unexpected unknown exception occurred.\n"; + // 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)); + if (!ErrorInfo.empty()) { + errs() << ErrorInfo << '\n'; + return 1; } - return 1; + // All that llvm-dis does is write the assembly to a file. + if (!DontPrint) + *Out << *M; + + return 0; } diff --git a/tools/llvm-extract/CMakeLists.txt b/tools/llvm-extract/CMakeLists.txt index 88e9343..a4e3266 100644 --- a/tools/llvm-extract/CMakeLists.txt +++ b/tools/llvm-extract/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS ipo bitreader bitwriter) +set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter) add_llvm_tool(llvm-extract llvm-extract.cpp diff --git a/tools/llvm-extract/Makefile b/tools/llvm-extract/Makefile index 2ef8841..5672aa3 100644 --- a/tools/llvm-extract/Makefile +++ b/tools/llvm-extract/Makefile @@ -10,7 +10,7 @@ LEVEL = ../.. TOOLNAME = llvm-extract -LINK_COMPONENTS := ipo bitreader bitwriter +LINK_COMPONENTS := ipo bitreader bitwriter asmparser # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index af0cf07..517244f 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -15,17 +15,19 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/PassManager.h" +#include "llvm/Assembly/PrintModulePass.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Transforms/IPO.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SystemUtils.h" #include "llvm/System/Signals.h" -#include <iostream> #include <memory> -#include <fstream> using namespace llvm; // InputFilename - The filename to read from. @@ -38,7 +40,7 @@ OutputFilename("o", cl::desc("Specify output filename"), cl::value_desc("filename"), cl::init("-")); static cl::opt<bool> -Force("f", cl::desc("Overwrite output files")); +Force("f", cl::desc("Enable binary output on terminals")); static cl::opt<bool> DeleteFn("delete", cl::desc("Delete specified Globals from Module")); @@ -57,28 +59,25 @@ static cl::opt<std::string> ExtractGlobal("glob", cl::desc("Specify global to extract"), cl::init(""), cl::value_desc("global")); +static cl::opt<bool> +OutputAssembly("S", + cl::desc("Write output as LLVM assembly"), cl::Hidden); + int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); + SMDiagnostic Err; std::auto_ptr<Module> M; - - MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename); - if (Buffer == 0) { - cerr << argv[0] << ": Error reading file '" + InputFilename + "'\n"; - return 1; - } else { - M.reset(ParseBitcodeFile(Buffer, Context)); - } - delete Buffer; - + M.reset(ParseIRFile(InputFilename, Err, Context)); + if (M.get() == 0) { - cerr << argv[0] << ": bitcode didn't read correctly.\n"; + Err.Print(argv[0], errs()); return 1; } @@ -91,8 +90,8 @@ int main(int argc, char **argv) { Function *F = M.get()->getFunction(ExtractFunc); if (F == 0 && G == 0) { - cerr << argv[0] << ": program doesn't contain function named '" - << ExtractFunc << "' or a global named '" << ExtractGlobal << "'!\n"; + errs() << argv[0] << ": program doesn't contain function named '" + << ExtractFunc << "' or a global named '" << ExtractGlobal << "'!\n"; return 1; } @@ -111,28 +110,24 @@ int main(int argc, char **argv) { Passes.add(createDeadTypeEliminationPass()); // Remove dead types... Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls - std::ostream *Out = 0; - - if (OutputFilename != "-") { // Not stdout? - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - cerr << argv[0] << ": error opening '" << OutputFilename - << "': file exists!\n" - << "Use -f command line argument to force output\n"; - return 1; - } - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - Out = new std::ofstream(OutputFilename.c_str(), io_mode); - } else { // Specified stdout - // FIXME: cout is not binary! - Out = &std::cout; + // 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); + if (!ErrorInfo.empty()) { + errs() << ErrorInfo << '\n'; + return 1; } - Passes.add(CreateBitcodeWriterPass(*Out)); + if (OutputAssembly) + Passes.add(createPrintModulePass(&Out)); + else if (Force || !CheckBitcodeOutputToConsole(Out, true)) + Passes.add(createBitcodeWriterPass(Out)); + Passes.run(*M.get()); - if (Out != &std::cout) - delete Out; return 0; } diff --git a/tools/llvm-ld/Optimize.cpp b/tools/llvm-ld/Optimize.cpp index e466895..6143dc8 100644 --- a/tools/llvm-ld/Optimize.cpp +++ b/tools/llvm-ld/Optimize.cpp @@ -18,6 +18,7 @@ #include "llvm/Analysis/Verifier.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/StandardPasses.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/DynamicLibrary.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" @@ -25,7 +26,6 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" -#include <iostream> using namespace llvm; // Pass Name Options as generated by the PassNameParser @@ -109,8 +109,8 @@ void Optimize(Module* M) { if (Opt->getNormalCtor()) addPass(Passes, Opt->getNormalCtor()()); else - std::cerr << "llvm-ld: cannot create pass: " << Opt->getPassName() - << "\n"; + errs() << "llvm-ld: cannot create pass: " << Opt->getPassName() + << "\n"; } // The user's passes may leave cruft around. Clean up after them them but diff --git a/tools/llvm-ld/llvm-ld.cpp b/tools/llvm-ld/llvm-ld.cpp index 2b9d255..ef3c250 100644 --- a/tools/llvm-ld/llvm-ld.cpp +++ b/tools/llvm-ld/llvm-ld.cpp @@ -12,7 +12,7 @@ // Additionally, this program outputs a shell script that is used to invoke LLI // to execute the program. In this manner, the generated executable (a.out for // example), is directly executable, whereas the bitcode file actually lives in -// the a.out.bc file generated by this program. Also, Force is on by default. +// the a.out.bc file generated by this program. // // Note that if someone (or a script) deletes the executable program generated, // the .bc file will be left around. Considering that this is a temporary hack, @@ -29,21 +29,24 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetMachineRegistry.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/SystemUtils.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Signals.h" #include "llvm/Config/config.h" -#include <fstream> #include <memory> #include <cstring> using namespace llvm; +// Rightly this should go in a header file but it just seems such a waste. +namespace llvm { +extern void Optimize(Module*); +} + // Input/Output Options static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore, cl::desc("<input bitcode files>")); @@ -52,6 +55,10 @@ static cl::opt<std::string> OutputFilename("o", cl::init("a.out"), cl::desc("Override output filename"), cl::value_desc("filename")); +static cl::opt<std::string> BitcodeOutputFilename("b", cl::init(""), + cl::desc("Override bitcode output filename"), + cl::value_desc("filename")); + static cl::opt<bool> Verbose("v", cl::desc("Print information about actions taken")); @@ -124,7 +131,7 @@ static std::string progname; /// Message - The message to print to standard error. /// static void PrintAndExit(const std::string &Message, int errcode = 1) { - cerr << progname << ": " << Message << "\n"; + errs() << progname << ": " << Message << "\n"; llvm_shutdown(); exit(errcode); } @@ -133,8 +140,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) - cout << "'" << *I << "'" << " "; - cout << "\n" << std::flush; + outs() << "'" << *I << "'" << " "; + outs() << "\n"; outs().flush(); } /// CopyEnv - This function takes an array of environment variables and makes a @@ -219,14 +226,14 @@ static void RemoveEnv(const char * name, char ** const envp) { void GenerateBitcode(Module* M, const std::string& FileName) { if (Verbose) - cout << "Generating Bitcode To " << FileName << '\n'; + outs() << "Generating Bitcode To " << FileName << '\n'; // Create the output file. - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - std::ofstream Out(FileName.c_str(), io_mode); - if (!Out.good()) - PrintAndExit("error opening '" + FileName + "' for writing!"); + std::string ErrorInfo; + raw_fd_ostream Out(FileName.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary); + if (!ErrorInfo.empty()) + PrintAndExit(ErrorInfo); // Ensure that the bitcode file gets removed from the disk if we get a // terminating signal. @@ -267,7 +274,7 @@ static int GenerateAssembly(const std::string &OutputFilename, args.push_back(0); if (Verbose) { - cout << "Generating Assembly With: \n"; + outs() << "Generating Assembly With: \n"; PrintCommand(args); } @@ -290,7 +297,7 @@ static int GenerateCFile(const std::string &OutputFile, args.push_back(0); if (Verbose) { - cout << "Generating C Source With: \n"; + outs() << "Generating C Source With: \n"; PrintCommand(args); } @@ -387,7 +394,7 @@ static int GenerateNative(const std::string &OutputFilename, Args.push_back(0); if (Verbose) { - cout << "Generating Native Executable With:\n"; + outs() << "Generating Native Executable With:\n"; PrintCommand(Args); } @@ -402,13 +409,14 @@ static int GenerateNative(const std::string &OutputFilename, /// bitcode file for the program. static void EmitShellScript(char **argv) { if (Verbose) - cout << "Emitting Shell Script\n"; + outs() << "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 // build tree to the destination file. std::string ErrMsg; - sys::Path llvmstub = FindExecutable("llvm-stub.exe", argv[0]); + sys::Path llvmstub = FindExecutable("llvm-stub.exe", argv[0], + (void *)(intptr_t)&Optimize); if (llvmstub.isEmpty()) PrintAndExit("Could not find llvm-stub.exe executable!"); @@ -419,9 +427,10 @@ static void EmitShellScript(char **argv) { #endif // Output the script to start the program... - std::ofstream Out2(OutputFilename.c_str()); - if (!Out2.good()) - PrintAndExit("error opening '" + OutputFilename + "' for writing!"); + std::string ErrorInfo; + raw_fd_ostream Out2(OutputFilename.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) + PrintAndExit(ErrorInfo); Out2 << "#!/bin/sh\n"; // Allow user to setenv LLVMINTERP if lli is not in their PATH. @@ -457,9 +466,9 @@ static void EmitShellScript(char **argv) { if (FullLibraryPath.isEmpty()) FullLibraryPath = sys::Path::FindLibrary(*i); if (!FullLibraryPath.isEmpty()) - Out2 << " -load=" << FullLibraryPath.toString() << " \\\n"; + Out2 << " -load=" << FullLibraryPath.str() << " \\\n"; } - Out2 << " $0.bc ${1+\"$@\"}\n"; + Out2 << " " << BitcodeOutputFilename << " ${1+\"$@\"}\n"; Out2.close(); } @@ -497,17 +506,12 @@ static void BuildLinkItems( } } -// Rightly this should go in a header file but it just seems such a waste. -namespace llvm { -extern void Optimize(Module*); -} - int main(int argc, char **argv, char **envp) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. try { // Initial global variable above for convenience printing of program name. @@ -568,16 +572,20 @@ int main(int argc, char **argv, char **envp) { sys::Path ExeFile( OutputFilename ); if (ExeFile.getSuffix() == "") { ExeFile.appendSuffix("exe"); - OutputFilename = ExeFile.toString(); + OutputFilename = ExeFile.str(); } } #endif // Generate the bitcode for the optimized module. - std::string RealBitcodeOutput = OutputFilename; + // If -b wasn't specified, use the name specified + // with -o to construct BitcodeOutputFilename. + if (BitcodeOutputFilename.empty()) { + BitcodeOutputFilename = OutputFilename; + if (!LinkAsLibrary) BitcodeOutputFilename += ".bc"; + } - if (!LinkAsLibrary) RealBitcodeOutput += ".bc"; - GenerateBitcode(Composite.get(), RealBitcodeOutput); + GenerateBitcode(Composite.get(), BitcodeOutputFilename); // If we are not linking a library, generate either a native executable // or a JIT shell script, depending upon what the user wants. @@ -602,12 +610,12 @@ int main(int argc, char **argv, char **envp) { const char* args[4]; args[0] = I->c_str(); - args[1] = RealBitcodeOutput.c_str(); + args[1] = BitcodeOutputFilename.c_str(); args[2] = tmp_output.c_str(); args[3] = 0; if (0 == sys::Program::ExecuteAndWait(prog, args, 0,0,0,0, &ErrMsg)) { if (tmp_output.isBitcodeFile() || tmp_output.isBitcodeFile()) { - sys::Path target(RealBitcodeOutput); + sys::Path target(BitcodeOutputFilename); target.eraseFromDisk(); if (tmp_output.renamePathOnDisk(target, &ErrMsg)) PrintAndExit(ErrMsg, 2); @@ -633,21 +641,22 @@ int main(int argc, char **argv, char **envp) { sys::RemoveFileOnSignal(sys::Path(OutputFilename)); // Determine the locations of the llc and gcc programs. - sys::Path llc = FindExecutable("llc", argv[0]); + sys::Path llc = FindExecutable("llc", argv[0], + (void *)(intptr_t)&Optimize); if (llc.isEmpty()) PrintAndExit("Failed to find llc"); - sys::Path gcc = FindExecutable("gcc", argv[0]); + sys::Path gcc = sys::Program::FindProgramByName("gcc"); if (gcc.isEmpty()) PrintAndExit("Failed to find gcc"); // Generate an assembly language file for the bitcode. std::string ErrMsg; - if (0 != GenerateAssembly(AssemblyFile.toString(), RealBitcodeOutput, + if (0 != GenerateAssembly(AssemblyFile.str(), BitcodeOutputFilename, llc, ErrMsg)) PrintAndExit(ErrMsg); - if (0 != GenerateNative(OutputFilename, AssemblyFile.toString(), + if (0 != GenerateNative(OutputFilename, AssemblyFile.str(), NativeLinkItems, gcc, envp, ErrMsg)) PrintAndExit(ErrMsg); @@ -662,22 +671,22 @@ int main(int argc, char **argv, char **envp) { sys::RemoveFileOnSignal(sys::Path(OutputFilename)); // Determine the locations of the llc and gcc programs. - sys::Path llc = FindExecutable("llc", argv[0]); + sys::Path llc = FindExecutable("llc", argv[0], + (void *)(intptr_t)&Optimize); if (llc.isEmpty()) PrintAndExit("Failed to find llc"); - sys::Path gcc = FindExecutable("gcc", argv[0]); + sys::Path gcc = sys::Program::FindProgramByName("gcc"); if (gcc.isEmpty()) PrintAndExit("Failed to find gcc"); // Generate an assembly language file for the bitcode. std::string ErrMsg; - if (0 != GenerateCFile( - CFile.toString(), RealBitcodeOutput, llc, ErrMsg)) + if (GenerateCFile(CFile.str(), BitcodeOutputFilename, llc, ErrMsg)) PrintAndExit(ErrMsg); - if (0 != GenerateNative(OutputFilename, CFile.toString(), - NativeLinkItems, gcc, envp, ErrMsg)) + if (GenerateNative(OutputFilename, CFile.str(), + NativeLinkItems, gcc, envp, ErrMsg)) PrintAndExit(ErrMsg); // Remove the assembly language file. @@ -693,10 +702,10 @@ int main(int argc, char **argv, char **envp) { PrintAndExit(ErrMsg); // Make the bitcode file readable and directly executable in LLEE as well - if (sys::Path(RealBitcodeOutput).makeExecutableOnDisk(&ErrMsg)) + if (sys::Path(BitcodeOutputFilename).makeExecutableOnDisk(&ErrMsg)) PrintAndExit(ErrMsg); - if (sys::Path(RealBitcodeOutput).makeReadableOnDisk(&ErrMsg)) + if (sys::Path(BitcodeOutputFilename).makeReadableOnDisk(&ErrMsg)) PrintAndExit(ErrMsg); } } catch (const std::string& msg) { diff --git a/tools/llvm-link/CMakeLists.txt b/tools/llvm-link/CMakeLists.txt index 69a435e..11933f7 100644 --- a/tools/llvm-link/CMakeLists.txt +++ b/tools/llvm-link/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS linker bitreader bitwriter) +set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser) add_llvm_tool(llvm-link llvm-link.cpp diff --git a/tools/llvm-link/Makefile b/tools/llvm-link/Makefile index ddc7a59..2637018 100644 --- a/tools/llvm-link/Makefile +++ b/tools/llvm-link/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. TOOLNAME = llvm-link -LINK_COMPONENTS = linker bitreader bitwriter +LINK_COMPONENTS = linker bitreader bitwriter asmparser # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index f65e602..fae4d10 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -21,11 +21,11 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Streams.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/IRReader.h" #include "llvm/System/Signals.h" #include "llvm/System/Path.h" -#include <fstream> -#include <iostream> #include <memory> using namespace llvm; @@ -37,7 +37,12 @@ static cl::opt<std::string> OutputFilename("o", cl::desc("Override output filename"), cl::init("-"), cl::value_desc("filename")); -static cl::opt<bool> Force("f", cl::desc("Overwrite output files")); +static cl::opt<bool> +Force("f", cl::desc("Enable binary output on terminals")); + +static cl::opt<bool> +OutputAssembly("S", + cl::desc("Write output as LLVM assembly"), cl::Hidden); static cl::opt<bool> Verbose("v", cl::desc("Print information about actions taken")); @@ -48,34 +53,28 @@ DumpAsm("d", cl::desc("Print assembly as linked"), cl::Hidden); // LoadFile - Read the specified bitcode file in and return it. This routine // searches the link path for the specified file to try to find it... // -static inline std::auto_ptr<Module> LoadFile(const std::string &FN, +static inline std::auto_ptr<Module> LoadFile(const char *argv0, + const std::string &FN, LLVMContext& Context) { sys::Path Filename; if (!Filename.set(FN)) { - cerr << "Invalid file name: '" << FN << "'\n"; + errs() << "Invalid file name: '" << FN << "'\n"; return std::auto_ptr<Module>(); } - std::string ErrorMessage; + SMDiagnostic Err; if (Filename.exists()) { - if (Verbose) cerr << "Loading '" << Filename.c_str() << "'\n"; + if (Verbose) errs() << "Loading '" << Filename.c_str() << "'\n"; Module* Result = 0; - const std::string &FNStr = Filename.toString(); - if (MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(FNStr, - &ErrorMessage)) { - Result = ParseBitcodeFile(Buffer, Context, &ErrorMessage); - delete Buffer; - } + const std::string &FNStr = Filename.str(); + Result = ParseIRFile(FNStr, Err, Context); if (Result) return std::auto_ptr<Module>(Result); // Load successful! - if (Verbose) { - cerr << "Error opening bitcode file: '" << Filename.c_str() << "'"; - if (ErrorMessage.size()) cerr << ": " << ErrorMessage; - cerr << "\n"; - } + if (Verbose) + Err.Print(argv0, errs()); } else { - cerr << "Bitcode file: '" << Filename.c_str() << "' does not exist.\n"; + errs() << "Bitcode file: '" << Filename.c_str() << "' does not exist.\n"; } return std::auto_ptr<Module>(); @@ -86,32 +85,34 @@ int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm linker\n"); unsigned BaseArg = 0; std::string ErrorMessage; - std::auto_ptr<Module> Composite(LoadFile(InputFilenames[BaseArg], Context)); + std::auto_ptr<Module> Composite(LoadFile(argv[0], + InputFilenames[BaseArg], Context)); if (Composite.get() == 0) { - cerr << argv[0] << ": error loading file '" - << InputFilenames[BaseArg] << "'\n"; + errs() << argv[0] << ": error loading file '" + << InputFilenames[BaseArg] << "'\n"; return 1; } for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) { - std::auto_ptr<Module> M(LoadFile(InputFilenames[i], Context)); + std::auto_ptr<Module> M(LoadFile(argv[0], + InputFilenames[i], Context)); if (M.get() == 0) { - cerr << argv[0] << ": error loading file '" <<InputFilenames[i]<< "'\n"; + errs() << argv[0] << ": error loading file '" <<InputFilenames[i]<< "'\n"; return 1; } - if (Verbose) cerr << "Linking in '" << InputFilenames[i] << "'\n"; + if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n"; if (Linker::LinkModules(Composite.get(), M.get(), &ErrorMessage)) { - cerr << argv[0] << ": link error in '" << InputFilenames[i] - << "': " << ErrorMessage << "\n"; + errs() << argv[0] << ": link error in '" << InputFilenames[i] + << "': " << ErrorMessage << "\n"; return 1; } } @@ -119,39 +120,32 @@ int main(int argc, char **argv) { // TODO: Iterate over the -l list and link in any modules containing // global symbols that have not been resolved so far. - if (DumpAsm) cerr << "Here's the assembly:\n" << *Composite.get(); + if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; - // FIXME: cout is not binary! - std::ostream *Out = &std::cout; // Default to printing to stdout... - if (OutputFilename != "-") { - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - cerr << argv[0] << ": error opening '" << OutputFilename - << "': file exists!\n" - << "Use -f command line argument to force output\n"; - return 1; - } - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - Out = new std::ofstream(OutputFilename.c_str(), io_mode); - if (!Out->good()) { - cerr << argv[0] << ": error opening '" << OutputFilename << "'!\n"; - return 1; - } + std::string ErrorInfo; + std::auto_ptr<raw_ostream> + Out(new raw_fd_ostream(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.get())) { - cerr << argv[0] << ": linked module is broken!\n"; + if (verifyModule(*Composite)) { + errs() << argv[0] << ": linked module is broken!\n"; return 1; } - if (Verbose) cerr << "Writing bitcode...\n"; - WriteBitcodeToFile(Composite.get(), *Out); + if (Verbose) errs() << "Writing bitcode...\n"; + if (OutputAssembly) { + *Out << *Composite; + } else if (Force || !CheckBitcodeOutputToConsole(*Out, true)) + WriteBitcodeToFile(Composite.get(), *Out); - if (Out != &std::cout) delete Out; return 0; } diff --git a/tools/llvm-mc/AsmCond.h b/tools/llvm-mc/AsmCond.h new file mode 100644 index 0000000..92a115e --- /dev/null +++ b/tools/llvm-mc/AsmCond.h @@ -0,0 +1,40 @@ +//===- AsmCond.h - Assembly file conditional assembly ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef ASMCOND_H +#define ASMCOND_H + +namespace llvm { + +/// AsmCond - Class to support conditional assembly +/// +/// The conditional assembly feature (.if, .else, .elseif and .endif) is +/// implemented with AsmCond that tells us what we are in the middle of +/// processing. Ignore can be either true or false. When true we are ignoring +/// the block of code in the middle of a conditional. + +class AsmCond { +public: + enum ConditionalAssemblyType { + NoCond, // no conditional is being processed + IfCond, // inside if conditional + ElseIfCond, // inside elseif conditional + ElseCond // inside else conditional + }; + + ConditionalAssemblyType TheCond; + bool CondMet; + bool Ignore; + + AsmCond() : TheCond(NoCond), CondMet(false), Ignore(false) {} +}; + +} // end namespace llvm + +#endif diff --git a/tools/llvm-mc/AsmLexer.cpp b/tools/llvm-mc/AsmLexer.cpp index 7b744fb..99055c6 100644 --- a/tools/llvm-mc/AsmLexer.cpp +++ b/tools/llvm-mc/AsmLexer.cpp @@ -12,30 +12,24 @@ //===----------------------------------------------------------------------===// #include "AsmLexer.h" -#include "llvm/ADT/StringSet.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Config/config.h" // for strtoull. +#include "llvm/MC/MCAsmInfo.h" #include <cerrno> #include <cstdio> #include <cstdlib> using namespace llvm; -static StringSet<> &getSS(void *TheSS) { - return *(StringSet<>*)TheSS; -} - -AsmLexer::AsmLexer(SourceMgr &SM) : SrcMgr(SM) { +AsmLexer::AsmLexer(SourceMgr &SM, const MCAsmInfo &_MAI) : SrcMgr(SM), + MAI(_MAI) { CurBuffer = 0; CurBuf = SrcMgr.getMemoryBuffer(CurBuffer); CurPtr = CurBuf->getBufferStart(); TokStart = 0; - - TheStringSet = new StringSet<>(); } AsmLexer::~AsmLexer() { - delete &getSS(TheStringSet); } SMLoc AsmLexer::getLoc() const { @@ -48,12 +42,27 @@ void AsmLexer::PrintMessage(SMLoc Loc, const std::string &Msg, } /// ReturnError - Set the error to the specified string at the specified -/// location. This is defined to always return asmtok::Error. -asmtok::TokKind AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { +/// location. This is defined to always return AsmToken::Error. +AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), Msg, "error"); - return asmtok::Error; + return AsmToken(AsmToken::Error, StringRef(Loc, 0)); +} + +/// EnterIncludeFile - Enter the specified file. This prints an error and +/// returns true on failure. +bool AsmLexer::EnterIncludeFile(const std::string &Filename) { + int NewBuf = SrcMgr.AddIncludeFile(Filename, SMLoc::getFromPointer(CurPtr)); + if (NewBuf == -1) + return true; + + // Save the line number and lex buffer of the includer. + CurBuffer = NewBuf; + CurBuf = SrcMgr.getMemoryBuffer(CurBuffer); + CurPtr = CurBuf->getBufferStart(); + return false; } + int AsmLexer::getNextChar() { char CurChar = *CurPtr++; switch (CurChar) { @@ -72,6 +81,10 @@ int AsmLexer::getNextChar() { CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc); CurBuf = SrcMgr.getMemoryBuffer(CurBuffer); CurPtr = ParentIncludeLoc.getPointer(); + + // Reset the token start pointer to the start of the new file. + TokStart = CurPtr; + return getNextChar(); } @@ -83,37 +96,20 @@ int AsmLexer::getNextChar() { } /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* -asmtok::TokKind AsmLexer::LexIdentifier() { +AsmToken AsmLexer::LexIdentifier() { while (isalnum(*CurPtr) || *CurPtr == '_' || *CurPtr == '$' || *CurPtr == '.' || *CurPtr == '@') ++CurPtr; - // Unique string. - CurStrVal = - getSS(TheStringSet).GetOrCreateValue(TokStart, CurPtr, 0).getKeyData(); - return asmtok::Identifier; -} - -/// LexPercent: Register: %[a-zA-Z0-9]+ -asmtok::TokKind AsmLexer::LexPercent() { - if (!isalnum(*CurPtr)) - return asmtok::Percent; // Single %. - - while (isalnum(*CurPtr)) - ++CurPtr; - - // Unique string. - CurStrVal = - getSS(TheStringSet).GetOrCreateValue(TokStart, CurPtr, 0).getKeyData(); - return asmtok::Register; + return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); } /// LexSlash: Slash: / /// C-Style Comment: /* ... */ -asmtok::TokKind AsmLexer::LexSlash() { +AsmToken AsmLexer::LexSlash() { switch (*CurPtr) { case '*': break; // C style comment. case '/': return ++CurPtr, LexLineComment(); - default: return asmtok::Slash; + default: return AsmToken(AsmToken::Slash, StringRef(CurPtr, 1)); } // C Style comment. @@ -135,14 +131,16 @@ asmtok::TokKind AsmLexer::LexSlash() { /// LexLineComment: Comment: #[^\n]* /// : //[^\n]* -asmtok::TokKind AsmLexer::LexLineComment() { +AsmToken AsmLexer::LexLineComment() { + // FIXME: This is broken if we happen to a comment at the end of a file, which + // was .included, and which doesn't end with a newline. int CurChar = getNextChar(); while (CurChar != '\n' && CurChar != '\n' && CurChar != EOF) CurChar = getNextChar(); if (CurChar == EOF) - return asmtok::Eof; - return asmtok::EndOfStatement; + return AsmToken(AsmToken::Eof, StringRef(CurPtr, 0)); + return AsmToken(AsmToken::EndOfStatement, StringRef(CurPtr, 0)); } @@ -154,7 +152,7 @@ asmtok::TokKind AsmLexer::LexLineComment() { /// Hex integer: 0x[0-9a-fA-F]+ /// Decimal integer: [1-9][0-9]* /// TODO: FP literal. -asmtok::TokKind AsmLexer::LexDigit() { +AsmToken AsmLexer::LexDigit() { if (*CurPtr == ':') return ReturnError(TokStart, "FIXME: local label not implemented"); if (*CurPtr == 'f' || *CurPtr == 'b') @@ -164,8 +162,8 @@ asmtok::TokKind AsmLexer::LexDigit() { if (CurPtr[-1] != '0') { while (isdigit(*CurPtr)) ++CurPtr; - CurIntVal = strtoll(TokStart, 0, 10); - return asmtok::IntVal; + return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), + strtoll(TokStart, 0, 10)); } if (*CurPtr == 'b') { @@ -177,8 +175,8 @@ asmtok::TokKind AsmLexer::LexDigit() { // Requires at least one binary digit. if (CurPtr == NumStart) return ReturnError(CurPtr-2, "Invalid binary number"); - CurIntVal = strtoll(NumStart, 0, 2); - return asmtok::IntVal; + return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), + strtoll(NumStart, 0, 2)); } if (*CurPtr == 'x') { @@ -192,29 +190,28 @@ asmtok::TokKind AsmLexer::LexDigit() { return ReturnError(CurPtr-2, "Invalid hexadecimal number"); errno = 0; - CurIntVal = strtoll(NumStart, 0, 16); if (errno == EINVAL) return ReturnError(CurPtr-2, "Invalid hexadecimal number"); if (errno == ERANGE) { errno = 0; - CurIntVal = (int64_t)strtoull(NumStart, 0, 16); if (errno == EINVAL) return ReturnError(CurPtr-2, "Invalid hexadecimal number"); if (errno == ERANGE) return ReturnError(CurPtr-2, "Hexadecimal number out of range"); } - return asmtok::IntVal; + return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), + (int64_t) strtoull(NumStart, 0, 16)); } // Must be an octal number, it starts with 0. while (*CurPtr >= '0' && *CurPtr <= '7') ++CurPtr; - CurIntVal = strtoll(TokStart, 0, 8); - return asmtok::IntVal; + return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), + strtoll(TokStart, 0, 8)); } /// LexQuote: String: "..." -asmtok::TokKind AsmLexer::LexQuote() { +AsmToken AsmLexer::LexQuote() { int CurChar = getNextChar(); // TODO: does gas allow multiline string constants? while (CurChar != '"') { @@ -229,18 +226,35 @@ asmtok::TokKind AsmLexer::LexQuote() { CurChar = getNextChar(); } - // Unique string, include quotes for now. - CurStrVal = - getSS(TheStringSet).GetOrCreateValue(TokStart, CurPtr, 0).getKeyData(); - return asmtok::String; + return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); +} + +StringRef AsmLexer::LexUntilEndOfStatement() { + TokStart = CurPtr; + + while (!isAtStartOfComment(*CurPtr) && // Start of line comment. + *CurPtr != ';' && // End of statement marker. + *CurPtr != '\n' && + *CurPtr != '\r' && + (*CurPtr != 0 || CurPtr != CurBuf->getBufferEnd())) { + ++CurPtr; + } + return StringRef(TokStart, CurPtr-TokStart); } +bool AsmLexer::isAtStartOfComment(char Char) { + // FIXME: This won't work for multi-character comment indicators like "//". + return Char == *MAI.getCommentString(); +} -asmtok::TokKind AsmLexer::LexToken() { +AsmToken AsmLexer::LexToken() { TokStart = CurPtr; // This always consumes at least one character. int CurChar = getNextChar(); + if (isAtStartOfComment(CurChar)) + return LexLineComment(); + switch (CurChar) { default: // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* @@ -249,7 +263,7 @@ asmtok::TokKind AsmLexer::LexToken() { // Unknown character, emit an error. return ReturnError(TokStart, "invalid character in input"); - case EOF: return asmtok::Eof; + case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); case 0: case ' ': case '\t': @@ -257,52 +271,61 @@ asmtok::TokKind AsmLexer::LexToken() { return LexToken(); case '\n': // FALL THROUGH. case '\r': // FALL THROUGH. - case ';': return asmtok::EndOfStatement; - case ':': return asmtok::Colon; - case '+': return asmtok::Plus; - case '-': return asmtok::Minus; - case '~': return asmtok::Tilde; - case '(': return asmtok::LParen; - case ')': return asmtok::RParen; - case '*': return asmtok::Star; - case ',': return asmtok::Comma; - case '$': return asmtok::Dollar; + case ';': return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); + case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); + case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); + case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); + case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); + case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); + case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); + case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); + case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); + case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); + case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); + case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); + case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); + case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); case '=': if (*CurPtr == '=') - return ++CurPtr, asmtok::EqualEqual; - return asmtok::Equal; + return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); case '|': if (*CurPtr == '|') - return ++CurPtr, asmtok::PipePipe; - return asmtok::Pipe; - case '^': return asmtok::Caret; + return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); + case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); case '&': if (*CurPtr == '&') - return ++CurPtr, asmtok::AmpAmp; - return asmtok::Amp; + return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); case '!': if (*CurPtr == '=') - return ++CurPtr, asmtok::ExclaimEqual; - return asmtok::Exclaim; - case '%': return LexPercent(); + return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); + case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); case '/': return LexSlash(); - case '#': return LexLineComment(); + case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); case '"': return LexQuote(); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return LexDigit(); case '<': switch (*CurPtr) { - case '<': return ++CurPtr, asmtok::LessLess; - case '=': return ++CurPtr, asmtok::LessEqual; - case '>': return ++CurPtr, asmtok::LessGreater; - default: return asmtok::Less; + case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, + StringRef(TokStart, 2)); + case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, + StringRef(TokStart, 2)); + case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, + StringRef(TokStart, 2)); + default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); } case '>': switch (*CurPtr) { - case '>': return ++CurPtr, asmtok::GreaterGreater; - case '=': return ++CurPtr, asmtok::GreaterEqual; - default: return asmtok::Greater; + case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, + StringRef(TokStart, 2)); + case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, + StringRef(TokStart, 2)); + default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); } // TODO: Quoted identifiers (objc methods etc) diff --git a/tools/llvm-mc/AsmLexer.h b/tools/llvm-mc/AsmLexer.h index 6360b12..0696abc 100644 --- a/tools/llvm-mc/AsmLexer.h +++ b/tools/llvm-mc/AsmLexer.h @@ -14,6 +14,9 @@ #ifndef ASMLEXER_H #define ASMLEXER_H +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCAsmLexer.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/Support/DataTypes.h" #include <string> #include <cassert> @@ -22,95 +25,53 @@ namespace llvm { class MemoryBuffer; class SourceMgr; class SMLoc; - -namespace asmtok { - enum TokKind { - // Markers - Eof, Error, - - // String values. - Identifier, - Register, - String, - - // Integer values. - IntVal, - - // No-value. - EndOfStatement, - Colon, - Plus, Minus, Tilde, - Slash, // '/' - LParen, RParen, - Star, Comma, Dollar, Equal, EqualEqual, - - Pipe, PipePipe, Caret, - Amp, AmpAmp, Exclaim, ExclaimEqual, Percent, - Less, LessEqual, LessLess, LessGreater, - Greater, GreaterEqual, GreaterGreater - }; -} +class MCAsmInfo; /// AsmLexer - Lexer class for assembly files. -class AsmLexer { +class AsmLexer : public MCAsmLexer { SourceMgr &SrcMgr; + const MCAsmInfo &MAI; const char *CurPtr; const MemoryBuffer *CurBuf; - // A llvm::StringSet<>, which provides uniqued and null-terminated strings. - void *TheStringSet; - // Information about the current token. const char *TokStart; - asmtok::TokKind CurKind; - const char *CurStrVal; // This is valid for Identifier. - int64_t CurIntVal; - - /// CurBuffer - This is the current buffer index we're lexing from as managed - /// by the SourceMgr object. + + /// This is the current buffer index we're lexing from as managed by the + /// SourceMgr object. int CurBuffer; void operator=(const AsmLexer&); // DO NOT IMPLEMENT AsmLexer(const AsmLexer&); // DO NOT IMPLEMENT + +protected: + /// LexToken - Read the next token and return its code. + virtual AsmToken LexToken(); + public: - AsmLexer(SourceMgr &SrcMgr); + AsmLexer(SourceMgr &SrcMgr, const MCAsmInfo &MAI); ~AsmLexer(); - asmtok::TokKind Lex() { - return CurKind = LexToken(); - } - - asmtok::TokKind getKind() const { return CurKind; } - bool is(asmtok::TokKind K) const { return CurKind == K; } - bool isNot(asmtok::TokKind K) const { return CurKind != K; } - - const char *getCurStrVal() const { - assert((CurKind == asmtok::Identifier || CurKind == asmtok::Register || - CurKind == asmtok::String) && - "This token doesn't have a string value"); - return CurStrVal; - } - int64_t getCurIntVal() const { - assert(CurKind == asmtok::IntVal && "This token isn't an integer"); - return CurIntVal; - } - SMLoc getLoc() const; + StringRef LexUntilEndOfStatement(); + + bool isAtStartOfComment(char Char); + + /// EnterIncludeFile - Enter the specified file. This returns true on failure. + bool EnterIncludeFile(const std::string &Filename); + void PrintMessage(SMLoc Loc, const std::string &Msg, const char *Type) const; private: int getNextChar(); - asmtok::TokKind ReturnError(const char *Loc, const std::string &Msg); + AsmToken ReturnError(const char *Loc, const std::string &Msg); - /// LexToken - Read the next token and return its code. - asmtok::TokKind LexToken(); - asmtok::TokKind LexIdentifier(); - asmtok::TokKind LexPercent(); - asmtok::TokKind LexSlash(); - asmtok::TokKind LexLineComment(); - asmtok::TokKind LexDigit(); - asmtok::TokKind LexQuote(); + AsmToken LexIdentifier(); + AsmToken LexSlash(); + AsmToken LexLineComment(); + AsmToken LexDigit(); + AsmToken LexQuote(); }; } // end namespace llvm diff --git a/tools/llvm-mc/AsmParser.cpp b/tools/llvm-mc/AsmParser.cpp index f5bf589..aae27f5d 100644 --- a/tools/llvm-mc/AsmParser.cpp +++ b/tools/llvm-mc/AsmParser.cpp @@ -13,21 +13,79 @@ #include "AsmParser.h" -#include "AsmExpr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmParser.h" using namespace llvm; -void AsmParser::Warning(SMLoc L, const char *Msg) { - Lexer.PrintMessage(L, Msg, "warning"); +// Mach-O section uniquing. +// +// FIXME: Figure out where this should live, it should be shared by +// TargetLoweringObjectFile. +typedef StringMap<const MCSectionMachO*> MachOUniqueMapTy; + +AsmParser::AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, + const MCAsmInfo &_MAI) + : Lexer(_SM, _MAI), Ctx(_Ctx), Out(_Out), TargetParser(0), + SectionUniquingMap(0) { + // Debugging directives. + AddDirectiveHandler(".file", &AsmParser::ParseDirectiveFile); + AddDirectiveHandler(".line", &AsmParser::ParseDirectiveLine); + AddDirectiveHandler(".loc", &AsmParser::ParseDirectiveLoc); +} + + + +AsmParser::~AsmParser() { + // If we have the MachO uniquing map, free it. + delete (MachOUniqueMapTy*)SectionUniquingMap; } -bool AsmParser::Error(SMLoc L, const char *Msg) { - Lexer.PrintMessage(L, Msg, "error"); +const MCSection *AsmParser::getMachOSection(const StringRef &Segment, + const StringRef &Section, + unsigned TypeAndAttributes, + unsigned Reserved2, + SectionKind Kind) const { + // We unique sections by their segment/section pair. The returned section + // may not have the same flags as the requested section, if so this should be + // diagnosed by the client as an error. + + // Create the map if it doesn't already exist. + if (SectionUniquingMap == 0) + SectionUniquingMap = new MachOUniqueMapTy(); + MachOUniqueMapTy &Map = *(MachOUniqueMapTy*)SectionUniquingMap; + + // Form the name to look up. + SmallString<64> Name; + Name += Segment; + Name.push_back(','); + Name += Section; + + // Do the lookup, if we have a hit, return it. + const MCSectionMachO *&Entry = Map[Name.str()]; + + // FIXME: This should validate the type and attributes. + if (Entry) return Entry; + + // Otherwise, return a new section. + return Entry = MCSectionMachO::Create(Segment, Section, TypeAndAttributes, + Reserved2, Kind, Ctx); +} + +void AsmParser::Warning(SMLoc L, const Twine &Msg) { + Lexer.PrintMessage(L, Msg.str(), "warning"); +} + +bool AsmParser::Error(SMLoc L, const Twine &Msg) { + Lexer.PrintMessage(L, Msg.str(), "error"); return true; } @@ -37,31 +95,87 @@ bool AsmParser::TokError(const char *Msg) { } bool AsmParser::Run() { + // Create the initial section. + // + // FIXME: Support -n. + // FIXME: Target hook & command line option for initial section. + Out.SwitchSection(getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind())); + + // Prime the lexer. Lexer.Lex(); bool HadError = false; + AsmCond StartingCondState = TheCondState; + // While we have input, parse each statement. - while (Lexer.isNot(asmtok::Eof)) { + while (Lexer.isNot(AsmToken::Eof)) { + // Handle conditional assembly here before calling ParseStatement() + if (Lexer.getKind() == AsmToken::Identifier) { + // If we have an identifier, handle it as the key symbol. + AsmToken ID = Lexer.getTok(); + SMLoc IDLoc = ID.getLoc(); + StringRef IDVal = ID.getString(); + + if (IDVal == ".if" || + IDVal == ".elseif" || + IDVal == ".else" || + IDVal == ".endif") { + if (!ParseConditionalAssemblyDirectives(IDVal, IDLoc)) + continue; + HadError = true; + EatToEndOfStatement(); + continue; + } + } + if (TheCondState.Ignore) { + EatToEndOfStatement(); + continue; + } + if (!ParseStatement()) continue; - // If we had an error, remember it and recover by skipping to the next line. + // We had an error, remember it and recover by skipping to the next line. HadError = true; EatToEndOfStatement(); } + + if (TheCondState.TheCond != StartingCondState.TheCond || + TheCondState.Ignore != StartingCondState.Ignore) + return TokError("unmatched .ifs or .elses"); + if (!HadError) + Out.Finish(); + return HadError; } +/// ParseConditionalAssemblyDirectives - parse the conditional assembly +/// directives +bool AsmParser::ParseConditionalAssemblyDirectives(StringRef Directive, + SMLoc DirectiveLoc) { + if (Directive == ".if") + return ParseDirectiveIf(DirectiveLoc); + if (Directive == ".elseif") + return ParseDirectiveElseIf(DirectiveLoc); + if (Directive == ".else") + return ParseDirectiveElse(DirectiveLoc); + if (Directive == ".endif") + return ParseDirectiveEndIf(DirectiveLoc); + return true; +} + /// EatToEndOfStatement - Throw away the rest of the line for testing purposes. void AsmParser::EatToEndOfStatement() { - while (Lexer.isNot(asmtok::EndOfStatement) && - Lexer.isNot(asmtok::Eof)) + while (Lexer.isNot(AsmToken::EndOfStatement) && + Lexer.isNot(AsmToken::Eof)) Lexer.Lex(); // Eat EOL. - if (Lexer.is(asmtok::EndOfStatement)) + if (Lexer.is(AsmToken::EndOfStatement)) Lexer.Lex(); } @@ -71,66 +185,71 @@ void AsmParser::EatToEndOfStatement() { /// /// parenexpr ::= expr) /// -bool AsmParser::ParseParenExpr(AsmExpr *&Res) { +bool AsmParser::ParseParenExpr(const MCExpr *&Res) { if (ParseExpression(Res)) return true; - if (Lexer.isNot(asmtok::RParen)) + if (Lexer.isNot(AsmToken::RParen)) return TokError("expected ')' in parentheses expression"); Lexer.Lex(); return false; } +MCSymbol *AsmParser::CreateSymbol(StringRef Name) { + if (MCSymbol *S = Ctx.LookupSymbol(Name)) + return S; + + // If the label starts with L it is an assembler temporary label. + if (Name.startswith("L")) + return Ctx.CreateTemporarySymbol(Name); + + return Ctx.CreateSymbol(Name); +} + /// ParsePrimaryExpr - Parse a primary expression and return it. /// primaryexpr ::= (parenexpr /// primaryexpr ::= symbol /// primaryexpr ::= number /// primaryexpr ::= ~,+,- primaryexpr -bool AsmParser::ParsePrimaryExpr(AsmExpr *&Res) { +bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res) { switch (Lexer.getKind()) { default: return TokError("unknown token in expression"); - case asmtok::Exclaim: + case AsmToken::Exclaim: Lexer.Lex(); // Eat the operator. if (ParsePrimaryExpr(Res)) return true; - Res = new AsmUnaryExpr(AsmUnaryExpr::LNot, Res); + Res = MCUnaryExpr::CreateLNot(Res, getContext()); return false; - case asmtok::Identifier: { + case AsmToken::String: + case AsmToken::Identifier: // This is a label, this should be parsed as part of an expression, to // handle things like LFOO+4. - MCSymbol *Sym = Ctx.GetOrCreateSymbol(Lexer.getCurStrVal()); - - // If this is use of an undefined symbol then mark it external. - if (!Sym->getSection() && !Ctx.GetSymbolValue(Sym)) - Sym->setExternal(true); - - Res = new AsmSymbolRefExpr(Sym); + Res = MCSymbolRefExpr::Create(Lexer.getTok().getIdentifier(), getContext()); Lexer.Lex(); // Eat identifier. return false; - } - case asmtok::IntVal: - Res = new AsmConstantExpr(Lexer.getCurIntVal()); - Lexer.Lex(); // Eat identifier. + case AsmToken::Integer: + Res = MCConstantExpr::Create(Lexer.getTok().getIntVal(), getContext()); + Lexer.Lex(); // Eat token. return false; - case asmtok::LParen: + case AsmToken::LParen: Lexer.Lex(); // Eat the '('. return ParseParenExpr(Res); - case asmtok::Minus: + case AsmToken::Minus: Lexer.Lex(); // Eat the operator. if (ParsePrimaryExpr(Res)) return true; - Res = new AsmUnaryExpr(AsmUnaryExpr::Minus, Res); + Res = MCUnaryExpr::CreateMinus(Res, getContext()); return false; - case asmtok::Plus: + case AsmToken::Plus: Lexer.Lex(); // Eat the operator. if (ParsePrimaryExpr(Res)) return true; - Res = new AsmUnaryExpr(AsmUnaryExpr::Plus, Res); + Res = MCUnaryExpr::CreatePlus(Res, getContext()); return false; - case asmtok::Tilde: + case AsmToken::Tilde: Lexer.Lex(); // Eat the operator. if (ParsePrimaryExpr(Res)) return true; - Res = new AsmUnaryExpr(AsmUnaryExpr::Not, Res); + Res = MCUnaryExpr::CreateNot(Res, getContext()); return false; } } @@ -142,119 +261,101 @@ bool AsmParser::ParsePrimaryExpr(AsmExpr *&Res) { /// expr ::= expr *,/,%,<<,>> expr -> highest. /// expr ::= primaryexpr /// -bool AsmParser::ParseExpression(AsmExpr *&Res) { +bool AsmParser::ParseExpression(const MCExpr *&Res) { Res = 0; return ParsePrimaryExpr(Res) || ParseBinOpRHS(1, Res); } -bool AsmParser::ParseAbsoluteExpression(int64_t &Res) { - AsmExpr *Expr; - - SMLoc StartLoc = Lexer.getLoc(); - if (ParseExpression(Expr)) +bool AsmParser::ParseParenExpression(const MCExpr *&Res) { + if (ParseParenExpr(Res)) return true; - if (!Expr->EvaluateAsAbsolute(Ctx, Res)) - return Error(StartLoc, "expected absolute expression"); - return false; } -bool AsmParser::ParseRelocatableExpression(MCValue &Res) { - AsmExpr *Expr; +bool AsmParser::ParseAbsoluteExpression(int64_t &Res) { + const MCExpr *Expr; SMLoc StartLoc = Lexer.getLoc(); if (ParseExpression(Expr)) return true; - if (!Expr->EvaluateAsRelocatable(Ctx, Res)) - return Error(StartLoc, "expected relocatable expression"); - - return false; -} - -bool AsmParser::ParseParenRelocatableExpression(MCValue &Res) { - AsmExpr *Expr; - - SMLoc StartLoc = Lexer.getLoc(); - if (ParseParenExpr(Expr)) - return true; - - if (!Expr->EvaluateAsRelocatable(Ctx, Res)) - return Error(StartLoc, "expected relocatable expression"); + if (!Expr->EvaluateAsAbsolute(Ctx, Res)) + return Error(StartLoc, "expected absolute expression"); return false; } -static unsigned getBinOpPrecedence(asmtok::TokKind K, - AsmBinaryExpr::Opcode &Kind) { +static unsigned getBinOpPrecedence(AsmToken::TokenKind K, + MCBinaryExpr::Opcode &Kind) { switch (K) { - default: return 0; // not a binop. + default: + return 0; // not a binop. // Lowest Precedence: &&, || - case asmtok::AmpAmp: - Kind = AsmBinaryExpr::LAnd; + case AsmToken::AmpAmp: + Kind = MCBinaryExpr::LAnd; return 1; - case asmtok::PipePipe: - Kind = AsmBinaryExpr::LOr; + case AsmToken::PipePipe: + Kind = MCBinaryExpr::LOr; return 1; // Low Precedence: +, -, ==, !=, <>, <, <=, >, >= - case asmtok::Plus: - Kind = AsmBinaryExpr::Add; + case AsmToken::Plus: + Kind = MCBinaryExpr::Add; return 2; - case asmtok::Minus: - Kind = AsmBinaryExpr::Sub; + case AsmToken::Minus: + Kind = MCBinaryExpr::Sub; return 2; - case asmtok::EqualEqual: - Kind = AsmBinaryExpr::EQ; + case AsmToken::EqualEqual: + Kind = MCBinaryExpr::EQ; return 2; - case asmtok::ExclaimEqual: - case asmtok::LessGreater: - Kind = AsmBinaryExpr::NE; + case AsmToken::ExclaimEqual: + case AsmToken::LessGreater: + Kind = MCBinaryExpr::NE; return 2; - case asmtok::Less: - Kind = AsmBinaryExpr::LT; + case AsmToken::Less: + Kind = MCBinaryExpr::LT; return 2; - case asmtok::LessEqual: - Kind = AsmBinaryExpr::LTE; + case AsmToken::LessEqual: + Kind = MCBinaryExpr::LTE; return 2; - case asmtok::Greater: - Kind = AsmBinaryExpr::GT; + case AsmToken::Greater: + Kind = MCBinaryExpr::GT; return 2; - case asmtok::GreaterEqual: - Kind = AsmBinaryExpr::GTE; + case AsmToken::GreaterEqual: + Kind = MCBinaryExpr::GTE; return 2; // Intermediate Precedence: |, &, ^ // // FIXME: gas seems to support '!' as an infix operator? - case asmtok::Pipe: - Kind = AsmBinaryExpr::Or; + case AsmToken::Pipe: + Kind = MCBinaryExpr::Or; return 3; - case asmtok::Caret: - Kind = AsmBinaryExpr::Xor; + case AsmToken::Caret: + Kind = MCBinaryExpr::Xor; return 3; - case asmtok::Amp: - Kind = AsmBinaryExpr::And; + case AsmToken::Amp: + Kind = MCBinaryExpr::And; return 3; // Highest Precedence: *, /, %, <<, >> - case asmtok::Star: - Kind = AsmBinaryExpr::Mul; + case AsmToken::Star: + Kind = MCBinaryExpr::Mul; return 4; - case asmtok::Slash: - Kind = AsmBinaryExpr::Div; + case AsmToken::Slash: + Kind = MCBinaryExpr::Div; return 4; - case asmtok::Percent: - Kind = AsmBinaryExpr::Mod; + case AsmToken::Percent: + Kind = MCBinaryExpr::Mod; return 4; - case asmtok::LessLess: - Kind = AsmBinaryExpr::Shl; + case AsmToken::LessLess: + Kind = MCBinaryExpr::Shl; return 4; - case asmtok::GreaterGreater: - Kind = AsmBinaryExpr::Shr; + case AsmToken::GreaterGreater: + Kind = MCBinaryExpr::Shr; return 4; } } @@ -262,9 +363,9 @@ static unsigned getBinOpPrecedence(asmtok::TokKind K, /// ParseBinOpRHS - Parse all binary operators with precedence >= 'Precedence'. /// Res contains the LHS of the expression on input. -bool AsmParser::ParseBinOpRHS(unsigned Precedence, AsmExpr *&Res) { +bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res) { while (1) { - AsmBinaryExpr::Opcode Kind = AsmBinaryExpr::Add; + MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add; unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind); // If the next token is lower precedence than we are allowed to eat, return @@ -275,19 +376,19 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, AsmExpr *&Res) { Lexer.Lex(); // Eat the next primary expression. - AsmExpr *RHS; + const MCExpr *RHS; if (ParsePrimaryExpr(RHS)) return true; // If BinOp binds less tightly with RHS than the operator after RHS, let // the pending operator take RHS as its LHS. - AsmBinaryExpr::Opcode Dummy; + MCBinaryExpr::Opcode Dummy; unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy); if (TokPrec < NextTokPrec) { if (ParseBinOpRHS(Precedence+1, RHS)) return true; } // Merge LHS and RHS according to operator. - Res = new AsmBinaryExpr(Kind, Res, RHS); + Res = MCBinaryExpr::Create(Kind, Res, RHS, getContext()); } } @@ -299,24 +400,23 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, AsmExpr *&Res) { /// ::= Label* Directive ...Operands... EndOfStatement /// ::= Label* Identifier OperandList* EndOfStatement bool AsmParser::ParseStatement() { - switch (Lexer.getKind()) { - default: - return TokError("unexpected token at start of statement"); - case asmtok::EndOfStatement: + if (Lexer.is(AsmToken::EndOfStatement)) { Lexer.Lex(); return false; - case asmtok::Identifier: - break; - // TODO: Recurse on local labels etc. } - - // If we have an identifier, handle it as the key symbol. - SMLoc IDLoc = Lexer.getLoc(); - const char *IDVal = Lexer.getCurStrVal(); - - // Consume the identifier, see what is after it. - switch (Lexer.Lex()) { - case asmtok::Colon: { + + // Statements always start with an identifier. + AsmToken ID = Lexer.getTok(); + SMLoc IDLoc = ID.getLoc(); + StringRef IDVal; + if (ParseIdentifier(IDVal)) + return TokError("unexpected token at start of statement"); + + // FIXME: Recurse on local labels? + + // See what kind of statement we have. + switch (Lexer.getKind()) { + case AsmToken::Colon: { // identifier ':' -> Label. Lexer.Lex(); @@ -325,25 +425,21 @@ bool AsmParser::ParseStatement() { // FIXME: Diagnostics. Note the location of the definition as a label. // FIXME: This doesn't diagnose assignment to a symbol which has been // implicitly marked as external. - MCSymbol *Sym = Ctx.GetOrCreateSymbol(IDVal); - if (Sym->getSection()) + MCSymbol *Sym = CreateSymbol(IDVal); + if (!Sym->isUndefined()) return Error(IDLoc, "invalid symbol redefinition"); - if (Ctx.GetSymbolValue(Sym)) - return Error(IDLoc, "symbol already used as assembler variable"); - // Since we saw a label, create a symbol and emit it. - // FIXME: If the label starts with L it is an assembler temporary label. - // Why does the client of this api need to know this? + // Emit the label. Out.EmitLabel(Sym); return ParseStatement(); } - case asmtok::Equal: + case AsmToken::Equal: // identifier '=' ... -> assignment statement Lexer.Lex(); - return ParseAssignment(IDVal, false); + return ParseAssignment(IDVal); default: // Normal instruction or directive. break; @@ -352,184 +448,261 @@ bool AsmParser::ParseStatement() { // Otherwise, we have a normal instruction or directive. if (IDVal[0] == '.') { // FIXME: This should be driven based on a hash lookup and callback. - if (!strcmp(IDVal, ".section")) + if (IDVal == ".section") return ParseDirectiveDarwinSection(); - if (!strcmp(IDVal, ".text")) + if (IDVal == ".text") // FIXME: This changes behavior based on the -static flag to the // assembler. - return ParseDirectiveSectionSwitch("__TEXT,__text", - "regular,pure_instructions"); - if (!strcmp(IDVal, ".const")) - return ParseDirectiveSectionSwitch("__TEXT,__const"); - if (!strcmp(IDVal, ".static_const")) - return ParseDirectiveSectionSwitch("__TEXT,__static_const"); - if (!strcmp(IDVal, ".cstring")) - return ParseDirectiveSectionSwitch("__TEXT,__cstring", - "cstring_literals"); - if (!strcmp(IDVal, ".literal4")) - return ParseDirectiveSectionSwitch("__TEXT,__literal4", "4byte_literals"); - if (!strcmp(IDVal, ".literal8")) - return ParseDirectiveSectionSwitch("__TEXT,__literal8", "8byte_literals"); - if (!strcmp(IDVal, ".literal16")) - return ParseDirectiveSectionSwitch("__TEXT,__literal16", - "16byte_literals"); - if (!strcmp(IDVal, ".constructor")) - return ParseDirectiveSectionSwitch("__TEXT,__constructor"); - if (!strcmp(IDVal, ".destructor")) - return ParseDirectiveSectionSwitch("__TEXT,__destructor"); - if (!strcmp(IDVal, ".fvmlib_init0")) - return ParseDirectiveSectionSwitch("__TEXT,__fvmlib_init0"); - if (!strcmp(IDVal, ".fvmlib_init1")) - return ParseDirectiveSectionSwitch("__TEXT,__fvmlib_init1"); - if (!strcmp(IDVal, ".symbol_stub")) // FIXME: Different on PPC. - return ParseDirectiveSectionSwitch("__IMPORT,__jump_table,symbol_stubs", - "self_modifying_code+pure_instructions,5"); - // FIXME: .picsymbol_stub on PPC. - if (!strcmp(IDVal, ".data")) - return ParseDirectiveSectionSwitch("__DATA,__data"); - if (!strcmp(IDVal, ".static_data")) - return ParseDirectiveSectionSwitch("__DATA,__static_data"); - if (!strcmp(IDVal, ".non_lazy_symbol_pointer")) - return ParseDirectiveSectionSwitch("__DATA,__nl_symbol_pointer", - "non_lazy_symbol_pointers"); - if (!strcmp(IDVal, ".lazy_symbol_pointer")) - return ParseDirectiveSectionSwitch("__DATA,__la_symbol_pointer", - "lazy_symbol_pointers"); - if (!strcmp(IDVal, ".dyld")) - return ParseDirectiveSectionSwitch("__DATA,__dyld"); - if (!strcmp(IDVal, ".mod_init_func")) - return ParseDirectiveSectionSwitch("__DATA,__mod_init_func", - "mod_init_funcs"); - if (!strcmp(IDVal, ".mod_term_func")) - return ParseDirectiveSectionSwitch("__DATA,__mod_term_func", - "mod_term_funcs"); - if (!strcmp(IDVal, ".const_data")) - return ParseDirectiveSectionSwitch("__DATA,__const", "regular"); + return ParseDirectiveSectionSwitch("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); + if (IDVal == ".const") + return ParseDirectiveSectionSwitch("__TEXT", "__const"); + if (IDVal == ".static_const") + return ParseDirectiveSectionSwitch("__TEXT", "__static_const"); + if (IDVal == ".cstring") + return ParseDirectiveSectionSwitch("__TEXT","__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + if (IDVal == ".literal4") + return ParseDirectiveSectionSwitch("__TEXT", "__literal4", + MCSectionMachO::S_4BYTE_LITERALS, + 4); + if (IDVal == ".literal8") + return ParseDirectiveSectionSwitch("__TEXT", "__literal8", + MCSectionMachO::S_8BYTE_LITERALS, + 8); + if (IDVal == ".literal16") + return ParseDirectiveSectionSwitch("__TEXT","__literal16", + MCSectionMachO::S_16BYTE_LITERALS, + 16); + if (IDVal == ".constructor") + return ParseDirectiveSectionSwitch("__TEXT","__constructor"); + if (IDVal == ".destructor") + return ParseDirectiveSectionSwitch("__TEXT","__destructor"); + if (IDVal == ".fvmlib_init0") + return ParseDirectiveSectionSwitch("__TEXT","__fvmlib_init0"); + if (IDVal == ".fvmlib_init1") + return ParseDirectiveSectionSwitch("__TEXT","__fvmlib_init1"); + + // FIXME: The assembler manual claims that this has the self modify code + // flag, at least on x86-32, but that does not appear to be correct. + if (IDVal == ".symbol_stub") + return ParseDirectiveSectionSwitch("__TEXT","__symbol_stub", + MCSectionMachO::S_SYMBOL_STUBS | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + // FIXME: Different on PPC and ARM. + 0, 16); + // FIXME: PowerPC only? + if (IDVal == ".picsymbol_stub") + return ParseDirectiveSectionSwitch("__TEXT","__picsymbol_stub", + MCSectionMachO::S_SYMBOL_STUBS | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, 26); + if (IDVal == ".data") + return ParseDirectiveSectionSwitch("__DATA", "__data"); + if (IDVal == ".static_data") + return ParseDirectiveSectionSwitch("__DATA", "__static_data"); + + // FIXME: The section names of these two are misspelled in the assembler + // manual. + if (IDVal == ".non_lazy_symbol_pointer") + return ParseDirectiveSectionSwitch("__DATA", "__nl_symbol_ptr", + MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS, + 4); + if (IDVal == ".lazy_symbol_pointer") + return ParseDirectiveSectionSwitch("__DATA", "__la_symbol_ptr", + MCSectionMachO::S_LAZY_SYMBOL_POINTERS, + 4); + + if (IDVal == ".dyld") + return ParseDirectiveSectionSwitch("__DATA", "__dyld"); + if (IDVal == ".mod_init_func") + return ParseDirectiveSectionSwitch("__DATA", "__mod_init_func", + MCSectionMachO::S_MOD_INIT_FUNC_POINTERS, + 4); + if (IDVal == ".mod_term_func") + return ParseDirectiveSectionSwitch("__DATA", "__mod_term_func", + MCSectionMachO::S_MOD_TERM_FUNC_POINTERS, + 4); + if (IDVal == ".const_data") + return ParseDirectiveSectionSwitch("__DATA", "__const"); - // FIXME: Verify attributes on sections. - if (!strcmp(IDVal, ".objc_class")) - return ParseDirectiveSectionSwitch("__OBJC,__class"); - if (!strcmp(IDVal, ".objc_meta_class")) - return ParseDirectiveSectionSwitch("__OBJC,__meta_class"); - if (!strcmp(IDVal, ".objc_cat_cls_meth")) - return ParseDirectiveSectionSwitch("__OBJC,__cat_cls_meth"); - if (!strcmp(IDVal, ".objc_cat_inst_meth")) - return ParseDirectiveSectionSwitch("__OBJC,__cat_inst_meth"); - if (!strcmp(IDVal, ".objc_protocol")) - return ParseDirectiveSectionSwitch("__OBJC,__protocol"); - if (!strcmp(IDVal, ".objc_string_object")) - return ParseDirectiveSectionSwitch("__OBJC,__string_object"); - if (!strcmp(IDVal, ".objc_cls_meth")) - return ParseDirectiveSectionSwitch("__OBJC,__cls_meth"); - if (!strcmp(IDVal, ".objc_inst_meth")) - return ParseDirectiveSectionSwitch("__OBJC,__inst_meth"); - if (!strcmp(IDVal, ".objc_cls_refs")) - return ParseDirectiveSectionSwitch("__OBJC,__cls_refs"); - if (!strcmp(IDVal, ".objc_message_refs")) - return ParseDirectiveSectionSwitch("__OBJC,__message_refs"); - if (!strcmp(IDVal, ".objc_symbols")) - return ParseDirectiveSectionSwitch("__OBJC,__symbols"); - if (!strcmp(IDVal, ".objc_category")) - return ParseDirectiveSectionSwitch("__OBJC,__category"); - if (!strcmp(IDVal, ".objc_class_vars")) - return ParseDirectiveSectionSwitch("__OBJC,__class_vars"); - if (!strcmp(IDVal, ".objc_instance_vars")) - return ParseDirectiveSectionSwitch("__OBJC,__instance_vars"); - if (!strcmp(IDVal, ".objc_module_info")) - return ParseDirectiveSectionSwitch("__OBJC,__module_info"); - if (!strcmp(IDVal, ".objc_class_names")) - return ParseDirectiveSectionSwitch("__TEXT,__cstring","cstring_literals"); - if (!strcmp(IDVal, ".objc_meth_var_types")) - return ParseDirectiveSectionSwitch("__TEXT,__cstring","cstring_literals"); - if (!strcmp(IDVal, ".objc_meth_var_names")) - return ParseDirectiveSectionSwitch("__TEXT,__cstring","cstring_literals"); - if (!strcmp(IDVal, ".objc_selector_strs")) - return ParseDirectiveSectionSwitch("__OBJC,__selector_strs"); + if (IDVal == ".objc_class") + return ParseDirectiveSectionSwitch("__OBJC", "__class", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_meta_class") + return ParseDirectiveSectionSwitch("__OBJC", "__meta_class", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_cat_cls_meth") + return ParseDirectiveSectionSwitch("__OBJC", "__cat_cls_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_cat_inst_meth") + return ParseDirectiveSectionSwitch("__OBJC", "__cat_inst_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_protocol") + return ParseDirectiveSectionSwitch("__OBJC", "__protocol", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_string_object") + return ParseDirectiveSectionSwitch("__OBJC", "__string_object", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_cls_meth") + return ParseDirectiveSectionSwitch("__OBJC", "__cls_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_inst_meth") + return ParseDirectiveSectionSwitch("__OBJC", "__inst_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_cls_refs") + return ParseDirectiveSectionSwitch("__OBJC", "__cls_refs", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP | + MCSectionMachO::S_LITERAL_POINTERS, + 4); + if (IDVal == ".objc_message_refs") + return ParseDirectiveSectionSwitch("__OBJC", "__message_refs", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP | + MCSectionMachO::S_LITERAL_POINTERS, + 4); + if (IDVal == ".objc_symbols") + return ParseDirectiveSectionSwitch("__OBJC", "__symbols", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_category") + return ParseDirectiveSectionSwitch("__OBJC", "__category", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_class_vars") + return ParseDirectiveSectionSwitch("__OBJC", "__class_vars", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_instance_vars") + return ParseDirectiveSectionSwitch("__OBJC", "__instance_vars", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_module_info") + return ParseDirectiveSectionSwitch("__OBJC", "__module_info", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_class_names") + return ParseDirectiveSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + if (IDVal == ".objc_meth_var_types") + return ParseDirectiveSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + if (IDVal == ".objc_meth_var_names") + return ParseDirectiveSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + if (IDVal == ".objc_selector_strs") + return ParseDirectiveSectionSwitch("__OBJC", "__selector_strs", + MCSectionMachO::S_CSTRING_LITERALS); // Assembler features - if (!strcmp(IDVal, ".set")) + if (IDVal == ".set") return ParseDirectiveSet(); // Data directives - if (!strcmp(IDVal, ".ascii")) + if (IDVal == ".ascii") return ParseDirectiveAscii(false); - if (!strcmp(IDVal, ".asciz")) + if (IDVal == ".asciz") return ParseDirectiveAscii(true); - // FIXME: Target hooks for size? Also for "word", "hword". - if (!strcmp(IDVal, ".byte")) + if (IDVal == ".byte") return ParseDirectiveValue(1); - if (!strcmp(IDVal, ".short")) + if (IDVal == ".short") return ParseDirectiveValue(2); - if (!strcmp(IDVal, ".long")) + if (IDVal == ".long") return ParseDirectiveValue(4); - if (!strcmp(IDVal, ".quad")) + if (IDVal == ".quad") return ParseDirectiveValue(8); // FIXME: Target hooks for IsPow2. - if (!strcmp(IDVal, ".align")) + if (IDVal == ".align") return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); - if (!strcmp(IDVal, ".align32")) + if (IDVal == ".align32") return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); - if (!strcmp(IDVal, ".balign")) + if (IDVal == ".balign") return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1); - if (!strcmp(IDVal, ".balignw")) + if (IDVal == ".balignw") return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2); - if (!strcmp(IDVal, ".balignl")) + if (IDVal == ".balignl") return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4); - if (!strcmp(IDVal, ".p2align")) + if (IDVal == ".p2align") return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); - if (!strcmp(IDVal, ".p2alignw")) + if (IDVal == ".p2alignw") return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2); - if (!strcmp(IDVal, ".p2alignl")) + if (IDVal == ".p2alignl") return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); - if (!strcmp(IDVal, ".org")) + if (IDVal == ".org") return ParseDirectiveOrg(); - if (!strcmp(IDVal, ".fill")) + if (IDVal == ".fill") return ParseDirectiveFill(); - if (!strcmp(IDVal, ".space")) + if (IDVal == ".space") return ParseDirectiveSpace(); // Symbol attribute directives - if (!strcmp(IDVal, ".globl") || !strcmp(IDVal, ".global")) + + if (IDVal == ".globl" || IDVal == ".global") return ParseDirectiveSymbolAttribute(MCStreamer::Global); - if (!strcmp(IDVal, ".hidden")) + if (IDVal == ".hidden") return ParseDirectiveSymbolAttribute(MCStreamer::Hidden); - if (!strcmp(IDVal, ".indirect_symbol")) + if (IDVal == ".indirect_symbol") return ParseDirectiveSymbolAttribute(MCStreamer::IndirectSymbol); - if (!strcmp(IDVal, ".internal")) + if (IDVal == ".internal") return ParseDirectiveSymbolAttribute(MCStreamer::Internal); - if (!strcmp(IDVal, ".lazy_reference")) + if (IDVal == ".lazy_reference") return ParseDirectiveSymbolAttribute(MCStreamer::LazyReference); - if (!strcmp(IDVal, ".no_dead_strip")) + if (IDVal == ".no_dead_strip") return ParseDirectiveSymbolAttribute(MCStreamer::NoDeadStrip); - if (!strcmp(IDVal, ".private_extern")) + if (IDVal == ".private_extern") return ParseDirectiveSymbolAttribute(MCStreamer::PrivateExtern); - if (!strcmp(IDVal, ".protected")) + if (IDVal == ".protected") return ParseDirectiveSymbolAttribute(MCStreamer::Protected); - if (!strcmp(IDVal, ".reference")) + if (IDVal == ".reference") return ParseDirectiveSymbolAttribute(MCStreamer::Reference); - if (!strcmp(IDVal, ".weak")) + if (IDVal == ".weak") return ParseDirectiveSymbolAttribute(MCStreamer::Weak); - if (!strcmp(IDVal, ".weak_definition")) + if (IDVal == ".weak_definition") return ParseDirectiveSymbolAttribute(MCStreamer::WeakDefinition); - if (!strcmp(IDVal, ".weak_reference")) + if (IDVal == ".weak_reference") return ParseDirectiveSymbolAttribute(MCStreamer::WeakReference); + if (IDVal == ".comm") + return ParseDirectiveComm(/*IsLocal=*/false); + if (IDVal == ".lcomm") + return ParseDirectiveComm(/*IsLocal=*/true); + if (IDVal == ".zerofill") + return ParseDirectiveDarwinZerofill(); + if (IDVal == ".desc") + return ParseDirectiveDarwinSymbolDesc(); + if (IDVal == ".lsym") + return ParseDirectiveDarwinLsym(); + + if (IDVal == ".subsections_via_symbols") + return ParseDirectiveDarwinSubsectionsViaSymbols(); + if (IDVal == ".abort") + return ParseDirectiveAbort(); + if (IDVal == ".include") + return ParseDirectiveInclude(); + if (IDVal == ".dump") + return ParseDirectiveDarwinDumpOrLoad(IDLoc, /*IsDump=*/true); + if (IDVal == ".load") + return ParseDirectiveDarwinDumpOrLoad(IDLoc, /*IsLoad=*/false); + + // Look up the handler in the handler table, + bool(AsmParser::*Handler)(StringRef, SMLoc) = DirectiveMap[IDVal]; + if (Handler) + return (this->*Handler)(IDVal, IDLoc); + + // Target hook for parsing target specific directives. + if (!getTargetParser().ParseDirective(ID)) + return false; + Warning(IDLoc, "ignoring directive for now"); EatToEndOfStatement(); return false; } MCInst Inst; - if (ParseX86InstOperands(IDVal, Inst)) + if (getTargetParser().ParseInstruction(IDVal, Inst)) return true; - if (Lexer.isNot(asmtok::EndOfStatement)) + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in argument list"); // Eat the end of statement marker. @@ -542,15 +715,16 @@ bool AsmParser::ParseStatement() { return false; } -bool AsmParser::ParseAssignment(const char *Name, bool IsDotSet) { +bool AsmParser::ParseAssignment(const StringRef &Name) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); - MCValue Value; - if (ParseRelocatableExpression(Value)) + const MCExpr *Value; + SMLoc StartLoc = Lexer.getLoc(); + if (ParseExpression(Value)) return true; - if (Lexer.isNot(asmtok::EndOfStatement)) + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in assignment"); // Eat the end of statement marker. @@ -559,18 +733,29 @@ bool AsmParser::ParseAssignment(const char *Name, bool IsDotSet) { // Diagnose assignment to a label. // // FIXME: Diagnostics. Note the location of the definition as a label. - // FIXME: This doesn't diagnose assignment to a symbol which has been - // implicitly marked as external. // FIXME: Handle '.'. // FIXME: Diagnose assignment to protected identifier (e.g., register name). - MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name); - if (Sym->getSection()) - return Error(EqualLoc, "invalid assignment to symbol emitted as a label"); - if (Sym->isExternal()) - return Error(EqualLoc, "invalid assignment to external symbol"); + MCSymbol *Sym = CreateSymbol(Name); + if (!Sym->isUndefined() && !Sym->isAbsolute()) + return Error(EqualLoc, "symbol has already been defined"); // Do the assignment. - Out.EmitAssignment(Sym, Value, IsDotSet); + Out.EmitAssignment(Sym, Value); + + return false; +} + +/// ParseIdentifier: +/// ::= identifier +/// ::= string +bool AsmParser::ParseIdentifier(StringRef &Res) { + if (Lexer.isNot(AsmToken::Identifier) && + Lexer.isNot(AsmToken::String)) + return true; + + Res = Lexer.getTok().getIdentifier(); + + Lexer.Lex(); // Consume the identifier token. return false; } @@ -578,16 +763,16 @@ bool AsmParser::ParseAssignment(const char *Name, bool IsDotSet) { /// ParseDirectiveSet: /// ::= .set identifier ',' expression bool AsmParser::ParseDirectiveSet() { - if (Lexer.isNot(asmtok::Identifier)) - return TokError("expected identifier after '.set' directive"); + StringRef Name; - const char *Name = Lexer.getCurStrVal(); + if (ParseIdentifier(Name)) + return TokError("expected identifier after '.set' directive"); - if (Lexer.Lex() != asmtok::Comma) + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in '.set'"); Lexer.Lex(); - return ParseAssignment(Name, true); + return ParseAssignment(Name); } /// ParseDirectiveSection: @@ -595,69 +780,152 @@ bool AsmParser::ParseDirectiveSet() { /// FIXME: This should actually parse out the segment, section, attributes and /// sizeof_stub fields. bool AsmParser::ParseDirectiveDarwinSection() { - if (Lexer.isNot(asmtok::Identifier)) - return TokError("expected identifier after '.section' directive"); - - std::string Section = Lexer.getCurStrVal(); + SMLoc Loc = Lexer.getLoc(); + + StringRef SectionName; + if (ParseIdentifier(SectionName)) + return Error(Loc, "expected identifier after '.section' directive"); + + // Verify there is a following comma. + if (!Lexer.is(AsmToken::Comma)) + return TokError("unexpected token in '.section' directive"); + + std::string SectionSpec = SectionName; + SectionSpec += ","; + + // Add all the tokens until the end of the line, ParseSectionSpecifier will + // handle this. + StringRef EOL = Lexer.LexUntilEndOfStatement(); + SectionSpec.append(EOL.begin(), EOL.end()); + Lexer.Lex(); - - // Accept a comma separated list of modifiers. - while (Lexer.is(asmtok::Comma)) { - Lexer.Lex(); - - if (Lexer.isNot(asmtok::Identifier)) - return TokError("expected identifier in '.section' directive"); - Section += ','; - Section += Lexer.getCurStrVal(); - Lexer.Lex(); - } - - if (Lexer.isNot(asmtok::EndOfStatement)) + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.section' directive"); Lexer.Lex(); - Out.SwitchSection(Ctx.GetSection(Section.c_str())); + + StringRef Segment, Section; + unsigned TAA, StubSize; + std::string ErrorStr = + MCSectionMachO::ParseSectionSpecifier(SectionSpec, Segment, Section, + TAA, StubSize); + + if (!ErrorStr.empty()) + return Error(Loc, ErrorStr.c_str()); + + // FIXME: Arch specific. + Out.SwitchSection(getMachOSection(Segment, Section, TAA, StubSize, + SectionKind())); return false; } -bool AsmParser::ParseDirectiveSectionSwitch(const char *Section, - const char *Directives) { - if (Lexer.isNot(asmtok::EndOfStatement)) +/// ParseDirectiveSectionSwitch - +bool AsmParser::ParseDirectiveSectionSwitch(const char *Segment, + const char *Section, + unsigned TAA, unsigned Align, + unsigned StubSize) { + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in section switching directive"); Lexer.Lex(); - std::string SectionStr = Section; - if (Directives && Directives[0]) { - SectionStr += ","; - SectionStr += Directives; + // FIXME: Arch specific. + Out.SwitchSection(getMachOSection(Segment, Section, TAA, StubSize, + SectionKind())); + + // Set the implicit alignment, if any. + // + // FIXME: This isn't really what 'as' does; I think it just uses the implicit + // alignment on the section (e.g., if one manually inserts bytes into the + // section, then just issueing the section switch directive will not realign + // the section. However, this is arguably more reasonable behavior, and there + // is no good reason for someone to intentionally emit incorrectly sized + // values into the implicitly aligned sections. + if (Align) + Out.EmitValueToAlignment(Align, 0, 1, 0); + + return false; +} + +bool AsmParser::ParseEscapedString(std::string &Data) { + assert(Lexer.is(AsmToken::String) && "Unexpected current token!"); + + Data = ""; + StringRef Str = Lexer.getTok().getStringContents(); + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + if (Str[i] != '\\') { + Data += Str[i]; + continue; + } + + // Recognize escaped characters. Note that this escape semantics currently + // loosely follows Darwin 'as'. Notably, it doesn't support hex escapes. + ++i; + if (i == e) + return TokError("unexpected backslash at end of string"); + + // Recognize octal sequences. + if ((unsigned) (Str[i] - '0') <= 7) { + // Consume up to three octal characters. + unsigned Value = Str[i] - '0'; + + if (i + 1 != e && ((unsigned) (Str[i + 1] - '0')) <= 7) { + ++i; + Value = Value * 8 + (Str[i] - '0'); + + if (i + 1 != e && ((unsigned) (Str[i + 1] - '0')) <= 7) { + ++i; + Value = Value * 8 + (Str[i] - '0'); + } + } + + if (Value > 255) + return TokError("invalid octal escape sequence (out of range)"); + + Data += (unsigned char) Value; + continue; + } + + // Otherwise recognize individual escapes. + switch (Str[i]) { + default: + // Just reject invalid escape sequences for now. + return TokError("invalid escape sequence (unrecognized character)"); + + case 'b': Data += '\b'; break; + case 'f': Data += '\f'; break; + case 'n': Data += '\n'; break; + case 'r': Data += '\r'; break; + case 't': Data += '\t'; break; + case '"': Data += '"'; break; + case '\\': Data += '\\'; break; + } } - - Out.SwitchSection(Ctx.GetSection(Section)); + return false; } /// ParseDirectiveAscii: /// ::= ( .ascii | .asciz ) [ "string" ( , "string" )* ] bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { - if (Lexer.isNot(asmtok::EndOfStatement)) { + if (Lexer.isNot(AsmToken::EndOfStatement)) { for (;;) { - if (Lexer.isNot(asmtok::String)) + if (Lexer.isNot(AsmToken::String)) return TokError("expected string in '.ascii' or '.asciz' directive"); - // FIXME: This shouldn't use a const char* + strlen, the string could have - // embedded nulls. - // FIXME: Should have accessor for getting string contents. - const char *Str = Lexer.getCurStrVal(); - Out.EmitBytes(Str + 1, strlen(Str) - 2); + std::string Data; + if (ParseEscapedString(Data)) + return true; + + Out.EmitBytes(Data); if (ZeroTerminated) - Out.EmitBytes("\0", 1); + Out.EmitBytes(StringRef("\0", 1)); Lexer.Lex(); - if (Lexer.is(asmtok::EndOfStatement)) + if (Lexer.is(AsmToken::EndOfStatement)) break; - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in '.ascii' or '.asciz' directive"); Lexer.Lex(); } @@ -670,19 +938,20 @@ bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { /// ParseDirectiveValue /// ::= (.byte | .short | ... ) [ expression (, expression)* ] bool AsmParser::ParseDirectiveValue(unsigned Size) { - if (Lexer.isNot(asmtok::EndOfStatement)) { + if (Lexer.isNot(AsmToken::EndOfStatement)) { for (;;) { - MCValue Expr; - if (ParseRelocatableExpression(Expr)) + const MCExpr *Value; + SMLoc StartLoc = Lexer.getLoc(); + if (ParseExpression(Value)) return true; - Out.EmitValue(Expr, Size); + Out.EmitValue(Value, Size); - if (Lexer.is(asmtok::EndOfStatement)) + if (Lexer.is(AsmToken::EndOfStatement)) break; // FIXME: Improve diagnostic. - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lexer.Lex(); } @@ -701,8 +970,8 @@ bool AsmParser::ParseDirectiveSpace() { int64_t FillExpr = 0; bool HasFillExpr = false; - if (Lexer.isNot(asmtok::EndOfStatement)) { - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in '.space' directive"); Lexer.Lex(); @@ -711,7 +980,7 @@ bool AsmParser::ParseDirectiveSpace() { HasFillExpr = true; - if (Lexer.isNot(asmtok::EndOfStatement)) + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.space' directive"); } @@ -722,7 +991,7 @@ bool AsmParser::ParseDirectiveSpace() { // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. for (uint64_t i = 0, e = NumBytes; i != e; ++i) - Out.EmitValue(MCValue::get(FillExpr), 1); + Out.EmitValue(MCConstantExpr::Create(FillExpr, getContext()), 1); return false; } @@ -734,7 +1003,7 @@ bool AsmParser::ParseDirectiveFill() { if (ParseAbsoluteExpression(NumValues)) return true; - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in '.fill' directive"); Lexer.Lex(); @@ -742,7 +1011,7 @@ bool AsmParser::ParseDirectiveFill() { if (ParseAbsoluteExpression(FillSize)) return true; - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in '.fill' directive"); Lexer.Lex(); @@ -750,16 +1019,16 @@ bool AsmParser::ParseDirectiveFill() { if (ParseAbsoluteExpression(FillExpr)) return true; - if (Lexer.isNot(asmtok::EndOfStatement)) + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.fill' directive"); Lexer.Lex(); - if (FillSize != 1 && FillSize != 2 && FillSize != 4) - return TokError("invalid '.fill' size, expected 1, 2, or 4"); + if (FillSize != 1 && FillSize != 2 && FillSize != 4 && FillSize != 8) + return TokError("invalid '.fill' size, expected 1, 2, 4, or 8"); for (uint64_t i = 0, e = NumValues; i != e; ++i) - Out.EmitValue(MCValue::get(FillExpr), FillSize); + Out.EmitValue(MCConstantExpr::Create(FillExpr, getContext()), FillSize); return false; } @@ -767,21 +1036,22 @@ bool AsmParser::ParseDirectiveFill() { /// ParseDirectiveOrg /// ::= .org expression [ , expression ] bool AsmParser::ParseDirectiveOrg() { - MCValue Offset; - if (ParseRelocatableExpression(Offset)) + const MCExpr *Offset; + SMLoc StartLoc = Lexer.getLoc(); + if (ParseExpression(Offset)) return true; // Parse optional fill expression. int64_t FillExpr = 0; - if (Lexer.isNot(asmtok::EndOfStatement)) { - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in '.org' directive"); Lexer.Lex(); if (ParseAbsoluteExpression(FillExpr)) return true; - if (Lexer.isNot(asmtok::EndOfStatement)) + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.org' directive"); } @@ -797,6 +1067,7 @@ bool AsmParser::ParseDirectiveOrg() { /// ParseDirectiveAlign /// ::= {.align, ...} expression [ , expression [ , expression ]] bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { + SMLoc AlignmentLoc = Lexer.getLoc(); int64_t Alignment; if (ParseAbsoluteExpression(Alignment)) return true; @@ -805,22 +1076,22 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { bool HasFillExpr = false; int64_t FillExpr = 0; int64_t MaxBytesToFill = 0; - if (Lexer.isNot(asmtok::EndOfStatement)) { - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lexer.Lex(); // The fill expression can be omitted while specifying a maximum number of // alignment bytes, e.g: // .align 3,,4 - if (Lexer.isNot(asmtok::Comma)) { + if (Lexer.isNot(AsmToken::Comma)) { HasFillExpr = true; if (ParseAbsoluteExpression(FillExpr)) return true; } - if (Lexer.isNot(asmtok::EndOfStatement)) { - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lexer.Lex(); @@ -828,7 +1099,7 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { if (ParseAbsoluteExpression(MaxBytesToFill)) return true; - if (Lexer.isNot(asmtok::EndOfStatement)) + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); } } @@ -843,15 +1114,20 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { // Compute alignment in bytes. if (IsPow2) { // FIXME: Diagnose overflow. - Alignment = 1 << Alignment; + if (Alignment >= 32) { + Error(AlignmentLoc, "invalid alignment value"); + Alignment = 31; + } + + Alignment = 1ULL << Alignment; } - // Diagnose non-sensical max bytes to fill. + // Diagnose non-sensical max bytes to align. if (MaxBytesLoc.isValid()) { if (MaxBytesToFill < 1) { - Warning(MaxBytesLoc, "alignment directive can never be satisfied in this " - "many bytes, ignoring"); - return false; + Error(MaxBytesLoc, "alignment directive can never be satisfied in this " + "many bytes, ignoring maximum bytes expression"); + MaxBytesToFill = 0; } if (MaxBytesToFill >= Alignment) { @@ -870,24 +1146,21 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { /// ParseDirectiveSymbolAttribute /// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] bool AsmParser::ParseDirectiveSymbolAttribute(MCStreamer::SymbolAttr Attr) { - if (Lexer.isNot(asmtok::EndOfStatement)) { + if (Lexer.isNot(AsmToken::EndOfStatement)) { for (;;) { - if (Lexer.isNot(asmtok::Identifier)) + StringRef Name; + + if (ParseIdentifier(Name)) return TokError("expected identifier in directive"); - MCSymbol *Sym = Ctx.GetOrCreateSymbol(Lexer.getCurStrVal()); - Lexer.Lex(); - - // If this is use of an undefined symbol then mark it external. - if (!Sym->getSection() && !Ctx.GetSymbolValue(Sym)) - Sym->setExternal(true); + MCSymbol *Sym = CreateSymbol(Name); Out.EmitSymbolAttribute(Sym, Attr); - if (Lexer.is(asmtok::EndOfStatement)) + if (Lexer.is(AsmToken::EndOfStatement)) break; - if (Lexer.isNot(asmtok::Comma)) + if (Lexer.isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lexer.Lex(); } @@ -896,3 +1169,513 @@ bool AsmParser::ParseDirectiveSymbolAttribute(MCStreamer::SymbolAttr Attr) { Lexer.Lex(); return false; } + +/// ParseDirectiveDarwinSymbolDesc +/// ::= .desc identifier , expression +bool AsmParser::ParseDirectiveDarwinSymbolDesc() { + StringRef Name; + if (ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = CreateSymbol(Name); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.desc' directive"); + Lexer.Lex(); + + SMLoc DescLoc = Lexer.getLoc(); + int64_t DescValue; + if (ParseAbsoluteExpression(DescValue)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.desc' directive"); + + Lexer.Lex(); + + // Set the n_desc field of this Symbol to this DescValue + Out.EmitSymbolDesc(Sym, DescValue); + + return false; +} + +/// ParseDirectiveComm +/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ] +bool AsmParser::ParseDirectiveComm(bool IsLocal) { + SMLoc IDLoc = Lexer.getLoc(); + StringRef Name; + if (ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = CreateSymbol(Name); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lexer.Lex(); + + int64_t Size; + SMLoc SizeLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Size)) + return true; + + int64_t Pow2Alignment = 0; + SMLoc Pow2AlignmentLoc; + if (Lexer.is(AsmToken::Comma)) { + Lexer.Lex(); + Pow2AlignmentLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Pow2Alignment)) + return true; + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.comm' or '.lcomm' directive"); + + Lexer.Lex(); + + // NOTE: a size of zero for a .comm should create a undefined symbol + // but a size of .lcomm creates a bss symbol of size zero. + if (Size < 0) + return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't " + "be less than zero"); + + // NOTE: The alignment in the directive is a power of 2 value, the assember + // may internally end up wanting an alignment in bytes. + // FIXME: Diagnose overflow. + if (Pow2Alignment < 0) + return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm' directive " + "alignment, can't be less than zero"); + + if (!Sym->isUndefined()) + return Error(IDLoc, "invalid symbol redefinition"); + + // '.lcomm' is equivalent to '.zerofill'. + // Create the Symbol as a common or local common with Size and Pow2Alignment + if (IsLocal) { + Out.EmitZerofill(getMachOSection("__DATA", "__bss", + MCSectionMachO::S_ZEROFILL, 0, + SectionKind()), + Sym, Size, 1 << Pow2Alignment); + return false; + } + + Out.EmitCommonSymbol(Sym, Size, 1 << Pow2Alignment); + return false; +} + +/// ParseDirectiveDarwinZerofill +/// ::= .zerofill segname , sectname [, identifier , size_expression [ +/// , align_expression ]] +bool AsmParser::ParseDirectiveDarwinZerofill() { + // FIXME: Handle quoted names here. + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("expected segment name after '.zerofill' directive"); + StringRef Segment = Lexer.getTok().getString(); + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("expected section name after comma in '.zerofill' " + "directive"); + StringRef Section = Lexer.getTok().getString(); + Lexer.Lex(); + + // If this is the end of the line all that was wanted was to create the + // the section but with no symbol. + if (Lexer.is(AsmToken::EndOfStatement)) { + // Create the zerofill section but no symbol + Out.EmitZerofill(getMachOSection(Segment, Section, + MCSectionMachO::S_ZEROFILL, 0, + SectionKind())); + return false; + } + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("expected identifier in directive"); + + // handle the identifier as the key symbol. + SMLoc IDLoc = Lexer.getLoc(); + MCSymbol *Sym = CreateSymbol(Lexer.getTok().getString()); + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lexer.Lex(); + + int64_t Size; + SMLoc SizeLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Size)) + return true; + + int64_t Pow2Alignment = 0; + SMLoc Pow2AlignmentLoc; + if (Lexer.is(AsmToken::Comma)) { + Lexer.Lex(); + Pow2AlignmentLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Pow2Alignment)) + return true; + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.zerofill' directive"); + + Lexer.Lex(); + + if (Size < 0) + return Error(SizeLoc, "invalid '.zerofill' directive size, can't be less " + "than zero"); + + // NOTE: The alignment in the directive is a power of 2 value, the assember + // may internally end up wanting an alignment in bytes. + // FIXME: Diagnose overflow. + if (Pow2Alignment < 0) + return Error(Pow2AlignmentLoc, "invalid '.zerofill' directive alignment, " + "can't be less than zero"); + + if (!Sym->isUndefined()) + return Error(IDLoc, "invalid symbol redefinition"); + + // Create the zerofill Symbol with Size and Pow2Alignment + // + // FIXME: Arch specific. + Out.EmitZerofill(getMachOSection(Segment, Section, + MCSectionMachO::S_ZEROFILL, 0, + SectionKind()), + Sym, Size, 1 << Pow2Alignment); + + return false; +} + +/// ParseDirectiveDarwinSubsectionsViaSymbols +/// ::= .subsections_via_symbols +bool AsmParser::ParseDirectiveDarwinSubsectionsViaSymbols() { + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.subsections_via_symbols' directive"); + + Lexer.Lex(); + + Out.EmitAssemblerFlag(MCStreamer::SubsectionsViaSymbols); + + return false; +} + +/// ParseDirectiveAbort +/// ::= .abort [ "abort_string" ] +bool AsmParser::ParseDirectiveAbort() { + // FIXME: Use loc from directive. + SMLoc Loc = Lexer.getLoc(); + + StringRef Str = ""; + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::String)) + return TokError("expected string in '.abort' directive"); + + Str = Lexer.getTok().getString(); + + Lexer.Lex(); + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.abort' directive"); + + Lexer.Lex(); + + // FIXME: Handle here. + if (Str.empty()) + Error(Loc, ".abort detected. Assembly stopping."); + else + Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); + + return false; +} + +/// ParseDirectiveLsym +/// ::= .lsym identifier , expression +bool AsmParser::ParseDirectiveDarwinLsym() { + StringRef Name; + if (ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = CreateSymbol(Name); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.lsym' directive"); + Lexer.Lex(); + + const MCExpr *Value; + SMLoc StartLoc = Lexer.getLoc(); + if (ParseExpression(Value)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.lsym' directive"); + + Lexer.Lex(); + + // We don't currently support this directive. + // + // FIXME: Diagnostic location! + (void) Sym; + return TokError("directive '.lsym' is unsupported"); +} + +/// ParseDirectiveInclude +/// ::= .include "filename" +bool AsmParser::ParseDirectiveInclude() { + if (Lexer.isNot(AsmToken::String)) + return TokError("expected string in '.include' directive"); + + std::string Filename = Lexer.getTok().getString(); + SMLoc IncludeLoc = Lexer.getLoc(); + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.include' directive"); + + // Strip the quotes. + Filename = Filename.substr(1, Filename.size()-2); + + // Attempt to switch the lexer to the included file before consuming the end + // of statement to avoid losing it when we switch. + if (Lexer.EnterIncludeFile(Filename)) { + Lexer.PrintMessage(IncludeLoc, + "Could not find include file '" + Filename + "'", + "error"); + return true; + } + + return false; +} + +/// ParseDirectiveDarwinDumpOrLoad +/// ::= ( .dump | .load ) "filename" +bool AsmParser::ParseDirectiveDarwinDumpOrLoad(SMLoc IDLoc, bool IsDump) { + if (Lexer.isNot(AsmToken::String)) + return TokError("expected string in '.dump' or '.load' directive"); + + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.dump' or '.load' directive"); + + Lexer.Lex(); + + // FIXME: If/when .dump and .load are implemented they will be done in the + // the assembly parser and not have any need for an MCStreamer API. + if (IsDump) + Warning(IDLoc, "ignoring directive .dump for now"); + else + Warning(IDLoc, "ignoring directive .load for now"); + + return false; +} + +/// ParseDirectiveIf +/// ::= .if expression +bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { + // Consume the identifier that was the .if directive + Lexer.Lex(); + + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + if(TheCondState.Ignore) { + EatToEndOfStatement(); + } + else { + int64_t ExprValue; + if (ParseAbsoluteExpression(ExprValue)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.if' directive"); + + Lexer.Lex(); + + TheCondState.CondMet = ExprValue; + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// ParseDirectiveElseIf +/// ::= .elseif expression +bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) { + if (TheCondState.TheCond != AsmCond::IfCond && + TheCondState.TheCond != AsmCond::ElseIfCond) + Error(DirectiveLoc, "Encountered a .elseif that doesn't follow a .if or " + " an .elseif"); + TheCondState.TheCond = AsmCond::ElseIfCond; + + // Consume the identifier that was the .elseif directive + Lexer.Lex(); + + bool LastIgnoreState = false; + if (!TheCondStack.empty()) + LastIgnoreState = TheCondStack.back().Ignore; + if (LastIgnoreState || TheCondState.CondMet) { + TheCondState.Ignore = true; + EatToEndOfStatement(); + } + else { + int64_t ExprValue; + if (ParseAbsoluteExpression(ExprValue)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.elseif' directive"); + + Lexer.Lex(); + TheCondState.CondMet = ExprValue; + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// ParseDirectiveElse +/// ::= .else +bool AsmParser::ParseDirectiveElse(SMLoc DirectiveLoc) { + // Consume the identifier that was the .else directive + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.else' directive"); + + Lexer.Lex(); + + if (TheCondState.TheCond != AsmCond::IfCond && + TheCondState.TheCond != AsmCond::ElseIfCond) + Error(DirectiveLoc, "Encountered a .else that doesn't follow a .if or an " + ".elseif"); + TheCondState.TheCond = AsmCond::ElseCond; + bool LastIgnoreState = false; + if (!TheCondStack.empty()) + LastIgnoreState = TheCondStack.back().Ignore; + if (LastIgnoreState || TheCondState.CondMet) + TheCondState.Ignore = true; + else + TheCondState.Ignore = false; + + return false; +} + +/// ParseDirectiveEndIf +/// ::= .endif +bool AsmParser::ParseDirectiveEndIf(SMLoc DirectiveLoc) { + // Consume the identifier that was the .endif directive + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.endif' directive"); + + Lexer.Lex(); + + if ((TheCondState.TheCond == AsmCond::NoCond) || + TheCondStack.empty()) + Error(DirectiveLoc, "Encountered a .endif that doesn't follow a .if or " + ".else"); + if (!TheCondStack.empty()) { + TheCondState = TheCondStack.back(); + TheCondStack.pop_back(); + } + + return false; +} + +/// ParseDirectiveFile +/// ::= .file [number] string +bool AsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { + // FIXME: I'm not sure what this is. + int64_t FileNumber = -1; + if (Lexer.is(AsmToken::Integer)) { + FileNumber = Lexer.getTok().getIntVal(); + Lexer.Lex(); + + if (FileNumber < 1) + return TokError("file number less than one"); + } + + if (Lexer.isNot(AsmToken::String)) + return TokError("unexpected token in '.file' directive"); + + StringRef FileName = Lexer.getTok().getString(); + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.file' directive"); + + // FIXME: Do something with the .file. + + return false; +} + +/// ParseDirectiveLine +/// ::= .line [number] +bool AsmParser::ParseDirectiveLine(StringRef, SMLoc DirectiveLoc) { + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Integer)) + return TokError("unexpected token in '.line' directive"); + + int64_t LineNumber = Lexer.getTok().getIntVal(); + (void) LineNumber; + Lexer.Lex(); + + // FIXME: Do something with the .line. + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.file' directive"); + + return false; +} + + +/// ParseDirectiveLoc +/// ::= .loc number [number [number]] +bool AsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { + if (Lexer.isNot(AsmToken::Integer)) + return TokError("unexpected token in '.loc' directive"); + + // FIXME: What are these fields? + int64_t FileNumber = Lexer.getTok().getIntVal(); + (void) FileNumber; + // FIXME: Validate file. + + Lexer.Lex(); + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Integer)) + return TokError("unexpected token in '.loc' directive"); + + int64_t Param2 = Lexer.getTok().getIntVal(); + (void) Param2; + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Integer)) + return TokError("unexpected token in '.loc' directive"); + + int64_t Param3 = Lexer.getTok().getIntVal(); + (void) Param3; + Lexer.Lex(); + + // FIXME: Do something with the .loc. + } + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.file' directive"); + + return false; +} + diff --git a/tools/llvm-mc/AsmParser.h b/tools/llvm-mc/AsmParser.h index 333b284..171dfcd 100644 --- a/tools/llvm-mc/AsmParser.h +++ b/tools/llvm-mc/AsmParser.h @@ -14,89 +14,110 @@ #ifndef ASMPARSER_H #define ASMPARSER_H +#include <vector> #include "AsmLexer.h" +#include "AsmCond.h" +#include "llvm/MC/MCAsmParser.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/ADT/StringMap.h" namespace llvm { -class AsmExpr; +class AsmCond; class MCContext; +class MCExpr; class MCInst; class MCStreamer; +class MCAsmInfo; class MCValue; +class TargetAsmParser; +class Twine; -class AsmParser { -public: - struct X86Operand; - +class AsmParser : public MCAsmParser { private: AsmLexer Lexer; MCContext &Ctx; MCStreamer &Out; - + TargetAsmParser *TargetParser; + + AsmCond TheCondState; + std::vector<AsmCond> TheCondStack; + + // FIXME: Figure out where this should leave, the code is a copy of that which + // is also used by TargetLoweringObjectFile. + mutable void *SectionUniquingMap; + + /// DirectiveMap - This is a table handlers for directives. Each handler is + /// invoked after the directive identifier is read and is responsible for + /// parsing and validating the rest of the directive. The handler is passed + /// in the directive name and the location of the directive keyword. + StringMap<bool(AsmParser::*)(StringRef, SMLoc)> DirectiveMap; public: - AsmParser(SourceMgr &SM, MCContext &ctx, MCStreamer &OutStr) - : Lexer(SM), Ctx(ctx), Out(OutStr) {} - ~AsmParser() {} - + AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, + const MCAsmInfo &_MAI); + ~AsmParser(); + bool Run(); + + void AddDirectiveHandler(StringRef Directive, + bool (AsmParser::*Handler)(StringRef, SMLoc)) { + DirectiveMap[Directive] = Handler; + } +public: + TargetAsmParser &getTargetParser() const { return *TargetParser; } + void setTargetParser(TargetAsmParser &P) { TargetParser = &P; } + + /// @name MCAsmParser Interface + /// { + + virtual MCAsmLexer &getLexer() { return Lexer; } + virtual MCContext &getContext() { return Ctx; } + virtual MCStreamer &getStreamer() { return Out; } + + virtual void Warning(SMLoc L, const Twine &Meg); + virtual bool Error(SMLoc L, const Twine &Msg); + + virtual bool ParseExpression(const MCExpr *&Res); + virtual bool ParseParenExpression(const MCExpr *&Res); + virtual bool ParseAbsoluteExpression(int64_t &Res); + + /// } + private: + MCSymbol *CreateSymbol(StringRef Name); + + // FIXME: See comment on SectionUniquingMap. + const MCSection *getMachOSection(const StringRef &Segment, + const StringRef &Section, + unsigned TypeAndAttributes, + unsigned Reserved2, + SectionKind Kind) const; + bool ParseStatement(); - void Warning(SMLoc L, const char *Msg); - bool Error(SMLoc L, const char *Msg); bool TokError(const char *Msg); + bool ParseConditionalAssemblyDirectives(StringRef Directive, + SMLoc DirectiveLoc); void EatToEndOfStatement(); - bool ParseAssignment(const char *Name, bool IsDotSet); - - /// ParseExpression - Parse a general assembly expression. - /// - /// @param Res - The resulting expression. The pointer value is null on error. - /// @result - False on success. - bool ParseExpression(AsmExpr *&Res); - - /// ParseAbsoluteExpression - Parse an expression which must evaluate to an - /// absolute value. - /// - /// @param Res - The value of the absolute expression. The result is undefined - /// on error. - /// @result - False on success. - bool ParseAbsoluteExpression(int64_t &Res); - - /// ParseRelocatableExpression - Parse an expression which must be - /// relocatable. - /// - /// @param Res - The relocatable expression value. The result is undefined on - /// error. - /// @result - False on success. - bool ParseRelocatableExpression(MCValue &Res); - - /// ParseParenRelocatableExpression - Parse an expression which must be - /// relocatable, assuming that an initial '(' has already been consumed. - /// - /// @param Res - The relocatable expression value. The result is undefined on - /// error. - /// @result - False on success. - /// - /// @see ParseRelocatableExpression, ParseParenExpr. - bool ParseParenRelocatableExpression(MCValue &Res); - - bool ParsePrimaryExpr(AsmExpr *&Res); - bool ParseBinOpRHS(unsigned Precedence, AsmExpr *&Res); - bool ParseParenExpr(AsmExpr *&Res); - - // X86 specific. - bool ParseX86InstOperands(const char *InstName, MCInst &Inst); - bool ParseX86Operand(X86Operand &Op); - bool ParseX86MemOperand(X86Operand &Op); - bool ParseX86Register(X86Operand &Op); + bool ParseAssignment(const StringRef &Name); + + bool ParsePrimaryExpr(const MCExpr *&Res); + bool ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res); + bool ParseParenExpr(const MCExpr *&Res); + + /// ParseIdentifier - Parse an identifier or string (as a quoted identifier) + /// and set \arg Res to the identifier contents. + bool ParseIdentifier(StringRef &Res); // Directive Parsing. bool ParseDirectiveDarwinSection(); // Darwin specific ".section". - bool ParseDirectiveSectionSwitch(const char *Section, - const char *Directives = 0); + bool ParseDirectiveSectionSwitch(const char *Segment, const char *Section, + unsigned TAA = 0, unsigned ImplicitAlign = 0, + unsigned StubSize = 0); bool ParseDirectiveAscii(bool ZeroTerminated); // ".ascii", ".asciiz" bool ParseDirectiveValue(unsigned Size); // ".byte", ".long", ... bool ParseDirectiveFill(); // ".fill" @@ -109,7 +130,32 @@ private: /// ParseDirectiveSymbolAttribute - Parse a directive like ".globl" which /// accepts a single symbol (which should be a label or an external). bool ParseDirectiveSymbolAttribute(MCStreamer::SymbolAttr Attr); - + bool ParseDirectiveDarwinSymbolDesc(); // Darwin specific ".desc" + bool ParseDirectiveDarwinLsym(); // Darwin specific ".lsym" + + bool ParseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm" + bool ParseDirectiveDarwinZerofill(); // Darwin specific ".zerofill" + + // Darwin specific ".subsections_via_symbols" + bool ParseDirectiveDarwinSubsectionsViaSymbols(); + // Darwin specific .dump and .load + bool ParseDirectiveDarwinDumpOrLoad(SMLoc IDLoc, bool IsDump); + + bool ParseDirectiveAbort(); // ".abort" + bool ParseDirectiveInclude(); // ".include" + + bool ParseDirectiveIf(SMLoc DirectiveLoc); // ".if" + bool ParseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" + bool ParseDirectiveElse(SMLoc DirectiveLoc); // ".else" + bool ParseDirectiveEndIf(SMLoc DirectiveLoc); // .endif + + bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); // ".file" + bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); // ".line" + bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); // ".loc" + + /// ParseEscapedString - Parse the current token as a string which may include + /// escaped characters and return the string contents. + bool ParseEscapedString(std::string &Data); }; } // end namespace llvm diff --git a/tools/llvm-mc/CMakeLists.txt b/tools/llvm-mc/CMakeLists.txt index b21a4b1..ce9d63b 100644 --- a/tools/llvm-mc/CMakeLists.txt +++ b/tools/llvm-mc/CMakeLists.txt @@ -1,9 +1,7 @@ -set(LLVM_LINK_COMPONENTS support MC) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC) add_llvm_tool(llvm-mc llvm-mc.cpp - AsmExpr.cpp AsmLexer.cpp AsmParser.cpp - MC-X86Specific.cpp ) diff --git a/tools/llvm-mc/Makefile b/tools/llvm-mc/Makefile index 3c327da..9bfb773 100644 --- a/tools/llvm-mc/Makefile +++ b/tools/llvm-mc/Makefile @@ -9,9 +9,16 @@ LEVEL = ../.. TOOLNAME = llvm-mc -LINK_COMPONENTS := support MC # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 +NO_INSTALL = 1 -include $(LEVEL)/Makefile.common +# Include this here so we can get the configuration of the targets +# that have been configured for construction. We have to do this +# early so we can set up LINK_COMPONENTS before including Makefile.rules +include $(LEVEL)/Makefile.config + +LINK_COMPONENTS := $(TARGETS_TO_BUILD) MC support + +include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index b52edd1..329efe9 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -12,16 +12,25 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/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/ADT/OwningPtr.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/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Signals.h" +#include "llvm/Target/TargetAsmParser.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" // FIXME. +#include "llvm/Target/TargetSelect.h" #include "AsmParser.h" using namespace llvm; @@ -32,10 +41,39 @@ static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); +static cl::opt<bool> +ShowEncoding("show-encoding", cl::desc("Show instruction encodings")); + +static cl::opt<unsigned> +OutputAsmVariant("output-asm-variant", + cl::desc("Syntax variant to use for output printing")); + +enum OutputFileType { + OFT_AssemblyFile, + OFT_ObjectFile +}; +static cl::opt<OutputFileType> +FileType("filetype", cl::init(OFT_AssemblyFile), + cl::desc("Choose an output file type:"), + cl::values( + clEnumValN(OFT_AssemblyFile, "asm", + "Emit an assembly ('.s') file"), + clEnumValN(OFT_ObjectFile, "obj", + "Emit a native object ('.o') file"), + clEnumValEnd)); + +static cl::opt<bool> +Force("f", cl::desc("Enable binary output on terminals")); + static cl::list<std::string> IncludeDirs("I", cl::desc("Directory of include files"), cl::value_desc("directory"), cl::Prefix); +static cl::opt<std::string> +TripleName("triple", cl::desc("Target triple to assemble for," + "see -version for available targets"), + cl::init(LLVM_HOSTTRIPLE)); + enum ActionType { AC_AsLex, AC_Assemble @@ -50,6 +88,18 @@ Action(cl::desc("Action to perform:"), "Assemble a .s file (default)"), clEnumValEnd)); +static const Target *GetTarget(const char *ProgName) { + // Get the target specific parser. + std::string Error; + const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); + if (TheTarget) + return TheTarget; + + errs() << ProgName << ": error: unable to get target for '" << TripleName + << "', see --version and --triple.\n"; + return 0; +} + static int AsLexInput(const char *ProgName) { std::string ErrorMessage; MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename, @@ -72,78 +122,103 @@ static int AsLexInput(const char *ProgName) { // it later. SrcMgr.setIncludeDirs(IncludeDirs); - AsmLexer Lexer(SrcMgr); + const Target *TheTarget = GetTarget(ProgName); + if (!TheTarget) + return 1; + + const MCAsmInfo *MAI = TheTarget->createAsmInfo(TripleName); + assert(MAI && "Unable to create target asm info!"); + + AsmLexer Lexer(SrcMgr, *MAI); bool Error = false; - asmtok::TokKind Tok = Lexer.Lex(); - while (Tok != asmtok::Eof) { - switch (Tok) { + while (Lexer.Lex().isNot(AsmToken::Eof)) { + switch (Lexer.getKind()) { default: Lexer.PrintMessage(Lexer.getLoc(), "unknown token", "warning"); Error = true; break; - case asmtok::Error: + case AsmToken::Error: Error = true; // error already printed. break; - case asmtok::Identifier: - outs() << "identifier: " << Lexer.getCurStrVal() << '\n'; - break; - case asmtok::Register: - outs() << "register: " << Lexer.getCurStrVal() << '\n'; + case AsmToken::Identifier: + outs() << "identifier: " << Lexer.getTok().getString() << '\n'; break; - case asmtok::String: - outs() << "string: " << Lexer.getCurStrVal() << '\n'; + case AsmToken::String: + outs() << "string: " << Lexer.getTok().getString() << '\n'; break; - case asmtok::IntVal: - outs() << "int: " << Lexer.getCurIntVal() << '\n'; + case AsmToken::Integer: + outs() << "int: " << Lexer.getTok().getString() << '\n'; break; - case asmtok::Amp: outs() << "Amp\n"; break; - case asmtok::AmpAmp: outs() << "AmpAmp\n"; break; - case asmtok::Caret: outs() << "Caret\n"; break; - case asmtok::Colon: outs() << "Colon\n"; break; - case asmtok::Comma: outs() << "Comma\n"; break; - case asmtok::Dollar: outs() << "Dollar\n"; break; - case asmtok::EndOfStatement: outs() << "EndOfStatement\n"; break; - case asmtok::Eof: outs() << "Eof\n"; break; - case asmtok::Equal: outs() << "Equal\n"; break; - case asmtok::EqualEqual: outs() << "EqualEqual\n"; break; - case asmtok::Exclaim: outs() << "Exclaim\n"; break; - case asmtok::ExclaimEqual: outs() << "ExclaimEqual\n"; break; - case asmtok::Greater: outs() << "Greater\n"; break; - case asmtok::GreaterEqual: outs() << "GreaterEqual\n"; break; - case asmtok::GreaterGreater: outs() << "GreaterGreater\n"; break; - case asmtok::LParen: outs() << "LParen\n"; break; - case asmtok::Less: outs() << "Less\n"; break; - case asmtok::LessEqual: outs() << "LessEqual\n"; break; - case asmtok::LessGreater: outs() << "LessGreater\n"; break; - case asmtok::LessLess: outs() << "LessLess\n"; break; - case asmtok::Minus: outs() << "Minus\n"; break; - case asmtok::Percent: outs() << "Percent\n"; break; - case asmtok::Pipe: outs() << "Pipe\n"; break; - case asmtok::PipePipe: outs() << "PipePipe\n"; break; - case asmtok::Plus: outs() << "Plus\n"; break; - case asmtok::RParen: outs() << "RParen\n"; break; - case asmtok::Slash: outs() << "Slash\n"; break; - case asmtok::Star: outs() << "Star\n"; break; - case asmtok::Tilde: outs() << "Tilde\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; } - - Tok = Lexer.Lex(); } 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); +} + static int AssembleInput(const char *ProgName) { - std::string ErrorMessage; - MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename, - &ErrorMessage); + const Target *TheTarget = GetTarget(ProgName); + if (!TheTarget) + return 1; + + std::string Error; + MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename, &Error); if (Buffer == 0) { errs() << ProgName << ": "; - if (ErrorMessage.size()) - errs() << ErrorMessage << "\n"; + if (Error.size()) + errs() << Error << "\n"; else errs() << "input file didn't read correctly.\n"; return 1; @@ -151,7 +226,7 @@ static int AssembleInput(const char *ProgName) { SourceMgr SrcMgr; - // Tell SrcMgr about this buffer, which is what TGParser will pick up. + // Tell SrcMgr about this buffer, which is what the parser will pick up. SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); // Record the location of the include directories so that the lexer can find @@ -159,13 +234,53 @@ static int AssembleInput(const char *ProgName) { SrcMgr.setIncludeDirs(IncludeDirs); MCContext Ctx; - OwningPtr<MCStreamer> Str(createAsmStreamer(Ctx, outs())); + 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, "")); + + if (!TM) { + errs() << ProgName << ": error: could not create target for triple '" + << TripleName << "'.\n"; + return 1; + } + + OwningPtr<MCInstPrinter> IP; + OwningPtr<MCCodeEmitter> CE; + OwningPtr<MCStreamer> Str; + + const MCAsmInfo *MAI = TheTarget->createAsmInfo(TripleName); + assert(MAI && "Unable to create target asm info!"); - // FIXME: Target hook & command line option for initial section. - Str.get()->SwitchSection(Ctx.GetSection("__TEXT,__text,regular,pure_instructions")); + if (FileType == OFT_AssemblyFile) { + IP.reset(TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *Out)); + if (ShowEncoding) + CE.reset(TheTarget->createCodeEmitter(*TM)); + Str.reset(createAsmStreamer(Ctx, *Out, *MAI, IP.get(), CE.get())); + } else { + assert(FileType == OFT_ObjectFile && "Invalid file type!"); + CE.reset(TheTarget->createCodeEmitter(*TM)); + Str.reset(createMachOStreamer(Ctx, *Out, CE.get())); + } - AsmParser Parser(SrcMgr, Ctx, *Str.get()); - return Parser.Run(); + AsmParser Parser(SrcMgr, Ctx, *Str.get(), *MAI); + OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(Parser)); + if (!TAP) { + errs() << ProgName + << ": error: this target does not support assembly parsing.\n"; + return 1; + } + + Parser.setTargetParser(*TAP.get()); + + int Res = Parser.Run(); + if (Out != &fouts()) + delete Out; + + return Res; } @@ -174,6 +289,14 @@ int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + // Initialize targets and assembly printers/parsers. + llvm::InitializeAllTargetInfos(); + // FIXME: We shouldn't need to initialize the Target(Machine)s. + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllAsmParsers(); + cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n"); switch (Action) { diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 4e01180..2baf532 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -24,12 +24,12 @@ #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 <algorithm> #include <cctype> #include <cerrno> #include <cstring> -#include <iostream> using namespace llvm; namespace { @@ -88,7 +88,8 @@ 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.hasAvailableExternallyLinkage()) return; + if (GV.hasPrivateLinkage() || GV.hasLinkerPrivateLinkage() || + GV.hasAvailableExternallyLinkage()) return; const std::string SymbolAddrStr = " "; // Not used yet... char TypeChar = TypeCharForSymbol(GV); @@ -99,31 +100,31 @@ static void DumpSymbolNameForGlobalValue(GlobalValue &GV) { if (GV.hasLocalLinkage () && ExternalOnly) return; if (OutputFormat == posix) { - std::cout << GV.getName () << " " << TypeCharForSymbol(GV) << " " - << SymbolAddrStr << "\n"; + outs() << GV.getName () << " " << TypeCharForSymbol(GV) << " " + << SymbolAddrStr << "\n"; } else if (OutputFormat == bsd) { - std::cout << SymbolAddrStr << " " << TypeCharForSymbol(GV) << " " - << GV.getName () << "\n"; + outs() << SymbolAddrStr << " " << TypeCharForSymbol(GV) << " " + << GV.getName () << "\n"; } else if (OutputFormat == sysv) { std::string PaddedName (GV.getName ()); while (PaddedName.length () < 20) PaddedName += " "; - std::cout << PaddedName << "|" << SymbolAddrStr << "| " - << TypeCharForSymbol(GV) - << " | | | |\n"; + outs() << PaddedName << "|" << SymbolAddrStr << "| " + << TypeCharForSymbol(GV) + << " | | | |\n"; } } static void DumpSymbolNamesFromModule(Module *M) { const std::string &Filename = M->getModuleIdentifier (); if (OutputFormat == posix && MultipleFiles) { - std::cout << Filename << ":\n"; + outs() << Filename << ":\n"; } else if (OutputFormat == bsd && MultipleFiles) { - std::cout << "\n" << Filename << ":\n"; + outs() << "\n" << Filename << ":\n"; } else if (OutputFormat == sysv) { - std::cout << "\n\nSymbols from " << Filename << ":\n\n" - << "Name Value Class Type" - << " Size Line Section\n"; + outs() << "\n\nSymbols from " << Filename << ":\n\n" + << "Name Value Class Type" + << " Size Line Section\n"; } std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue); std::for_each (M->global_begin(), M->global_end(), @@ -133,7 +134,7 @@ static void DumpSymbolNamesFromModule(Module *M) { } static void DumpSymbolNamesFromFile(std::string &Filename) { - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); std::string ErrorMessage; sys::Path aPath(Filename); // Note: Currently we do not support reading an archive from stdin. @@ -144,29 +145,28 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { if (Buffer.get()) Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); - if (Result) + if (Result) { DumpSymbolNamesFromModule(Result); - else { - std::cerr << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; - return; - } + delete Result; + } else + errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; } else if (aPath.isArchive()) { std::string ErrMsg; Archive* archive = Archive::OpenAndLoad(sys::Path(Filename), Context, &ErrorMessage); if (!archive) - std::cerr << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; + errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; std::vector<Module *> Modules; if (archive->getAllModules(Modules, &ErrorMessage)) { - std::cerr << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; + errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; return; } MultipleFiles = true; std::for_each (Modules.begin(), Modules.end(), DumpSymbolNamesFromModule); } else { - std::cerr << ToolName << ": " << Filename << ": " - << "unrecognizable file type\n"; + errs() << ToolName << ": " << Filename << ": " + << "unrecognizable file type\n"; return; } } diff --git a/tools/llvm-prof/llvm-prof.cpp b/tools/llvm-prof/llvm-prof.cpp index 2cff296..cff139e 100644 --- a/tools/llvm-prof/llvm-prof.cpp +++ b/tools/llvm-prof/llvm-prof.cpp @@ -16,17 +16,20 @@ #include "llvm/InstrTypes.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" +#include "llvm/PassManager.h" #include "llvm/Assembly/AsmAnnotationWriter.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/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Format.h" #include "llvm/System/Signals.h" #include <algorithm> -#include <iostream> #include <iomanip> #include <map> #include <set> @@ -55,71 +58,202 @@ namespace { // PairSecondSort - A sorting predicate to sort by the second element of a pair. template<class T> struct PairSecondSortReverse - : public std::binary_function<std::pair<T, unsigned>, - std::pair<T, unsigned>, bool> { - bool operator()(const std::pair<T, unsigned> &LHS, - const std::pair<T, unsigned> &RHS) const { + : public std::binary_function<std::pair<T, double>, + std::pair<T, double>, bool> { + bool operator()(const std::pair<T, double> &LHS, + const std::pair<T, double> &RHS) const { return LHS.second > RHS.second; } }; +static double ignoreMissing(double w) { + if (w == ProfileInfo::MissingValue) return 0; + return w; +} + namespace { class ProfileAnnotator : public AssemblyAnnotationWriter { - std::map<const Function *, unsigned> &FuncFreqs; - std::map<const BasicBlock*, unsigned> &BlockFreqs; - std::map<ProfileInfoLoader::Edge, unsigned> &EdgeFreqs; + ProfileInfo &PI; public: - ProfileAnnotator(std::map<const Function *, unsigned> &FF, - std::map<const BasicBlock*, unsigned> &BF, - std::map<ProfileInfoLoader::Edge, unsigned> &EF) - : FuncFreqs(FF), BlockFreqs(BF), EdgeFreqs(EF) {} + ProfileAnnotator(ProfileInfo& pi) : PI(pi) {} virtual void emitFunctionAnnot(const Function *F, raw_ostream &OS) { - OS << ";;; %" << F->getName() << " called " << FuncFreqs[F] - << " times.\n;;;\n"; + double w = PI.getExecutionCount(F); + if (w != ProfileInfo::MissingValue) { + OS << ";;; %" << F->getName() << " called "<<(unsigned)w + <<" times.\n;;;\n"; + } } virtual void emitBasicBlockStartAnnot(const BasicBlock *BB, raw_ostream &OS) { - if (BlockFreqs.empty()) return; - std::map<const BasicBlock *, unsigned>::const_iterator I = - BlockFreqs.find(BB); - if (I != BlockFreqs.end()) - OS << "\t;;; Basic block executed " << I->second << " times.\n"; - else - OS << "\t;;; Never executed!\n"; + double w = PI.getExecutionCount(BB); + if (w != ProfileInfo::MissingValue) { + if (w != 0) { + OS << "\t;;; Basic block executed " << (unsigned)w << " times.\n"; + } else { + OS << "\t;;; Never executed!\n"; + } + } } virtual void emitBasicBlockEndAnnot(const BasicBlock *BB, raw_ostream &OS) { - if (EdgeFreqs.empty()) return; - // Figure out how many times each successor executed. - std::vector<std::pair<const BasicBlock*, unsigned> > SuccCounts; - const TerminatorInst *TI = BB->getTerminator(); + std::vector<std::pair<ProfileInfo::Edge, double> > SuccCounts; - std::map<ProfileInfoLoader::Edge, unsigned>::iterator I = - EdgeFreqs.lower_bound(std::make_pair(const_cast<BasicBlock*>(BB), 0U)); - for (; I != EdgeFreqs.end() && I->first.first == BB; ++I) - if (I->second) - SuccCounts.push_back(std::make_pair(TI->getSuccessor(I->first.second), - I->second)); + const TerminatorInst *TI = BB->getTerminator(); + for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; ++s) { + BasicBlock* Succ = TI->getSuccessor(s); + double w = ignoreMissing(PI.getEdgeWeight(std::make_pair(BB, Succ))); + if (w != 0) + SuccCounts.push_back(std::make_pair(std::make_pair(BB, Succ), w)); + } if (!SuccCounts.empty()) { OS << "\t;;; Out-edge counts:"; for (unsigned i = 0, e = SuccCounts.size(); i != e; ++i) - OS << " [" << SuccCounts[i].second << " -> " - << SuccCounts[i].first->getName() << "]"; + OS << " [" << (SuccCounts[i]).second << " -> " + << (SuccCounts[i]).first.second->getName() << "]"; OS << "\n"; } } }; } +namespace { + /// ProfileInfoPrinterPass - Helper pass to dump the profile information for + /// a module. + // + // FIXME: This should move elsewhere. + class ProfileInfoPrinterPass : public ModulePass { + ProfileInfoLoader &PIL; + public: + static char ID; // Class identification, replacement for typeinfo. + explicit ProfileInfoPrinterPass(ProfileInfoLoader &_PIL) + : ModulePass(&ID), PIL(_PIL) {} + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired<ProfileInfo>(); + } + + bool runOnModule(Module &M); + }; +} + +char ProfileInfoPrinterPass::ID = 0; + +bool ProfileInfoPrinterPass::runOnModule(Module &M) { + ProfileInfo &PI = getAnalysis<ProfileInfo>(); + std::map<const Function *, unsigned> FuncFreqs; + std::map<const BasicBlock*, unsigned> BlockFreqs; + std::map<ProfileInfo::Edge, unsigned> EdgeFreqs; + + // Output a report. Eventually, there will be multiple reports selectable on + // the command line, for now, just keep things simple. + + // Emit the most frequent function table... + std::vector<std::pair<Function*, double> > FunctionCounts; + std::vector<std::pair<BasicBlock*, double> > Counts; + for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) { + if (FI->isDeclaration()) continue; + double w = ignoreMissing(PI.getExecutionCount(FI)); + FunctionCounts.push_back(std::make_pair(FI, w)); + for (Function::iterator BB = FI->begin(), BBE = FI->end(); + BB != BBE; ++BB) { + double w = ignoreMissing(PI.getExecutionCount(BB)); + Counts.push_back(std::make_pair(BB, w)); + } + } + + // Sort by the frequency, backwards. + sort(FunctionCounts.begin(), FunctionCounts.end(), + PairSecondSortReverse<Function*>()); + + double TotalExecutions = 0; + for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) + TotalExecutions += FunctionCounts[i].second; + + outs() << "===" << std::string(73, '-') << "===\n" + << "LLVM profiling output for execution"; + if (PIL.getNumExecutions() != 1) outs() << "s"; + outs() << ":\n"; + + for (unsigned i = 0, e = PIL.getNumExecutions(); i != e; ++i) { + outs() << " "; + if (e != 1) outs() << i+1 << ". "; + outs() << PIL.getExecution(i) << "\n"; + } + + outs() << "\n===" << std::string(73, '-') << "===\n"; + outs() << "Function execution frequencies:\n\n"; + + // Print out the function frequencies... + outs() << " ## Frequency\n"; + for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) { + if (FunctionCounts[i].second == 0) { + outs() << "\n NOTE: " << e-i << " function" + << (e-i-1 ? "s were" : " was") << " never executed!\n"; + break; + } + + outs() << format("%3d", i+1) << ". " + << format("%5.2g", FunctionCounts[i].second) << "/" + << format("%g", TotalExecutions) << " " + << FunctionCounts[i].first->getNameStr() << "\n"; + } + + std::set<Function*> FunctionsToPrint; + + TotalExecutions = 0; + for (unsigned i = 0, e = Counts.size(); i != e; ++i) + TotalExecutions += Counts[i].second; + + // Sort by the frequency, backwards. + sort(Counts.begin(), Counts.end(), + PairSecondSortReverse<BasicBlock*>()); + + outs() << "\n===" << std::string(73, '-') << "===\n"; + outs() << "Top 20 most frequently executed basic blocks:\n\n"; + + // Print out the function frequencies... + outs() <<" ## %% \tFrequency\n"; + unsigned BlocksToPrint = Counts.size(); + if (BlocksToPrint > 20) BlocksToPrint = 20; + for (unsigned i = 0; i != BlocksToPrint; ++i) { + if (Counts[i].second == 0) break; + Function *F = Counts[i].first->getParent(); + outs() << format("%3d", i+1) << ". " + << format("%5g", Counts[i].second/(double)TotalExecutions*100) << "% " + << format("%5.0f", Counts[i].second) << "/" + << format("%g", TotalExecutions) << "\t" + << F->getNameStr() << "() - " + << Counts[i].first->getNameStr() << "\n"; + FunctionsToPrint.insert(F); + } + + if (PrintAnnotatedLLVM || PrintAllCode) { + outs() << "\n===" << std::string(73, '-') << "===\n"; + outs() << "Annotated LLVM code for the module:\n\n"; + + ProfileAnnotator PA(PI); + + if (FunctionsToPrint.empty() || PrintAllCode) + M.print(outs(), &PA); + else + // Print just a subset of the functions. + for (std::set<Function*>::iterator I = FunctionsToPrint.begin(), + E = FunctionsToPrint.end(); I != E; ++I) + (*I)->print(outs(), &PA); + } + + return false; +} int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. try { cl::ParseCommandLineOptions(argc, argv, "llvm profile dump decoder\n"); @@ -133,128 +267,29 @@ int main(int argc, char **argv) { delete Buffer; } if (M == 0) { - std::cerr << argv[0] << ": " << BitcodeFile << ": " + errs() << argv[0] << ": " << BitcodeFile << ": " << ErrorMessage << "\n"; return 1; } - // Read the profiling information - ProfileInfoLoader PI(argv[0], ProfileDataFile, *M); - - std::map<const Function *, unsigned> FuncFreqs; - std::map<const BasicBlock*, unsigned> BlockFreqs; - std::map<ProfileInfoLoader::Edge, unsigned> EdgeFreqs; - - // Output a report. Eventually, there will be multiple reports selectable on - // the command line, for now, just keep things simple. - - // Emit the most frequent function table... - std::vector<std::pair<Function*, unsigned> > FunctionCounts; - PI.getFunctionCounts(FunctionCounts); - FuncFreqs.insert(FunctionCounts.begin(), FunctionCounts.end()); - - // Sort by the frequency, backwards. - sort(FunctionCounts.begin(), FunctionCounts.end(), - PairSecondSortReverse<Function*>()); - - uint64_t TotalExecutions = 0; - for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) - TotalExecutions += FunctionCounts[i].second; - - std::cout << "===" << std::string(73, '-') << "===\n" - << "LLVM profiling output for execution"; - if (PI.getNumExecutions() != 1) std::cout << "s"; - std::cout << ":\n"; - - for (unsigned i = 0, e = PI.getNumExecutions(); i != e; ++i) { - std::cout << " "; - if (e != 1) std::cout << i+1 << ". "; - std::cout << PI.getExecution(i) << "\n"; - } - - std::cout << "\n===" << std::string(73, '-') << "===\n"; - std::cout << "Function execution frequencies:\n\n"; - - // Print out the function frequencies... - std::cout << " ## Frequency\n"; - for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) { - if (FunctionCounts[i].second == 0) { - std::cout << "\n NOTE: " << e-i << " function" << - (e-i-1 ? "s were" : " was") << " never executed!\n"; - break; - } - - std::cout << std::setw(3) << i+1 << ". " - << std::setw(5) << FunctionCounts[i].second << "/" - << TotalExecutions << " " - << FunctionCounts[i].first->getName().c_str() << "\n"; - } - - std::set<Function*> FunctionsToPrint; - - // If we have block count information, print out the LLVM module with - // frequency annotations. - if (PI.hasAccurateBlockCounts()) { - std::vector<std::pair<BasicBlock*, unsigned> > Counts; - PI.getBlockCounts(Counts); - - TotalExecutions = 0; - for (unsigned i = 0, e = Counts.size(); i != e; ++i) - TotalExecutions += Counts[i].second; - - // Sort by the frequency, backwards. - sort(Counts.begin(), Counts.end(), - PairSecondSortReverse<BasicBlock*>()); - - std::cout << "\n===" << std::string(73, '-') << "===\n"; - std::cout << "Top 20 most frequently executed basic blocks:\n\n"; - - // Print out the function frequencies... - std::cout <<" ## %% \tFrequency\n"; - unsigned BlocksToPrint = Counts.size(); - if (BlocksToPrint > 20) BlocksToPrint = 20; - for (unsigned i = 0; i != BlocksToPrint; ++i) { - if (Counts[i].second == 0) break; - Function *F = Counts[i].first->getParent(); - std::cout << std::setw(3) << i+1 << ". " - << std::setw(5) << std::setprecision(2) - << Counts[i].second/(double)TotalExecutions*100 << "% " - << std::setw(5) << Counts[i].second << "/" - << TotalExecutions << "\t" - << F->getName().c_str() << "() - " - << Counts[i].first->getName().c_str() << "\n"; - FunctionsToPrint.insert(F); - } - - BlockFreqs.insert(Counts.begin(), Counts.end()); - } - - if (PI.hasAccurateEdgeCounts()) { - std::vector<std::pair<ProfileInfoLoader::Edge, unsigned> > Counts; - PI.getEdgeCounts(Counts); - EdgeFreqs.insert(Counts.begin(), Counts.end()); - } + // Read the profiling information. This is redundant since we load it again + // using the standard profile info provider pass, but for now this gives us + // access to additional information not exposed via the ProfileInfo + // interface. + ProfileInfoLoader PIL(argv[0], ProfileDataFile, *M); - if (PrintAnnotatedLLVM || PrintAllCode) { - std::cout << "\n===" << std::string(73, '-') << "===\n"; - std::cout << "Annotated LLVM code for the module:\n\n"; - - ProfileAnnotator PA(FuncFreqs, BlockFreqs, EdgeFreqs); - - if (FunctionsToPrint.empty() || PrintAllCode) - M->print(std::cout, &PA); - else - // Print just a subset of the functions. - for (std::set<Function*>::iterator I = FunctionsToPrint.begin(), - E = FunctionsToPrint.end(); I != E; ++I) - (*I)->print(std::cout, &PA); - } + // Run the printer pass. + PassManager PassMgr; + PassMgr.add(createProfileLoaderPass(ProfileDataFile)); + PassMgr.add(new ProfileInfoPrinterPass(PIL)); + PassMgr.run(*M); return 0; } catch (const std::string& msg) { - std::cerr << argv[0] << ": " << msg << "\n"; + errs() << argv[0] << ": " << msg << "\n"; } catch (...) { - std::cerr << argv[0] << ": Unexpected unknown exception occurred.\n"; + errs() << argv[0] << ": Unexpected unknown exception occurred.\n"; } + return 1; } diff --git a/tools/llvm-ranlib/llvm-ranlib.cpp b/tools/llvm-ranlib/llvm-ranlib.cpp index d9bcc48..dffe3ad 100644 --- a/tools/llvm-ranlib/llvm-ranlib.cpp +++ b/tools/llvm-ranlib/llvm-ranlib.cpp @@ -17,6 +17,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Signals.h" #include <iostream> #include <iomanip> @@ -48,7 +49,7 @@ int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc, argv); - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Have the command line options parsed and handle things @@ -87,13 +88,13 @@ int main(int argc, char **argv) { printSymbolTable(TheArchive); } catch (const char* msg) { - std::cerr << argv[0] << ": " << msg << "\n\n"; + errs() << argv[0] << ": " << msg << "\n\n"; exitCode = 1; } catch (const std::string& msg) { - std::cerr << argv[0] << ": " << msg << "\n"; + errs() << argv[0] << ": " << msg << "\n"; exitCode = 2; } catch (...) { - std::cerr << argv[0] << ": An unexpected unknown exception occurred.\n"; + errs() << argv[0] << ": An unexpected unknown exception occurred.\n"; exitCode = 3; } return exitCode; diff --git a/tools/llvm-stub/llvm-stub.c b/tools/llvm-stub/llvm-stub.c index e5624a9..f2e478e 100644 --- a/tools/llvm-stub/llvm-stub.c +++ b/tools/llvm-stub/llvm-stub.c @@ -61,11 +61,10 @@ int main(int argc, char** argv) { Args[1] = strcat(strcpy((char*)malloc(strlen(argv[0])+4), argv[0]), ".bc"); /* The rest of the args are as before. */ - memcpy(Args+2, argv+1, sizeof(char*)*argc); + memcpy((char **)Args+2, argv+1, sizeof(char*)*argc); /* Run the JIT. */ - execvp(Interp, (char *const*)Args); - + execvp(Interp, (char **)Args); /* if _execv returns, the JIT could not be started. */ fprintf(stderr, "Could not execute the LLVM JIT. Either add 'lli' to your" " path, or set the\ninterpreter you want to use in the LLVMINTERP " diff --git a/tools/llvmc/doc/LLVMC-Reference.rst b/tools/llvmc/doc/LLVMC-Reference.rst index b43c3e3..fad2ccc 100644 --- a/tools/llvmc/doc/LLVMC-Reference.rst +++ b/tools/llvmc/doc/LLVMC-Reference.rst @@ -97,6 +97,11 @@ configuration libraries: the ``-o`` option. The ``--save-temps=cwd`` and ``--save-temps`` switches are both synonyms for the default behaviour. +* ``--temp-dir DIRECTORY`` - Store temporary files in the given directory. This + directory is deleted on exit unless ``--save-temps`` is specified. If + ``--save-temps=obj`` is also specified, ``--temp-dir`` is given the + precedence. + * ``--check-graph`` - Check the compilation for common errors like mismatched output/input language names, multiple default edges and cycles. Because of plugins, these checks can't be performed at compile-time. Exit with code zero @@ -347,6 +352,12 @@ separate option groups syntactically. 3))``. Only list options can have this attribute; you can, however, use the ``one_or_more`` and ``zero_or_one`` properties. + - ``init`` - this option has a default value, either a string (if it is a + parameter), or a boolean (if it is a switch; boolean constants are called + ``true`` and ``false``). List options can't have this attribute. Usage + examples: ``(switch_option "foo", (init true))``; ``(prefix_option "bar", + (init "baz"))``. + - ``extern`` - this option is defined in some other plugin, see below. External options @@ -362,7 +373,8 @@ for. Example:: (switch_option "E", (extern)) ... -See also the section on plugin `priorities`__. +If an external option has additional attributes besides 'extern', they are +ignored. See also the section on plugin `priorities`__. __ priorities_ @@ -446,17 +458,27 @@ use TableGen inheritance instead. - ``empty`` - The opposite of ``not_empty``. Equivalent to ``(not (not_empty X))``. Provided for convenience. + - ``single_input_file`` - Returns true if there was only one input file + provided on the command-line. Used without arguments: + ``(single_input_file)``. + + - ``multiple_input_files`` - Equivalent to ``(not (single_input_file))`` (the + case of zero input files is considered an error). + - ``default`` - Always evaluates to true. Should always be the last test in the ``case`` expression. - - ``and`` - A standard logical combinator that returns true iff all - of its arguments return true. Used like this: ``(and (test1), - (test2), ... (testN))``. Nesting of ``and`` and ``or`` is allowed, - but not encouraged. + - ``and`` - A standard binary logical combinator that returns true iff all of + its arguments return true. Used like this: ``(and (test1), (test2), + ... (testN))``. Nesting of ``and`` and ``or`` is allowed, but not + encouraged. + + - ``or`` - A binary logical combinator that returns true iff any of its + arguments returns true. Example: ``(or (test1), (test2), ... (testN))``. + + - ``not`` - Standard unary logical combinator that negates its + argument. Example: ``(not (or (test1), (test2), ... (testN)))``. - - ``or`` - Another logical combinator that returns true only if any - one of its arguments returns true. Example: ``(or (test1), - (test2), ... (testN))``. Writing a tool description @@ -487,8 +509,8 @@ The complete list of all currently implemented tool properties follows. - ``in_language`` - input language name. Can be either a string or a list, in case the tool supports multiple input languages. - - ``out_language`` - output language name. Tools are not allowed to - have multiple output languages. + - ``out_language`` - output language name. Multiple output languages are not + allowed. - ``output_suffix`` - output file suffix. Can also be changed dynamically, see documentation on actions. diff --git a/tools/llvmc/example/Hello/Hello.cpp b/tools/llvmc/example/Hello/Hello.cpp index 23a13a5..9c96bd0 100644 --- a/tools/llvmc/example/Hello/Hello.cpp +++ b/tools/llvmc/example/Hello/Hello.cpp @@ -13,13 +13,12 @@ #include "llvm/CompilerDriver/CompilationGraph.h" #include "llvm/CompilerDriver/Plugin.h" - -#include <iostream> +#include "llvm/Support/raw_ostream.h" namespace { struct MyPlugin : public llvmc::BasePlugin { void PopulateLanguageMap(llvmc::LanguageMap&) const - { std::cout << "Hello!\n"; } + { outs() << "Hello!\n"; } void PopulateCompilationGraph(llvmc::CompilationGraph&) const {} diff --git a/tools/llvmc/example/mcc16/driver/Main.cpp b/tools/llvmc/example/mcc16/driver/Main.cpp index b1f5b67..f42e17f 100644 --- a/tools/llvmc/example/mcc16/driver/Main.cpp +++ b/tools/llvmc/example/mcc16/driver/Main.cpp @@ -7,8 +7,31 @@ // //===----------------------------------------------------------------------===// // -// Just include CompilerDriver/Main.inc. +// Usually this file just includes CompilerDriver/Main.inc, but here we apply +// some trickery to make the built-in '-save-temps' option hidden and enable +// '--temp-dir' by default. // //===----------------------------------------------------------------------===// -#include "llvm/CompilerDriver/Main.inc" +#include "llvm/CompilerDriver/BuiltinOptions.h" +#include "llvm/CompilerDriver/ForceLinkage.h" +#include "llvm/System/Path.h" + +namespace llvmc { + int Main(int argc, char** argv); +} + +int main(int argc, char** argv) { + + // HACK + SaveTemps.setHiddenFlag(llvm::cl::Hidden); + TempDirname = "tmp-objs"; + + // Remove the temp dir if already exists. + llvm::sys::Path tempDir; + tempDir = TempDirname; + tempDir.eraseFromDisk(true); + + llvmc::ForceLinkage(); + return llvmc::Main(argc, argv); +} diff --git a/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td b/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td index de85fa9..3d25ab6 100644 --- a/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td +++ b/tools/llvmc/example/mcc16/plugins/PIC16Base/PIC16Base.td @@ -55,7 +55,7 @@ def llvm_ld_lto : Tool<[ (in_language "llvm-bitcode"), (out_language "llvm-bitcode"), (output_suffix "bc"), - (cmd_line "$CALL(GetBinDir)llvm-ld -link-as-library $INFILE -o $OUTFILE"), + (cmd_line "$CALL(GetBinDir)llvm-ld -L $CALL(GetStdLibsDir) -l std $INFILE -b $OUTFILE"), (actions (case (switch_on "g"), (append_cmd "-disable-opt"), (not_empty "Wo,"), (unpack_values "Wo,"))), @@ -66,7 +66,7 @@ def llc : Tool<[ (in_language "llvm-bitcode"), (out_language "assembler"), (output_suffix "s"), - (cmd_line "$CALL(GetBinDir)llc -march=pic16 -f $INFILE -o $OUTFILE"), + (cmd_line "$CALL(GetBinDir)llc -march=pic16 -disable-jump-tables -f $INFILE -o $OUTFILE"), (actions (case (switch_on "S"), (stop_compilation), (not_empty "Wllc,"), (unpack_values "Wllc,"), @@ -87,7 +87,7 @@ def mplink : Tool<[ (in_language "object-code"), (out_language "executable"), (output_suffix "out"), - (cmd_line "$CALL(GetBinDir)mplink.exe /k $CALL(GetStdLinkerScriptsDir) /l $CALL(GetStdLibsDir) 16f1937.lkr intrinsics.lib std.lib $INFILE -o $OUTFILE"), + (cmd_line "$CALL(GetBinDir)mplink.exe -k $CALL(GetStdLinkerScriptsDir) -l $CALL(GetStdLibsDir) 16f1937_g.lkr intrinsics.lib devices.lib $INFILE -o $OUTFILE"), (actions (case (not_empty "Wl,"), (unpack_values "Wl,"))), (join) diff --git a/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp b/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp index 21a25b3..f8492ed 100644 --- a/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp +++ b/tools/llvmc/example/mcc16/plugins/PIC16Base/PluginMain.cpp @@ -10,13 +10,17 @@ namespace llvmc { } // Returns the platform specific directory separator via #ifdefs. -static std::string GetDirSeparator(void) { +static std::string GetDirSeparator() { +#ifdef _WIN32 + return "\\"; +#else return "/"; +#endif } namespace hooks { // Get the dir where c16 executables reside. -std::string GetBinDir (void) { +std::string GetBinDir() { // Construct a Path object from the program name. void *P = (void*) (intptr_t) GetBinDir; sys::Path ProgramFullPath @@ -30,7 +34,7 @@ std::string GetBinDir (void) { } // Get the Top-level Installation dir for c16. -std::string GetInstallDir (void) { +std::string GetInstallDir() { sys::Path BinDirPath = sys::Path(GetBinDir()); // Go one more level up to get the install dir. @@ -40,22 +44,22 @@ std::string GetInstallDir (void) { } // Get the dir where the c16 header files reside. -std::string GetStdHeadersDir (void) { +std::string GetStdHeadersDir() { return GetInstallDir() + "include"; } // Get the dir where the assembler header files reside. -std::string GetStdAsmHeadersDir (void) { +std::string GetStdAsmHeadersDir() { return GetInstallDir() + "inc"; } // Get the dir where the linker scripts reside. -std::string GetStdLinkerScriptsDir (void) { +std::string GetStdLinkerScriptsDir() { return GetInstallDir() + "lkr"; } // Get the dir where startup code, intrinsics and lib reside. -std::string GetStdLibsDir (void) { +std::string GetStdLibsDir() { return GetInstallDir() + "lib"; } } diff --git a/tools/llvmc/plugins/Base/Base.td.in b/tools/llvmc/plugins/Base/Base.td.in index 757078a..be325a0 100644 --- a/tools/llvmc/plugins/Base/Base.td.in +++ b/tools/llvmc/plugins/Base/Base.td.in @@ -1,4 +1,4 @@ -//===- Base.td - LLVMC2 toolchain descriptions -------------*- tablegen -*-===// +//===- Base.td - LLVMC toolchain descriptions --------------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file contains compilation graph description used by llvmc2. +// This file contains compilation graph description used by llvmc. // //===----------------------------------------------------------------------===// @@ -32,10 +32,17 @@ def OptList : OptionList<[ (help "Enable threads")), (parameter_option "linker", (help "Choose linker (possible values: gcc, g++)")), + (parameter_option "MF", + (help "Specify a file to write dependencies to"), (hidden)), + (parameter_option "MT", + (help "Change the name of the rule emitted by dependency generation"), + (hidden)), (parameter_list_option "include", (help "Include the named file prior to preprocessing")), (prefix_list_option "I", (help "Add a directory to include path")), + (prefix_list_option "D", + (help "Define a macro")), (prefix_list_option "Wa,", (help "Pass options to assembler")), (prefix_list_option "Wllc,", @@ -70,19 +77,25 @@ class llvm_gcc_based <string cmd_prefix, string in_lang, string E_ext> : Tool< !strconcat(cmd_prefix, " -c $INFILE -o $OUTFILE -emit-llvm"))), (actions (case + (and (multiple_input_files), (or (switch_on "S"), (switch_on "c"))), + (error "cannot specify -o with -c or -S with multiple files"), (switch_on "E"), [(stop_compilation), (output_suffix E_ext)], (and (switch_on "emit-llvm"), (switch_on "S")), [(output_suffix "ll"), (stop_compilation)], (and (switch_on "emit-llvm"), (switch_on "c")), (stop_compilation), (switch_on "fsyntax-only"), (stop_compilation), (not_empty "include"), (forward "include"), - (not_empty "I"), (forward "I"))), + (not_empty "I"), (forward "I"), + (not_empty "D"), (forward "D"), + (not_empty "MF"), (forward "MF"), + (not_empty "MT"), (forward "MT"))), (sink) ]>; def llvm_gcc_c : llvm_gcc_based<"@LLVMGCCCOMMAND@ -x c", "c", "i">; def llvm_gcc_cpp : llvm_gcc_based<"@LLVMGXXCOMMAND@ -x c++", "c++", "i">; -def llvm_gcc_m : llvm_gcc_based<"@LLVMGCCCOMMAND@ -x objective-c", "objective-c", "mi">; +def llvm_gcc_m : llvm_gcc_based<"@LLVMGCCCOMMAND@ -x objective-c", + "objective-c", "mi">; def llvm_gcc_mxx : llvm_gcc_based<"@LLVMGCCCOMMAND@ -x objective-c++", "objective-c++", "mi">; @@ -98,7 +111,8 @@ def llvm_as : Tool< [(in_language "llvm-assembler"), (out_language "llvm-bitcode"), (output_suffix "bc"), - (cmd_line "llvm-as $INFILE -o $OUTFILE") + (cmd_line "llvm-as $INFILE -o $OUTFILE"), + (actions (case (switch_on "emit-llvm"), (stop_compilation))) ]>; def llvm_gcc_assembler : Tool< @@ -112,7 +126,7 @@ def llvm_gcc_assembler : Tool< ]>; def llc : Tool< -[(in_language "llvm-bitcode"), +[(in_language ["llvm-bitcode", "llvm-assembler"]), (out_language "assembler"), (output_suffix "s"), (cmd_line "llc -f $INFILE -o $OUTFILE"), @@ -132,7 +146,7 @@ class llvm_gcc_based_linker <string cmd_prefix> : Tool< (switch_on "pthread"), (append_cmd "-lpthread"), (not_empty "L"), (forward "L"), (not_empty "l"), (forward "l"), - (not_empty "Wl,"), (unpack_values "Wl,"))) + (not_empty "Wl,"), (forward "Wl,"))) ]>; // Default linker @@ -165,7 +179,7 @@ def CompilationGraph : CompilationGraph<[ Edge<"root", "llvm_gcc_cpp">, Edge<"root", "llvm_gcc_m">, Edge<"root", "llvm_gcc_mxx">, - Edge<"root", "llvm_as">, + Edge<"root", "llc">, Edge<"llvm_gcc_c", "llc">, Edge<"llvm_gcc_cpp", "llc">, @@ -173,6 +187,8 @@ def CompilationGraph : CompilationGraph<[ 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))>, diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index 1a21132..c621721 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -30,26 +30,25 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/FileWriters.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/Mangler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/StandardPasses.h" #include "llvm/Support/SystemUtils.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Host.h" +#include "llvm/System/Program.h" #include "llvm/System/Signals.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetMachineRegistry.h" +#include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Config/config.h" - - #include <cstdlib> -#include <fstream> #include <unistd.h> #include <fcntl.h> @@ -75,11 +74,10 @@ LTOCodeGenerator::LTOCodeGenerator() _linker("LinkTimeOptimizer", "ld-temp.o", _context), _target(NULL), _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false), _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), - _nativeObjectFile(NULL), _gccPath(NULL), _assemblerPath(NULL) + _nativeObjectFile(NULL), _assemblerPath(NULL) { - InitializeAllTargets(); - InitializeAllAsmPrinters(); - + InitializeAllTargets(); + InitializeAllAsmPrinters(); } LTOCodeGenerator::~LTOCodeGenerator() @@ -126,13 +124,6 @@ bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model, return true; } -void LTOCodeGenerator::setGccPath(const char* path) -{ - if ( _gccPath ) - delete _gccPath; - _gccPath = new sys::Path(path); -} - void LTOCodeGenerator::setAssemblerPath(const char* path) { if ( _assemblerPath ) @@ -146,31 +137,34 @@ void LTOCodeGenerator::addMustPreserveSymbol(const char* sym) } -bool LTOCodeGenerator::writeMergedModules(const char* path, std::string& errMsg) -{ - if ( this->determineTarget(errMsg) ) - return true; +bool LTOCodeGenerator::writeMergedModules(const char *path, + std::string &errMsg) { + if (determineTarget(errMsg)) + return true; - // mark which symbols can not be internalized - this->applyScopeRestrictions(); + // mark which symbols can not be internalized + applyScopeRestrictions(); - // create output file - std::ofstream out(path, std::ios_base::out|std::ios::trunc|std::ios::binary); - if ( out.fail() ) { - errMsg = "could not open bitcode file for writing: "; - errMsg += path; - return true; - } - - // write bitcode to it - WriteBitcodeToFile(_linker.getModule(), out); - if ( out.fail() ) { - errMsg = "could not write bitcode file: "; - errMsg += path; - return true; - } + // create output file + std::string ErrInfo; + raw_fd_ostream Out(path, ErrInfo, + raw_fd_ostream::F_Binary); + if (!ErrInfo.empty()) { + errMsg = "could not open bitcode file for writing: "; + errMsg += path; + return true; + } - return false; + // write bitcode to it + WriteBitcodeToFile(_linker.getModule(), Out); + + if (Out.has_error()) { + errMsg = "could not write bitcode file: "; + errMsg += path; + return true; + } + + return false; } @@ -185,7 +179,8 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) // generate assembly code bool genResult = false; { - raw_fd_ostream asmFile(uniqueAsmPath.c_str(), false, errMsg); + raw_fd_ostream asmFD(uniqueAsmPath.c_str(), errMsg); + formatted_raw_ostream asmFile(asmFD); if (!errMsg.empty()) return NULL; genResult = this->generateAssemblyCode(asmFile, errMsg); @@ -206,9 +201,8 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) sys::RemoveFileOnSignal(uniqueObjPath); // assemble the assembly code - const std::string& uniqueObjStr = uniqueObjPath.toString(); - bool asmResult = this->assemble(uniqueAsmPath.toString(), - uniqueObjStr, errMsg); + const std::string& uniqueObjStr = uniqueObjPath.str(); + bool asmResult = this->assemble(uniqueAsmPath.str(), uniqueObjStr, errMsg); if ( !asmResult ) { // remove old buffer if compile() called twice delete _nativeObjectFile; @@ -237,9 +231,6 @@ bool LTOCodeGenerator::assemble(const std::string& asmPath, if ( _assemblerPath ) { tool = *_assemblerPath; needsCompilerOptions = false; - } - else if ( _gccPath ) { - tool = *_gccPath; } else { // find compiler driver tool = sys::Program::FindProgramByName("gcc"); @@ -324,11 +315,12 @@ bool LTOCodeGenerator::assemble(const std::string& asmPath, bool LTOCodeGenerator::determineTarget(std::string& errMsg) { if ( _target == NULL ) { + std::string Triple = _linker.getModule()->getTargetTriple(); + if (Triple.empty()) + Triple = sys::getHostTriple(); + // create target machine from info for merged modules - Module* mergedModule = _linker.getModule(); - const TargetMachineRegistry::entry* march = - TargetMachineRegistry::getClosestStaticTargetForModule( - *mergedModule, errMsg); + const Target *march = TargetRegistry::lookupTarget(Triple, errMsg); if ( march == NULL ) return true; @@ -347,9 +339,8 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) } // construct LTModule, hand over ownership of module and target - std::string FeatureStr = - getFeatureString(_linker.getModule()->getTargetTriple().c_str()); - _target = march->CtorFn(*mergedModule, FeatureStr.c_str()); + std::string FeatureStr = getFeatureString(Triple.c_str()); + _target = march->createTargetMachine(Triple, FeatureStr); } return false; } @@ -366,19 +357,19 @@ void LTOCodeGenerator::applyScopeRestrictions() // mark which symbols can not be internalized if ( !_mustPreserveSymbols.empty() ) { Mangler mangler(*mergedModule, - _target->getTargetAsmInfo()->getGlobalPrefix()); + _target->getMCAsmInfo()->getGlobalPrefix()); std::vector<const char*> mustPreserveList; for (Module::iterator f = mergedModule->begin(), e = mergedModule->end(); f != e; ++f) { if ( !f->isDeclaration() - && _mustPreserveSymbols.count(mangler.getValueName(f)) ) - mustPreserveList.push_back(::strdup(f->getName().c_str())); + && _mustPreserveSymbols.count(mangler.getMangledName(f)) ) + mustPreserveList.push_back(::strdup(f->getNameStr().c_str())); } for (Module::global_iterator v = mergedModule->global_begin(), e = mergedModule->global_end(); v != e; ++v) { if ( !v->isDeclaration() - && _mustPreserveSymbols.count(mangler.getValueName(v)) ) - mustPreserveList.push_back(::strdup(v->getName().c_str())); + && _mustPreserveSymbols.count(mangler.getMangledName(v)) ) + mustPreserveList.push_back(::strdup(v->getNameStr().c_str())); } passes.add(createInternalizePass(mustPreserveList)); } @@ -390,10 +381,10 @@ void LTOCodeGenerator::applyScopeRestrictions() } /// Optimize merged modules using various IPO passes -bool LTOCodeGenerator::generateAssemblyCode(raw_ostream& out, +bool LTOCodeGenerator::generateAssemblyCode(formatted_raw_ostream& out, std::string& errMsg) { - if ( this->determineTarget(errMsg) ) + if ( this->determineTarget(errMsg) ) return true; // mark which symbols can not be internalized @@ -401,9 +392,19 @@ bool LTOCodeGenerator::generateAssemblyCode(raw_ostream& out, Module* mergedModule = _linker.getModule(); - // If target supports exception handling then enable it now. - if ( _target->getTargetAsmInfo()->doesSupportExceptionHandling() ) - llvm::ExceptionHandling = true; + // If target supports exception handling then enable it now. + switch (_target->getMCAsmInfo()->getExceptionHandlingType()) { + case ExceptionHandling::Dwarf: + llvm::DwarfExceptionHandling = true; + break; + case ExceptionHandling::SjLj: + llvm::SjLjExceptionHandling = true; + break; + case ExceptionHandling::None: + break; + default: + assert (0 && "Unknown exception handling model!"); + } // if options were requested, set them if ( !_codegenOptions.empty() ) @@ -430,16 +431,16 @@ bool LTOCodeGenerator::generateAssemblyCode(raw_ostream& out, codeGenPasses->add(new TargetData(*_target->getTargetData())); - MachineCodeEmitter* mce = NULL; + ObjectCodeEmitter* oce = NULL; switch (_target->addPassesToEmitFile(*codeGenPasses, out, TargetMachine::AssemblyFile, CodeGenOpt::Aggressive)) { case FileModel::MachOFile: - mce = AddMachOWriter(*codeGenPasses, out, *_target); + oce = AddMachOWriter(*codeGenPasses, out, *_target); break; case FileModel::ElfFile: - mce = AddELFWriter(*codeGenPasses, out, *_target); + oce = AddELFWriter(*codeGenPasses, out, *_target); break; case FileModel::AsmFile: break; @@ -449,7 +450,7 @@ bool LTOCodeGenerator::generateAssemblyCode(raw_ostream& out, return true; } - if (_target->addPassesToEmitFileFinish(*codeGenPasses, mce, + if (_target->addPassesToEmitFileFinish(*codeGenPasses, oce, CodeGenOpt::Aggressive)) { errMsg = "target does not support generation of this file type"; return true; @@ -467,6 +468,7 @@ bool LTOCodeGenerator::generateAssemblyCode(raw_ostream& out, codeGenPasses->run(*it); codeGenPasses->doFinalization(); + return false; // success } diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h index 5548050..0ebec2c 100644 --- a/tools/lto/LTOCodeGenerator.h +++ b/tools/lto/LTOCodeGenerator.h @@ -37,7 +37,6 @@ public: bool addModule(class LTOModule*, std::string& errMsg); bool setDebugInfo(lto_debug_model, std::string& errMsg); bool setCodePICModel(lto_codegen_model, std::string& errMsg); - void setGccPath(const char* path); void setAssemblerPath(const char* path); void addMustPreserveSymbol(const char* sym); bool writeMergedModules(const char* path, @@ -45,7 +44,7 @@ public: const void* compile(size_t* length, std::string& errMsg); void setCodeGenDebugOptions(const char *opts); private: - bool generateAssemblyCode(llvm::raw_ostream& out, + bool generateAssemblyCode(llvm::formatted_raw_ostream& out, std::string& errMsg); bool assemble(const std::string& asmPath, const std::string& objPath, std::string& errMsg); @@ -63,7 +62,6 @@ private: StringSet _mustPreserveSymbols; llvm::MemoryBuffer* _nativeObjectFile; std::vector<const char*> _codegenOptions; - llvm::sys::Path* _gccPath; llvm::sys::Path* _assemblerPath; }; diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 9c8baef..e1cf48d 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -24,21 +24,21 @@ #include "llvm/Support/Mangler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MathExtras.h" +#include "llvm/System/Host.h" #include "llvm/System/Path.h" #include "llvm/System/Process.h" #include "llvm/Target/SubtargetFeature.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetMachineRegistry.h" -#include "llvm/Target/TargetAsmInfo.h" - -#include <fstream> +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" using namespace llvm; bool LTOModule::isBitcodeFile(const void* mem, size_t length) { - return ( llvm::sys::IdentifyFileType((char*)mem, length) - == llvm::sys::Bitcode_FileType ); + return llvm::sys::IdentifyFileType((char*)mem, length) + == llvm::sys::Bitcode_FileType; } bool LTOModule::isBitcodeFile(const char* path) @@ -50,7 +50,7 @@ bool LTOModule::isBitcodeFileForTarget(const void* mem, size_t length, const char* triplePrefix) { MemoryBuffer* buffer = makeBuffer(mem, length); - if ( buffer == NULL ) + if (!buffer) return false; return isTargetMatch(buffer, triplePrefix); } @@ -71,12 +71,12 @@ bool LTOModule::isTargetMatch(MemoryBuffer* buffer, const char* triplePrefix) OwningPtr<ModuleProvider> mp(getBitcodeModuleProvider(buffer, getGlobalContext())); // on success, mp owns buffer and both are deleted at end of this method - if ( !mp ) { + if (!mp) { delete buffer; return false; } std::string actualTarget = mp->getModule()->getTargetTriple(); - return ( strncmp(actualTarget.c_str(), triplePrefix, + return (strncmp(actualTarget.c_str(), triplePrefix, strlen(triplePrefix)) == 0); } @@ -90,7 +90,7 @@ LTOModule* LTOModule::makeLTOModule(const char* path, std::string& errMsg) { OwningPtr<MemoryBuffer> buffer(MemoryBuffer::getFile(path, &errMsg)); - if ( !buffer ) + if (!buffer) return NULL; return makeLTOModule(buffer.get(), errMsg); } @@ -103,8 +103,8 @@ 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) ) + if ((((uintptr_t)endPtr & (sys::Process::GetPageSize()-1)) == 0) + || (*endPtr != 0)) return MemoryBuffer::getMemBufferCopy(startPtr, endPtr); else return MemoryBuffer::getMemBuffer(startPtr, endPtr); @@ -115,7 +115,7 @@ LTOModule* LTOModule::makeLTOModule(const void* mem, size_t length, std::string& errMsg) { OwningPtr<MemoryBuffer> buffer(makeBuffer(mem, length)); - if ( !buffer ) + if (!buffer) return NULL; return makeLTOModule(buffer.get(), errMsg); } @@ -127,6 +127,8 @@ LTOModule* LTOModule::makeLTOModule(const void* mem, size_t length, /// subtarget. It would be better if we could encode this information into the /// IR. See <rdar://5972456>. std::string getFeatureString(const char *TargetTriple) { + InitializeAllTargets(); + SubtargetFeatures Features; if (strncmp(TargetTriple, "powerpc-apple-", 14) == 0) { @@ -142,20 +144,25 @@ std::string getFeatureString(const char *TargetTriple) { LTOModule* LTOModule::makeLTOModule(MemoryBuffer* buffer, std::string& errMsg) { + InitializeAllTargets(); + // parse bitcode buffer OwningPtr<Module> m(ParseBitcodeFile(buffer, getGlobalContext(), &errMsg)); - if ( !m ) + if (!m) return NULL; - // find machine architecture for this module - const TargetMachineRegistry::entry* march = - TargetMachineRegistry::getClosestStaticTargetForModule(*m, errMsg); - if ( march == 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 - std::string FeatureStr = getFeatureString(m->getTargetTriple().c_str()); - TargetMachine* target = march->CtorFn(*m, FeatureStr); + std::string FeatureStr = getFeatureString(Triple.c_str()); + TargetMachine* target = march->createTargetMachine(Triple, FeatureStr); return new LTOModule(m.take(), target); } @@ -189,7 +196,7 @@ bool LTOModule::objcClassNameFromExpression(Constant* c, std::string& name) if (GlobalVariable* gvn = dyn_cast<GlobalVariable>(op)) { Constant* cn = gvn->getInitializer(); if (ConstantArray* ca = dyn_cast<ConstantArray>(cn)) { - if ( ca->isCString() ) { + if (ca->isCString()) { name = ".objc_class_name_" + ca->getAsString(); return true; } @@ -205,9 +212,9 @@ 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) ) { + if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { NameAndAttributes info; - if ( _undefines.find(superclassName.c_str()) == _undefines.end() ) { + 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; @@ -217,7 +224,7 @@ void LTOModule::addObjCClass(GlobalVariable* clgv) } // third slot in __OBJC,__class is pointer to class name std::string className; - if ( objcClassNameFromExpression(c->getOperand(2), className) ) { + if (objcClassNameFromExpression(c->getOperand(2), className)) { const char* symbolName = ::strdup(className.c_str()); NameAndAttributes info; info.name = symbolName; @@ -238,9 +245,9 @@ 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) ) { + if (objcClassNameFromExpression(c->getOperand(1), targetclassName)) { NameAndAttributes info; - if ( _undefines.find(targetclassName.c_str()) == _undefines.end() ){ + 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; @@ -256,9 +263,9 @@ void LTOModule::addObjCCategory(GlobalVariable* clgv) void LTOModule::addObjCClassRef(GlobalVariable* clgv) { std::string targetclassName; - if ( objcClassNameFromExpression(clgv->getInitializer(), targetclassName) ){ + if (objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) { NameAndAttributes info; - if ( _undefines.find(targetclassName.c_str()) == _undefines.end() ) { + 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; @@ -293,23 +300,23 @@ void LTOModule::addDefinedDataSymbol(GlobalValue* v, Mangler& mangler) // 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 */ ) { + 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 (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 ) { + 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 ) { + else if (v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0) { if (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) { addObjCClassRef(gv); } @@ -325,35 +332,35 @@ void LTOModule::addDefinedDataSymbol(GlobalValue* v, Mangler& mangler) void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler, - bool isFunction) + bool isFunction) { // ignore all llvm.* symbols - if ( strncmp(def->getNameStart(), "llvm.", 5) == 0 ) + if (def->getName().startswith("llvm.")) return; // string is owned by _defines - const char* symbolName = ::strdup(mangler.getValueName(def).c_str()); + const char* symbolName = ::strdup(mangler.getMangledName(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 ) + if (isFunction) attr |= LTO_SYMBOL_PERMISSIONS_CODE; else { GlobalVariable* gv = dyn_cast<GlobalVariable>(def); - if ( (gv != NULL) && gv->isConstant() ) + if (gv && gv->isConstant()) attr |= LTO_SYMBOL_PERMISSIONS_RODATA; else attr |= LTO_SYMBOL_PERMISSIONS_DATA; } // set definition part - if ( def->hasWeakLinkage() || def->hasLinkOnceLinkage() ) { + if (def->hasWeakLinkage() || def->hasLinkOnceLinkage()) { attr |= LTO_SYMBOL_DEFINITION_WEAK; } - else if ( def->hasCommonLinkage()) { + else if (def->hasCommonLinkage()) { attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; } else { @@ -361,12 +368,12 @@ void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler, } // set scope part - if ( def->hasHiddenVisibility() ) + if (def->hasHiddenVisibility()) attr |= LTO_SYMBOL_SCOPE_HIDDEN; - else if ( def->hasProtectedVisibility() ) + else if (def->hasProtectedVisibility()) attr |= LTO_SYMBOL_SCOPE_PROTECTED; - else if ( def->hasExternalLinkage() || def->hasWeakLinkage() - || def->hasLinkOnceLinkage() || def->hasCommonLinkage() ) + else if (def->hasExternalLinkage() || def->hasWeakLinkage() + || def->hasLinkOnceLinkage() || def->hasCommonLinkage()) attr |= LTO_SYMBOL_SCOPE_DEFAULT; else attr |= LTO_SYMBOL_SCOPE_INTERNAL; @@ -381,7 +388,7 @@ void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler, void LTOModule::addAsmGlobalSymbol(const char *name) { // only add new define if not already defined - if ( _defines.count(name, &name[strlen(name)+1]) == 0 ) + if (_defines.count(name) == 0) return; // string is owned by _defines @@ -398,10 +405,14 @@ void LTOModule::addAsmGlobalSymbol(const char *name) { void LTOModule::addPotentialUndefinedSymbol(GlobalValue* decl, Mangler &mangler) { // ignore all llvm.* symbols - if ( strncmp(decl->getNameStart(), "llvm.", 5) == 0 ) + if (decl->getName().startswith("llvm.")) return; - const char* name = mangler.getValueName(decl).c_str(); + // ignore all aliases + if (isa<GlobalAlias>(decl)) + return; + + std::string name = mangler.getMangledName(decl); // we already have the symbol if (_undefines.find(name) != _undefines.end()) @@ -409,7 +420,7 @@ void LTOModule::addPotentialUndefinedSymbol(GlobalValue* decl, Mangler &mangler) NameAndAttributes info; // string is owned by _undefines - info.name = ::strdup(name); + info.name = ::strdup(name.c_str()); if (decl->hasExternalWeakLinkage()) info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; else @@ -419,11 +430,11 @@ void LTOModule::addPotentialUndefinedSymbol(GlobalValue* decl, Mangler &mangler) -// Find exeternal symbols referenced by VALUE. This is a recursive function. +// 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() ) + 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 @@ -431,11 +442,11 @@ void LTOModule::findExternalRefs(Value* value, Mangler &mangler) { // 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.. + // Handle ConstantExpr, ConstantStruct, ConstantArry etc. for (unsigned i = 0, e = c->getNumOperands(); i != e; ++i) findExternalRefs(c->getOperand(i), mangler); } @@ -443,11 +454,11 @@ void LTOModule::findExternalRefs(Value* value, Mangler &mangler) { void LTOModule::lazyParseSymbols() { - if ( !_symbolsParsed ) { + if (!_symbolsParsed) { _symbolsParsed = true; // Use mangler to add GlobalPrefix to names to match linker names. - Mangler mangler(*_module, _target->getTargetAsmInfo()->getGlobalPrefix()); + Mangler mangler(*_module, _target->getMCAsmInfo()->getGlobalPrefix()); // add chars used in ObjC method names so method names aren't mangled mangler.markCharAcceptable('['); mangler.markCharAcceptable(']'); @@ -459,7 +470,7 @@ void LTOModule::lazyParseSymbols() // add functions for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { - if ( f->isDeclaration() ) + if (f->isDeclaration()) addPotentialUndefinedSymbol(f, mangler); else addDefinedFunctionSymbol(f, mangler); @@ -468,7 +479,7 @@ void LTOModule::lazyParseSymbols() // add data for (Module::global_iterator v = _module->global_begin(), e = _module->global_end(); v != e; ++v) { - if ( v->isDeclaration() ) + if (v->isDeclaration()) addPotentialUndefinedSymbol(v, mangler); else addDefinedDataSymbol(v, mangler); @@ -505,8 +516,7 @@ void LTOModule::lazyParseSymbols() 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->getKeyData(), it->getKeyData()+ - it->getKeyLength()) == 0 ) { + if (_defines.count(it->getKey()) == 0) { NameAndAttributes info = it->getValue(); _symbols.push_back(info); } @@ -525,7 +535,7 @@ uint32_t LTOModule::getSymbolCount() lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) { lazyParseSymbols(); - if ( index < _symbols.size() ) + if (index < _symbols.size()) return _symbols[index].attributes; else return lto_symbol_attributes(0); @@ -534,9 +544,8 @@ lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) const char* LTOModule::getSymbolName(uint32_t index) { lazyParseSymbols(); - if ( index < _symbols.size() ) + if (index < _symbols.size()) return _symbols[index].name; else return NULL; } - diff --git a/tools/lto/Makefile b/tools/lto/Makefile index c8ad9fe..3120aa5 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -22,7 +22,7 @@ LINK_COMPONENTS := $(TARGETS_TO_BUILD) ipo scalaropts linker bitreader bitwriter include $(LEVEL)/Makefile.common -ifeq ($(OS),Darwin) +ifeq ($(HOST_OS),Darwin) # set dylib internal version number to llvmCore submission number ifdef LLVM_SUBMIT_VERSION LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \ diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index 936aeae..cc841bd 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -203,14 +203,6 @@ bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) } // -// sets the path to gcc -// -void lto_codegen_set_gcc_path(lto_code_gen_t cg, const char* path) -{ - cg->setGccPath(path); -} - -// // sets the path to the assembler tool // void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path) diff --git a/tools/opt/AnalysisWrappers.cpp b/tools/opt/AnalysisWrappers.cpp index 631a0dd..18360f8 100644 --- a/tools/opt/AnalysisWrappers.cpp +++ b/tools/opt/AnalysisWrappers.cpp @@ -21,6 +21,7 @@ #include "llvm/Pass.h" #include "llvm/Support/CallSite.h" #include "llvm/Analysis/CallGraph.h" +#include "llvm/Support/raw_ostream.h" #include <iostream> using namespace llvm; @@ -33,27 +34,31 @@ namespace { static char ID; // Pass ID, replacement for typeid ExternalFunctionsPassedConstants() : ModulePass(&ID) {} virtual bool runOnModule(Module &M) { - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->isDeclaration()) { - bool PrintedFn = false; - for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); - UI != E; ++UI) - if (Instruction *User = dyn_cast<Instruction>(*UI)) { - CallSite CS = CallSite::get(User); - if (CS.getInstruction()) { - for (CallSite::arg_iterator AI = CS.arg_begin(), - E = CS.arg_end(); AI != E; ++AI) - if (isa<Constant>(*AI)) { - if (!PrintedFn) { - std::cerr << "Function '" << I->getName() << "':\n"; - PrintedFn = true; - } - std::cerr << *User; - break; - } - } + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { + if (!I->isDeclaration()) continue; + + bool PrintedFn = false; + for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); + UI != E; ++UI) { + Instruction *User = dyn_cast<Instruction>(*UI); + if (!User) continue; + + CallSite CS = CallSite::get(User); + if (!CS.getInstruction()) continue; + + for (CallSite::arg_iterator AI = CS.arg_begin(), + E = CS.arg_end(); AI != E; ++AI) { + if (!isa<Constant>(*AI)) continue; + + if (!PrintedFn) { + errs() << "Function '" << I->getName() << "':\n"; + PrintedFn = true; } + errs() << *User; + break; + } } + } return false; } @@ -77,7 +82,7 @@ namespace { AU.addRequiredTransitive<CallGraph>(); } virtual bool runOnModule(Module &M) { - getAnalysis<CallGraph>().print(std::cerr, &M); + getAnalysis<CallGraph>().print(errs(), &M); return false; } }; diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt index efcca80..b75cda0 100644 --- a/tools/opt/CMakeLists.txt +++ b/tools/opt/CMakeLists.txt @@ -1,5 +1,5 @@ set(LLVM_REQUIRES_EH 1) -set(LLVM_LINK_COMPONENTS bitreader bitwriter instrumentation scalaropts ipo) +set(LLVM_LINK_COMPONENTS bitreader asmparser bitwriter instrumentation scalaropts ipo) add_llvm_tool(opt AnalysisWrappers.cpp diff --git a/tools/opt/GraphPrinters.cpp b/tools/opt/GraphPrinters.cpp index 5d581e4..1ae6be2 100644 --- a/tools/opt/GraphPrinters.cpp +++ b/tools/opt/GraphPrinters.cpp @@ -28,9 +28,10 @@ static void WriteGraphToFile(std::ostream &O, const std::string &GraphName, const GraphType >) { std::string Filename = GraphName + ".dot"; O << "Writing '" << Filename << "'..."; - std::ofstream F(Filename.c_str()); + std::string ErrInfo; + raw_fd_ostream F(Filename.c_str(), ErrInfo); - if (F.good()) + if (ErrInfo.empty()) WriteGraph(F, GT); else O << " error opening file for writing!"; @@ -70,8 +71,7 @@ namespace { return false; } - void print(std::ostream &OS) const {} - void print(std::ostream &OS, const llvm::Module*) const {} + void print(raw_ostream &OS, const llvm::Module*) const {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<CallGraph>(); diff --git a/tools/opt/Makefile b/tools/opt/Makefile index 0afb002..b17be34 100644 --- a/tools/opt/Makefile +++ b/tools/opt/Makefile @@ -10,6 +10,6 @@ LEVEL = ../.. TOOLNAME = opt REQUIRES_EH := 1 -LINK_COMPONENTS := bitreader bitwriter instrumentation scalaropts ipo +LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo include $(LEVEL)/Makefile.common diff --git a/tools/opt/PrintSCC.cpp b/tools/opt/PrintSCC.cpp index be65264..66709ff 100644 --- a/tools/opt/PrintSCC.cpp +++ b/tools/opt/PrintSCC.cpp @@ -29,8 +29,8 @@ #include "llvm/Module.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Support/CFG.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SCCIterator.h" -#include <iostream> using namespace llvm; namespace { @@ -39,7 +39,7 @@ namespace { CFGSCC() : FunctionPass(&ID) {} bool runOnFunction(Function& func); - void print(std::ostream &O, const Module* = 0) const { } + void print(raw_ostream &O, const Module* = 0) const { } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -53,7 +53,7 @@ namespace { // run - Print out SCCs in the call graph for the specified module. bool runOnModule(Module &M); - void print(std::ostream &O, const Module* = 0) const { } + void print(raw_ostream &O, const Module* = 0) const { } // getAnalysisUsage - This pass requires the CallGraph. virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -73,18 +73,18 @@ namespace { bool CFGSCC::runOnFunction(Function &F) { unsigned sccNum = 0; - std::cout << "SCCs for Function " << F.getName() << " in PostOrder:"; + outs() << "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; - std::cout << "\nSCC #" << ++sccNum << " : "; + outs() << "\nSCC #" << ++sccNum << " : "; for (std::vector<BasicBlock*>::const_iterator I = nextSCC.begin(), E = nextSCC.end(); I != E; ++I) - std::cout << (*I)->getName() << ", "; + outs() << (*I)->getName() << ", "; if (nextSCC.size() == 1 && SCCI.hasLoop()) - std::cout << " (Has self-loop)."; + outs() << " (Has self-loop)."; } - std::cout << "\n"; + outs() << "\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; - std::cout << "SCCs for the program in PostOrder:"; + outs() << "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; - std::cout << "\nSCC #" << ++sccNum << " : "; + outs() << "\nSCC #" << ++sccNum << " : "; for (std::vector<CallGraphNode*>::const_iterator I = nextSCC.begin(), E = nextSCC.end(); I != E; ++I) - std::cout << ((*I)->getFunction() ? (*I)->getFunction()->getName() - : std::string("Indirect CallGraph node")) << ", "; + outs() << ((*I)->getFunction() ? (*I)->getFunction()->getNameStr() + : std::string("Indirect CallGraph node")) << ", "; if (nextSCC.size() == 1 && SCCI.hasLoop()) - std::cout << " (Has self-loop)."; + outs() << " (Has self-loop)."; } - std::cout << "\n"; + outs() << "\n"; return true; } diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 6891619..fe0e036 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -26,17 +26,15 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Support/PassNameParser.h" #include "llvm/System/Signals.h" +#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/StandardPasses.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/raw_ostream.h" #include "llvm/LinkAllPasses.h" #include "llvm/LinkAllVMCore.h" -#include <iostream> -#include <fstream> #include <memory> #include <algorithm> using namespace llvm; @@ -50,7 +48,7 @@ PassList(cl::desc("Optimizations available:")); // Other command line options... // static cl::opt<std::string> -InputFilename(cl::Positional, cl::desc("<input bitcode file>"), +InputFilename(cl::Positional, cl::desc("<input bitcode file>"), cl::init("-"), cl::value_desc("filename")); static cl::opt<std::string> @@ -58,7 +56,7 @@ OutputFilename("o", cl::desc("Override output filename"), cl::value_desc("filename"), cl::init("-")); static cl::opt<bool> -Force("f", cl::desc("Overwrite output files")); +Force("f", cl::desc("Enable binary output on terminals")); static cl::opt<bool> PrintEachXForm("p", cl::desc("Print module after each transformation")); @@ -68,6 +66,10 @@ NoOutput("disable-output", cl::desc("Do not write result bitcode file"), cl::Hidden); static cl::opt<bool> +OutputAssembly("S", + cl::desc("Write output as LLVM assembly"), cl::Hidden); + +static cl::opt<bool> NoVerify("disable-verify", cl::desc("Do not verify result module"), cl::Hidden); static cl::opt<bool> @@ -80,15 +82,23 @@ StripDebug("strip-debug", static cl::opt<bool> DisableInline("disable-inlining", cl::desc("Do not run the inliner pass")); -static cl::opt<bool> -DisableOptimizations("disable-opt", +static cl::opt<bool> +DisableOptimizations("disable-opt", cl::desc("Do not run any optimization passes")); static cl::opt<bool> -StandardCompileOpts("std-compile-opts", +DisableInternalize("disable-internalize", + cl::desc("Do not mark all symbols as internal")); + +static cl::opt<bool> +StandardCompileOpts("std-compile-opts", cl::desc("Include the standard compile time optimizations")); static cl::opt<bool> +StandardLinkOpts("std-link-opts", + cl::desc("Include the standard link time optimizations")); + +static cl::opt<bool> OptLevelO1("O1", cl::desc("Optimization level 1. Similar to llvm-gcc -O1")); @@ -102,7 +112,8 @@ OptLevelO3("O3", static cl::opt<bool> UnitAtATime("funit-at-a-time", - cl::desc("Enable IPO. This is same as llvm-gcc's -funit-at-a-time")); + cl::desc("Enable IPO. This is same as llvm-gcc's -funit-at-a-time"), + cl::init(true)); static cl::opt<bool> DisableSimplifyLibCalls("disable-simplify-libcalls", @@ -123,23 +134,24 @@ namespace { struct CallGraphSCCPassPrinter : public CallGraphSCCPass { static char ID; const PassInfo *PassToPrint; - CallGraphSCCPassPrinter(const PassInfo *PI) : + CallGraphSCCPassPrinter(const PassInfo *PI) : CallGraphSCCPass(&ID), PassToPrint(PI) {} - virtual bool runOnSCC(const std::vector<CallGraphNode *>&SCC) { + virtual bool runOnSCC(std::vector<CallGraphNode *>&SCC) { if (!Quiet) { - cout << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + outs() << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; for (unsigned i = 0, e = SCC.size(); i != e; ++i) { Function *F = SCC[i]->getFunction(); - if (F) - getAnalysisID<Pass>(PassToPrint).print(cout, F->getParent()); + if (F) { + getAnalysisID<Pass>(PassToPrint).print(outs(), F->getParent()); + } } } // Get and print pass... return false; } - + virtual const char *getPassName() const { return "'Pass' Printer"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -158,8 +170,8 @@ struct ModulePassPrinter : public ModulePass { virtual bool runOnModule(Module &M) { if (!Quiet) { - cout << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; - getAnalysisID<Pass>(PassToPrint).print(cout, &M); + outs() << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + getAnalysisID<Pass>(PassToPrint).print(outs(), &M); } // Get and print pass... @@ -182,12 +194,12 @@ struct FunctionPassPrinter : public FunctionPass { PassToPrint(PI) {} virtual bool runOnFunction(Function &F) { - if (!Quiet) { - cout << "Printing analysis '" << PassToPrint->getPassName() - << "' for function '" << F.getName() << "':\n"; + if (!Quiet) { + outs() << "Printing analysis '" << PassToPrint->getPassName() + << "' for function '" << F.getName() << "':\n"; } // Get and print pass... - getAnalysisID<Pass>(PassToPrint).print(cout, F.getParent()); + getAnalysisID<Pass>(PassToPrint).print(outs(), F.getParent()); return false; } @@ -204,19 +216,19 @@ char FunctionPassPrinter::ID = 0; struct LoopPassPrinter : public LoopPass { static char ID; const PassInfo *PassToPrint; - LoopPassPrinter(const PassInfo *PI) : + LoopPassPrinter(const PassInfo *PI) : LoopPass(&ID), PassToPrint(PI) {} virtual bool runOnLoop(Loop *L, LPPassManager &LPM) { if (!Quiet) { - cout << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; - getAnalysisID<Pass>(PassToPrint).print(cout, + outs() << "Printing analysis '" << PassToPrint->getPassName() << "':\n"; + getAnalysisID<Pass>(PassToPrint).print(outs(), L->getHeader()->getParent()->getParent()); } // Get and print pass... return false; } - + virtual const char *getPassName() const { return "'Pass' Printer"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -230,17 +242,17 @@ char LoopPassPrinter::ID = 0; struct BasicBlockPassPrinter : public BasicBlockPass { const PassInfo *PassToPrint; static char ID; - BasicBlockPassPrinter(const PassInfo *PI) + BasicBlockPassPrinter(const PassInfo *PI) : BasicBlockPass(&ID), PassToPrint(PI) {} virtual bool runOnBasicBlock(BasicBlock &BB) { if (!Quiet) { - cout << "Printing Analysis info for BasicBlock '" << BB.getName() - << "': Pass " << PassToPrint->getPassName() << ":\n"; + outs() << "Printing Analysis info for BasicBlock '" << BB.getName() + << "': Pass " << PassToPrint->getPassName() << ":\n"; } // Get and print pass... - getAnalysisID<Pass>(PassToPrint).print(cout, BB.getParent()->getParent()); + getAnalysisID<Pass>(PassToPrint).print(outs(), BB.getParent()->getParent()); return false; } @@ -261,8 +273,8 @@ inline void addPass(PassManager &PM, Pass *P) { if (VerifyEach) PM.add(createVerifierPass()); } -/// AddOptimizationPasses - This routine adds optimization passes -/// based on selected optimization level, OptLevel. This routine +/// AddOptimizationPasses - This routine adds optimization passes +/// based on selected optimization level, OptLevel. This routine /// duplicates llvm-gcc behaviour. /// /// OptLevel - Optimization Level @@ -294,7 +306,7 @@ void AddStandardCompilePasses(PassManager &PM) { llvm::Pass *InliningPass = !DisableInline ? createFunctionInliningPass() : 0; // -std-compile-opts adds the same module passes as -O3. - createStandardModulePasses(&PM, 3, + createStandardModulePasses(&PM, 3, /*OptimizeSize=*/ false, /*UnitAtATime=*/ true, /*UnrollLoops=*/ true, @@ -303,6 +315,20 @@ void AddStandardCompilePasses(PassManager &PM) { InliningPass); } +void AddStandardLinkPasses(PassManager &PM) { + PM.add(createVerifierPass()); // Verify that input is correct + + // If the -strip-debug command line option was specified, do it. + if (StripDebug) + addPass(PM, createStripSymbolsPass(true)); + + if (DisableOptimizations) return; + + createStandardLTOPasses(&PM, /*Internalize=*/ !DisableInternalize, + /*RunInliner=*/ !DisableInline, + /*VerifyEach=*/ VerifyEach); +} + } // anonymous namespace @@ -311,7 +337,7 @@ void AddStandardCompilePasses(PassManager &PM) { // int main(int argc, char **argv) { llvm_shutdown_obj X; // Call llvm_shutdown() on exit. - LLVMContext Context; + LLVMContext &Context = getGlobalContext(); try { cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .bc modular optimizer and analysis printer\n"); @@ -321,56 +347,41 @@ int main(int argc, char **argv) { // FIXME: The choice of target should be controllable on the command line. std::auto_ptr<TargetMachine> target; - std::string ErrorMessage; + SMDiagnostic Err; // Load the input module... std::auto_ptr<Module> M; - if (MemoryBuffer *Buffer - = MemoryBuffer::getFileOrSTDIN(InputFilename, &ErrorMessage)) { - M.reset(ParseBitcodeFile(Buffer, Context, &ErrorMessage)); - delete Buffer; - } - + M.reset(ParseIRFile(InputFilename, Err, Context)); + if (M.get() == 0) { - cerr << argv[0] << ": "; - if (ErrorMessage.size()) - cerr << ErrorMessage << "\n"; - else - cerr << "bitcode didn't read correctly.\n"; + Err.Print(argv[0], errs()); return 1; } // Figure out what stream we are supposed to write to... - // FIXME: cout is not binary! - std::ostream *Out = &std::cout; // Default to printing to stdout... + // FIXME: outs() is not binary! + raw_ostream *Out = &outs(); // Default to printing to stdout... if (OutputFilename != "-") { - if (!Force && std::ifstream(OutputFilename.c_str())) { - // If force is not specified, make sure not to overwrite a file! - cerr << argv[0] << ": error opening '" << OutputFilename - << "': file exists!\n" - << "Use -f command line argument to force output\n"; - return 1; - } - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - Out = new std::ofstream(OutputFilename.c_str(), io_mode); - - if (!Out->good()) { - cerr << argv[0] << ": error opening " << OutputFilename << "!\n"; - return 1; - } - // 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; + } } // If the output is set to be emitted to standard out, and standard out is a // 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 && CheckBitcodeOutputToConsole(Out,!Quiet)) { - NoOutput = true; - } + if (!Force && !NoOutput && !OutputAssembly) + if (CheckBitcodeOutputToConsole(*Out, !Quiet)) + NoOutput = true; // Create a PassManager to hold and optimize the collection of passes we are // about to build... @@ -385,7 +396,7 @@ int main(int argc, char **argv) { FPasses = new FunctionPassManager(new ExistingModuleProvider(M.get())); FPasses->add(new TargetData(M.get())); } - + // If the -strip-debug command line option was specified, add it. If // -std-compile-opts was also specified, it will handle StripDebug. if (StripDebug && !StandardCompileOpts) @@ -395,12 +406,18 @@ int main(int argc, char **argv) { for (unsigned i = 0; i < PassList.size(); ++i) { // Check to see if -std-compile-opts was specified before this option. If // so, handle it. - if (StandardCompileOpts && + if (StandardCompileOpts && StandardCompileOpts.getPosition() < PassList.getPosition(i)) { AddStandardCompilePasses(Passes); StandardCompileOpts = false; } - + + if (StandardLinkOpts && + StandardLinkOpts.getPosition() < PassList.getPosition(i)) { + AddStandardLinkPasses(Passes); + StandardLinkOpts = false; + } + if (OptLevelO1 && OptLevelO1.getPosition() < PassList.getPosition(i)) { AddOptimizationPasses(Passes, *FPasses, 1); OptLevelO1 = false; @@ -421,8 +438,8 @@ int main(int argc, char **argv) { if (PassInf->getNormalCtor()) P = PassInf->getNormalCtor()(); else - cerr << argv[0] << ": cannot create pass: " - << PassInf->getPassName() << "\n"; + errs() << argv[0] << ": cannot create pass: " + << PassInf->getPassName() << "\n"; if (P) { bool isBBPass = dynamic_cast<BasicBlockPass*>(P) != 0; bool isLPass = !isBBPass && dynamic_cast<LoopPass*>(P) != 0; @@ -444,30 +461,36 @@ int main(int argc, char **argv) { Passes.add(new ModulePassPrinter(PassInf)); } } - + if (PrintEachXForm) Passes.add(createPrintModulePass(&errs())); } - + // If -std-compile-opts was specified at the end of the pass list, add them. if (StandardCompileOpts) { AddStandardCompilePasses(Passes); StandardCompileOpts = false; - } + } + + if (StandardLinkOpts) { + AddStandardLinkPasses(Passes); + StandardLinkOpts = false; + } if (OptLevelO1) { - AddOptimizationPasses(Passes, *FPasses, 1); - } + AddOptimizationPasses(Passes, *FPasses, 1); + } if (OptLevelO2) { - AddOptimizationPasses(Passes, *FPasses, 2); - } + AddOptimizationPasses(Passes, *FPasses, 2); + } if (OptLevelO3) { - AddOptimizationPasses(Passes, *FPasses, 3); - } + AddOptimizationPasses(Passes, *FPasses, 3); + } if (OptLevelO1 || OptLevelO2 || OptLevelO3) { + FPasses->doInitialization(); for (Module::iterator I = M.get()->begin(), E = M.get()->end(); I != E; ++I) FPasses->run(*I); @@ -477,22 +500,26 @@ int main(int argc, char **argv) { if (!NoVerify && !VerifyEach) Passes.add(createVerifierPass()); - // Write bitcode out to disk or cout as the last step... - if (!NoOutput && !AnalyzeOnly) - Passes.add(CreateBitcodeWriterPass(*Out)); + // Write bitcode or assembly out to disk or outs() as the last step... + if (!NoOutput && !AnalyzeOnly) { + if (OutputAssembly) + Passes.add(createPrintModulePass(Out)); + else + Passes.add(createBitcodeWriterPass(*Out)); + } // Now that we have all of the passes ready, run them. Passes.run(*M.get()); - // Delete the ofstream. - if (Out != &std::cout) + // Delete the raw_fd_ostream. + if (Out != &outs()) delete Out; return 0; } catch (const std::string& msg) { - cerr << argv[0] << ": " << msg << "\n"; + errs() << argv[0] << ": " << msg << "\n"; } catch (...) { - cerr << argv[0] << ": Unexpected unknown exception occurred.\n"; + errs() << argv[0] << ": Unexpected unknown exception occurred.\n"; } llvm_shutdown(); return 1; |