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"
24 // OutputType - Allow the user to specify the way code should be run, to test
25 // for miscompilation.
28 RunLLI, RunJIT, RunLLC, RunCBE
31 InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
32 cl::values(clEnumValN(RunLLI, "run-lli", "Execute with LLI"),
33 clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
34 clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
35 clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
39 InputFile("input", cl::init("/dev/null"),
40 cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
43 /// AbstractInterpreter Class - Subclasses of this class are used to execute
44 /// LLVM bytecode in a variety of ways. This abstract interface hides this
45 /// complexity behind a simple interface.
47 struct AbstractInterpreter {
49 virtual ~AbstractInterpreter() {}
51 /// ExecuteProgram - Run the specified bytecode file, emitting output to the
52 /// specified filename. This returns the exit code of the program.
54 virtual int ExecuteProgram(const std::string &Bytecode,
55 const std::string &OutputFile,
56 const std::string &SharedLib = "") = 0;
60 //===----------------------------------------------------------------------===//
61 // LLI Implementation of AbstractIntepreter interface
63 class LLI : public AbstractInterpreter {
64 std::string LLIPath; // The path to the LLI executable
66 LLI(const std::string &Path) : LLIPath(Path) { }
68 // LLI create method - Try to find the LLI executable
69 static LLI *create(BugDriver *BD, std::string &Message) {
70 std::string LLIPath = FindExecutable("lli", BD->getToolName());
71 if (!LLIPath.empty()) {
72 Message = "Found lli: " + LLIPath + "\n";
73 return new LLI(LLIPath);
76 Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
79 virtual int ExecuteProgram(const std::string &Bytecode,
80 const std::string &OutputFile,
81 const std::string &SharedLib = "");
84 int LLI::ExecuteProgram(const std::string &Bytecode,
85 const std::string &OutputFile,
86 const std::string &SharedLib) {
87 if (SharedLib != "") {
88 std::cerr << "LLI currently does not support loading shared libraries.\n"
93 const char *Args[] = {
95 "-abort-on-exception",
97 "-force-interpreter=true",
102 return RunProgramWithTimeout(LLIPath, Args,
103 InputFile, OutputFile, OutputFile);
106 //===----------------------------------------------------------------------===//
107 // GCC Implementation of AbstractIntepreter interface
109 // This is not a *real* AbstractInterpreter as it does not accept bytecode
110 // files, but only input acceptable to GCC, i.e. C, C++, and assembly files
112 class GCC : public AbstractInterpreter {
113 std::string GCCPath; // The path to the gcc executable
115 GCC(const std::string &gccPath) : GCCPath(gccPath) { }
117 // GCC create method - Try to find the `gcc' executable
118 static GCC *create(BugDriver *BD, std::string &Message) {
119 std::string GCCPath = FindExecutable("gcc", BD->getToolName());
120 if (GCCPath.empty()) {
121 Message = "Cannot find `gcc' in bugpoint executable directory or PATH!\n";
125 Message = "Found gcc: " + GCCPath + "\n";
126 return new GCC(GCCPath);
129 virtual int ExecuteProgram(const std::string &ProgramFile,
130 const std::string &OutputFile,
131 const std::string &SharedLib = "");
133 int MakeSharedObject(const std::string &InputFile,
134 std::string &OutputFile);
136 void ProcessFailure(const char **Args);
139 int GCC::ExecuteProgram(const std::string &ProgramFile,
140 const std::string &OutputFile,
141 const std::string &SharedLib) {
142 std::string OutputBinary = "bugpoint.gcc.exe";
143 const char **GCCArgs;
145 const char *ArgsWithoutSO[] = {
147 ProgramFile.c_str(), // Specify the input filename...
148 "-o", OutputBinary.c_str(), // Output to the right filename...
149 "-lm", // Hard-code the math library...
150 "-O2", // Optimize the program a bit...
153 const char *ArgsWithSO[] = {
155 ProgramFile.c_str(), // Specify the input filename...
156 SharedLib.c_str(), // Specify the shared library to link in...
157 "-o", OutputBinary.c_str(), // Output to the right filename...
158 "-lm", // Hard-code the math library...
159 "-O2", // Optimize the program a bit...
163 GCCArgs = (SharedLib == "") ? ArgsWithoutSO : ArgsWithSO;
164 std::cout << "<gcc>";
165 if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null",
166 "/dev/null", "/dev/null")) {
167 ProcessFailure(GCCArgs);
168 exit(1); // Leave stuff around for the user to inspect or debug the CBE
171 const char *ProgramArgs[] = {
172 OutputBinary.c_str(),
176 std::cout << "<program>";
178 // Now that we have a binary, run it!
179 int ProgramResult = RunProgramWithTimeout(OutputBinary, ProgramArgs,
180 InputFile, OutputFile, OutputFile);
182 removeFile(OutputBinary);
183 return ProgramResult;
186 int GCC::MakeSharedObject(const std::string &InputFile,
187 std::string &OutputFile) {
188 OutputFile = "./bugpoint.so";
189 // Compile the C/asm file into a shared object
190 const char* GCCArgs[] = {
192 InputFile.c_str(), // Specify the input filename...
193 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
194 "-G", // Compile a shared library, `-G' for Sparc
196 "-shared", // `-shared' for Linux/X86, maybe others
198 "-o", OutputFile.c_str(), // Output to the right filename...
199 "-O2", // Optimize the program a bit...
203 std::cout << "<gcc>";
204 if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
206 ProcessFailure(GCCArgs);
212 void GCC::ProcessFailure(const char** GCCArgs) {
213 std::cerr << "\n*** bugpoint error: invocation of the C compiler failed!\n";
214 for (const char **Arg = GCCArgs; *Arg; ++Arg)
215 std::cerr << " " << *Arg;
218 // Rerun the compiler, capturing any error messages to print them.
219 std::string ErrorFilename = getUniqueFilename("bugpoint.gcc.errors");
220 RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
221 ErrorFilename.c_str());
223 // Print out the error messages generated by GCC if possible...
224 std::ifstream ErrorFile(ErrorFilename.c_str());
226 std::copy(std::istreambuf_iterator<char>(ErrorFile),
227 std::istreambuf_iterator<char>(),
228 std::ostreambuf_iterator<char>(std::cerr));
233 removeFile(ErrorFilename);
236 //===----------------------------------------------------------------------===//
237 // LLC Implementation of AbstractIntepreter interface
239 class LLC : public AbstractInterpreter {
240 std::string LLCPath; // The path to the LLC executable
243 LLC(const std::string &llcPath, GCC *Gcc)
244 : LLCPath(llcPath), gcc(Gcc) { }
245 ~LLC() { delete gcc; }
247 // LLC create method - Try to find the LLC executable
248 static LLC *create(BugDriver *BD, std::string &Message) {
249 std::string LLCPath = FindExecutable("llc", BD->getToolName());
250 if (LLCPath.empty()) {
251 Message = "Cannot find `llc' in bugpoint executable directory or PATH!\n";
255 Message = "Found llc: " + LLCPath + "\n";
256 GCC *gcc = GCC::create(BD, Message);
257 return new LLC(LLCPath, gcc);
260 virtual int ExecuteProgram(const std::string &Bytecode,
261 const std::string &OutputFile,
262 const std::string &SharedLib = "");
264 int OutputAsm(const std::string &Bytecode,
265 std::string &OutputAsmFile);
269 int LLC::OutputAsm(const std::string &Bytecode,
270 std::string &OutputAsmFile) {
271 OutputAsmFile = "bugpoint.llc.s";
272 const char *LLCArgs[] = {
274 "-o", OutputAsmFile.c_str(), // Output to the Asm file
275 "-f", // Overwrite as necessary...
276 Bytecode.c_str(), // This is the input bytecode
280 std::cout << "<llc>";
281 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
283 // If LLC failed on the bytecode, print error...
284 std::cerr << "bugpoint error: `llc' failed!\n";
285 removeFile(OutputAsmFile);
292 int LLC::ExecuteProgram(const std::string &Bytecode,
293 const std::string &OutputFile,
294 const std::string &SharedLib) {
296 std::string OutputAsmFile;
297 if (OutputAsm(Bytecode, OutputAsmFile)) {
298 std::cerr << "Could not generate asm code with `llc', exiting.\n";
302 // Assuming LLC worked, compile the result with GCC and run it.
303 int Result = gcc->ExecuteProgram(OutputAsmFile, OutputFile, SharedLib);
304 removeFile(OutputAsmFile);
309 //===----------------------------------------------------------------------===//
310 // JIT Implementation of AbstractIntepreter interface
312 class JIT : public AbstractInterpreter {
313 std::string LLIPath; // The path to the LLI executable
315 JIT(const std::string &Path) : LLIPath(Path) { }
317 // JIT create method - Try to find the LLI executable
318 static JIT *create(BugDriver *BD, std::string &Message) {
319 std::string LLIPath = FindExecutable("lli", BD->getToolName());
320 if (!LLIPath.empty()) {
321 Message = "Found lli: " + LLIPath + "\n";
322 return new JIT(LLIPath);
325 Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
328 virtual int ExecuteProgram(const std::string &Bytecode,
329 const std::string &OutputFile,
330 const std::string &SharedLib = "");
333 int JIT::ExecuteProgram(const std::string &Bytecode,
334 const std::string &OutputFile,
335 const std::string &SharedLib) {
336 if (SharedLib == "") {
337 const char* Args[] = {
338 LLIPath.c_str(), "-quiet", "-force-interpreter=false", Bytecode.c_str(),
341 return RunProgramWithTimeout(LLIPath, Args,
342 InputFile, OutputFile, OutputFile);
344 std::string SharedLibOpt = "-load=" + SharedLib;
345 const char* Args[] = {
346 LLIPath.c_str(), "-quiet", "-force-interpreter=false",
347 SharedLibOpt.c_str(),
351 return RunProgramWithTimeout(LLIPath, Args,
352 InputFile, OutputFile, OutputFile);
356 //===----------------------------------------------------------------------===//
357 // CBE Implementation of AbstractIntepreter interface
359 class CBE : public AbstractInterpreter {
360 std::string DISPath; // The path to the LLVM 'dis' executable
363 CBE(const std::string &disPath, GCC *Gcc) : DISPath(disPath), gcc(Gcc) { }
364 ~CBE() { delete gcc; }
366 // CBE create method - Try to find the 'dis' executable
367 static CBE *create(BugDriver *BD, std::string &Message) {
368 std::string DISPath = FindExecutable("dis", BD->getToolName());
369 if (DISPath.empty()) {
370 Message = "Cannot find `dis' in bugpoint executable directory or PATH!\n";
374 Message = "Found dis: " + DISPath + "\n";
376 GCC *gcc = GCC::create(BD, Message);
377 return new CBE(DISPath, gcc);
380 virtual int ExecuteProgram(const std::string &Bytecode,
381 const std::string &OutputFile,
382 const std::string &SharedLib = "");
384 // Sometimes we just want to go half-way and only generate the C file,
385 // not necessarily compile it with GCC and run the program
386 virtual int OutputC(const std::string &Bytecode,
387 std::string &OutputCFile);
391 int CBE::OutputC(const std::string &Bytecode,
392 std::string &OutputCFile) {
393 OutputCFile = "bugpoint.cbe.c";
394 const char *DisArgs[] = {
396 "-o", OutputCFile.c_str(), // Output to the C file
398 "-f", // Overwrite as necessary...
399 Bytecode.c_str(), // This is the input bytecode
403 std::cout << "<cbe>";
404 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
406 // If dis failed on the bytecode, print error...
407 std::cerr << "bugpoint error: `dis -c' failed!\n";
415 int CBE::ExecuteProgram(const std::string &Bytecode,
416 const std::string &OutputFile,
417 const std::string &SharedLib) {
418 std::string OutputCFile;
419 if (OutputC(Bytecode, OutputCFile)) {
420 std::cerr << "Could not generate C code with `dis', exiting.\n";
424 int Result = gcc->ExecuteProgram(OutputCFile, OutputFile, SharedLib);
425 removeFile(OutputCFile);
431 //===----------------------------------------------------------------------===//
432 // BugDriver method implementation
435 /// initializeExecutionEnvironment - This method is used to set up the
436 /// environment for executing LLVM programs.
438 bool BugDriver::initializeExecutionEnvironment() {
439 std::cout << "Initializing execution environment: ";
441 // FIXME: This should default to searching for the best interpreter to use on
442 // this platform, which would be JIT, then LLC, then CBE, then LLI.
444 // Create an instance of the AbstractInterpreter interface as specified on the
447 switch (InterpreterSel) {
448 case RunLLI: Interpreter = LLI::create(this, Message); break;
449 case RunLLC: Interpreter = LLC::create(this, Message); break;
450 case RunJIT: Interpreter = JIT::create(this, Message); break;
451 case RunCBE: Interpreter = CBE::create(this, Message); break;
453 Message = " Sorry, this back-end is not supported by bugpoint right now!\n";
457 std::cout << Message;
459 // If there was an error creating the selected interpreter, quit with error.
460 return Interpreter == 0;
464 /// executeProgram - This method runs "Program", capturing the output of the
465 /// program to a file, returning the filename of the file. A recommended
466 /// filename may be optionally specified.
468 std::string BugDriver::executeProgram(std::string OutputFile,
469 std::string BytecodeFile,
470 std::string SharedObject,
471 AbstractInterpreter *AI) {
472 assert((Interpreter || AI) &&"Interpreter should have been created already!");
473 bool CreatedBytecode = false;
474 if (BytecodeFile.empty()) {
475 // Emit the program to a bytecode file...
476 BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
478 if (writeProgramToFile(BytecodeFile, Program)) {
479 std::cerr << ToolName << ": Error emitting bytecode to file '"
480 << BytecodeFile << "'!\n";
483 CreatedBytecode = true;
486 if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
488 // Check to see if this is a valid output filename...
489 OutputFile = getUniqueFilename(OutputFile);
491 // Actually execute the program!
492 int RetVal = (AI != 0) ?
493 AI->ExecuteProgram(BytecodeFile, OutputFile, SharedObject) :
494 Interpreter->ExecuteProgram(BytecodeFile, OutputFile, SharedObject);
496 // Remove the temporary bytecode file.
497 if (CreatedBytecode) removeFile(BytecodeFile);
499 // Return the filename we captured the output to.
503 std::string BugDriver::executeProgramWithCBE(std::string OutputFile,
504 std::string BytecodeFile,
505 std::string SharedObject) {
507 CBE *cbe = CBE::create(this, Output);
508 Output = executeProgram(OutputFile, BytecodeFile, SharedObject, cbe);
513 int BugDriver::compileSharedObject(const std::string &BytecodeFile,
514 std::string &SharedObject) {
515 assert(Interpreter && "Interpreter should have been created already!");
516 std::string Message, OutputCFile;
519 CBE *cbe = CBE::create(this, Message);
520 cbe->OutputC(BytecodeFile, OutputCFile);
522 #if 0 /* This is an alternative, as yet unimplemented */
524 LLC *llc = LLC::create(this, Message);
525 if (llc->OutputAsm(BytecodeFile, OutputFile)) {
526 std::cerr << "Could not generate asm code with `llc', exiting.\n";
531 GCC *gcc = GCC::create(this, Message);
532 gcc->MakeSharedObject(OutputCFile, SharedObject);
534 // Remove the intermediate C file
535 removeFile(OutputCFile);
537 // We are done with the CBE & GCC
545 /// diffProgram - This method executes the specified module and diffs the output
546 /// against the file specified by ReferenceOutputFile. If the output is
547 /// different, true is returned.
549 bool BugDriver::diffProgram(const std::string &BytecodeFile,
550 const std::string &SharedObject,
551 bool RemoveBytecode) {
552 // Execute the program, generating an output file...
553 std::string Output = executeProgram("", BytecodeFile, SharedObject);
555 std::ifstream ReferenceFile(ReferenceOutputFile.c_str());
556 if (!ReferenceFile) {
557 std::cerr << "Couldn't open reference output file '"
558 << ReferenceOutputFile << "'\n";
562 std::ifstream OutputFile(Output.c_str());
564 std::cerr << "Couldn't open output file: " << Output << "'!\n";
568 bool FilesDifferent = false;
570 // Compare the two files...
573 C1 = ReferenceFile.get();
574 C2 = OutputFile.get();
575 if (C1 != C2) { FilesDifferent = true; break; }
579 if (RemoveBytecode) removeFile(BytecodeFile);
580 return FilesDifferent;