Fix the build on PowerPC/Darwin - it thought we were declaring a new
[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);
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   sys::Path BytecodePath (BytecodeFile);
199   FileRemover BytecodeFileRemover(BytecodePath, CreatedBytecode);
200
201   if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
202
203   // Check to see if this is a valid output filename...
204   sys::Path uniqueFile(OutputFile);
205   uniqueFile.makeUnique();
206   OutputFile = uniqueFile.toString();
207
208   // Figure out which shared objects to run, if any.
209   std::vector<std::string> SharedObjs(AdditionalSOs);
210   if (!SharedObj.empty())
211     SharedObjs.push_back(SharedObj);
212
213   // Actually execute the program!
214   int RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
215                                   OutputFile, SharedObjs, TimeoutValue);
216
217   if (RetVal == -1) {
218     std::cerr << "<timeout>";
219     static bool FirstTimeout = true;
220     if (FirstTimeout) {
221       std::cout << "\n"
222  "*** Program execution timed out!  This mechanism is designed to handle\n"
223  "    programs stuck in infinite loops gracefully.  The -timeout option\n"
224  "    can be used to change the timeout threshold or disable it completely\n"
225  "    (with -timeout=0).  This message is only displayed once.\n";
226       FirstTimeout = false;
227     }
228   }
229
230   if (ProgramExitedNonzero != 0)
231     *ProgramExitedNonzero = (RetVal != 0);
232
233   // Return the filename we captured the output to.
234   return OutputFile;
235 }
236
237 /// executeProgramWithCBE - Used to create reference output with the C
238 /// backend, if reference output is not provided.
239 ///
240 std::string BugDriver::executeProgramWithCBE(std::string OutputFile) {
241   bool ProgramExitedNonzero;
242   std::string outFN = executeProgram(OutputFile, "", "",
243                                      (AbstractInterpreter*)cbe,
244                                      &ProgramExitedNonzero);
245   if (ProgramExitedNonzero) {
246     std::cerr
247       << "Warning: While generating reference output, program exited with\n"
248       << "non-zero exit code. This will NOT be treated as a failure.\n";
249     CheckProgramExitCode = false;
250   }
251   return outFN;
252 }
253
254 std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) {
255   assert(Interpreter && "Interpreter should have been created already!");
256   sys::Path OutputCFile;
257
258   // Using CBE
259   cbe->OutputC(BytecodeFile, OutputCFile);
260
261 #if 0 /* This is an alternative, as yet unimplemented */
262   // Using LLC
263   std::string Message;
264   LLC *llc = createLLCtool(Message);
265   if (llc->OutputAsm(BytecodeFile, OutputFile)) {
266     std::cerr << "Could not generate asm code with `llc', exiting.\n";
267     exit(1);
268   }
269 #endif
270
271   std::string SharedObjectFile;
272   if (gcc->MakeSharedObject(OutputCFile.toString(), GCC::CFile, 
273                             SharedObjectFile))
274     exit(1);
275
276   // Remove the intermediate C file
277   OutputCFile.destroyFile();
278
279   return "./" + SharedObjectFile;
280 }
281
282
283 /// diffProgram - This method executes the specified module and diffs the output
284 /// against the file specified by ReferenceOutputFile.  If the output is
285 /// different, true is returned.
286 ///
287 bool BugDriver::diffProgram(const std::string &BytecodeFile,
288                             const std::string &SharedObject,
289                             bool RemoveBytecode) {
290   bool ProgramExitedNonzero;
291
292   // Execute the program, generating an output file...
293   sys::Path Output (executeProgram("", BytecodeFile, SharedObject, 0,
294                                       &ProgramExitedNonzero));
295
296   // If we're checking the program exit code, assume anything nonzero is bad.
297   if (CheckProgramExitCode && ProgramExitedNonzero) {
298     Output.destroyFile();
299     if (RemoveBytecode) 
300       sys::Path(BytecodeFile).destroyFile();
301     return true;
302   }
303
304   std::string Error;
305   bool FilesDifferent = false;
306   if (DiffFiles(ReferenceOutputFile, Output.toString(), &Error)) {
307     if (!Error.empty()) {
308       std::cerr << "While diffing output: " << Error << '\n';
309       exit(1);
310     }
311     FilesDifferent = true;
312   }
313   
314   // Remove the generated output.
315   Output.destroyFile();
316
317   // Remove the bytecode file if we are supposed to.
318   if (RemoveBytecode) sys::Path(BytecodeFile).destroyFile();
319   return FilesDifferent;
320 }
321
322 bool BugDriver::isExecutingJIT() {
323   return InterpreterSel == RunJIT;
324 }
325