Moved SystemUtils.h to include/Support and SystemUtils.cpp to lib/Support.
[oota-llvm.git] / tools / bugpoint / ExecutionDriver.cpp
1 //===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
2 //
3 // This file contains code used to execute the program utilizing one of the
4 // various ways of running LLVM bytecode.
5 //
6 //===----------------------------------------------------------------------===//
7
8 /*
9 BUGPOINT NOTES:
10
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.
15 */
16
17 #include "BugDriver.h"
18 #include "Support/SystemUtils.h"
19 #include "Support/CommandLine.h"
20 #include "Support/Debug.h"
21 #include "Support/FileUtilities.h"
22 #include <fstream>
23 #include <iostream>
24
25 namespace {
26   // OutputType - Allow the user to specify the way code should be run, to test
27   // for miscompilation.
28   //
29   enum OutputType {
30     RunLLI, RunJIT, RunLLC, RunCBE
31   };
32   cl::opt<OutputType>
33   InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
34                  cl::values(clEnumValN(RunLLI, "run-lli", "Execute with LLI"),
35                             clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
36                             clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
37                             clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
38                             0));
39
40   cl::opt<std::string>
41   InputFile("input", cl::init("/dev/null"),
42             cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
43
44   enum FileType { AsmFile, CFile };
45 }
46
47 // Anything specified after the --args option are taken as arguments to the
48 // program being debugged.
49 cl::list<std::string>
50 InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
51           cl::ZeroOrMore);
52
53 /// AbstractInterpreter Class - Subclasses of this class are used to execute
54 /// LLVM bytecode in a variety of ways.  This abstract interface hides this
55 /// complexity behind a simple interface.
56 ///
57 struct AbstractInterpreter {
58
59   virtual ~AbstractInterpreter() {}
60
61   /// ExecuteProgram - Run the specified bytecode file, emitting output to the
62   /// specified filename.  This returns the exit code of the program.
63   ///
64   virtual int ExecuteProgram(const std::string &Bytecode,
65                              const std::string &OutputFile,
66                              const std::string &SharedLib = "") = 0;
67 };
68
69
70 //===----------------------------------------------------------------------===//
71 // LLI Implementation of AbstractIntepreter interface
72 //
73 class LLI : public AbstractInterpreter {
74   std::string LLIPath;          // The path to the LLI executable
75 public:
76   LLI(const std::string &Path) : LLIPath(Path) { }
77
78   // LLI create method - Try to find the LLI executable
79   static LLI *create(BugDriver *BD, std::string &Message) {
80     std::string LLIPath = FindExecutable("lli", BD->getToolName());
81     if (!LLIPath.empty()) {
82       Message = "Found lli: " + LLIPath + "\n";
83       return new LLI(LLIPath);
84     }
85
86     Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
87     return 0;
88   }
89   virtual int ExecuteProgram(const std::string &Bytecode,
90                              const std::string &OutputFile,
91                              const std::string &SharedLib = "");
92 };
93
94 int LLI::ExecuteProgram(const std::string &Bytecode,
95                         const std::string &OutputFile,
96                         const std::string &SharedLib) {
97   if (!SharedLib.empty()) {
98     std::cerr << "LLI currently does not support loading shared libraries.\n"
99               << "Exiting.\n";
100     exit(1);
101   }
102
103   std::vector<const char*> LLIArgs;
104   LLIArgs.push_back(LLIPath.c_str());
105   LLIArgs.push_back("-abort-on-exception");
106   LLIArgs.push_back("-quiet");
107   LLIArgs.push_back("-force-interpreter=true");
108   LLIArgs.push_back(Bytecode.c_str());
109   // Add optional parameters to the running program from Argv
110   for (unsigned i=0, e = InputArgv.size(); i != e; ++i)
111     LLIArgs.push_back(InputArgv[i].c_str());
112   LLIArgs.push_back(0);
113
114   std::cout << "<lli>" << std::flush;
115   DEBUG(std::cerr << "\nAbout to run:\n\t";
116         for (unsigned i=0, e = LLIArgs.size(); i != e; ++i)
117           std::cerr << " " << LLIArgs[i];
118         std::cerr << "\n";
119         );
120   return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
121                                InputFile, OutputFile, OutputFile);
122 }
123
124 //===----------------------------------------------------------------------===//
125 // GCC abstraction
126 //
127 // This is not a *real* AbstractInterpreter as it does not accept bytecode
128 // files, but only input acceptable to GCC, i.e. C, C++, and assembly files
129 //
130 class GCC {
131   std::string GCCPath;          // The path to the gcc executable
132 public:
133   GCC(const std::string &gccPath) : GCCPath(gccPath) { }
134   virtual ~GCC() {}
135
136   // GCC create method - Try to find the `gcc' executable
137   static GCC *create(BugDriver *BD, std::string &Message) {
138     std::string GCCPath = FindExecutable("gcc", BD->getToolName());
139     if (GCCPath.empty()) {
140       Message = "Cannot find `gcc' in bugpoint executable directory or PATH!\n";
141       return 0;
142     }
143
144     Message = "Found gcc: " + GCCPath + "\n";
145     return new GCC(GCCPath);
146   }
147
148   virtual int ExecuteProgram(const std::string &ProgramFile,
149                              FileType fileType,
150                              const std::string &OutputFile,
151                              const std::string &SharedLib = "");
152
153   int MakeSharedObject(const std::string &InputFile,
154                        FileType fileType,
155                        std::string &OutputFile);
156   
157   void ProcessFailure(const char **Args);
158 };
159
160 int GCC::ExecuteProgram(const std::string &ProgramFile,
161                         FileType fileType,
162                         const std::string &OutputFile,
163                         const std::string &SharedLib) {
164   std::string OutputBinary = getUniqueFilename("bugpoint.gcc.exe");
165   std::vector<const char*> GCCArgs;
166
167   GCCArgs.push_back(GCCPath.c_str());
168   if (!SharedLib.empty()) // Specify the shared library to link in...
169     GCCArgs.push_back(SharedLib.c_str());
170   GCCArgs.push_back("-x");
171   GCCArgs.push_back((fileType == AsmFile) ? "assembler" : "c");
172   GCCArgs.push_back(ProgramFile.c_str());  // Specify the input filename...
173   GCCArgs.push_back("-o");
174   GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
175   GCCArgs.push_back("-lm");                // Hard-code the math library...
176   GCCArgs.push_back("-O2");                // Optimize the program a bit...
177   GCCArgs.push_back(0);                    // NULL terminator
178
179   std::cout << "<gcc>" << std::flush;
180   if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
181                             "/dev/null")) {
182     ProcessFailure(&GCCArgs[0]);
183     exit(1);
184   }
185
186   std::vector<const char*> ProgramArgs;
187   ProgramArgs.push_back(OutputBinary.c_str());
188   // Add optional parameters to the running program from Argv
189   for (unsigned i=0, e = InputArgv.size(); i != e; ++i)
190     ProgramArgs.push_back(InputArgv[i].c_str());
191   ProgramArgs.push_back(0);                // NULL terminator
192
193   // Now that we have a binary, run it!
194   std::cout << "<program>" << std::flush;
195   DEBUG(std::cerr << "\nAbout to run:\n\t";
196         for (unsigned i=0, e = ProgramArgs.size(); i != e; ++i)
197           std::cerr << " " << ProgramArgs[i];
198         std::cerr << "\n";
199         );
200   int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
201                                             InputFile, OutputFile, OutputFile);
202   removeFile(OutputBinary);
203   return ProgramResult;
204 }
205
206 int GCC::MakeSharedObject(const std::string &InputFile,
207                           FileType fileType,
208                           std::string &OutputFile) {
209   OutputFile = getUniqueFilename("./bugpoint.so");
210   // Compile the C/asm file into a shared object
211   const char* GCCArgs[] = {
212     GCCPath.c_str(),
213     "-x", (fileType == AsmFile) ? "assembler" : "c",
214     InputFile.c_str(),           // Specify the input filename...
215 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
216     "-G",                        // Compile a shared library, `-G' for Sparc
217 #else                             
218     "-shared",                   // `-shared' for Linux/X86, maybe others
219 #endif
220     "-o", OutputFile.c_str(),    // Output to the right filename...
221     "-O2",                       // Optimize the program a bit...
222     0
223   };
224   
225   std::cout << "<gcc>" << std::flush;
226   if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
227                            "/dev/null")) {
228     ProcessFailure(GCCArgs);
229     exit(1);
230   }
231   return 0;
232 }
233
234 void GCC::ProcessFailure(const char** GCCArgs) {
235   std::cerr << "\n*** bugpoint error: invocation of the C compiler failed!\n";
236   for (const char **Arg = GCCArgs; *Arg; ++Arg)
237     std::cerr << " " << *Arg;
238   std::cerr << "\n";
239
240   // Rerun the compiler, capturing any error messages to print them.
241   std::string ErrorFilename = getUniqueFilename("bugpoint.gcc.errors");
242   RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
243                         ErrorFilename.c_str());
244
245   // Print out the error messages generated by GCC if possible...
246   std::ifstream ErrorFile(ErrorFilename.c_str());
247   if (ErrorFile) {
248     std::copy(std::istreambuf_iterator<char>(ErrorFile),
249               std::istreambuf_iterator<char>(),
250               std::ostreambuf_iterator<char>(std::cerr));
251     ErrorFile.close();
252     std::cerr << "\n";      
253   }
254
255   removeFile(ErrorFilename);
256 }
257
258 //===----------------------------------------------------------------------===//
259 // LLC Implementation of AbstractIntepreter interface
260 //
261 class LLC : public AbstractInterpreter {
262   std::string LLCPath;          // The path to the LLC executable
263   GCC *gcc;
264 public:
265   LLC(const std::string &llcPath, GCC *Gcc)
266     : LLCPath(llcPath), gcc(Gcc) { }
267   ~LLC() { delete gcc; }
268
269   // LLC create method - Try to find the LLC executable
270   static LLC *create(BugDriver *BD, std::string &Message) {
271     std::string LLCPath = FindExecutable("llc", BD->getToolName());
272     if (LLCPath.empty()) {
273       Message = "Cannot find `llc' in bugpoint executable directory or PATH!\n";
274       return 0;
275     }
276
277     Message = "Found llc: " + LLCPath + "\n";
278     GCC *gcc = GCC::create(BD, Message);
279     if (!gcc) {
280       std::cerr << Message << "\n";
281       exit(1);
282     }
283     return new LLC(LLCPath, gcc);
284   }
285
286   virtual int ExecuteProgram(const std::string &Bytecode,
287                              const std::string &OutputFile,
288                              const std::string &SharedLib = "");
289
290   int OutputAsm(const std::string &Bytecode,
291                 std::string &OutputAsmFile);
292 };
293
294 int LLC::OutputAsm(const std::string &Bytecode,
295                    std::string &OutputAsmFile) {
296   OutputAsmFile = "bugpoint.llc.s";
297   const char *LLCArgs[] = {
298     LLCPath.c_str(),
299     "-o", OutputAsmFile.c_str(), // Output to the Asm file
300     "-f",                        // Overwrite as necessary...
301     Bytecode.c_str(),            // This is the input bytecode
302     0
303   };
304
305   std::cout << "<llc>" << std::flush;
306   if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
307                             "/dev/null")) {                            
308     // If LLC failed on the bytecode, print error...
309     std::cerr << "bugpoint error: `llc' failed!\n";
310     removeFile(OutputAsmFile);
311     return 1;
312   }
313
314   return 0;
315 }
316
317 int LLC::ExecuteProgram(const std::string &Bytecode,
318                         const std::string &OutputFile,
319                         const std::string &SharedLib) {
320
321   std::string OutputAsmFile;
322   if (OutputAsm(Bytecode, OutputAsmFile)) {
323     std::cerr << "Could not generate asm code with `llc', exiting.\n";
324     exit(1);
325   }
326
327   // Assuming LLC worked, compile the result with GCC and run it.
328   int Result = gcc->ExecuteProgram(OutputAsmFile,AsmFile,OutputFile,SharedLib);
329   removeFile(OutputAsmFile);
330   return Result;
331 }
332
333
334 //===----------------------------------------------------------------------===//
335 // JIT Implementation of AbstractIntepreter interface
336 //
337 class JIT : public AbstractInterpreter {
338   std::string LLIPath;          // The path to the LLI executable
339 public:
340   JIT(const std::string &Path) : LLIPath(Path) { }
341
342   // JIT create method - Try to find the LLI executable
343   static JIT *create(BugDriver *BD, std::string &Message) {
344     std::string LLIPath = FindExecutable("lli", BD->getToolName());
345     if (!LLIPath.empty()) {
346       Message = "Found lli: " + LLIPath + "\n";
347       return new JIT(LLIPath);
348     }
349
350     Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
351     return 0;
352   }
353   virtual int ExecuteProgram(const std::string &Bytecode,
354                              const std::string &OutputFile,
355                              const std::string &SharedLib = "");
356 };
357
358 int JIT::ExecuteProgram(const std::string &Bytecode,
359                         const std::string &OutputFile,
360                         const std::string &SharedLib) {
361   // Construct a vector of parameters, incorporating those from the command-line
362   std::vector<const char*> JITArgs;
363   JITArgs.push_back(LLIPath.c_str());
364   JITArgs.push_back("-quiet");
365   JITArgs.push_back("-force-interpreter=false");
366   if (!SharedLib.empty()) {
367     JITArgs.push_back("-load");
368     JITArgs.push_back(SharedLib.c_str());
369   }
370   JITArgs.push_back(Bytecode.c_str());
371   // Add optional parameters to the running program from Argv
372   for (unsigned i=0, e = InputArgv.size(); i != e; ++i)
373     JITArgs.push_back(InputArgv[i].c_str());
374   JITArgs.push_back(0);
375
376   std::cout << "<jit>" << std::flush;
377   DEBUG(std::cerr << "\nAbout to run:\n\t";
378         for (unsigned i=0, e = JITArgs.size(); i != e; ++i)
379           std::cerr << " " << JITArgs[i];
380         std::cerr << "\n";
381         );
382   DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
383   return RunProgramWithTimeout(LLIPath, &JITArgs[0],
384                                InputFile, OutputFile, OutputFile);
385 }
386
387 //===----------------------------------------------------------------------===//
388 // CBE Implementation of AbstractIntepreter interface
389 //
390 class CBE : public AbstractInterpreter {
391   std::string DISPath;          // The path to the LLVM 'dis' executable
392   GCC *gcc;
393 public:
394   CBE(const std::string &disPath, GCC *Gcc) : DISPath(disPath), gcc(Gcc) { }
395   ~CBE() { delete gcc; }
396
397   // CBE create method - Try to find the 'dis' executable
398   static CBE *create(BugDriver *BD, std::string &Message) {
399     std::string DISPath = FindExecutable("dis", BD->getToolName());
400     if (DISPath.empty()) {
401       Message = "Cannot find `dis' in bugpoint executable directory or PATH!\n";
402       return 0;
403     }
404
405     Message = "Found dis: " + DISPath + "\n";
406
407     GCC *gcc = GCC::create(BD, Message);
408     if (!gcc) {
409       std::cerr << Message << "\n";
410       exit(1);
411     }
412     return new CBE(DISPath, gcc);
413   }
414
415   virtual int ExecuteProgram(const std::string &Bytecode,
416                              const std::string &OutputFile,
417                              const std::string &SharedLib = "");
418
419   // Sometimes we just want to go half-way and only generate the C file,
420   // not necessarily compile it with GCC and run the program
421   virtual int OutputC(const std::string &Bytecode,
422                       std::string &OutputCFile);
423
424 };
425
426 int CBE::OutputC(const std::string &Bytecode,
427                  std::string &OutputCFile) {
428   OutputCFile = "bugpoint.cbe.c";
429   const char *DisArgs[] = {
430     DISPath.c_str(),
431     "-o", OutputCFile.c_str(),   // Output to the C file
432     "-c",                        // Output to C
433     "-f",                        // Overwrite as necessary...
434     Bytecode.c_str(),            // This is the input bytecode
435     0
436   };
437
438   std::cout << "<cbe>" << std::flush;
439   if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
440                             "/dev/null")) {                            
441     // If dis failed on the bytecode, print error...
442     std::cerr << "bugpoint error: `dis -c' failed!\n";
443     return 1;
444   }
445
446   return 0;
447 }
448
449
450 int CBE::ExecuteProgram(const std::string &Bytecode,
451                         const std::string &OutputFile,
452                         const std::string &SharedLib) {
453   std::string OutputCFile;
454   if (OutputC(Bytecode, OutputCFile)) {
455     std::cerr << "Could not generate C code with `dis', exiting.\n";
456     exit(1);
457   }
458
459   int Result = gcc->ExecuteProgram(OutputCFile, CFile, OutputFile, SharedLib);
460   removeFile(OutputCFile);
461
462   return Result;
463 }
464
465
466 //===----------------------------------------------------------------------===//
467 // BugDriver method implementation
468 //
469
470 /// initializeExecutionEnvironment - This method is used to set up the
471 /// environment for executing LLVM programs.
472 ///
473 bool BugDriver::initializeExecutionEnvironment() {
474   std::cout << "Initializing execution environment: ";
475
476   // FIXME: This should default to searching for the best interpreter to use on
477   // this platform, which would be JIT, then LLC, then CBE, then LLI.
478
479   // Create an instance of the AbstractInterpreter interface as specified on the
480   // command line
481   std::string Message;
482   switch (InterpreterSel) {
483   case RunLLI: Interpreter = LLI::create(this, Message); break;
484   case RunLLC: Interpreter = LLC::create(this, Message); break;
485   case RunJIT: Interpreter = JIT::create(this, Message); break;
486   case RunCBE: Interpreter = CBE::create(this, Message); break;
487   default:
488     Message = " Sorry, this back-end is not supported by bugpoint right now!\n";
489     break;
490   }
491
492   std::cout << Message;
493
494   // Initialize auxiliary tools for debugging
495   cbe = CBE::create(this, Message);
496   if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
497   gcc = GCC::create(this, Message);
498   if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
499
500   // If there was an error creating the selected interpreter, quit with error.
501   return Interpreter == 0;
502 }
503
504
505 /// executeProgram - This method runs "Program", capturing the output of the
506 /// program to a file, returning the filename of the file.  A recommended
507 /// filename may be optionally specified.
508 ///
509 std::string BugDriver::executeProgram(std::string OutputFile,
510                                       std::string BytecodeFile,
511                                       std::string SharedObject,
512                                       AbstractInterpreter *AI) {
513   assert((Interpreter || AI) &&"Interpreter should have been created already!");
514   bool CreatedBytecode = false;
515   if (BytecodeFile.empty()) {
516     // Emit the program to a bytecode file...
517     BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
518
519     if (writeProgramToFile(BytecodeFile, Program)) {
520       std::cerr << ToolName << ": Error emitting bytecode to file '"
521                 << BytecodeFile << "'!\n";
522       exit(1);
523     }
524     CreatedBytecode = true;
525   }
526
527   if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
528
529   // Check to see if this is a valid output filename...
530   OutputFile = getUniqueFilename(OutputFile);
531
532   // Actually execute the program!
533   int RetVal = (AI != 0) ?
534     AI->ExecuteProgram(BytecodeFile, OutputFile, SharedObject) :
535     Interpreter->ExecuteProgram(BytecodeFile, OutputFile, SharedObject);
536
537   // Remove the temporary bytecode file.
538   if (CreatedBytecode) removeFile(BytecodeFile);
539
540   // Return the filename we captured the output to.
541   return OutputFile;
542 }
543
544 std::string BugDriver::executeProgramWithCBE(std::string OutputFile,
545                                              std::string BytecodeFile,
546                                              std::string SharedObject) {
547   return executeProgram(OutputFile, BytecodeFile, SharedObject, cbe);
548 }
549
550 int BugDriver::compileSharedObject(const std::string &BytecodeFile,
551                                    std::string &SharedObject) {
552   assert(Interpreter && "Interpreter should have been created already!");
553   std::string Message, OutputCFile;
554
555   // Using CBE
556   cbe->OutputC(BytecodeFile, OutputCFile);
557
558 #if 0 /* This is an alternative, as yet unimplemented */
559   // Using LLC
560   LLC *llc = LLC::create(this, Message);
561   if (llc->OutputAsm(BytecodeFile, OutputFile)) {
562     std::cerr << "Could not generate asm code with `llc', exiting.\n";
563     exit(1);
564   }
565 #endif
566
567   gcc->MakeSharedObject(OutputCFile, CFile, SharedObject);
568
569   // Remove the intermediate C file
570   removeFile(OutputCFile);
571
572   return 0;
573 }
574
575
576 /// diffProgram - This method executes the specified module and diffs the output
577 /// against the file specified by ReferenceOutputFile.  If the output is
578 /// different, true is returned.
579 ///
580 bool BugDriver::diffProgram(const std::string &BytecodeFile,
581                             const std::string &SharedObject,
582                             bool RemoveBytecode) {
583   // Execute the program, generating an output file...
584   std::string Output = executeProgram("", BytecodeFile, SharedObject);
585
586   std::string Error;
587   bool FilesDifferent = false;
588   if (DiffFiles(ReferenceOutputFile, Output, &Error)) {
589     if (!Error.empty()) {
590       std::cerr << "While diffing output: " << Error << "\n";
591       exit(1);
592     }
593     FilesDifferent = true;
594   }
595
596   if (RemoveBytecode) removeFile(BytecodeFile);
597   return FilesDifferent;
598 }
599
600 bool BugDriver::isExecutingJIT() {
601   return InterpreterSel == RunJIT;
602 }