Use a vector<char*> instead of char*[] so that we can add arbitrary number of
[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 "SystemUtils.h"
19 #include "Support/CommandLine.h"
20 #include "Support/Statistic.h"
21 #include <fstream>
22 #include <iostream>
23
24 namespace {
25   // OutputType - Allow the user to specify the way code should be run, to test
26   // for miscompilation.
27   //
28   enum OutputType {
29     RunLLI, RunJIT, RunLLC, RunCBE
30   };
31   cl::opt<OutputType>
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"),
37                             0));
38
39   cl::opt<std::string>
40   InputFile("input", cl::init("/dev/null"),
41             cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
42
43   enum FileType { AsmFile, CFile };
44 }
45
46 extern cl::list<std::string> InputArgv;
47
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.
51 ///
52 struct AbstractInterpreter {
53
54   virtual ~AbstractInterpreter() {}
55
56   /// ExecuteProgram - Run the specified bytecode file, emitting output to the
57   /// specified filename.  This returns the exit code of the program.
58   ///
59   virtual int ExecuteProgram(const std::string &Bytecode,
60                              const std::string &OutputFile,
61                              const std::string &SharedLib = "") = 0;
62 };
63
64
65 //===----------------------------------------------------------------------===//
66 // LLI Implementation of AbstractIntepreter interface
67 //
68 class LLI : public AbstractInterpreter {
69   std::string LLIPath;          // The path to the LLI executable
70 public:
71   LLI(const std::string &Path) : LLIPath(Path) { }
72
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);
79     }
80
81     Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
82     return 0;
83   }
84   virtual int ExecuteProgram(const std::string &Bytecode,
85                              const std::string &OutputFile,
86                              const std::string &SharedLib = "");
87 };
88
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"
94               << "Exiting.\n";
95     exit(1);
96   }
97
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());
107   Args.push_back(0);
108
109   std::cout << "<lli>";
110   return RunProgramWithTimeout(LLIPath, &Args[0],
111                                InputFile, OutputFile, OutputFile);
112 }
113
114 //===----------------------------------------------------------------------===//
115 // GCC abstraction
116 //
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
119 //
120 class GCC {
121   std::string GCCPath;          // The path to the gcc executable
122 public:
123   GCC(const std::string &gccPath) : GCCPath(gccPath) { }
124   virtual ~GCC() {}
125
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";
131       return 0;
132     }
133
134     Message = "Found gcc: " + GCCPath + "\n";
135     return new GCC(GCCPath);
136   }
137
138   virtual int ExecuteProgram(const std::string &ProgramFile,
139                              FileType fileType,
140                              const std::string &OutputFile,
141                              const std::string &SharedLib = "");
142
143   int MakeSharedObject(const std::string &InputFile,
144                        FileType fileType,
145                        std::string &OutputFile);
146   
147   void ProcessFailure(const char **Args);
148 };
149
150 int GCC::ExecuteProgram(const std::string &ProgramFile,
151                         FileType fileType,
152                         const std::string &OutputFile,
153                         const std::string &SharedLib) {
154   std::string OutputBinary = getUniqueFilename("bugpoint.gcc.exe");
155   std::vector<const char*> GCCArgs;
156
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
168
169   std::cout << "<gcc>";
170   if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
171                             "/dev/null")) {
172     ProcessFailure(&GCCArgs[0]);
173     exit(1);
174   }
175
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
182
183   // Now that we have a binary, run it!
184   std::cout << "<program>";
185   int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
186                                             InputFile, OutputFile, OutputFile);
187   std::cout << "\n";
188   removeFile(OutputBinary);
189   return ProgramResult;
190 }
191
192 int GCC::MakeSharedObject(const std::string &InputFile,
193                           FileType fileType,
194                           std::string &OutputFile) {
195   OutputFile = getUniqueFilename("./bugpoint.so");
196   // Compile the C/asm file into a shared object
197   const char* GCCArgs[] = {
198     GCCPath.c_str(),
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
203 #else                             
204     "-shared",                   // `-shared' for Linux/X86, maybe others
205 #endif
206     "-o", OutputFile.c_str(),    // Output to the right filename...
207     "-O2",                       // Optimize the program a bit...
208     0
209   };
210   
211   std::cout << "<gcc>";
212   if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
213                            "/dev/null")) {
214     ProcessFailure(GCCArgs);
215     exit(1);
216   }
217   return 0;
218 }
219
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;
224   std::cerr << "\n";
225
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());
230
231   // Print out the error messages generated by GCC if possible...
232   std::ifstream ErrorFile(ErrorFilename.c_str());
233   if (ErrorFile) {
234     std::copy(std::istreambuf_iterator<char>(ErrorFile),
235               std::istreambuf_iterator<char>(),
236               std::ostreambuf_iterator<char>(std::cerr));
237     ErrorFile.close();
238     std::cerr << "\n";      
239   }
240
241   removeFile(ErrorFilename);
242 }
243
244 //===----------------------------------------------------------------------===//
245 // LLC Implementation of AbstractIntepreter interface
246 //
247 class LLC : public AbstractInterpreter {
248   std::string LLCPath;          // The path to the LLC executable
249   GCC *gcc;
250 public:
251   LLC(const std::string &llcPath, GCC *Gcc)
252     : LLCPath(llcPath), gcc(Gcc) { }
253   ~LLC() { delete gcc; }
254
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";
260       return 0;
261     }
262
263     Message = "Found llc: " + LLCPath + "\n";
264     GCC *gcc = GCC::create(BD, Message);
265     if (!gcc) {
266       std::cerr << Message << "\n";
267       exit(1);
268     }
269     return new LLC(LLCPath, gcc);
270   }
271
272   virtual int ExecuteProgram(const std::string &Bytecode,
273                              const std::string &OutputFile,
274                              const std::string &SharedLib = "");
275
276   int OutputAsm(const std::string &Bytecode,
277                 std::string &OutputAsmFile);
278 };
279
280 int LLC::OutputAsm(const std::string &Bytecode,
281                    std::string &OutputAsmFile) {
282   OutputAsmFile = "bugpoint.llc.s";
283   const char *LLCArgs[] = {
284     LLCPath.c_str(),
285     "-o", OutputAsmFile.c_str(), // Output to the Asm file
286     "-f",                        // Overwrite as necessary...
287     Bytecode.c_str(),            // This is the input bytecode
288     0
289   };
290
291   std::cout << "<llc>";
292   if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
293                             "/dev/null")) {                            
294     // If LLC failed on the bytecode, print error...
295     std::cerr << "bugpoint error: `llc' failed!\n";
296     removeFile(OutputAsmFile);
297     return 1;
298   }
299
300   return 0;
301 }
302
303 int LLC::ExecuteProgram(const std::string &Bytecode,
304                         const std::string &OutputFile,
305                         const std::string &SharedLib) {
306
307   std::string OutputAsmFile;
308   if (OutputAsm(Bytecode, OutputAsmFile)) {
309     std::cerr << "Could not generate asm code with `llc', exiting.\n";
310     exit(1);
311   }
312
313   // Assuming LLC worked, compile the result with GCC and run it.
314   int Result = gcc->ExecuteProgram(OutputAsmFile,AsmFile,OutputFile,SharedLib);
315   removeFile(OutputAsmFile);
316   return Result;
317 }
318
319
320 //===----------------------------------------------------------------------===//
321 // JIT Implementation of AbstractIntepreter interface
322 //
323 class JIT : public AbstractInterpreter {
324   std::string LLIPath;          // The path to the LLI executable
325 public:
326   JIT(const std::string &Path) : LLIPath(Path) { }
327
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);
334     }
335
336     Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
337     return 0;
338   }
339   virtual int ExecuteProgram(const std::string &Bytecode,
340                              const std::string &OutputFile,
341                              const std::string &SharedLib = "");
342 };
343
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",
349     Bytecode.c_str(),
350     0
351   };
352
353   const char* ArgsWithSO[] = {
354     LLIPath.c_str(), "-quiet", "-force-interpreter=false", 
355     "-load", SharedLib.c_str(),
356     Bytecode.c_str(),
357     0
358   };
359
360   const char** JITArgs = SharedLib.empty() ? ArgsWithoutSO : ArgsWithSO;
361
362   std::cout << "<jit>";
363   DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
364   return RunProgramWithTimeout(LLIPath, JITArgs,
365                                InputFile, OutputFile, OutputFile);
366 }
367
368 //===----------------------------------------------------------------------===//
369 // CBE Implementation of AbstractIntepreter interface
370 //
371 class CBE : public AbstractInterpreter {
372   std::string DISPath;          // The path to the LLVM 'dis' executable
373   GCC *gcc;
374 public:
375   CBE(const std::string &disPath, GCC *Gcc) : DISPath(disPath), gcc(Gcc) { }
376   ~CBE() { delete gcc; }
377
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";
383       return 0;
384     }
385
386     Message = "Found dis: " + DISPath + "\n";
387
388     GCC *gcc = GCC::create(BD, Message);
389     if (!gcc) {
390       std::cerr << Message << "\n";
391       exit(1);
392     }
393     return new CBE(DISPath, gcc);
394   }
395
396   virtual int ExecuteProgram(const std::string &Bytecode,
397                              const std::string &OutputFile,
398                              const std::string &SharedLib = "");
399
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);
404
405 };
406
407 int CBE::OutputC(const std::string &Bytecode,
408                  std::string &OutputCFile) {
409   OutputCFile = "bugpoint.cbe.c";
410   const char *DisArgs[] = {
411     DISPath.c_str(),
412     "-o", OutputCFile.c_str(),   // Output to the C file
413     "-c",                        // Output to C
414     "-f",                        // Overwrite as necessary...
415     Bytecode.c_str(),            // This is the input bytecode
416     0
417   };
418
419   std::cout << "<cbe>";
420   if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
421                             "/dev/null")) {                            
422     // If dis failed on the bytecode, print error...
423     std::cerr << "bugpoint error: `dis -c' failed!\n";
424     return 1;
425   }
426
427   return 0;
428 }
429
430
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";
437     exit(1);
438   }
439
440   int Result = gcc->ExecuteProgram(OutputCFile, CFile, OutputFile, SharedLib);
441   removeFile(OutputCFile);
442
443   return Result;
444 }
445
446
447 //===----------------------------------------------------------------------===//
448 // BugDriver method implementation
449 //
450
451 /// initializeExecutionEnvironment - This method is used to set up the
452 /// environment for executing LLVM programs.
453 ///
454 bool BugDriver::initializeExecutionEnvironment() {
455   std::cout << "Initializing execution environment: ";
456
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.
459
460   // Create an instance of the AbstractInterpreter interface as specified on the
461   // command line
462   std::string Message;
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;
468   default:
469     Message = " Sorry, this back-end is not supported by bugpoint right now!\n";
470     break;
471   }
472
473   std::cout << Message;
474
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); }
480
481   // If there was an error creating the selected interpreter, quit with error.
482   return Interpreter == 0;
483 }
484
485
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.
489 ///
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");
499
500     if (writeProgramToFile(BytecodeFile, Program)) {
501       std::cerr << ToolName << ": Error emitting bytecode to file '"
502                 << BytecodeFile << "'!\n";
503       exit(1);
504     }
505     CreatedBytecode = true;
506   }
507
508   if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
509
510   // Check to see if this is a valid output filename...
511   OutputFile = getUniqueFilename(OutputFile);
512
513   // Actually execute the program!
514   int RetVal = (AI != 0) ?
515     AI->ExecuteProgram(BytecodeFile, OutputFile, SharedObject) :
516     Interpreter->ExecuteProgram(BytecodeFile, OutputFile, SharedObject);
517
518   // Remove the temporary bytecode file.
519   if (CreatedBytecode) removeFile(BytecodeFile);
520
521   // Return the filename we captured the output to.
522   return OutputFile;
523 }
524
525 std::string BugDriver::executeProgramWithCBE(std::string OutputFile,
526                                              std::string BytecodeFile,
527                                              std::string SharedObject) {
528   return executeProgram(OutputFile, BytecodeFile, SharedObject, cbe);
529 }
530
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;
535
536   // Using CBE
537   cbe->OutputC(BytecodeFile, OutputCFile);
538
539 #if 0 /* This is an alternative, as yet unimplemented */
540   // Using LLC
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";
544     exit(1);
545   }
546 #endif
547
548   gcc->MakeSharedObject(OutputCFile, CFile, SharedObject);
549
550   // Remove the intermediate C file
551   removeFile(OutputCFile);
552
553   return 0;
554 }
555
556
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.
560 ///
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);
566
567   std::ifstream ReferenceFile(ReferenceOutputFile.c_str());
568   if (!ReferenceFile) {
569     std::cerr << "Couldn't open reference output file '"
570               << ReferenceOutputFile << "'\n";
571     exit(1);
572   }
573
574   std::ifstream OutputFile(Output.c_str());
575   if (!OutputFile) {
576     std::cerr << "Couldn't open output file: " << Output << "'!\n";
577     exit(1);
578   }
579
580   bool FilesDifferent = false;
581
582   // Compare the two files...
583   int C1, C2;
584   do {
585     C1 = ReferenceFile.get();
586     C2 = OutputFile.get();
587     if (C1 != C2) { FilesDifferent = true; break; }
588   } while (C1 != EOF);
589
590   //removeFile(Output);
591   if (RemoveBytecode) removeFile(BytecodeFile);
592   return FilesDifferent;
593 }
594
595 bool BugDriver::isExecutingJIT() {
596   return InterpreterSel == RunJIT;
597 }