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