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 extern cl::list<std::string> InputArgv;
48 /// AbstractInterpreter Class - Subclasses of this class are used to execute
49 /// LLVM bytecode in a variety of ways. This abstract interface hides this
50 /// complexity behind a simple interface.
52 struct AbstractInterpreter {
54 virtual ~AbstractInterpreter() {}
56 /// ExecuteProgram - Run the specified bytecode file, emitting output to the
57 /// specified filename. This returns the exit code of the program.
59 virtual int ExecuteProgram(const std::string &Bytecode,
60 const std::string &OutputFile,
61 const std::string &SharedLib = "") = 0;
65 //===----------------------------------------------------------------------===//
66 // LLI Implementation of AbstractIntepreter interface
68 class LLI : public AbstractInterpreter {
69 std::string LLIPath; // The path to the LLI executable
71 LLI(const std::string &Path) : LLIPath(Path) { }
73 // LLI create method - Try to find the LLI executable
74 static LLI *create(BugDriver *BD, std::string &Message) {
75 std::string LLIPath = FindExecutable("lli", BD->getToolName());
76 if (!LLIPath.empty()) {
77 Message = "Found lli: " + LLIPath + "\n";
78 return new LLI(LLIPath);
81 Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
84 virtual int ExecuteProgram(const std::string &Bytecode,
85 const std::string &OutputFile,
86 const std::string &SharedLib = "");
89 int LLI::ExecuteProgram(const std::string &Bytecode,
90 const std::string &OutputFile,
91 const std::string &SharedLib) {
92 if (!SharedLib.empty()) {
93 std::cerr << "LLI currently does not support loading shared libraries.\n"
98 std::vector<const char*> Args;
99 Args.push_back(LLIPath.c_str());
100 Args.push_back("-abort-on-exception");
101 Args.push_back("-quiet");
102 Args.push_back("-force-interpreter=true");
103 Args.push_back(Bytecode.c_str());
104 // Add optional parameters to the running program from Argv
105 for (unsigned i=0, e = InputArgv.size(); i != e; ++i)
106 Args.push_back(InputArgv[i].c_str());
109 std::cout << "<lli>";
110 return RunProgramWithTimeout(LLIPath, &Args[0],
111 InputFile, OutputFile, OutputFile);
114 //===----------------------------------------------------------------------===//
117 // This is not a *real* AbstractInterpreter as it does not accept bytecode
118 // files, but only input acceptable to GCC, i.e. C, C++, and assembly files
121 std::string GCCPath; // The path to the gcc executable
123 GCC(const std::string &gccPath) : GCCPath(gccPath) { }
126 // GCC create method - Try to find the `gcc' executable
127 static GCC *create(BugDriver *BD, std::string &Message) {
128 std::string GCCPath = FindExecutable("gcc", BD->getToolName());
129 if (GCCPath.empty()) {
130 Message = "Cannot find `gcc' in bugpoint executable directory or PATH!\n";
134 Message = "Found gcc: " + GCCPath + "\n";
135 return new GCC(GCCPath);
138 virtual int ExecuteProgram(const std::string &ProgramFile,
140 const std::string &OutputFile,
141 const std::string &SharedLib = "");
143 int MakeSharedObject(const std::string &InputFile,
145 std::string &OutputFile);
147 void ProcessFailure(const char **Args);
150 int GCC::ExecuteProgram(const std::string &ProgramFile,
152 const std::string &OutputFile,
153 const std::string &SharedLib) {
154 std::string OutputBinary = getUniqueFilename("bugpoint.gcc.exe");
155 std::vector<const char*> GCCArgs;
157 GCCArgs.push_back(GCCPath.c_str());
158 if (!SharedLib.empty()) // Specify the shared library to link in...
159 GCCArgs.push_back(SharedLib.c_str());
160 GCCArgs.push_back("-x");
161 GCCArgs.push_back((fileType == AsmFile) ? "assembler" : "c");
162 GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename...
163 GCCArgs.push_back("-o");
164 GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
165 GCCArgs.push_back("-lm"); // Hard-code the math library...
166 GCCArgs.push_back("-O2"); // Optimize the program a bit...
167 GCCArgs.push_back(0); // NULL terminator
169 std::cout << "<gcc>";
170 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
172 ProcessFailure(&GCCArgs[0]);
176 std::vector<const char*> ProgramArgs;
177 ProgramArgs.push_back(OutputBinary.c_str());
178 // Add optional parameters to the running program from Argv
179 for (unsigned i=0, e = InputArgv.size(); i != e; ++i)
180 ProgramArgs.push_back(InputArgv[i].c_str());
181 ProgramArgs.push_back(0); // NULL terminator
183 // Now that we have a binary, run it!
184 std::cout << "<program>";
185 int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
186 InputFile, OutputFile, OutputFile);
188 removeFile(OutputBinary);
189 return ProgramResult;
192 int GCC::MakeSharedObject(const std::string &InputFile,
194 std::string &OutputFile) {
195 OutputFile = getUniqueFilename("./bugpoint.so");
196 // Compile the C/asm file into a shared object
197 const char* GCCArgs[] = {
199 "-x", (fileType == AsmFile) ? "assembler" : "c",
200 InputFile.c_str(), // Specify the input filename...
201 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
202 "-G", // Compile a shared library, `-G' for Sparc
204 "-shared", // `-shared' for Linux/X86, maybe others
206 "-o", OutputFile.c_str(), // Output to the right filename...
207 "-O2", // Optimize the program a bit...
211 std::cout << "<gcc>";
212 if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
214 ProcessFailure(GCCArgs);
220 void GCC::ProcessFailure(const char** GCCArgs) {
221 std::cerr << "\n*** bugpoint error: invocation of the C compiler failed!\n";
222 for (const char **Arg = GCCArgs; *Arg; ++Arg)
223 std::cerr << " " << *Arg;
226 // Rerun the compiler, capturing any error messages to print them.
227 std::string ErrorFilename = getUniqueFilename("bugpoint.gcc.errors");
228 RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
229 ErrorFilename.c_str());
231 // Print out the error messages generated by GCC if possible...
232 std::ifstream ErrorFile(ErrorFilename.c_str());
234 std::copy(std::istreambuf_iterator<char>(ErrorFile),
235 std::istreambuf_iterator<char>(),
236 std::ostreambuf_iterator<char>(std::cerr));
241 removeFile(ErrorFilename);
244 //===----------------------------------------------------------------------===//
245 // LLC Implementation of AbstractIntepreter interface
247 class LLC : public AbstractInterpreter {
248 std::string LLCPath; // The path to the LLC executable
251 LLC(const std::string &llcPath, GCC *Gcc)
252 : LLCPath(llcPath), gcc(Gcc) { }
253 ~LLC() { delete gcc; }
255 // LLC create method - Try to find the LLC executable
256 static LLC *create(BugDriver *BD, std::string &Message) {
257 std::string LLCPath = FindExecutable("llc", BD->getToolName());
258 if (LLCPath.empty()) {
259 Message = "Cannot find `llc' in bugpoint executable directory or PATH!\n";
263 Message = "Found llc: " + LLCPath + "\n";
264 GCC *gcc = GCC::create(BD, Message);
266 std::cerr << Message << "\n";
269 return new LLC(LLCPath, gcc);
272 virtual int ExecuteProgram(const std::string &Bytecode,
273 const std::string &OutputFile,
274 const std::string &SharedLib = "");
276 int OutputAsm(const std::string &Bytecode,
277 std::string &OutputAsmFile);
280 int LLC::OutputAsm(const std::string &Bytecode,
281 std::string &OutputAsmFile) {
282 OutputAsmFile = "bugpoint.llc.s";
283 const char *LLCArgs[] = {
285 "-o", OutputAsmFile.c_str(), // Output to the Asm file
286 "-f", // Overwrite as necessary...
287 Bytecode.c_str(), // This is the input bytecode
291 std::cout << "<llc>";
292 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
294 // If LLC failed on the bytecode, print error...
295 std::cerr << "bugpoint error: `llc' failed!\n";
296 removeFile(OutputAsmFile);
303 int LLC::ExecuteProgram(const std::string &Bytecode,
304 const std::string &OutputFile,
305 const std::string &SharedLib) {
307 std::string OutputAsmFile;
308 if (OutputAsm(Bytecode, OutputAsmFile)) {
309 std::cerr << "Could not generate asm code with `llc', exiting.\n";
313 // Assuming LLC worked, compile the result with GCC and run it.
314 int Result = gcc->ExecuteProgram(OutputAsmFile,AsmFile,OutputFile,SharedLib);
315 removeFile(OutputAsmFile);
320 //===----------------------------------------------------------------------===//
321 // JIT Implementation of AbstractIntepreter interface
323 class JIT : public AbstractInterpreter {
324 std::string LLIPath; // The path to the LLI executable
326 JIT(const std::string &Path) : LLIPath(Path) { }
328 // JIT create method - Try to find the LLI executable
329 static JIT *create(BugDriver *BD, std::string &Message) {
330 std::string LLIPath = FindExecutable("lli", BD->getToolName());
331 if (!LLIPath.empty()) {
332 Message = "Found lli: " + LLIPath + "\n";
333 return new JIT(LLIPath);
336 Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
339 virtual int ExecuteProgram(const std::string &Bytecode,
340 const std::string &OutputFile,
341 const std::string &SharedLib = "");
344 int JIT::ExecuteProgram(const std::string &Bytecode,
345 const std::string &OutputFile,
346 const std::string &SharedLib) {
347 const char* ArgsWithoutSO[] = {
348 LLIPath.c_str(), "-quiet", "-force-interpreter=false",
353 const char* ArgsWithSO[] = {
354 LLIPath.c_str(), "-quiet", "-force-interpreter=false",
355 "-load", SharedLib.c_str(),
360 const char** JITArgs = SharedLib.empty() ? ArgsWithoutSO : ArgsWithSO;
362 std::cout << "<jit>";
363 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
364 return RunProgramWithTimeout(LLIPath, JITArgs,
365 InputFile, OutputFile, OutputFile);
368 //===----------------------------------------------------------------------===//
369 // CBE Implementation of AbstractIntepreter interface
371 class CBE : public AbstractInterpreter {
372 std::string DISPath; // The path to the LLVM 'dis' executable
375 CBE(const std::string &disPath, GCC *Gcc) : DISPath(disPath), gcc(Gcc) { }
376 ~CBE() { delete gcc; }
378 // CBE create method - Try to find the 'dis' executable
379 static CBE *create(BugDriver *BD, std::string &Message) {
380 std::string DISPath = FindExecutable("dis", BD->getToolName());
381 if (DISPath.empty()) {
382 Message = "Cannot find `dis' in bugpoint executable directory or PATH!\n";
386 Message = "Found dis: " + DISPath + "\n";
388 GCC *gcc = GCC::create(BD, Message);
390 std::cerr << Message << "\n";
393 return new CBE(DISPath, gcc);
396 virtual int ExecuteProgram(const std::string &Bytecode,
397 const std::string &OutputFile,
398 const std::string &SharedLib = "");
400 // Sometimes we just want to go half-way and only generate the C file,
401 // not necessarily compile it with GCC and run the program
402 virtual int OutputC(const std::string &Bytecode,
403 std::string &OutputCFile);
407 int CBE::OutputC(const std::string &Bytecode,
408 std::string &OutputCFile) {
409 OutputCFile = "bugpoint.cbe.c";
410 const char *DisArgs[] = {
412 "-o", OutputCFile.c_str(), // Output to the C file
414 "-f", // Overwrite as necessary...
415 Bytecode.c_str(), // This is the input bytecode
419 std::cout << "<cbe>";
420 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
422 // If dis failed on the bytecode, print error...
423 std::cerr << "bugpoint error: `dis -c' failed!\n";
431 int CBE::ExecuteProgram(const std::string &Bytecode,
432 const std::string &OutputFile,
433 const std::string &SharedLib) {
434 std::string OutputCFile;
435 if (OutputC(Bytecode, OutputCFile)) {
436 std::cerr << "Could not generate C code with `dis', exiting.\n";
440 int Result = gcc->ExecuteProgram(OutputCFile, CFile, OutputFile, SharedLib);
441 removeFile(OutputCFile);
447 //===----------------------------------------------------------------------===//
448 // BugDriver method implementation
451 /// initializeExecutionEnvironment - This method is used to set up the
452 /// environment for executing LLVM programs.
454 bool BugDriver::initializeExecutionEnvironment() {
455 std::cout << "Initializing execution environment: ";
457 // FIXME: This should default to searching for the best interpreter to use on
458 // this platform, which would be JIT, then LLC, then CBE, then LLI.
460 // Create an instance of the AbstractInterpreter interface as specified on the
463 switch (InterpreterSel) {
464 case RunLLI: Interpreter = LLI::create(this, Message); break;
465 case RunLLC: Interpreter = LLC::create(this, Message); break;
466 case RunJIT: Interpreter = JIT::create(this, Message); break;
467 case RunCBE: Interpreter = CBE::create(this, Message); break;
469 Message = " Sorry, this back-end is not supported by bugpoint right now!\n";
473 std::cout << Message;
475 // Initialize auxiliary tools for debugging
476 cbe = CBE::create(this, Message);
477 if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
478 gcc = GCC::create(this, Message);
479 if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
481 // If there was an error creating the selected interpreter, quit with error.
482 return Interpreter == 0;
486 /// executeProgram - This method runs "Program", capturing the output of the
487 /// program to a file, returning the filename of the file. A recommended
488 /// filename may be optionally specified.
490 std::string BugDriver::executeProgram(std::string OutputFile,
491 std::string BytecodeFile,
492 std::string SharedObject,
493 AbstractInterpreter *AI) {
494 assert((Interpreter || AI) &&"Interpreter should have been created already!");
495 bool CreatedBytecode = false;
496 if (BytecodeFile.empty()) {
497 // Emit the program to a bytecode file...
498 BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
500 if (writeProgramToFile(BytecodeFile, Program)) {
501 std::cerr << ToolName << ": Error emitting bytecode to file '"
502 << BytecodeFile << "'!\n";
505 CreatedBytecode = true;
508 if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
510 // Check to see if this is a valid output filename...
511 OutputFile = getUniqueFilename(OutputFile);
513 // Actually execute the program!
514 int RetVal = (AI != 0) ?
515 AI->ExecuteProgram(BytecodeFile, OutputFile, SharedObject) :
516 Interpreter->ExecuteProgram(BytecodeFile, OutputFile, SharedObject);
518 // Remove the temporary bytecode file.
519 if (CreatedBytecode) removeFile(BytecodeFile);
521 // Return the filename we captured the output to.
525 std::string BugDriver::executeProgramWithCBE(std::string OutputFile,
526 std::string BytecodeFile,
527 std::string SharedObject) {
528 return executeProgram(OutputFile, BytecodeFile, SharedObject, cbe);
531 int BugDriver::compileSharedObject(const std::string &BytecodeFile,
532 std::string &SharedObject) {
533 assert(Interpreter && "Interpreter should have been created already!");
534 std::string Message, OutputCFile;
537 cbe->OutputC(BytecodeFile, OutputCFile);
539 #if 0 /* This is an alternative, as yet unimplemented */
541 LLC *llc = LLC::create(this, Message);
542 if (llc->OutputAsm(BytecodeFile, OutputFile)) {
543 std::cerr << "Could not generate asm code with `llc', exiting.\n";
548 gcc->MakeSharedObject(OutputCFile, CFile, SharedObject);
550 // Remove the intermediate C file
551 removeFile(OutputCFile);
557 /// diffProgram - This method executes the specified module and diffs the output
558 /// against the file specified by ReferenceOutputFile. If the output is
559 /// different, true is returned.
561 bool BugDriver::diffProgram(const std::string &BytecodeFile,
562 const std::string &SharedObject,
563 bool RemoveBytecode) {
564 // Execute the program, generating an output file...
565 std::string Output = executeProgram("", BytecodeFile, SharedObject);
567 std::ifstream ReferenceFile(ReferenceOutputFile.c_str());
568 if (!ReferenceFile) {
569 std::cerr << "Couldn't open reference output file '"
570 << ReferenceOutputFile << "'\n";
574 std::ifstream OutputFile(Output.c_str());
576 std::cerr << "Couldn't open output file: " << Output << "'!\n";
580 bool FilesDifferent = false;
582 // Compare the two files...
585 C1 = ReferenceFile.get();
586 C2 = OutputFile.get();
587 if (C1 != C2) { FilesDifferent = true; break; }
590 //removeFile(Output);
591 if (RemoveBytecode) removeFile(BytecodeFile);
592 return FilesDifferent;
595 bool BugDriver::isExecutingJIT() {
596 return InterpreterSel == RunJIT;