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