X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fbugpoint%2FToolRunner.cpp;h=6c46ef18eb6bc1df014faa9e686e72d328a98322;hb=d7797496a36b46fc8a1c6a96c8a2ccbe53929567;hp=4baafd127b2f199ee1b43595e5a57ec1546644e5;hpb=18e05b4692068b2cc1dfbc3aeb682ac2ec63d11b;p=oota-llvm.git diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 4baafd127b2..6c46ef18eb6 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -13,7 +13,7 @@ #define DEBUG_TYPE "toolrunner" #include "ToolRunner.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Program.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" @@ -59,7 +59,8 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, const sys::Path &StdOutFile, const sys::Path &StdErrFile, unsigned NumSeconds = 0, - unsigned MemoryLimit = 0) { + unsigned MemoryLimit = 0, + std::string *ErrMsg = 0) { const sys::Path* redirects[3]; redirects[0] = &StdInFile; redirects[1] = &StdOutFile; @@ -76,7 +77,7 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, return sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, - NumSeconds, MemoryLimit); + NumSeconds, MemoryLimit, ErrMsg); } /// RunProgramRemotelyWithTimeout - This function runs the given program @@ -133,13 +134,15 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, return ReturnCode; } -static std::string ProcessFailure(sys::Path ProgPath, const char** Args) { +static std::string ProcessFailure(sys::Path ProgPath, const char** Args, + unsigned Timeout = 0, + unsigned MemoryLimit = 0) { std::ostringstream OS; OS << "\nError running tool:\n "; for (const char **Arg = Args; *Arg; ++Arg) OS << " " << *Arg; OS << "\n"; - + // Rerun the compiler, capturing any error messages to print them. sys::Path ErrorFilename("bugpoint.program_error_messages"); std::string ErrMsg; @@ -148,7 +151,8 @@ static std::string ProcessFailure(sys::Path ProgPath, const char** Args) { exit(1); } RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename, - ErrorFilename); // FIXME: check return code ? + ErrorFilename, Timeout, MemoryLimit); + // FIXME: check return code ? // Print out the error messages generated by GCC if possible... std::ifstream ErrorFile(ErrorFilename.c_str()); @@ -203,7 +207,8 @@ int LLI::ExecuteProgram(const std::string &Bitcode, LLIArgs.push_back(LLIPath.c_str()); LLIArgs.push_back("-force-interpreter=true"); - for (std::vector::const_iterator i = SharedLibs.begin(), e = SharedLibs.end(); i != e; ++i) { + for (std::vector::const_iterator i = SharedLibs.begin(), + e = SharedLibs.end(); i != e; ++i) { LLIArgs.push_back("-load"); LLIArgs.push_back((*i).c_str()); } @@ -226,7 +231,7 @@ int LLI::ExecuteProgram(const std::string &Bitcode, ); return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0], sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), - Timeout, MemoryLimit); + Timeout, MemoryLimit, Error); } // LLI create method - Try to find the LLI executable @@ -234,21 +239,82 @@ AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0, std::string &Message, const std::vector *ToolArgs) { std::string LLIPath = - FindExecutable("lli", Argv0, (void *)(intptr_t)&createLLI).str(); + PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createLLI).str(); if (!LLIPath.empty()) { Message = "Found lli: " + LLIPath + "\n"; return new LLI(LLIPath, ToolArgs); } - Message = "Cannot find `lli' in executable directory or PATH!\n"; + Message = "Cannot find `lli' in executable directory!\n"; return 0; } +//===---------------------------------------------------------------------===// +// Custom compiler command implementation of AbstractIntepreter interface +// +// Allows using a custom command for compiling the bitcode, thus allows, for +// example, to compile a bitcode fragment without linking or executing, then +// using a custom wrapper script to check for compiler errors. +namespace { + class CustomCompiler : public AbstractInterpreter { + std::string CompilerCommand; + std::vector CompilerArgs; + public: + CustomCompiler( + const std::string &CompilerCmd, std::vector CompArgs) : + CompilerCommand(CompilerCmd), CompilerArgs(CompArgs) {} + + virtual void compileProgram(const std::string &Bitcode, + std::string *Error, + unsigned Timeout = 0, + unsigned MemoryLimit = 0); + + virtual int ExecuteProgram(const std::string &Bitcode, + const std::vector &Args, + const std::string &InputFile, + const std::string &OutputFile, + std::string *Error, + const std::vector &GCCArgs = + std::vector(), + const std::vector &SharedLibs = + std::vector(), + unsigned Timeout = 0, + unsigned MemoryLimit = 0) { + *Error = "Execution not supported with -compile-custom"; + return -1; + } + }; +} + +void CustomCompiler::compileProgram(const std::string &Bitcode, + std::string *Error, + unsigned Timeout, + unsigned MemoryLimit) { + + std::vector ProgramArgs; + ProgramArgs.push_back(CompilerCommand.c_str()); + + for (std::size_t i = 0; i < CompilerArgs.size(); ++i) + ProgramArgs.push_back(CompilerArgs.at(i).c_str()); + ProgramArgs.push_back(Bitcode.c_str()); + ProgramArgs.push_back(0); + + // Add optional parameters to the running program from Argv + for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i) + ProgramArgs.push_back(CompilerArgs[i].c_str()); + + if (RunProgramWithTimeout( sys::Path(CompilerCommand), &ProgramArgs[0], + sys::Path(), sys::Path(), sys::Path(), + Timeout, MemoryLimit, Error)) + *Error = ProcessFailure(sys::Path(CompilerCommand), &ProgramArgs[0], + Timeout, MemoryLimit); +} + //===---------------------------------------------------------------------===// // Custom execution command implementation of AbstractIntepreter interface // // Allows using a custom command for executing the bitcode, thus allows, -// for example, to invoke a cross compiler for code generation followed by +// for example, to invoke a cross compiler for code generation followed by // a simulator that executes the generated binary. namespace { class CustomExecutor : public AbstractInterpreter { @@ -296,55 +362,78 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode, return RunProgramWithTimeout( sys::Path(ExecutionCommand), - &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), - sys::Path(OutputFile), Timeout, MemoryLimit); + &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), + sys::Path(OutputFile), Timeout, MemoryLimit, Error); } -// Custom execution environment create method, takes the execution command -// as arguments -AbstractInterpreter *AbstractInterpreter::createCustom( - std::string &Message, - const std::string &ExecCommandLine) { +// Tokenize the CommandLine to the command and the args to allow +// defining a full command line as the command instead of just the +// executed program. We cannot just pass the whole string after the command +// as a single argument because then program sees only a single +// command line argument (with spaces in it: "foo bar" instead +// of "foo" and "bar"). +// +// code borrowed from: +// http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html +static void lexCommand(std::string &Message, const std::string &CommandLine, + std::string &CmdPath, std::vector Args) { std::string Command = ""; - std::vector Args; std::string delimiters = " "; - // Tokenize the ExecCommandLine to the command and the args to allow - // defining a full command line as the command instead of just the - // executed program. We cannot just pass the whole string after the command - // as a single argument because then program sees only a single - // command line argument (with spaces in it: "foo bar" instead - // of "foo" and "bar"). - - // code borrowed from: - // http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html - std::string::size_type lastPos = - ExecCommandLine.find_first_not_of(delimiters, 0); - std::string::size_type pos = - ExecCommandLine.find_first_of(delimiters, lastPos); + std::string::size_type lastPos = CommandLine.find_first_not_of(delimiters, 0); + std::string::size_type pos = CommandLine.find_first_of(delimiters, lastPos); while (std::string::npos != pos || std::string::npos != lastPos) { - std::string token = ExecCommandLine.substr(lastPos, pos - lastPos); + std::string token = CommandLine.substr(lastPos, pos - lastPos); if (Command == "") Command = token; else Args.push_back(token); // Skip delimiters. Note the "not_of" - lastPos = ExecCommandLine.find_first_not_of(delimiters, pos); + lastPos = CommandLine.find_first_not_of(delimiters, pos); // Find next "non-delimiter" - pos = ExecCommandLine.find_first_of(delimiters, lastPos); + pos = CommandLine.find_first_of(delimiters, lastPos); } - std::string CmdPath = sys::Program::FindProgramByName(Command).str(); + CmdPath = sys::Program::FindProgramByName(Command).str(); if (CmdPath.empty()) { - Message = - std::string("Cannot find '") + Command + - "' in executable directory or PATH!\n"; - return 0; + Message = + std::string("Cannot find '") + Command + + "' in PATH!\n"; + return; } Message = "Found command in: " + CmdPath + "\n"; +} + +// Custom execution environment create method, takes the execution command +// as arguments +AbstractInterpreter *AbstractInterpreter::createCustomCompiler( + std::string &Message, + const std::string &CompileCommandLine) { + + std::string CmdPath; + std::vector Args; + lexCommand(Message, CompileCommandLine, CmdPath, Args); + if (CmdPath.empty()) + return 0; + + return new CustomCompiler(CmdPath, Args); +} + +// Custom execution environment create method, takes the execution command +// as arguments +AbstractInterpreter *AbstractInterpreter::createCustomExecutor( + std::string &Message, + const std::string &ExecCommandLine) { + + + std::string CmdPath; + std::vector Args; + lexCommand(Message, ExecCommandLine, CmdPath, Args); + if (CmdPath.empty()) + return 0; return new CustomExecutor(CmdPath, Args); } @@ -352,8 +441,9 @@ AbstractInterpreter *AbstractInterpreter::createCustom( //===----------------------------------------------------------------------===// // LLC Implementation of AbstractIntepreter interface // -GCC::FileType LLC::OutputCode(const std::string &Bitcode, - sys::Path &OutputAsmFile, std::string &Error) { +GCC::FileType LLC::OutputCode(const std::string &Bitcode, + sys::Path &OutputAsmFile, std::string &Error, + unsigned Timeout, unsigned MemoryLimit) { const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); sys::Path uniqueFile(Bitcode + Suffix); std::string ErrMsg; @@ -372,10 +462,10 @@ 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(Bitcode.c_str()); // This is the input bitcode - + if (UseIntegratedAssembler) LLCArgs.push_back("-filetype=obj"); - + LLCArgs.push_back (0); outs() << (UseIntegratedAssembler ? "" : ""); @@ -386,14 +476,17 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, errs() << "\n"; ); if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0], - sys::Path(), sys::Path(), sys::Path())) - Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]); - return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; + sys::Path(), sys::Path(), sys::Path(), + Timeout, MemoryLimit)) + Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0], + Timeout, MemoryLimit); + return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; } -void LLC::compileProgram(const std::string &Bitcode, std::string *Error) { +void LLC::compileProgram(const std::string &Bitcode, std::string *Error, + unsigned Timeout, unsigned MemoryLimit) { sys::Path OutputAsmFile; - OutputCode(Bitcode, OutputAsmFile, *Error); + OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit); OutputAsmFile.eraseFromDisk(); } @@ -408,8 +501,9 @@ int LLC::ExecuteProgram(const std::string &Bitcode, unsigned MemoryLimit) { sys::Path OutputAsmFile; - GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error); - FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); + GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, + MemoryLimit); + FileRemover OutFileRemover(OutputAsmFile.str(), !SaveTemps); std::vector GCCArgs(ArgsForGCC); GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); @@ -429,9 +523,9 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0, const std::vector *GCCArgs, bool UseIntegratedAssembler) { std::string LLCPath = - FindExecutable("llc", Argv0, (void *)(intptr_t)&createLLC).str(); + PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createLLC).str(); if (LLCPath.empty()) { - Message = "Cannot find `llc' in executable directory or PATH!\n"; + Message = "Cannot find `llc' in executable directory!\n"; return 0; } @@ -466,7 +560,7 @@ namespace { const std::vector &GCCArgs = std::vector(), const std::vector &SharedLibs = - std::vector(), + std::vector(), unsigned Timeout = 0, unsigned MemoryLimit = 0); }; @@ -509,7 +603,7 @@ int JIT::ExecuteProgram(const std::string &Bitcode, 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); + Timeout, MemoryLimit, Error); } /// createJIT - Try to find the LLI executable @@ -517,18 +611,19 @@ int JIT::ExecuteProgram(const std::string &Bitcode, AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0, std::string &Message, const std::vector *Args) { std::string LLIPath = - FindExecutable("lli", Argv0, (void *)(intptr_t)&createJIT).str(); + PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createJIT).str(); if (!LLIPath.empty()) { Message = "Found lli: " + LLIPath + "\n"; return new JIT(LLIPath, Args); } - Message = "Cannot find `lli' in executable directory or PATH!\n"; + Message = "Cannot find `lli' in executable directory!\n"; return 0; } GCC::FileType CBE::OutputCode(const std::string &Bitcode, - sys::Path &OutputCFile, std::string &Error) { + sys::Path &OutputCFile, std::string &Error, + unsigned Timeout, unsigned MemoryLimit) { sys::Path uniqueFile(Bitcode+".cbe.c"); std::string ErrMsg; if (uniqueFile.makeUnique(true, &ErrMsg)) { @@ -556,14 +651,15 @@ GCC::FileType CBE::OutputCode(const std::string &Bitcode, errs() << "\n"; ); if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(), - sys::Path())) - Error = ProcessFailure(LLCPath, &LLCArgs[0]); + sys::Path(), Timeout, MemoryLimit)) + Error = ProcessFailure(LLCPath, &LLCArgs[0], Timeout, MemoryLimit); return GCC::CFile; } -void CBE::compileProgram(const std::string &Bitcode, std::string *Error) { +void CBE::compileProgram(const std::string &Bitcode, std::string *Error, + unsigned Timeout, unsigned MemoryLimit) { sys::Path OutputCFile; - OutputCode(Bitcode, OutputCFile, *Error); + OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit); OutputCFile.eraseFromDisk(); } @@ -577,9 +673,9 @@ int CBE::ExecuteProgram(const std::string &Bitcode, unsigned Timeout, unsigned MemoryLimit) { sys::Path OutputCFile; - OutputCode(Bitcode, OutputCFile, *Error); + OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit); - FileRemover CFileRemove(OutputCFile, !SaveTemps); + FileRemover CFileRemove(OutputCFile.str(), !SaveTemps); std::vector GCCArgs(ArgsForGCC); GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); @@ -593,14 +689,14 @@ int CBE::ExecuteProgram(const std::string &Bitcode, /// CBE *AbstractInterpreter::createCBE(const char *Argv0, std::string &Message, - const std::string &GCCBinary, + const std::string &GCCBinary, const std::vector *Args, const std::vector *GCCArgs) { sys::Path LLCPath = - FindExecutable("llc", Argv0, (void *)(intptr_t)&createCBE); + PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createCBE); if (LLCPath.isEmpty()) { Message = - "Cannot find `llc' in executable directory or PATH!\n"; + "Cannot find `llc' in executable directory!\n"; return 0; } @@ -617,8 +713,8 @@ CBE *AbstractInterpreter::createCBE(const char *Argv0, // GCC abstraction // -static bool IsARMArchitecture(std::vector Args) { - for (std::vector::const_iterator +static bool IsARMArchitecture(std::vector Args) { + for (std::vector::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { if (StringRef(*I).equals_lower("-arch")) { ++I; @@ -662,14 +758,13 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // 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)) + if (TargetTriple.isOSDarwin() && !IsARMArchitecture(GCCArgs)) GCCArgs.push_back("-force_cpusubtype_ALL"); } } - + GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename. - + GCCArgs.push_back("-x"); GCCArgs.push_back("none"); GCCArgs.push_back("-o"); @@ -711,6 +806,10 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, std::vector ProgramArgs; + // Declared here so that the destructor only runs after + // ProgramArgs is used. + std::string Exec; + if (RemoteClientPath.isEmpty()) ProgramArgs.push_back(OutputBinary.c_str()); else { @@ -731,7 +830,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // Full path to the binary. We need to cd to the exec directory because // there is a dylib there that the exec expects to find in the CWD char* env_pwd = getenv("PWD"); - std::string Exec = "cd "; + Exec = "cd "; Exec += env_pwd; Exec += "; ./"; Exec += OutputBinary.c_str(); @@ -751,13 +850,13 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, errs() << "\n"; ); - FileRemover OutputBinaryRemover(OutputBinary, !SaveTemps); + FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps); if (RemoteClientPath.isEmpty()) { DEBUG(errs() << ""); return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), - Timeout, MemoryLimit); + Timeout, MemoryLimit, Error); } else { outs() << ""; outs().flush(); return RunProgramRemotelyWithTimeout(sys::Path(RemoteClientPath), @@ -779,7 +878,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, OutputFile = uniqueFilename.str(); std::vector GCCArgs; - + GCCArgs.push_back(GCCPath.c_str()); if (TargetTriple.getArch() == Triple::x86) @@ -800,9 +899,9 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCCArgs.push_back("none"); if (TargetTriple.getArch() == Triple::sparc) GCCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc - else if (TargetTriple.getOS() == Triple::Darwin) { + else if (TargetTriple.isOSDarwin()) { // link all source files into a single module in data segment, rather than - // generating blocks. dynamic_lookup requires that you set + // 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"); @@ -823,8 +922,8 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCCArgs.push_back(OutputFile.c_str()); // Output to the right filename. GCCArgs.push_back("-O2"); // Optimize the program a bit. - - + + // Add any arguments intended for GCC. We locate them here because this is // most likely -L and -l options that need to come before other libraries but // after the source. Other options won't be sensitive to placement on the @@ -833,7 +932,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCCArgs.push_back(ArgsForGCC[i].c_str()); GCCArgs.push_back(0); // NULL terminator - + outs() << ""; outs().flush(); DEBUG(errs() << "\nAbout to run:\t"; @@ -856,7 +955,7 @@ GCC *GCC::create(std::string &Message, const std::vector *Args) { sys::Path GCCPath = sys::Program::FindProgramByName(GCCBinary); if (GCCPath.isEmpty()) { - Message = "Cannot find `"+ GCCBinary +"' in executable directory or PATH!\n"; + Message = "Cannot find `"+ GCCBinary +"' in PATH!\n"; return 0; }