1 //===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
3 // This file contains code used to execute the program utilizing one of the
4 // various ways of running LLVM bytecode.
6 //===----------------------------------------------------------------------===//
11 1. Bugpoint should not leave any files behind if the program works properly
12 2. There should be an option to specify the program name, which specifies a
13 unique string to put into output files. This allows operation in the
14 SingleSource directory, e.g. default to the first input filename.
17 #include "BugDriver.h"
18 #include "SystemUtils.h"
19 #include "Support/CommandLine.h"
20 #include "Support/Statistic.h"
25 // OutputType - Allow the user to specify the way code should be run, to test
26 // for miscompilation.
29 RunLLI, RunJIT, RunLLC, RunCBE
32 InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
33 cl::values(clEnumValN(RunLLI, "run-lli", "Execute with LLI"),
34 clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
35 clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
36 clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
40 InputFile("input", cl::init("/dev/null"),
41 cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
43 enum FileType { AsmFile, CFile };
46 /// AbstractInterpreter Class - Subclasses of this class are used to execute
47 /// LLVM bytecode in a variety of ways. This abstract interface hides this
48 /// complexity behind a simple interface.
50 struct AbstractInterpreter {
52 virtual ~AbstractInterpreter() {}
54 /// ExecuteProgram - Run the specified bytecode file, emitting output to the
55 /// specified filename. This returns the exit code of the program.
57 virtual int ExecuteProgram(const std::string &Bytecode,
58 const std::string &OutputFile,
59 const std::string &SharedLib = "") = 0;
63 //===----------------------------------------------------------------------===//
64 // LLI Implementation of AbstractIntepreter interface
66 class LLI : public AbstractInterpreter {
67 std::string LLIPath; // The path to the LLI executable
69 LLI(const std::string &Path) : LLIPath(Path) { }
71 // LLI create method - Try to find the LLI executable
72 static LLI *create(BugDriver *BD, std::string &Message) {
73 std::string LLIPath = FindExecutable("lli", BD->getToolName());
74 if (!LLIPath.empty()) {
75 Message = "Found lli: " + LLIPath + "\n";
76 return new LLI(LLIPath);
79 Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
82 virtual int ExecuteProgram(const std::string &Bytecode,
83 const std::string &OutputFile,
84 const std::string &SharedLib = "");
87 int LLI::ExecuteProgram(const std::string &Bytecode,
88 const std::string &OutputFile,
89 const std::string &SharedLib) {
90 if (!SharedLib.empty()) {
91 std::cerr << "LLI currently does not support loading shared libraries.\n"
96 const char *Args[] = {
98 "-abort-on-exception",
100 "-force-interpreter=true",
105 std::cout << "<lli>";
106 return RunProgramWithTimeout(LLIPath, Args,
107 InputFile, OutputFile, OutputFile);
110 //===----------------------------------------------------------------------===//
113 // This is not a *real* AbstractInterpreter as it does not accept bytecode
114 // files, but only input acceptable to GCC, i.e. C, C++, and assembly files
117 std::string GCCPath; // The path to the gcc executable
119 GCC(const std::string &gccPath) : GCCPath(gccPath) { }
122 // GCC create method - Try to find the `gcc' executable
123 static GCC *create(BugDriver *BD, std::string &Message) {
124 std::string GCCPath = FindExecutable("gcc", BD->getToolName());
125 if (GCCPath.empty()) {
126 Message = "Cannot find `gcc' in bugpoint executable directory or PATH!\n";
130 Message = "Found gcc: " + GCCPath + "\n";
131 return new GCC(GCCPath);
134 virtual int ExecuteProgram(const std::string &ProgramFile,
136 const std::string &OutputFile,
137 const std::string &SharedLib = "");
139 int MakeSharedObject(const std::string &InputFile,
141 std::string &OutputFile);
143 void ProcessFailure(const char **Args);
146 int GCC::ExecuteProgram(const std::string &ProgramFile,
148 const std::string &OutputFile,
149 const std::string &SharedLib) {
150 std::string OutputBinary = getUniqueFilename("bugpoint.gcc.exe");
151 const char **GCCArgs;
153 const char *ArgsWithoutSO[] = {
155 "-x", (fileType == AsmFile) ? "assembler" : "c",
156 ProgramFile.c_str(), // Specify the input filename...
157 "-o", OutputBinary.c_str(), // Output to the right filename...
158 "-lm", // Hard-code the math library...
159 "-O2", // Optimize the program a bit...
162 const char *ArgsWithSO[] = {
164 SharedLib.c_str(), // Specify the shared library to link in...
165 "-x", (fileType == AsmFile) ? "assembler" : "c",
166 ProgramFile.c_str(), // Specify the input filename...
167 "-o", OutputBinary.c_str(), // Output to the right filename...
168 "-lm", // Hard-code the math library...
169 "-O2", // Optimize the program a bit...
173 GCCArgs = (SharedLib.empty()) ? ArgsWithoutSO : ArgsWithSO;
174 std::cout << "<gcc>";
175 if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
177 ProcessFailure(GCCArgs);
181 const char *ProgramArgs[] = {
182 OutputBinary.c_str(),
186 // Now that we have a binary, run it!
187 std::cout << "<program>";
188 int ProgramResult = RunProgramWithTimeout(OutputBinary, ProgramArgs,
189 InputFile, OutputFile, OutputFile);
191 removeFile(OutputBinary);
192 return ProgramResult;
195 int GCC::MakeSharedObject(const std::string &InputFile,
197 std::string &OutputFile) {
198 OutputFile = getUniqueFilename("./bugpoint.so");
199 // Compile the C/asm file into a shared object
200 const char* GCCArgs[] = {
202 "-x", (fileType == AsmFile) ? "assembler" : "c",
203 InputFile.c_str(), // Specify the input filename...
204 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
205 "-G", // Compile a shared library, `-G' for Sparc
207 "-shared", // `-shared' for Linux/X86, maybe others
209 "-o", OutputFile.c_str(), // Output to the right filename...
210 "-O2", // Optimize the program a bit...
214 std::cout << "<gcc>";
215 if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
217 ProcessFailure(GCCArgs);
223 void GCC::ProcessFailure(const char** GCCArgs) {
224 std::cerr << "\n*** bugpoint error: invocation of the C compiler failed!\n";
225 for (const char **Arg = GCCArgs; *Arg; ++Arg)
226 std::cerr << " " << *Arg;
229 // Rerun the compiler, capturing any error messages to print them.
230 std::string ErrorFilename = getUniqueFilename("bugpoint.gcc.errors");
231 RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
232 ErrorFilename.c_str());
234 // Print out the error messages generated by GCC if possible...
235 std::ifstream ErrorFile(ErrorFilename.c_str());
237 std::copy(std::istreambuf_iterator<char>(ErrorFile),
238 std::istreambuf_iterator<char>(),
239 std::ostreambuf_iterator<char>(std::cerr));
244 removeFile(ErrorFilename);
247 //===----------------------------------------------------------------------===//
248 // LLC Implementation of AbstractIntepreter interface
250 class LLC : public AbstractInterpreter {
251 std::string LLCPath; // The path to the LLC executable
254 LLC(const std::string &llcPath, GCC *Gcc)
255 : LLCPath(llcPath), gcc(Gcc) { }
256 ~LLC() { delete gcc; }
258 // LLC create method - Try to find the LLC executable
259 static LLC *create(BugDriver *BD, std::string &Message) {
260 std::string LLCPath = FindExecutable("llc", BD->getToolName());
261 if (LLCPath.empty()) {
262 Message = "Cannot find `llc' in bugpoint executable directory or PATH!\n";
266 Message = "Found llc: " + LLCPath + "\n";
267 GCC *gcc = GCC::create(BD, Message);
269 std::cerr << Message << "\n";
272 return new LLC(LLCPath, gcc);
275 virtual int ExecuteProgram(const std::string &Bytecode,
276 const std::string &OutputFile,
277 const std::string &SharedLib = "");
279 int OutputAsm(const std::string &Bytecode,
280 std::string &OutputAsmFile);
283 int LLC::OutputAsm(const std::string &Bytecode,
284 std::string &OutputAsmFile) {
285 OutputAsmFile = "bugpoint.llc.s";
286 const char *LLCArgs[] = {
288 "-o", OutputAsmFile.c_str(), // Output to the Asm file
289 "-f", // Overwrite as necessary...
290 Bytecode.c_str(), // This is the input bytecode
294 std::cout << "<llc>";
295 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
297 // If LLC failed on the bytecode, print error...
298 std::cerr << "bugpoint error: `llc' failed!\n";
299 removeFile(OutputAsmFile);
306 int LLC::ExecuteProgram(const std::string &Bytecode,
307 const std::string &OutputFile,
308 const std::string &SharedLib) {
310 std::string OutputAsmFile;
311 if (OutputAsm(Bytecode, OutputAsmFile)) {
312 std::cerr << "Could not generate asm code with `llc', exiting.\n";
316 // Assuming LLC worked, compile the result with GCC and run it.
317 int Result = gcc->ExecuteProgram(OutputAsmFile,AsmFile,OutputFile,SharedLib);
318 removeFile(OutputAsmFile);
323 //===----------------------------------------------------------------------===//
324 // JIT Implementation of AbstractIntepreter interface
326 class JIT : public AbstractInterpreter {
327 std::string LLIPath; // The path to the LLI executable
329 JIT(const std::string &Path) : LLIPath(Path) { }
331 // JIT create method - Try to find the LLI executable
332 static JIT *create(BugDriver *BD, std::string &Message) {
333 std::string LLIPath = FindExecutable("lli", BD->getToolName());
334 if (!LLIPath.empty()) {
335 Message = "Found lli: " + LLIPath + "\n";
336 return new JIT(LLIPath);
339 Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
342 virtual int ExecuteProgram(const std::string &Bytecode,
343 const std::string &OutputFile,
344 const std::string &SharedLib = "");
347 int JIT::ExecuteProgram(const std::string &Bytecode,
348 const std::string &OutputFile,
349 const std::string &SharedLib) {
350 const char* ArgsWithoutSO[] = {
351 LLIPath.c_str(), "-quiet", "-force-interpreter=false",
356 const char* ArgsWithSO[] = {
357 LLIPath.c_str(), "-quiet", "-force-interpreter=false",
358 "-load", SharedLib.c_str(),
363 const char** JITArgs = SharedLib.empty() ? ArgsWithoutSO : ArgsWithSO;
365 std::cout << "<jit>";
366 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
367 return RunProgramWithTimeout(LLIPath, JITArgs,
368 InputFile, OutputFile, OutputFile);
371 //===----------------------------------------------------------------------===//
372 // CBE Implementation of AbstractIntepreter interface
374 class CBE : public AbstractInterpreter {
375 std::string DISPath; // The path to the LLVM 'dis' executable
378 CBE(const std::string &disPath, GCC *Gcc) : DISPath(disPath), gcc(Gcc) { }
379 ~CBE() { delete gcc; }
381 // CBE create method - Try to find the 'dis' executable
382 static CBE *create(BugDriver *BD, std::string &Message) {
383 std::string DISPath = FindExecutable("dis", BD->getToolName());
384 if (DISPath.empty()) {
385 Message = "Cannot find `dis' in bugpoint executable directory or PATH!\n";
389 Message = "Found dis: " + DISPath + "\n";
391 GCC *gcc = GCC::create(BD, Message);
393 std::cerr << Message << "\n";
396 return new CBE(DISPath, gcc);
399 virtual int ExecuteProgram(const std::string &Bytecode,
400 const std::string &OutputFile,
401 const std::string &SharedLib = "");
403 // Sometimes we just want to go half-way and only generate the C file,
404 // not necessarily compile it with GCC and run the program
405 virtual int OutputC(const std::string &Bytecode,
406 std::string &OutputCFile);
410 int CBE::OutputC(const std::string &Bytecode,
411 std::string &OutputCFile) {
412 OutputCFile = "bugpoint.cbe.c";
413 const char *DisArgs[] = {
415 "-o", OutputCFile.c_str(), // Output to the C file
417 "-f", // Overwrite as necessary...
418 Bytecode.c_str(), // This is the input bytecode
422 std::cout << "<cbe>";
423 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
425 // If dis failed on the bytecode, print error...
426 std::cerr << "bugpoint error: `dis -c' failed!\n";
434 int CBE::ExecuteProgram(const std::string &Bytecode,
435 const std::string &OutputFile,
436 const std::string &SharedLib) {
437 std::string OutputCFile;
438 if (OutputC(Bytecode, OutputCFile)) {
439 std::cerr << "Could not generate C code with `dis', exiting.\n";
443 int Result = gcc->ExecuteProgram(OutputCFile, CFile, OutputFile, SharedLib);
444 removeFile(OutputCFile);
450 //===----------------------------------------------------------------------===//
451 // BugDriver method implementation
454 /// initializeExecutionEnvironment - This method is used to set up the
455 /// environment for executing LLVM programs.
457 bool BugDriver::initializeExecutionEnvironment() {
458 std::cout << "Initializing execution environment: ";
460 // FIXME: This should default to searching for the best interpreter to use on
461 // this platform, which would be JIT, then LLC, then CBE, then LLI.
463 // Create an instance of the AbstractInterpreter interface as specified on the
466 switch (InterpreterSel) {
467 case RunLLI: Interpreter = LLI::create(this, Message); break;
468 case RunLLC: Interpreter = LLC::create(this, Message); break;
469 case RunJIT: Interpreter = JIT::create(this, Message); break;
470 case RunCBE: Interpreter = CBE::create(this, Message); break;
472 Message = " Sorry, this back-end is not supported by bugpoint right now!\n";
476 std::cout << Message;
478 // Initialize auxiliary tools for debugging
479 cbe = CBE::create(this, Message);
480 if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
481 gcc = GCC::create(this, Message);
482 if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
484 // If there was an error creating the selected interpreter, quit with error.
485 return Interpreter == 0;
489 /// executeProgram - This method runs "Program", capturing the output of the
490 /// program to a file, returning the filename of the file. A recommended
491 /// filename may be optionally specified.
493 std::string BugDriver::executeProgram(std::string OutputFile,
494 std::string BytecodeFile,
495 std::string SharedObject,
496 AbstractInterpreter *AI) {
497 assert((Interpreter || AI) &&"Interpreter should have been created already!");
498 bool CreatedBytecode = false;
499 if (BytecodeFile.empty()) {
500 // Emit the program to a bytecode file...
501 BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
503 if (writeProgramToFile(BytecodeFile, Program)) {
504 std::cerr << ToolName << ": Error emitting bytecode to file '"
505 << BytecodeFile << "'!\n";
508 CreatedBytecode = true;
511 if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
513 // Check to see if this is a valid output filename...
514 OutputFile = getUniqueFilename(OutputFile);
516 // Actually execute the program!
517 int RetVal = (AI != 0) ?
518 AI->ExecuteProgram(BytecodeFile, OutputFile, SharedObject) :
519 Interpreter->ExecuteProgram(BytecodeFile, OutputFile, SharedObject);
521 // Remove the temporary bytecode file.
522 if (CreatedBytecode) removeFile(BytecodeFile);
524 // Return the filename we captured the output to.
528 std::string BugDriver::executeProgramWithCBE(std::string OutputFile,
529 std::string BytecodeFile,
530 std::string SharedObject) {
531 return executeProgram(OutputFile, BytecodeFile, SharedObject, cbe);
534 int BugDriver::compileSharedObject(const std::string &BytecodeFile,
535 std::string &SharedObject) {
536 assert(Interpreter && "Interpreter should have been created already!");
537 std::string Message, OutputCFile;
540 cbe->OutputC(BytecodeFile, OutputCFile);
542 #if 0 /* This is an alternative, as yet unimplemented */
544 LLC *llc = LLC::create(this, Message);
545 if (llc->OutputAsm(BytecodeFile, OutputFile)) {
546 std::cerr << "Could not generate asm code with `llc', exiting.\n";
551 gcc->MakeSharedObject(OutputCFile, CFile, SharedObject);
553 // Remove the intermediate C file
554 removeFile(OutputCFile);
560 /// diffProgram - This method executes the specified module and diffs the output
561 /// against the file specified by ReferenceOutputFile. If the output is
562 /// different, true is returned.
564 bool BugDriver::diffProgram(const std::string &BytecodeFile,
565 const std::string &SharedObject,
566 bool RemoveBytecode) {
567 // Execute the program, generating an output file...
568 std::string Output = executeProgram("", BytecodeFile, SharedObject);
570 std::ifstream ReferenceFile(ReferenceOutputFile.c_str());
571 if (!ReferenceFile) {
572 std::cerr << "Couldn't open reference output file '"
573 << ReferenceOutputFile << "'\n";
577 std::ifstream OutputFile(Output.c_str());
579 std::cerr << "Couldn't open output file: " << Output << "'!\n";
583 bool FilesDifferent = false;
585 // Compare the two files...
588 C1 = ReferenceFile.get();
589 C2 = OutputFile.get();
590 if (C1 != C2) { FilesDifferent = true; break; }
593 //removeFile(Output);
594 if (RemoveBytecode) removeFile(BytecodeFile);
595 return FilesDifferent;
598 bool BugDriver::isExecutingJIT() {
599 return InterpreterSel == RunJIT;