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