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