DEBUG got moved to Debug.h
[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/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>";
115   DEBUG(std::cerr << "About 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>";
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>";
195   DEBUG(std::cerr << "About 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   std::cout << "\n";
203   removeFile(OutputBinary);
204   return ProgramResult;
205 }
206
207 int GCC::MakeSharedObject(const std::string &InputFile,
208                           FileType fileType,
209                           std::string &OutputFile) {
210   OutputFile = getUniqueFilename("./bugpoint.so");
211   // Compile the C/asm file into a shared object
212   const char* GCCArgs[] = {
213     GCCPath.c_str(),
214     "-x", (fileType == AsmFile) ? "assembler" : "c",
215     InputFile.c_str(),           // Specify the input filename...
216 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
217     "-G",                        // Compile a shared library, `-G' for Sparc
218 #else                             
219     "-shared",                   // `-shared' for Linux/X86, maybe others
220 #endif
221     "-o", OutputFile.c_str(),    // Output to the right filename...
222     "-O2",                       // Optimize the program a bit...
223     0
224   };
225   
226   std::cout << "<gcc>";
227   if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
228                            "/dev/null")) {
229     ProcessFailure(GCCArgs);
230     exit(1);
231   }
232   return 0;
233 }
234
235 void GCC::ProcessFailure(const char** GCCArgs) {
236   std::cerr << "\n*** bugpoint error: invocation of the C compiler failed!\n";
237   for (const char **Arg = GCCArgs; *Arg; ++Arg)
238     std::cerr << " " << *Arg;
239   std::cerr << "\n";
240
241   // Rerun the compiler, capturing any error messages to print them.
242   std::string ErrorFilename = getUniqueFilename("bugpoint.gcc.errors");
243   RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
244                         ErrorFilename.c_str());
245
246   // Print out the error messages generated by GCC if possible...
247   std::ifstream ErrorFile(ErrorFilename.c_str());
248   if (ErrorFile) {
249     std::copy(std::istreambuf_iterator<char>(ErrorFile),
250               std::istreambuf_iterator<char>(),
251               std::ostreambuf_iterator<char>(std::cerr));
252     ErrorFile.close();
253     std::cerr << "\n";      
254   }
255
256   removeFile(ErrorFilename);
257 }
258
259 //===----------------------------------------------------------------------===//
260 // LLC Implementation of AbstractIntepreter interface
261 //
262 class LLC : public AbstractInterpreter {
263   std::string LLCPath;          // The path to the LLC executable
264   GCC *gcc;
265 public:
266   LLC(const std::string &llcPath, GCC *Gcc)
267     : LLCPath(llcPath), gcc(Gcc) { }
268   ~LLC() { delete gcc; }
269
270   // LLC create method - Try to find the LLC executable
271   static LLC *create(BugDriver *BD, std::string &Message) {
272     std::string LLCPath = FindExecutable("llc", BD->getToolName());
273     if (LLCPath.empty()) {
274       Message = "Cannot find `llc' in bugpoint executable directory or PATH!\n";
275       return 0;
276     }
277
278     Message = "Found llc: " + LLCPath + "\n";
279     GCC *gcc = GCC::create(BD, Message);
280     if (!gcc) {
281       std::cerr << Message << "\n";
282       exit(1);
283     }
284     return new LLC(LLCPath, gcc);
285   }
286
287   virtual int ExecuteProgram(const std::string &Bytecode,
288                              const std::string &OutputFile,
289                              const std::string &SharedLib = "");
290
291   int OutputAsm(const std::string &Bytecode,
292                 std::string &OutputAsmFile);
293 };
294
295 int LLC::OutputAsm(const std::string &Bytecode,
296                    std::string &OutputAsmFile) {
297   OutputAsmFile = "bugpoint.llc.s";
298   const char *LLCArgs[] = {
299     LLCPath.c_str(),
300     "-o", OutputAsmFile.c_str(), // Output to the Asm file
301     "-f",                        // Overwrite as necessary...
302     Bytecode.c_str(),            // This is the input bytecode
303     0
304   };
305
306   std::cout << "<llc>";
307   if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
308                             "/dev/null")) {                            
309     // If LLC failed on the bytecode, print error...
310     std::cerr << "bugpoint error: `llc' failed!\n";
311     removeFile(OutputAsmFile);
312     return 1;
313   }
314
315   return 0;
316 }
317
318 int LLC::ExecuteProgram(const std::string &Bytecode,
319                         const std::string &OutputFile,
320                         const std::string &SharedLib) {
321
322   std::string OutputAsmFile;
323   if (OutputAsm(Bytecode, OutputAsmFile)) {
324     std::cerr << "Could not generate asm code with `llc', exiting.\n";
325     exit(1);
326   }
327
328   // Assuming LLC worked, compile the result with GCC and run it.
329   int Result = gcc->ExecuteProgram(OutputAsmFile,AsmFile,OutputFile,SharedLib);
330   removeFile(OutputAsmFile);
331   return Result;
332 }
333
334
335 //===----------------------------------------------------------------------===//
336 // JIT Implementation of AbstractIntepreter interface
337 //
338 class JIT : public AbstractInterpreter {
339   std::string LLIPath;          // The path to the LLI executable
340 public:
341   JIT(const std::string &Path) : LLIPath(Path) { }
342
343   // JIT create method - Try to find the LLI executable
344   static JIT *create(BugDriver *BD, std::string &Message) {
345     std::string LLIPath = FindExecutable("lli", BD->getToolName());
346     if (!LLIPath.empty()) {
347       Message = "Found lli: " + LLIPath + "\n";
348       return new JIT(LLIPath);
349     }
350
351     Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
352     return 0;
353   }
354   virtual int ExecuteProgram(const std::string &Bytecode,
355                              const std::string &OutputFile,
356                              const std::string &SharedLib = "");
357 };
358
359 int JIT::ExecuteProgram(const std::string &Bytecode,
360                         const std::string &OutputFile,
361                         const std::string &SharedLib) {
362   // Construct a vector of parameters, incorporating those from the command-line
363   std::vector<const char*> JITArgs;
364   JITArgs.push_back(LLIPath.c_str());
365   JITArgs.push_back("-quiet");
366   JITArgs.push_back("-force-interpreter=false");
367   if (!SharedLib.empty()) {
368     JITArgs.push_back("-load");
369     JITArgs.push_back(SharedLib.c_str());
370   }
371   JITArgs.push_back(Bytecode.c_str());
372   // Add optional parameters to the running program from Argv
373   for (unsigned i=0, e = InputArgv.size(); i != e; ++i)
374     JITArgs.push_back(InputArgv[i].c_str());
375   JITArgs.push_back(0);
376
377   std::cout << "<jit>\n";
378   DEBUG(std::cerr << "About to run:\n\t";
379         for (unsigned i=0, e = JITArgs.size(); i != e; ++i)
380           std::cerr << " " << JITArgs[i];
381         std::cerr << "\n";
382         );
383   DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
384   return RunProgramWithTimeout(LLIPath, &JITArgs[0],
385                                InputFile, OutputFile, OutputFile);
386 }
387
388 //===----------------------------------------------------------------------===//
389 // CBE Implementation of AbstractIntepreter interface
390 //
391 class CBE : public AbstractInterpreter {
392   std::string DISPath;          // The path to the LLVM 'dis' executable
393   GCC *gcc;
394 public:
395   CBE(const std::string &disPath, GCC *Gcc) : DISPath(disPath), gcc(Gcc) { }
396   ~CBE() { delete gcc; }
397
398   // CBE create method - Try to find the 'dis' executable
399   static CBE *create(BugDriver *BD, std::string &Message) {
400     std::string DISPath = FindExecutable("dis", BD->getToolName());
401     if (DISPath.empty()) {
402       Message = "Cannot find `dis' in bugpoint executable directory or PATH!\n";
403       return 0;
404     }
405
406     Message = "Found dis: " + DISPath + "\n";
407
408     GCC *gcc = GCC::create(BD, Message);
409     if (!gcc) {
410       std::cerr << Message << "\n";
411       exit(1);
412     }
413     return new CBE(DISPath, gcc);
414   }
415
416   virtual int ExecuteProgram(const std::string &Bytecode,
417                              const std::string &OutputFile,
418                              const std::string &SharedLib = "");
419
420   // Sometimes we just want to go half-way and only generate the C file,
421   // not necessarily compile it with GCC and run the program
422   virtual int OutputC(const std::string &Bytecode,
423                       std::string &OutputCFile);
424
425 };
426
427 int CBE::OutputC(const std::string &Bytecode,
428                  std::string &OutputCFile) {
429   OutputCFile = "bugpoint.cbe.c";
430   const char *DisArgs[] = {
431     DISPath.c_str(),
432     "-o", OutputCFile.c_str(),   // Output to the C file
433     "-c",                        // Output to C
434     "-f",                        // Overwrite as necessary...
435     Bytecode.c_str(),            // This is the input bytecode
436     0
437   };
438
439   std::cout << "<cbe>";
440   if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
441                             "/dev/null")) {                            
442     // If dis failed on the bytecode, print error...
443     std::cerr << "bugpoint error: `dis -c' failed!\n";
444     return 1;
445   }
446
447   return 0;
448 }
449
450
451 int CBE::ExecuteProgram(const std::string &Bytecode,
452                         const std::string &OutputFile,
453                         const std::string &SharedLib) {
454   std::string OutputCFile;
455   if (OutputC(Bytecode, OutputCFile)) {
456     std::cerr << "Could not generate C code with `dis', exiting.\n";
457     exit(1);
458   }
459
460   int Result = gcc->ExecuteProgram(OutputCFile, CFile, OutputFile, SharedLib);
461   removeFile(OutputCFile);
462
463   return Result;
464 }
465
466
467 //===----------------------------------------------------------------------===//
468 // BugDriver method implementation
469 //
470
471 /// initializeExecutionEnvironment - This method is used to set up the
472 /// environment for executing LLVM programs.
473 ///
474 bool BugDriver::initializeExecutionEnvironment() {
475   std::cout << "Initializing execution environment: ";
476
477   // FIXME: This should default to searching for the best interpreter to use on
478   // this platform, which would be JIT, then LLC, then CBE, then LLI.
479
480   // Create an instance of the AbstractInterpreter interface as specified on the
481   // command line
482   std::string Message;
483   switch (InterpreterSel) {
484   case RunLLI: Interpreter = LLI::create(this, Message); break;
485   case RunLLC: Interpreter = LLC::create(this, Message); break;
486   case RunJIT: Interpreter = JIT::create(this, Message); break;
487   case RunCBE: Interpreter = CBE::create(this, Message); break;
488   default:
489     Message = " Sorry, this back-end is not supported by bugpoint right now!\n";
490     break;
491   }
492
493   std::cout << Message;
494
495   // Initialize auxiliary tools for debugging
496   cbe = CBE::create(this, Message);
497   if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
498   gcc = GCC::create(this, Message);
499   if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
500
501   // If there was an error creating the selected interpreter, quit with error.
502   return Interpreter == 0;
503 }
504
505
506 /// executeProgram - This method runs "Program", capturing the output of the
507 /// program to a file, returning the filename of the file.  A recommended
508 /// filename may be optionally specified.
509 ///
510 std::string BugDriver::executeProgram(std::string OutputFile,
511                                       std::string BytecodeFile,
512                                       std::string SharedObject,
513                                       AbstractInterpreter *AI) {
514   assert((Interpreter || AI) &&"Interpreter should have been created already!");
515   bool CreatedBytecode = false;
516   if (BytecodeFile.empty()) {
517     // Emit the program to a bytecode file...
518     BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
519
520     if (writeProgramToFile(BytecodeFile, Program)) {
521       std::cerr << ToolName << ": Error emitting bytecode to file '"
522                 << BytecodeFile << "'!\n";
523       exit(1);
524     }
525     CreatedBytecode = true;
526   }
527
528   if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
529
530   // Check to see if this is a valid output filename...
531   OutputFile = getUniqueFilename(OutputFile);
532
533   // Actually execute the program!
534   int RetVal = (AI != 0) ?
535     AI->ExecuteProgram(BytecodeFile, OutputFile, SharedObject) :
536     Interpreter->ExecuteProgram(BytecodeFile, OutputFile, SharedObject);
537
538   // Remove the temporary bytecode file.
539   if (CreatedBytecode) removeFile(BytecodeFile);
540
541   // Return the filename we captured the output to.
542   return OutputFile;
543 }
544
545 std::string BugDriver::executeProgramWithCBE(std::string OutputFile,
546                                              std::string BytecodeFile,
547                                              std::string SharedObject) {
548   return executeProgram(OutputFile, BytecodeFile, SharedObject, cbe);
549 }
550
551 int BugDriver::compileSharedObject(const std::string &BytecodeFile,
552                                    std::string &SharedObject) {
553   assert(Interpreter && "Interpreter should have been created already!");
554   std::string Message, OutputCFile;
555
556   // Using CBE
557   cbe->OutputC(BytecodeFile, OutputCFile);
558
559 #if 0 /* This is an alternative, as yet unimplemented */
560   // Using LLC
561   LLC *llc = LLC::create(this, Message);
562   if (llc->OutputAsm(BytecodeFile, OutputFile)) {
563     std::cerr << "Could not generate asm code with `llc', exiting.\n";
564     exit(1);
565   }
566 #endif
567
568   gcc->MakeSharedObject(OutputCFile, CFile, SharedObject);
569
570   // Remove the intermediate C file
571   removeFile(OutputCFile);
572
573   return 0;
574 }
575
576
577 /// diffProgram - This method executes the specified module and diffs the output
578 /// against the file specified by ReferenceOutputFile.  If the output is
579 /// different, true is returned.
580 ///
581 bool BugDriver::diffProgram(const std::string &BytecodeFile,
582                             const std::string &SharedObject,
583                             bool RemoveBytecode) {
584   // Execute the program, generating an output file...
585   std::string Output = executeProgram("", BytecodeFile, SharedObject);
586
587   std::string Error;
588   bool FilesDifferent = false;
589   if (DiffFiles(ReferenceOutputFile, Output, &Error)) {
590     if (!Error.empty()) {
591       std::cerr << "While diffing output: " << Error << "\n";
592       exit(1);
593     }
594     FilesDifferent = true;
595   }
596
597   if (RemoveBytecode) removeFile(BytecodeFile);
598   return FilesDifferent;
599 }
600
601 bool BugDriver::isExecutingJIT() {
602   return InterpreterSel == RunJIT;
603 }