Remove trailing whitespace
[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 "llvm/Support/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 using namespace llvm;
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     AutoPick, RunLLI, RunJIT, RunLLC, RunCBE
30   };
31
32   cl::opt<double>
33   AbsTolerance("abs-tolerance", cl::desc("Absolute error tolerated"),
34                cl::init(0.0));
35   cl::opt<double>
36   RelTolerance("rel-tolerance", cl::desc("Relative error tolerated"),
37                cl::init(0.0));
38
39   cl::opt<OutputType>
40   InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
41                  cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
42                             clEnumValN(RunLLI, "run-int",
43                                        "Execute with the interpreter"),
44                             clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
45                             clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
46                             clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
47                             clEnumValEnd),
48                  cl::init(AutoPick));
49
50   cl::opt<bool>
51   CheckProgramExitCode("check-exit-code",
52                    cl::desc("Assume nonzero exit code is failure (default on)"),
53                        cl::init(true));
54
55   cl::opt<std::string>
56   InputFile("input", cl::init("/dev/null"),
57             cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
58
59   cl::list<std::string>
60   AdditionalSOs("additional-so",
61                 cl::desc("Additional shared objects to load "
62                          "into executing programs"));
63
64   cl::opt<unsigned>
65   TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"),
66                cl::desc("Number of seconds program is allowed to run before it "
67                         "is killed (default is 300s), 0 disables timeout"));
68 }
69
70 namespace llvm {
71   // Anything specified after the --args option are taken as arguments to the
72   // program being debugged.
73   cl::list<std::string>
74   InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
75             cl::ZeroOrMore, cl::PositionalEatsArgs);
76
77   cl::list<std::string>
78   ToolArgv("tool-args", cl::Positional, cl::desc("<tool arguments>..."),
79            cl::ZeroOrMore, cl::PositionalEatsArgs);
80 }
81
82 //===----------------------------------------------------------------------===//
83 // BugDriver method implementation
84 //
85
86 /// initializeExecutionEnvironment - This method is used to set up the
87 /// environment for executing LLVM programs.
88 ///
89 bool BugDriver::initializeExecutionEnvironment() {
90   std::cout << "Initializing execution environment: ";
91
92   // Create an instance of the AbstractInterpreter interface as specified on
93   // the command line
94   cbe = 0;
95   std::string Message;
96
97   switch (InterpreterSel) {
98   case AutoPick:
99     InterpreterSel = RunCBE;
100     Interpreter = cbe = AbstractInterpreter::createCBE(getToolName(), Message,
101                                                        &ToolArgv);
102     if (!Interpreter) {
103       InterpreterSel = RunJIT;
104       Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
105                                                    &ToolArgv);
106     }
107     if (!Interpreter) {
108       InterpreterSel = RunLLC;
109       Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
110                                                    &ToolArgv);
111     }
112     if (!Interpreter) {
113       InterpreterSel = RunLLI;
114       Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
115                                                    &ToolArgv);
116     }
117     if (!Interpreter) {
118       InterpreterSel = AutoPick;
119       Message = "Sorry, I can't automatically select an interpreter!\n";
120     }
121     break;
122   case RunLLI:
123     Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
124                                                  &ToolArgv);
125     break;
126   case RunLLC:
127     Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
128                                                  &ToolArgv);
129     break;
130   case RunJIT:
131     Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
132                                                  &ToolArgv);
133     break;
134   case RunCBE:
135     Interpreter = cbe = AbstractInterpreter::createCBE(getToolName(), Message,
136                                                        &ToolArgv);
137     break;
138   default:
139     Message = "Sorry, this back-end is not supported by bugpoint right now!\n";
140     break;
141   }
142   std::cerr << Message;
143
144   // Initialize auxiliary tools for debugging
145   if (!cbe) {
146     cbe = AbstractInterpreter::createCBE(getToolName(), Message, &ToolArgv);
147     if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
148   }
149   gcc = GCC::create(getToolName(), Message);
150   if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
151
152   // If there was an error creating the selected interpreter, quit with error.
153   return Interpreter == 0;
154 }
155
156 /// compileProgram - Try to compile the specified module, throwing an exception
157 /// if an error occurs, or returning normally if not.  This is used for code
158 /// generation crash testing.
159 ///
160 void BugDriver::compileProgram(Module *M) {
161   // Emit the program to a bytecode file...
162   sys::Path BytecodeFile ("bugpoint-test-program.bc");
163   BytecodeFile.makeUnique();
164   if (writeProgramToFile(BytecodeFile.toString(), M)) {
165     std::cerr << ToolName << ": Error emitting bytecode to file '"
166               << BytecodeFile << "'!\n";
167     exit(1);
168   }
169
170     // Remove the temporary bytecode file when we are done.
171   FileRemover BytecodeFileRemover(BytecodeFile);
172
173   // Actually compile the program!
174   Interpreter->compileProgram(BytecodeFile.toString());
175 }
176
177
178 /// executeProgram - This method runs "Program", capturing the output of the
179 /// program to a file, returning the filename of the file.  A recommended
180 /// filename may be optionally specified.
181 ///
182 std::string BugDriver::executeProgram(std::string OutputFile,
183                                       std::string BytecodeFile,
184                                       const std::string &SharedObj,
185                                       AbstractInterpreter *AI,
186                                       bool *ProgramExitedNonzero) {
187   if (AI == 0) AI = Interpreter;
188   assert(AI && "Interpreter should have been created already!");
189   bool CreatedBytecode = false;
190   if (BytecodeFile.empty()) {
191     // Emit the program to a bytecode file...
192     sys::Path uniqueFilename("bugpoint-test-program.bc");
193     uniqueFilename.makeUnique();
194     BytecodeFile = uniqueFilename.toString();
195
196     if (writeProgramToFile(BytecodeFile, Program)) {
197       std::cerr << ToolName << ": Error emitting bytecode to file '"
198                 << BytecodeFile << "'!\n";
199       exit(1);
200     }
201     CreatedBytecode = true;
202   }
203
204   // Remove the temporary bytecode file when we are done.
205   sys::Path BytecodePath (BytecodeFile);
206   FileRemover BytecodeFileRemover(BytecodePath, CreatedBytecode);
207
208   if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
209
210   // Check to see if this is a valid output filename...
211   sys::Path uniqueFile(OutputFile);
212   uniqueFile.makeUnique();
213   OutputFile = uniqueFile.toString();
214
215   // Figure out which shared objects to run, if any.
216   std::vector<std::string> SharedObjs(AdditionalSOs);
217   if (!SharedObj.empty())
218     SharedObjs.push_back(SharedObj);
219
220   // Actually execute the program!
221   int RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
222                                   OutputFile, SharedObjs, TimeoutValue);
223
224   if (RetVal == -1) {
225     std::cerr << "<timeout>";
226     static bool FirstTimeout = true;
227     if (FirstTimeout) {
228       std::cout << "\n"
229  "*** Program execution timed out!  This mechanism is designed to handle\n"
230  "    programs stuck in infinite loops gracefully.  The -timeout option\n"
231  "    can be used to change the timeout threshold or disable it completely\n"
232  "    (with -timeout=0).  This message is only displayed once.\n";
233       FirstTimeout = false;
234     }
235   }
236
237   if (ProgramExitedNonzero != 0)
238     *ProgramExitedNonzero = (RetVal != 0);
239
240   // Return the filename we captured the output to.
241   return OutputFile;
242 }
243
244 /// executeProgramWithCBE - Used to create reference output with the C
245 /// backend, if reference output is not provided.
246 ///
247 std::string BugDriver::executeProgramWithCBE(std::string OutputFile) {
248   bool ProgramExitedNonzero;
249   std::string outFN = executeProgram(OutputFile, "", "",
250                                      (AbstractInterpreter*)cbe,
251                                      &ProgramExitedNonzero);
252   if (ProgramExitedNonzero) {
253     std::cerr
254       << "Warning: While generating reference output, program exited with\n"
255       << "non-zero exit code. This will NOT be treated as a failure.\n";
256     CheckProgramExitCode = false;
257   }
258   return outFN;
259 }
260
261 std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) {
262   assert(Interpreter && "Interpreter should have been created already!");
263   sys::Path OutputCFile;
264
265   // Using CBE
266   cbe->OutputC(BytecodeFile, OutputCFile);
267
268 #if 0 /* This is an alternative, as yet unimplemented */
269   // Using LLC
270   std::string Message;
271   LLC *llc = createLLCtool(Message);
272   if (llc->OutputAsm(BytecodeFile, OutputFile)) {
273     std::cerr << "Could not generate asm code with `llc', exiting.\n";
274     exit(1);
275   }
276 #endif
277
278   std::string SharedObjectFile;
279   if (gcc->MakeSharedObject(OutputCFile.toString(), GCC::CFile,
280                             SharedObjectFile))
281     exit(1);
282
283   // Remove the intermediate C file
284   OutputCFile.destroyFile();
285
286   return "./" + SharedObjectFile;
287 }
288
289
290 /// diffProgram - This method executes the specified module and diffs the output
291 /// against the file specified by ReferenceOutputFile.  If the output is
292 /// different, true is returned.
293 ///
294 bool BugDriver::diffProgram(const std::string &BytecodeFile,
295                             const std::string &SharedObject,
296                             bool RemoveBytecode) {
297   bool ProgramExitedNonzero;
298
299   // Execute the program, generating an output file...
300   sys::Path Output (executeProgram("", BytecodeFile, SharedObject, 0,
301                                       &ProgramExitedNonzero));
302
303   // If we're checking the program exit code, assume anything nonzero is bad.
304   if (CheckProgramExitCode && ProgramExitedNonzero) {
305     Output.destroyFile();
306     if (RemoveBytecode)
307       sys::Path(BytecodeFile).destroyFile();
308     return true;
309   }
310
311   std::string Error;
312   bool FilesDifferent = false;
313   if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile),
314                                         sys::Path(Output.toString()),
315                                         AbsTolerance, RelTolerance, &Error)) {
316     if (Diff == 2) {
317       std::cerr << "While diffing output: " << Error << '\n';
318       exit(1);
319     }
320     FilesDifferent = true;
321   }
322
323   // Remove the generated output.
324   Output.destroyFile();
325
326   // Remove the bytecode file if we are supposed to.
327   if (RemoveBytecode) sys::Path(BytecodeFile).destroyFile();
328   return FilesDifferent;
329 }
330
331 bool BugDriver::isExecutingJIT() {
332   return InterpreterSel == RunJIT;
333 }
334