Pretty straightforward replacement of "bytecode" by "bitcode"
[oota-llvm.git] / tools / bugpoint / ExecutionDriver.cpp
1 //===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains code used to execute the program utilizing one of the
11 // various ways of running LLVM bitcode.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "BugDriver.h"
16 #include "ToolRunner.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/FileUtilities.h"
20 #include "llvm/Support/SystemUtils.h"
21 #include <fstream>
22 #include <iostream>
23
24 using namespace llvm;
25
26 namespace {
27   // OutputType - Allow the user to specify the way code should be run, to test
28   // for miscompilation.
29   //
30   enum OutputType {
31     AutoPick, RunLLI, RunJIT, RunLLC, RunCBE, CBE_bug, LLC_Safe
32   };
33
34   cl::opt<double>
35   AbsTolerance("abs-tolerance", cl::desc("Absolute error tolerated"),
36                cl::init(0.0));
37   cl::opt<double>
38   RelTolerance("rel-tolerance", cl::desc("Relative error tolerated"),
39                cl::init(0.0));
40
41   cl::opt<OutputType>
42   InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
43                  cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
44                             clEnumValN(RunLLI, "run-int",
45                                        "Execute with the interpreter"),
46                             clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
47                             clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
48                             clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
49                             clEnumValN(CBE_bug,"cbe-bug", "Find CBE bugs"),
50                             clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"),
51                             clEnumValEnd),
52                  cl::init(AutoPick));
53
54   cl::opt<bool>
55   CheckProgramExitCode("check-exit-code",
56                    cl::desc("Assume nonzero exit code is failure (default on)"),
57                        cl::init(true));
58
59   cl::opt<bool>
60   AppendProgramExitCode("append-exit-code",
61       cl::desc("Append the exit code to the output so it gets diff'd too"),
62       cl::init(false));
63
64   cl::opt<std::string>
65   InputFile("input", cl::init("/dev/null"),
66             cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
67
68   cl::list<std::string>
69   AdditionalSOs("additional-so",
70                 cl::desc("Additional shared objects to load "
71                          "into executing programs"));
72
73   cl::list<std::string>
74     AdditionalLinkerArgs("Xlinker", 
75       cl::desc("Additional arguments to pass to the linker"));
76 }
77
78 namespace llvm {
79   // Anything specified after the --args option are taken as arguments to the
80   // program being debugged.
81   cl::list<std::string>
82   InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
83             cl::ZeroOrMore, cl::PositionalEatsArgs);
84
85   cl::list<std::string>
86   ToolArgv("tool-args", cl::Positional, cl::desc("<tool arguments>..."),
87            cl::ZeroOrMore, cl::PositionalEatsArgs);
88 }
89
90 //===----------------------------------------------------------------------===//
91 // BugDriver method implementation
92 //
93
94 /// initializeExecutionEnvironment - This method is used to set up the
95 /// environment for executing LLVM programs.
96 ///
97 bool BugDriver::initializeExecutionEnvironment() {
98   std::cout << "Initializing execution environment: ";
99
100   // Create an instance of the AbstractInterpreter interface as specified on
101   // the command line
102   cbe = 0;
103   std::string Message;
104
105   switch (InterpreterSel) {
106   case AutoPick:
107     InterpreterSel = RunCBE;
108     Interpreter = cbe = AbstractInterpreter::createCBE(getToolName(), Message,
109                                                        &ToolArgv);
110     if (!Interpreter) {
111       InterpreterSel = RunJIT;
112       Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
113                                                    &ToolArgv);
114     }
115     if (!Interpreter) {
116       InterpreterSel = RunLLC;
117       Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
118                                                    &ToolArgv);
119     }
120     if (!Interpreter) {
121       InterpreterSel = RunLLI;
122       Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
123                                                    &ToolArgv);
124     }
125     if (!Interpreter) {
126       InterpreterSel = AutoPick;
127       Message = "Sorry, I can't automatically select an interpreter!\n";
128     }
129     break;
130   case RunLLI:
131     Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
132                                                  &ToolArgv);
133     break;
134   case RunLLC:
135     Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
136                                                  &ToolArgv);
137     break;
138   case RunJIT:
139     Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
140                                                  &ToolArgv);
141     break;
142   case LLC_Safe:
143     Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
144                                                  &ToolArgv);
145     break;
146   case RunCBE:
147   case CBE_bug:
148     Interpreter = AbstractInterpreter::createCBE(getToolName(), Message,
149                                                  &ToolArgv);
150     break;
151   default:
152     Message = "Sorry, this back-end is not supported by bugpoint right now!\n";
153     break;
154   }
155   std::cerr << Message;
156
157   // Initialize auxiliary tools for debugging
158   if (InterpreterSel == RunCBE) {
159     // We already created a CBE, reuse it.
160     cbe = Interpreter;
161   } else if (InterpreterSel == CBE_bug || InterpreterSel == LLC_Safe) {
162     // We want to debug the CBE itself or LLC is known-good.  Use LLC as the
163     // 'known-good' compiler.
164     std::vector<std::string> ToolArgs;
165     ToolArgs.push_back("--relocation-model=pic");
166     cbe = AbstractInterpreter::createLLC(getToolName(), Message, &ToolArgs);
167   } else {
168     cbe = AbstractInterpreter::createCBE(getToolName(), Message, &ToolArgv);
169   }
170   if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
171   
172   gcc = GCC::create(getToolName(), Message);
173   if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
174
175   // If there was an error creating the selected interpreter, quit with error.
176   return Interpreter == 0;
177 }
178
179 /// compileProgram - Try to compile the specified module, throwing an exception
180 /// if an error occurs, or returning normally if not.  This is used for code
181 /// generation crash testing.
182 ///
183 void BugDriver::compileProgram(Module *M) {
184   // Emit the program to a bitcode file...
185   sys::Path BitcodeFile ("bugpoint-test-program.bc");
186   std::string ErrMsg;
187   if (BitcodeFile.makeUnique(true,&ErrMsg)) {
188     std::cerr << ToolName << ": Error making unique filename: " << ErrMsg 
189               << "\n";
190     exit(1);
191   }
192   if (writeProgramToFile(BitcodeFile.toString(), M)) {
193     std::cerr << ToolName << ": Error emitting bitcode to file '"
194               << BitcodeFile << "'!\n";
195     exit(1);
196   }
197
198     // Remove the temporary bitcode file when we are done.
199   FileRemover BitcodeFileRemover(BitcodeFile);
200
201   // Actually compile the program!
202   Interpreter->compileProgram(BitcodeFile.toString());
203 }
204
205
206 /// executeProgram - This method runs "Program", capturing the output of the
207 /// program to a file, returning the filename of the file.  A recommended
208 /// filename may be optionally specified.
209 ///
210 std::string BugDriver::executeProgram(std::string OutputFile,
211                                       std::string BitcodeFile,
212                                       const std::string &SharedObj,
213                                       AbstractInterpreter *AI,
214                                       bool *ProgramExitedNonzero) {
215   if (AI == 0) AI = Interpreter;
216   assert(AI && "Interpreter should have been created already!");
217   bool CreatedBitcode = false;
218   std::string ErrMsg;
219   if (BitcodeFile.empty()) {
220     // Emit the program to a bitcode file...
221     sys::Path uniqueFilename("bugpoint-test-program.bc");
222     if (uniqueFilename.makeUnique(true, &ErrMsg)) {
223       std::cerr << ToolName << ": Error making unique filename: " 
224                 << ErrMsg << "!\n";
225       exit(1);
226     }
227     BitcodeFile = uniqueFilename.toString();
228
229     if (writeProgramToFile(BitcodeFile, Program)) {
230       std::cerr << ToolName << ": Error emitting bitcode to file '"
231                 << BitcodeFile << "'!\n";
232       exit(1);
233     }
234     CreatedBitcode = true;
235   }
236
237   // Remove the temporary bitcode file when we are done.
238   sys::Path BitcodePath (BitcodeFile);
239   FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode);
240
241   if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
242
243   // Check to see if this is a valid output filename...
244   sys::Path uniqueFile(OutputFile);
245   if (uniqueFile.makeUnique(true, &ErrMsg)) {
246     std::cerr << ToolName << ": Error making unique filename: "
247               << ErrMsg << "\n";
248     exit(1);
249   }
250   OutputFile = uniqueFile.toString();
251
252   // Figure out which shared objects to run, if any.
253   std::vector<std::string> SharedObjs(AdditionalSOs);
254   if (!SharedObj.empty())
255     SharedObjs.push_back(SharedObj);
256
257   
258   // If this is an LLC or CBE run, then the GCC compiler might get run to 
259   // compile the program. If so, we should pass the user's -Xlinker options
260   // as the GCCArgs.
261   int RetVal = 0;
262   if (InterpreterSel == RunLLC || InterpreterSel == RunCBE ||
263       InterpreterSel == CBE_bug || InterpreterSel == LLC_Safe)
264     RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile,
265                                 OutputFile, AdditionalLinkerArgs, SharedObjs, 
266                                 Timeout, MemoryLimit);
267   else 
268     RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile,
269                                 OutputFile, std::vector<std::string>(), 
270                                 SharedObjs, Timeout, MemoryLimit);
271
272   if (RetVal == -1) {
273     std::cerr << "<timeout>";
274     static bool FirstTimeout = true;
275     if (FirstTimeout) {
276       std::cout << "\n"
277  "*** Program execution timed out!  This mechanism is designed to handle\n"
278  "    programs stuck in infinite loops gracefully.  The -timeout option\n"
279  "    can be used to change the timeout threshold or disable it completely\n"
280  "    (with -timeout=0).  This message is only displayed once.\n";
281       FirstTimeout = false;
282     }
283   }
284
285   if (AppendProgramExitCode) {
286     std::ofstream outFile(OutputFile.c_str(), std::ios_base::app);
287     outFile << "exit " << RetVal << '\n';
288     outFile.close();
289   }
290
291   if (ProgramExitedNonzero != 0)
292     *ProgramExitedNonzero = (RetVal != 0);
293
294   // Return the filename we captured the output to.
295   return OutputFile;
296 }
297
298 /// executeProgramWithCBE - Used to create reference output with the C
299 /// backend, if reference output is not provided.
300 ///
301 std::string BugDriver::executeProgramWithCBE(std::string OutputFile) {
302   bool ProgramExitedNonzero;
303   std::string outFN = executeProgram(OutputFile, "", "", cbe,
304                                      &ProgramExitedNonzero);
305   if (ProgramExitedNonzero) {
306     std::cerr
307       << "Warning: While generating reference output, program exited with\n"
308       << "non-zero exit code. This will NOT be treated as a failure.\n";
309     CheckProgramExitCode = false;
310   }
311   return outFN;
312 }
313
314 std::string BugDriver::compileSharedObject(const std::string &BitcodeFile) {
315   assert(Interpreter && "Interpreter should have been created already!");
316   sys::Path OutputFile;
317
318   // Using CBE
319   GCC::FileType FT = cbe->OutputCode(BitcodeFile, OutputFile);
320
321   std::string SharedObjectFile;
322   if (gcc->MakeSharedObject(OutputFile.toString(), FT,
323                             SharedObjectFile, AdditionalLinkerArgs))
324     exit(1);
325
326   // Remove the intermediate C file
327   OutputFile.eraseFromDisk();
328
329   return "./" + SharedObjectFile;
330 }
331
332 /// createReferenceFile - calls compileProgram and then records the output
333 /// into ReferenceOutputFile. Returns true if reference file created, false 
334 /// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
335 /// this function.
336 ///
337 bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) {
338   try {
339     compileProgram(Program);
340   } catch (ToolExecutionError &) {
341     return false;
342   }
343   try {
344     ReferenceOutputFile = executeProgramWithCBE(Filename);
345     std::cout << "Reference output is: " << ReferenceOutputFile << "\n\n";
346   } catch (ToolExecutionError &TEE) {
347     std::cerr << TEE.what();
348     if (Interpreter != cbe) {
349       std::cerr << "*** There is a bug running the C backend.  Either debug"
350                 << " it (use the -run-cbe bugpoint option), or fix the error"
351                 << " some other way.\n";
352     }
353     return false;
354   }
355   return true;
356 }
357
358 /// diffProgram - This method executes the specified module and diffs the
359 /// output against the file specified by ReferenceOutputFile.  If the output
360 /// is different, true is returned.  If there is a problem with the code
361 /// generator (e.g., llc crashes), this will throw an exception.
362 ///
363 bool BugDriver::diffProgram(const std::string &BitcodeFile,
364                             const std::string &SharedObject,
365                             bool RemoveBitcode) {
366   bool ProgramExitedNonzero;
367
368   // Execute the program, generating an output file...
369   sys::Path Output(executeProgram("", BitcodeFile, SharedObject, 0,
370                                       &ProgramExitedNonzero));
371
372   // If we're checking the program exit code, assume anything nonzero is bad.
373   if (CheckProgramExitCode && ProgramExitedNonzero) {
374     Output.eraseFromDisk();
375     if (RemoveBitcode)
376       sys::Path(BitcodeFile).eraseFromDisk();
377     return true;
378   }
379
380   std::string Error;
381   bool FilesDifferent = false;
382   if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile),
383                                         sys::Path(Output.toString()),
384                                         AbsTolerance, RelTolerance, &Error)) {
385     if (Diff == 2) {
386       std::cerr << "While diffing output: " << Error << '\n';
387       exit(1);
388     }
389     FilesDifferent = true;
390   }
391
392   // Remove the generated output.
393   Output.eraseFromDisk();
394
395   // Remove the bitcode file if we are supposed to.
396   if (RemoveBitcode)
397     sys::Path(BitcodeFile).eraseFromDisk();
398   return FilesDifferent;
399 }
400
401 bool BugDriver::isExecutingJIT() {
402   return InterpreterSel == RunJIT;
403 }
404