ToolRunner.cpp revision 629e48768abd320107eae8e23d5af1e38d4c0fbe
1//===-- ToolRunner.cpp ----------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file was developed by the LLVM research group and is distributed under 6// the University of Illinois Open Source License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the interfaces described in the ToolRunner.h file. 11// 12//===----------------------------------------------------------------------===// 13 14#define DEBUG_TYPE "toolrunner" 15#include "ToolRunner.h" 16#include "llvm/Config/config.h" // for HAVE_LINK_R 17#include "llvm/System/Program.h" 18#include "llvm/Support/Debug.h" 19#include "llvm/Support/FileUtilities.h" 20#include <fstream> 21#include <sstream> 22#include <iostream> 23using namespace llvm; 24 25ToolExecutionError::~ToolExecutionError() throw() { } 26 27/// RunProgramWithTimeout - This function provides an alternate interface to the 28/// sys::Program::ExecuteAndWait interface. 29/// @see sys:Program::ExecuteAndWait 30static int RunProgramWithTimeout(const sys::Path &ProgramPath, 31 const char **Args, 32 const sys::Path &StdInFile, 33 const sys::Path &StdOutFile, 34 const sys::Path &StdErrFile, 35 unsigned NumSeconds = 0) { 36 const sys::Path* redirects[3]; 37 redirects[0] = &StdInFile; 38 redirects[1] = &StdOutFile; 39 redirects[2] = &StdErrFile; 40 41 return 42 sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, NumSeconds); 43} 44 45 46 47static void ProcessFailure(sys::Path ProgPath, const char** Args) { 48 std::ostringstream OS; 49 OS << "\nError running tool:\n "; 50 for (const char **Arg = Args; *Arg; ++Arg) 51 OS << " " << *Arg; 52 OS << "\n"; 53 54 // Rerun the compiler, capturing any error messages to print them. 55 sys::Path ErrorFilename("error_messages"); 56 ErrorFilename.makeUnique(); 57 RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename, 58 ErrorFilename); 59 60 // Print out the error messages generated by GCC if possible... 61 std::ifstream ErrorFile(ErrorFilename.c_str()); 62 if (ErrorFile) { 63 std::copy(std::istreambuf_iterator<char>(ErrorFile), 64 std::istreambuf_iterator<char>(), 65 std::ostreambuf_iterator<char>(OS)); 66 ErrorFile.close(); 67 } 68 69 ErrorFilename.eraseFromDisk(); 70 throw ToolExecutionError(OS.str()); 71} 72 73//===---------------------------------------------------------------------===// 74// LLI Implementation of AbstractIntepreter interface 75// 76namespace { 77 class LLI : public AbstractInterpreter { 78 std::string LLIPath; // The path to the LLI executable 79 std::vector<std::string> ToolArgs; // Args to pass to LLI 80 public: 81 LLI(const std::string &Path, const std::vector<std::string> *Args) 82 : LLIPath(Path) { 83 ToolArgs.clear (); 84 if (Args) { ToolArgs = *Args; } 85 } 86 87 virtual int ExecuteProgram(const std::string &Bytecode, 88 const std::vector<std::string> &Args, 89 const std::string &InputFile, 90 const std::string &OutputFile, 91 const std::vector<std::string> &GCCArgs, 92 const std::vector<std::string> &SharedLibs = 93 std::vector<std::string>(), 94 unsigned Timeout = 0); 95 }; 96} 97 98int LLI::ExecuteProgram(const std::string &Bytecode, 99 const std::vector<std::string> &Args, 100 const std::string &InputFile, 101 const std::string &OutputFile, 102 const std::vector<std::string> &GCCArgs, 103 const std::vector<std::string> &SharedLibs, 104 unsigned Timeout) { 105 if (!SharedLibs.empty()) 106 throw ToolExecutionError("LLI currently does not support " 107 "loading shared libraries."); 108 109 if (!GCCArgs.empty()) 110 throw ToolExecutionError("LLI currently does not support " 111 "GCC Arguments."); 112 std::vector<const char*> LLIArgs; 113 LLIArgs.push_back(LLIPath.c_str()); 114 LLIArgs.push_back("-force-interpreter=true"); 115 116 // Add any extra LLI args. 117 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 118 LLIArgs.push_back(ToolArgs[i].c_str()); 119 120 LLIArgs.push_back(Bytecode.c_str()); 121 // Add optional parameters to the running program from Argv 122 for (unsigned i=0, e = Args.size(); i != e; ++i) 123 LLIArgs.push_back(Args[i].c_str()); 124 LLIArgs.push_back(0); 125 126 std::cout << "<lli>" << std::flush; 127 DEBUG(std::cerr << "\nAbout to run:\t"; 128 for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i) 129 std::cerr << " " << LLIArgs[i]; 130 std::cerr << "\n"; 131 ); 132 return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0], 133 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), 134 Timeout); 135} 136 137// LLI create method - Try to find the LLI executable 138AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath, 139 std::string &Message, 140 const std::vector<std::string> *ToolArgs) { 141 std::string LLIPath = FindExecutable("lli", ProgPath).toString(); 142 if (!LLIPath.empty()) { 143 Message = "Found lli: " + LLIPath + "\n"; 144 return new LLI(LLIPath, ToolArgs); 145 } 146 147 Message = "Cannot find `lli' in executable directory or PATH!\n"; 148 return 0; 149} 150 151//===----------------------------------------------------------------------===// 152// LLC Implementation of AbstractIntepreter interface 153// 154void LLC::OutputAsm(const std::string &Bytecode, sys::Path &OutputAsmFile) { 155 sys::Path uniqueFile(Bytecode+".llc.s"); 156 uniqueFile.makeUnique(); 157 OutputAsmFile = uniqueFile; 158 std::vector<const char *> LLCArgs; 159 LLCArgs.push_back (LLCPath.c_str()); 160 161 // Add any extra LLC args. 162 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 163 LLCArgs.push_back(ToolArgs[i].c_str()); 164 165 LLCArgs.push_back ("-o"); 166 LLCArgs.push_back (OutputAsmFile.c_str()); // Output to the Asm file 167 LLCArgs.push_back ("-f"); // Overwrite as necessary... 168 LLCArgs.push_back (Bytecode.c_str()); // This is the input bytecode 169 LLCArgs.push_back (0); 170 171 std::cout << "<llc>" << std::flush; 172 DEBUG(std::cerr << "\nAbout to run:\t"; 173 for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) 174 std::cerr << " " << LLCArgs[i]; 175 std::cerr << "\n"; 176 ); 177 if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0], 178 sys::Path(), sys::Path(), sys::Path())) 179 ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]); 180} 181 182void LLC::compileProgram(const std::string &Bytecode) { 183 sys::Path OutputAsmFile; 184 OutputAsm(Bytecode, OutputAsmFile); 185 OutputAsmFile.eraseFromDisk(); 186} 187 188int LLC::ExecuteProgram(const std::string &Bytecode, 189 const std::vector<std::string> &Args, 190 const std::string &InputFile, 191 const std::string &OutputFile, 192 const std::vector<std::string> &ArgsForGCC, 193 const std::vector<std::string> &SharedLibs, 194 unsigned Timeout) { 195 196 sys::Path OutputAsmFile; 197 OutputAsm(Bytecode, OutputAsmFile); 198 FileRemover OutFileRemover(OutputAsmFile); 199 200 std::vector<std::string> GCCArgs(ArgsForGCC); 201 GCCArgs.insert(GCCArgs.end(),SharedLibs.begin(),SharedLibs.end()); 202 203 // Assuming LLC worked, compile the result with GCC and run it. 204 return gcc->ExecuteProgram(OutputAsmFile.toString(), Args, GCC::AsmFile, 205 InputFile, OutputFile, GCCArgs, Timeout); 206} 207 208/// createLLC - Try to find the LLC executable 209/// 210LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath, 211 std::string &Message, 212 const std::vector<std::string> *Args) { 213 std::string LLCPath = FindExecutable("llc", ProgramPath).toString(); 214 if (LLCPath.empty()) { 215 Message = "Cannot find `llc' in executable directory or PATH!\n"; 216 return 0; 217 } 218 219 Message = "Found llc: " + LLCPath + "\n"; 220 GCC *gcc = GCC::create(ProgramPath, Message); 221 if (!gcc) { 222 std::cerr << Message << "\n"; 223 exit(1); 224 } 225 return new LLC(LLCPath, gcc, Args); 226} 227 228//===---------------------------------------------------------------------===// 229// JIT Implementation of AbstractIntepreter interface 230// 231namespace { 232 class JIT : public AbstractInterpreter { 233 std::string LLIPath; // The path to the LLI executable 234 std::vector<std::string> ToolArgs; // Args to pass to LLI 235 public: 236 JIT(const std::string &Path, const std::vector<std::string> *Args) 237 : LLIPath(Path) { 238 ToolArgs.clear (); 239 if (Args) { ToolArgs = *Args; } 240 } 241 242 virtual int ExecuteProgram(const std::string &Bytecode, 243 const std::vector<std::string> &Args, 244 const std::string &InputFile, 245 const std::string &OutputFile, 246 const std::vector<std::string> &GCCArgs = 247 std::vector<std::string>(), 248 const std::vector<std::string> &SharedLibs = 249 std::vector<std::string>(), 250 unsigned Timeout =0 ); 251 }; 252} 253 254int JIT::ExecuteProgram(const std::string &Bytecode, 255 const std::vector<std::string> &Args, 256 const std::string &InputFile, 257 const std::string &OutputFile, 258 const std::vector<std::string> &GCCArgs, 259 const std::vector<std::string> &SharedLibs, 260 unsigned Timeout) { 261 if (!GCCArgs.empty()) 262 throw ToolExecutionError("JIT does not support GCC Arguments."); 263 // Construct a vector of parameters, incorporating those from the command-line 264 std::vector<const char*> JITArgs; 265 JITArgs.push_back(LLIPath.c_str()); 266 JITArgs.push_back("-force-interpreter=false"); 267 268 // Add any extra LLI args. 269 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 270 JITArgs.push_back(ToolArgs[i].c_str()); 271 272 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) { 273 JITArgs.push_back("-load"); 274 JITArgs.push_back(SharedLibs[i].c_str()); 275 } 276 JITArgs.push_back(Bytecode.c_str()); 277 // Add optional parameters to the running program from Argv 278 for (unsigned i=0, e = Args.size(); i != e; ++i) 279 JITArgs.push_back(Args[i].c_str()); 280 JITArgs.push_back(0); 281 282 std::cout << "<jit>" << std::flush; 283 DEBUG(std::cerr << "\nAbout to run:\t"; 284 for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i) 285 std::cerr << " " << JITArgs[i]; 286 std::cerr << "\n"; 287 ); 288 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n"); 289 return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0], 290 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), 291 Timeout); 292} 293 294/// createJIT - Try to find the LLI executable 295/// 296AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath, 297 std::string &Message, const std::vector<std::string> *Args) { 298 std::string LLIPath = FindExecutable("lli", ProgPath).toString(); 299 if (!LLIPath.empty()) { 300 Message = "Found lli: " + LLIPath + "\n"; 301 return new JIT(LLIPath, Args); 302 } 303 304 Message = "Cannot find `lli' in executable directory or PATH!\n"; 305 return 0; 306} 307 308void CBE::OutputC(const std::string &Bytecode, sys::Path& OutputCFile) { 309 sys::Path uniqueFile(Bytecode+".cbe.c"); 310 uniqueFile.makeUnique(); 311 OutputCFile = uniqueFile; 312 std::vector<const char *> LLCArgs; 313 LLCArgs.push_back (LLCPath.c_str()); 314 315 // Add any extra LLC args. 316 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 317 LLCArgs.push_back(ToolArgs[i].c_str()); 318 319 LLCArgs.push_back ("-o"); 320 LLCArgs.push_back (OutputCFile.c_str()); // Output to the C file 321 LLCArgs.push_back ("-march=c"); // Output C language 322 LLCArgs.push_back ("-f"); // Overwrite as necessary... 323 LLCArgs.push_back (Bytecode.c_str()); // This is the input bytecode 324 LLCArgs.push_back (0); 325 326 std::cout << "<cbe>" << std::flush; 327 DEBUG(std::cerr << "\nAbout to run:\t"; 328 for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) 329 std::cerr << " " << LLCArgs[i]; 330 std::cerr << "\n"; 331 ); 332 if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(), 333 sys::Path())) 334 ProcessFailure(LLCPath, &LLCArgs[0]); 335} 336 337void CBE::compileProgram(const std::string &Bytecode) { 338 sys::Path OutputCFile; 339 OutputC(Bytecode, OutputCFile); 340 OutputCFile.eraseFromDisk(); 341} 342 343int CBE::ExecuteProgram(const std::string &Bytecode, 344 const std::vector<std::string> &Args, 345 const std::string &InputFile, 346 const std::string &OutputFile, 347 const std::vector<std::string> &ArgsForGCC, 348 const std::vector<std::string> &SharedLibs, 349 unsigned Timeout) { 350 sys::Path OutputCFile; 351 OutputC(Bytecode, OutputCFile); 352 353 FileRemover CFileRemove(OutputCFile); 354 355 std::vector<std::string> GCCArgs(ArgsForGCC); 356 GCCArgs.insert(GCCArgs.end(),SharedLibs.begin(),SharedLibs.end()); 357 return gcc->ExecuteProgram(OutputCFile.toString(), Args, GCC::CFile, 358 InputFile, OutputFile, GCCArgs, Timeout); 359} 360 361/// createCBE - Try to find the 'llc' executable 362/// 363CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath, 364 std::string &Message, 365 const std::vector<std::string> *Args) { 366 sys::Path LLCPath = FindExecutable("llc", ProgramPath); 367 if (LLCPath.isEmpty()) { 368 Message = 369 "Cannot find `llc' in executable directory or PATH!\n"; 370 return 0; 371 } 372 373 Message = "Found llc: " + LLCPath.toString() + "\n"; 374 GCC *gcc = GCC::create(ProgramPath, Message); 375 if (!gcc) { 376 std::cerr << Message << "\n"; 377 exit(1); 378 } 379 return new CBE(LLCPath, gcc, Args); 380} 381 382//===---------------------------------------------------------------------===// 383// GCC abstraction 384// 385int GCC::ExecuteProgram(const std::string &ProgramFile, 386 const std::vector<std::string> &Args, 387 FileType fileType, 388 const std::string &InputFile, 389 const std::string &OutputFile, 390 const std::vector<std::string> &ArgsForGCC, 391 unsigned Timeout ) { 392 std::vector<const char*> GCCArgs; 393 394 GCCArgs.push_back(GCCPath.c_str()); 395 396 // Specify -x explicitly in case the extension is wonky 397 GCCArgs.push_back("-x"); 398 if (fileType == CFile) { 399 GCCArgs.push_back("c"); 400 GCCArgs.push_back("-fno-strict-aliasing"); 401 } else { 402 GCCArgs.push_back("assembler"); 403#ifdef __APPLE__ 404 GCCArgs.push_back("-force_cpusubtype_ALL"); 405#endif 406 } 407 GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename... 408 GCCArgs.push_back("-x"); 409 GCCArgs.push_back("none"); 410 GCCArgs.push_back("-o"); 411 sys::Path OutputBinary (ProgramFile+".gcc.exe"); 412 OutputBinary.makeUnique(); 413 GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file... 414 415 // Add any arguments intended for GCC. We locate them here because this is 416 // most likely -L and -l options that need to come before other libraries but 417 // after the source. Other options won't be sensitive to placement on the 418 // command line, so this should be safe. 419 for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i) 420 GCCArgs.push_back(ArgsForGCC[i].c_str()); 421 422 GCCArgs.push_back("-lm"); // Hard-code the math library... 423 GCCArgs.push_back("-O2"); // Optimize the program a bit... 424#if defined (HAVE_LINK_R) 425 GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files 426#endif 427#ifdef __sparc__ 428 GCCArgs.push_back("-mcpu=v9"); 429#endif 430 GCCArgs.push_back(0); // NULL terminator 431 432 std::cout << "<gcc>" << std::flush; 433 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), 434 sys::Path())) { 435 ProcessFailure(GCCPath, &GCCArgs[0]); 436 exit(1); 437 } 438 439 std::vector<const char*> ProgramArgs; 440 441 ProgramArgs.push_back(OutputBinary.c_str()); 442 // Add optional parameters to the running program from Argv 443 for (unsigned i=0, e = Args.size(); i != e; ++i) 444 ProgramArgs.push_back(Args[i].c_str()); 445 ProgramArgs.push_back(0); // NULL terminator 446 447 // Now that we have a binary, run it! 448 std::cout << "<program>" << std::flush; 449 DEBUG(std::cerr << "\nAbout to run:\t"; 450 for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i) 451 std::cerr << " " << ProgramArgs[i]; 452 std::cerr << "\n"; 453 ); 454 455 FileRemover OutputBinaryRemover(OutputBinary); 456 return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], 457 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), 458 Timeout); 459} 460 461int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, 462 std::string &OutputFile) { 463 sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT); 464 uniqueFilename.makeUnique(); 465 OutputFile = uniqueFilename.toString(); 466 467 // Compile the C/asm file into a shared object 468 const char* GCCArgs[] = { 469 GCCPath.c_str(), 470 "-x", (fileType == AsmFile) ? "assembler" : "c", 471 "-fno-strict-aliasing", 472 InputFile.c_str(), // Specify the input filename... 473#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) 474 "-G", // Compile a shared library, `-G' for Sparc 475#elif defined(__APPLE__) 476 "-single_module", // link all source files into a single module 477 "-dynamiclib", // `-dynamiclib' for MacOS X/PowerPC 478 "-undefined", // in data segment, rather than generating 479 "dynamic_lookup", // blocks. dynamic_lookup requires that you set 480 // MACOSX_DEPLOYMENT_TARGET=10.3 in your env. 481#else 482 "-shared", // `-shared' for Linux/X86, maybe others 483#endif 484 485#if defined(__ia64__) || defined(__alpha__) 486 "-fPIC", // IA64 requires shared objs to contain PIC 487#endif 488#ifdef __sparc__ 489 "-mcpu=v9", 490#endif 491 "-o", OutputFile.c_str(), // Output to the right filename... 492 "-O2", // Optimize the program a bit... 493 0 494 }; 495 496 std::cout << "<gcc>" << std::flush; 497 if (RunProgramWithTimeout(GCCPath, GCCArgs, sys::Path(), sys::Path(), 498 sys::Path())) { 499 ProcessFailure(GCCPath, GCCArgs); 500 return 1; 501 } 502 return 0; 503} 504 505/// create - Try to find the `gcc' executable 506/// 507GCC *GCC::create(const std::string &ProgramPath, std::string &Message) { 508 sys::Path GCCPath = FindExecutable("gcc", ProgramPath); 509 if (GCCPath.isEmpty()) { 510 Message = "Cannot find `gcc' in executable directory or PATH!\n"; 511 return 0; 512 } 513 514 Message = "Found gcc: " + GCCPath.toString() + "\n"; 515 return new GCC(GCCPath); 516} 517