ExecutionDriver.cpp revision 248d1c65f1ce5bc04b892998b2c2061e6a5f8e1c
1//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file contains code used to execute the program utilizing one of the 11// various ways of running LLVM bitcode. 12// 13//===----------------------------------------------------------------------===// 14 15#include "BugDriver.h" 16#include "ToolRunner.h" 17#include "llvm/Support/CommandLine.h" 18#include "llvm/Support/Debug.h" 19#include "llvm/Support/FileUtilities.h" 20#include "llvm/Support/SystemUtils.h" 21#include "llvm/Support/raw_ostream.h" 22#include <fstream> 23 24using namespace llvm; 25 26namespace { 27 // OutputType - Allow the user to specify the way code should be run, to test 28 // for miscompilation. 29 // 30 enum OutputType { 31 AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, RunCBE, CBE_bug, LLC_Safe,Custom 32 }; 33 34 cl::opt<double> 35 AbsTolerance("abs-tolerance", cl::desc("Absolute error tolerated"), 36 cl::init(0.0)); 37 cl::opt<double> 38 RelTolerance("rel-tolerance", cl::desc("Relative error tolerated"), 39 cl::init(0.0)); 40 41 cl::opt<OutputType> 42 InterpreterSel(cl::desc("Specify the \"test\" i.e. suspect back-end:"), 43 cl::values(clEnumValN(AutoPick, "auto", "Use best guess"), 44 clEnumValN(RunLLI, "run-int", 45 "Execute with the interpreter"), 46 clEnumValN(RunJIT, "run-jit", "Execute with JIT"), 47 clEnumValN(RunLLC, "run-llc", "Compile with LLC"), 48 clEnumValN(RunLLCIA, "run-llc-ia", 49 "Compile with LLC with integrated assembler"), 50 clEnumValN(RunCBE, "run-cbe", "Compile with CBE"), 51 clEnumValN(CBE_bug,"cbe-bug", "Find CBE bugs"), 52 clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"), 53 clEnumValN(Custom, "run-custom", 54 "Use -exec-command to define a command to execute " 55 "the bitcode. Useful for cross-compilation."), 56 clEnumValEnd), 57 cl::init(AutoPick)); 58 59 cl::opt<OutputType> 60 SafeInterpreterSel(cl::desc("Specify \"safe\" i.e. known-good backend:"), 61 cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"), 62 clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"), 63 clEnumValN(RunCBE, "safe-run-cbe", "Compile with CBE"), 64 clEnumValN(Custom, "safe-run-custom", 65 "Use -exec-command to define a command to execute " 66 "the bitcode. Useful for cross-compilation."), 67 clEnumValEnd), 68 cl::init(AutoPick)); 69 70 cl::opt<std::string> 71 SafeInterpreterPath("safe-path", 72 cl::desc("Specify the path to the \"safe\" backend program"), 73 cl::init("")); 74 75 cl::opt<bool> 76 AppendProgramExitCode("append-exit-code", 77 cl::desc("Append the exit code to the output so it gets diff'd too"), 78 cl::init(false)); 79 80 cl::opt<std::string> 81 InputFile("input", cl::init("/dev/null"), 82 cl::desc("Filename to pipe in as stdin (default: /dev/null)")); 83 84 cl::list<std::string> 85 AdditionalSOs("additional-so", 86 cl::desc("Additional shared objects to load " 87 "into executing programs")); 88 89 cl::list<std::string> 90 AdditionalLinkerArgs("Xlinker", 91 cl::desc("Additional arguments to pass to the linker")); 92 93 cl::opt<std::string> 94 CustomExecCommand("exec-command", cl::init("simulate"), 95 cl::desc("Command to execute the bitcode (use with -run-custom) " 96 "(default: simulate)")); 97} 98 99namespace llvm { 100 // Anything specified after the --args option are taken as arguments to the 101 // program being debugged. 102 cl::list<std::string> 103 InputArgv("args", cl::Positional, cl::desc("<program arguments>..."), 104 cl::ZeroOrMore, cl::PositionalEatsArgs); 105 106 cl::opt<std::string> 107 OutputPrefix("output-prefix", cl::init("bugpoint"), 108 cl::desc("Prefix to use for outputs (default: 'bugpoint')")); 109} 110 111namespace { 112 cl::list<std::string> 113 ToolArgv("tool-args", cl::Positional, cl::desc("<tool arguments>..."), 114 cl::ZeroOrMore, cl::PositionalEatsArgs); 115 116 cl::list<std::string> 117 SafeToolArgv("safe-tool-args", cl::Positional, 118 cl::desc("<safe-tool arguments>..."), 119 cl::ZeroOrMore, cl::PositionalEatsArgs); 120 121 cl::opt<std::string> 122 GCCBinary("gcc", cl::init("gcc"), 123 cl::desc("The gcc binary to use. (default 'gcc')")); 124 125 cl::list<std::string> 126 GCCToolArgv("gcc-tool-args", cl::Positional, 127 cl::desc("<gcc-tool arguments>..."), 128 cl::ZeroOrMore, cl::PositionalEatsArgs); 129} 130 131//===----------------------------------------------------------------------===// 132// BugDriver method implementation 133// 134 135/// initializeExecutionEnvironment - This method is used to set up the 136/// environment for executing LLVM programs. 137/// 138bool BugDriver::initializeExecutionEnvironment() { 139 outs() << "Initializing execution environment: "; 140 141 // Create an instance of the AbstractInterpreter interface as specified on 142 // the command line 143 SafeInterpreter = 0; 144 std::string Message; 145 146 switch (InterpreterSel) { 147 case AutoPick: 148 InterpreterSel = RunCBE; 149 Interpreter = 150 AbstractInterpreter::createCBE(getToolName(), Message, GCCBinary, 151 &ToolArgv, &GCCToolArgv); 152 if (!Interpreter) { 153 InterpreterSel = RunJIT; 154 Interpreter = AbstractInterpreter::createJIT(getToolName(), Message, 155 &ToolArgv); 156 } 157 if (!Interpreter) { 158 InterpreterSel = RunLLC; 159 Interpreter = AbstractInterpreter::createLLC(getToolName(), Message, 160 GCCBinary, &ToolArgv, 161 &GCCToolArgv); 162 } 163 if (!Interpreter) { 164 InterpreterSel = RunLLI; 165 Interpreter = AbstractInterpreter::createLLI(getToolName(), Message, 166 &ToolArgv); 167 } 168 if (!Interpreter) { 169 InterpreterSel = AutoPick; 170 Message = "Sorry, I can't automatically select an interpreter!\n"; 171 } 172 break; 173 case RunLLI: 174 Interpreter = AbstractInterpreter::createLLI(getToolName(), Message, 175 &ToolArgv); 176 break; 177 case RunLLC: 178 case RunLLCIA: 179 case LLC_Safe: 180 Interpreter = AbstractInterpreter::createLLC(getToolName(), Message, 181 GCCBinary, &ToolArgv, 182 &GCCToolArgv, 183 InterpreterSel == RunLLCIA); 184 break; 185 case RunJIT: 186 Interpreter = AbstractInterpreter::createJIT(getToolName(), Message, 187 &ToolArgv); 188 break; 189 case RunCBE: 190 case CBE_bug: 191 Interpreter = AbstractInterpreter::createCBE(getToolName(), Message, 192 GCCBinary, &ToolArgv, 193 &GCCToolArgv); 194 break; 195 case Custom: 196 Interpreter = AbstractInterpreter::createCustom(Message, CustomExecCommand); 197 break; 198 default: 199 Message = "Sorry, this back-end is not supported by bugpoint right now!\n"; 200 break; 201 } 202 if (!Interpreter) 203 errs() << Message; 204 else // Display informational messages on stdout instead of stderr 205 outs() << Message; 206 207 std::string Path = SafeInterpreterPath; 208 if (Path.empty()) 209 Path = getToolName(); 210 std::vector<std::string> SafeToolArgs = SafeToolArgv; 211 switch (SafeInterpreterSel) { 212 case AutoPick: 213 // In "cbe-bug" mode, default to using LLC as the "safe" backend. 214 if (!SafeInterpreter && 215 InterpreterSel == CBE_bug) { 216 SafeInterpreterSel = RunLLC; 217 SafeToolArgs.push_back("--relocation-model=pic"); 218 SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, 219 GCCBinary, 220 &SafeToolArgs, 221 &GCCToolArgv); 222 } 223 224 // In "llc-safe" mode, default to using LLC as the "safe" backend. 225 if (!SafeInterpreter && 226 InterpreterSel == LLC_Safe) { 227 SafeInterpreterSel = RunLLC; 228 SafeToolArgs.push_back("--relocation-model=pic"); 229 SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, 230 GCCBinary, 231 &SafeToolArgs, 232 &GCCToolArgv); 233 } 234 235 // Pick a backend that's different from the test backend. The JIT and 236 // LLC backends share a lot of code, so prefer to use the CBE as the 237 // safe back-end when testing them. 238 if (!SafeInterpreter && 239 InterpreterSel != RunCBE) { 240 SafeInterpreterSel = RunCBE; 241 SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message, 242 GCCBinary, 243 &SafeToolArgs, 244 &GCCToolArgv); 245 } 246 if (!SafeInterpreter && 247 InterpreterSel != RunLLC && 248 InterpreterSel != RunJIT) { 249 SafeInterpreterSel = RunLLC; 250 SafeToolArgs.push_back("--relocation-model=pic"); 251 SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, 252 GCCBinary, 253 &SafeToolArgs, 254 &GCCToolArgv); 255 } 256 if (!SafeInterpreter) { 257 SafeInterpreterSel = AutoPick; 258 Message = "Sorry, I can't automatically select an interpreter!\n"; 259 } 260 break; 261 case RunLLC: 262 case RunLLCIA: 263 SafeToolArgs.push_back("--relocation-model=pic"); 264 SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, 265 GCCBinary, &SafeToolArgs, 266 &GCCToolArgv, 267 SafeInterpreterSel == RunLLCIA); 268 break; 269 case RunCBE: 270 SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message, 271 GCCBinary, &SafeToolArgs, 272 &GCCToolArgv); 273 break; 274 case Custom: 275 SafeInterpreter = AbstractInterpreter::createCustom(Message, 276 CustomExecCommand); 277 break; 278 default: 279 Message = "Sorry, this back-end is not supported by bugpoint as the " 280 "\"safe\" backend right now!\n"; 281 break; 282 } 283 if (!SafeInterpreter) { outs() << Message << "\nExiting.\n"; exit(1); } 284 285 gcc = GCC::create(Message, GCCBinary, &GCCToolArgv); 286 if (!gcc) { outs() << Message << "\nExiting.\n"; exit(1); } 287 288 // If there was an error creating the selected interpreter, quit with error. 289 return Interpreter == 0; 290} 291 292/// compileProgram - Try to compile the specified module, returning false and 293/// setting Error if an error occurs. This is used for code generation 294/// crash testing. 295/// 296void BugDriver::compileProgram(Module *M, std::string *Error) const { 297 // Emit the program to a bitcode file... 298 sys::Path BitcodeFile (OutputPrefix + "-test-program.bc"); 299 std::string ErrMsg; 300 if (BitcodeFile.makeUnique(true, &ErrMsg)) { 301 errs() << ToolName << ": Error making unique filename: " << ErrMsg 302 << "\n"; 303 exit(1); 304 } 305 if (writeProgramToFile(BitcodeFile.str(), M)) { 306 errs() << ToolName << ": Error emitting bitcode to file '" 307 << BitcodeFile.str() << "'!\n"; 308 exit(1); 309 } 310 311 // Remove the temporary bitcode file when we are done. 312 FileRemover BitcodeFileRemover(BitcodeFile, !SaveTemps); 313 314 // Actually compile the program! 315 Interpreter->compileProgram(BitcodeFile.str(), Error, Timeout, MemoryLimit); 316} 317 318 319/// executeProgram - This method runs "Program", capturing the output of the 320/// program to a file, returning the filename of the file. A recommended 321/// filename may be optionally specified. 322/// 323std::string BugDriver::executeProgram(const Module *Program, 324 std::string OutputFile, 325 std::string BitcodeFile, 326 const std::string &SharedObj, 327 AbstractInterpreter *AI, 328 std::string *Error) const { 329 if (AI == 0) AI = Interpreter; 330 assert(AI && "Interpreter should have been created already!"); 331 bool CreatedBitcode = false; 332 std::string ErrMsg; 333 if (BitcodeFile.empty()) { 334 // Emit the program to a bitcode file... 335 sys::Path uniqueFilename(OutputPrefix + "-test-program.bc"); 336 if (uniqueFilename.makeUnique(true, &ErrMsg)) { 337 errs() << ToolName << ": Error making unique filename: " 338 << ErrMsg << "!\n"; 339 exit(1); 340 } 341 BitcodeFile = uniqueFilename.str(); 342 343 if (writeProgramToFile(BitcodeFile, Program)) { 344 errs() << ToolName << ": Error emitting bitcode to file '" 345 << BitcodeFile << "'!\n"; 346 exit(1); 347 } 348 CreatedBitcode = true; 349 } 350 351 // Remove the temporary bitcode file when we are done. 352 sys::Path BitcodePath(BitcodeFile); 353 FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps); 354 355 if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output"; 356 357 // Check to see if this is a valid output filename... 358 sys::Path uniqueFile(OutputFile); 359 if (uniqueFile.makeUnique(true, &ErrMsg)) { 360 errs() << ToolName << ": Error making unique filename: " 361 << ErrMsg << "\n"; 362 exit(1); 363 } 364 OutputFile = uniqueFile.str(); 365 366 // Figure out which shared objects to run, if any. 367 std::vector<std::string> SharedObjs(AdditionalSOs); 368 if (!SharedObj.empty()) 369 SharedObjs.push_back(SharedObj); 370 371 int RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile, OutputFile, 372 Error, AdditionalLinkerArgs, SharedObjs, 373 Timeout, MemoryLimit); 374 if (!Error->empty()) 375 return OutputFile; 376 377 if (RetVal == -1) { 378 errs() << "<timeout>"; 379 static bool FirstTimeout = true; 380 if (FirstTimeout) { 381 outs() << "\n" 382 "*** Program execution timed out! This mechanism is designed to handle\n" 383 " programs stuck in infinite loops gracefully. The -timeout option\n" 384 " can be used to change the timeout threshold or disable it completely\n" 385 " (with -timeout=0). This message is only displayed once.\n"; 386 FirstTimeout = false; 387 } 388 } 389 390 if (AppendProgramExitCode) { 391 std::ofstream outFile(OutputFile.c_str(), std::ios_base::app); 392 outFile << "exit " << RetVal << '\n'; 393 outFile.close(); 394 } 395 396 // Return the filename we captured the output to. 397 return OutputFile; 398} 399 400/// executeProgramSafely - Used to create reference output with the "safe" 401/// backend, if reference output is not provided. 402/// 403std::string BugDriver::executeProgramSafely(const Module *Program, 404 std::string OutputFile, 405 std::string *Error) const { 406 return executeProgram(Program, OutputFile, "", "", SafeInterpreter, Error); 407} 408 409std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, 410 std::string &Error) { 411 assert(Interpreter && "Interpreter should have been created already!"); 412 sys::Path OutputFile; 413 414 // Using the known-good backend. 415 GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile, 416 Error); 417 if (!Error.empty()) 418 return ""; 419 420 std::string SharedObjectFile; 421 bool Failure = gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile, 422 AdditionalLinkerArgs, Error); 423 if (!Error.empty()) 424 return ""; 425 if (Failure) 426 exit(1); 427 428 // Remove the intermediate C file 429 OutputFile.eraseFromDisk(); 430 431 return "./" + SharedObjectFile; 432} 433 434/// createReferenceFile - calls compileProgram and then records the output 435/// into ReferenceOutputFile. Returns true if reference file created, false 436/// otherwise. Note: initializeExecutionEnvironment should be called BEFORE 437/// this function. 438/// 439bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { 440 std::string Error; 441 compileProgram(Program, &Error); 442 if (!Error.empty()) 443 return false; 444 445 ReferenceOutputFile = executeProgramSafely(Program, Filename, &Error); 446 if (!Error.empty()) { 447 errs() << Error; 448 if (Interpreter != SafeInterpreter) { 449 errs() << "*** There is a bug running the \"safe\" backend. Either" 450 << " debug it (for example with the -run-cbe bugpoint option," 451 << " if CBE is being used as the \"safe\" backend), or fix the" 452 << " error some other way.\n"; 453 } 454 return false; 455 } 456 outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n"; 457 return true; 458} 459 460/// diffProgram - This method executes the specified module and diffs the 461/// output against the file specified by ReferenceOutputFile. If the output 462/// is different, 1 is returned. If there is a problem with the code 463/// generator (e.g., llc crashes), this will return -1 and set Error. 464/// 465bool BugDriver::diffProgram(const Module *Program, 466 const std::string &BitcodeFile, 467 const std::string &SharedObject, 468 bool RemoveBitcode, 469 std::string *ErrMsg) const { 470 // Execute the program, generating an output file... 471 sys::Path Output(executeProgram(Program, "", BitcodeFile, SharedObject, 0, 472 ErrMsg)); 473 if (!ErrMsg->empty()) 474 return false; 475 476 std::string Error; 477 bool FilesDifferent = false; 478 if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile), 479 sys::Path(Output.str()), 480 AbsTolerance, RelTolerance, &Error)) { 481 if (Diff == 2) { 482 errs() << "While diffing output: " << Error << '\n'; 483 exit(1); 484 } 485 FilesDifferent = true; 486 } 487 else { 488 // Remove the generated output if there are no differences. 489 Output.eraseFromDisk(); 490 } 491 492 // Remove the bitcode file if we are supposed to. 493 if (RemoveBitcode) 494 sys::Path(BitcodeFile).eraseFromDisk(); 495 return FilesDifferent; 496} 497 498bool BugDriver::isExecutingJIT() { 499 return InterpreterSel == RunJIT; 500} 501 502