ExecutionDriver.cpp revision 7bb11547e497d7b8fc87f61c1089eee808e3a1ee
1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//                     The LLVM Compiler Infrastructure
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// This file was developed by the LLVM research group and is distributed under
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// the University of Illinois Open Source License. See LICENSE.TXT for details.
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//===----------------------------------------------------------------------===//
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// This file contains code used to execute the program utilizing one of the
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// various ways of running LLVM bytecode.
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//===----------------------------------------------------------------------===//
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse WilsonBUGPOINT NOTES:
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson1. Bugpoint should not leave any files behind if the program works properly
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson2. There should be an option to specify the program name, which specifies a
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson   unique string to put into output files.  This allows operation in the
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson   SingleSource directory, e.g. default to the first input filename.
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson*/
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "BugDriver.h"
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "Support/CommandLine.h"
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "Support/Debug.h"
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "Support/FileUtilities.h"
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "Support/SystemUtils.h"
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "llvm/Support/ToolRunner.h"
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <fstream>
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <iostream>
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonusing namespace llvm;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonnamespace {
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // OutputType - Allow the user to specify the way code should be run, to test
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // for miscompilation.
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  //
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  enum OutputType {
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    AutoPick, RunLLI, RunJIT, RunLLC, RunCBE
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  };
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  cl::opt<OutputType>
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            clEnumValN(RunLLI, "run-int", "Execute with the interpreter"),
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            0),
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 cl::init(AutoPick));
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  cl::opt<bool>
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  CheckProgramExitCode("check-exit-code",
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                       cl::desc("Assume nonzero exit code is failure (default on)"),
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                       cl::init(true));
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  cl::opt<std::string>
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  InputFile("input", cl::init("/dev/null"),
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  cl::list<std::string>
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  AdditionalSOs("additional-so",
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                cl::desc("Additional shared objects to load "
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         "into executing programs"));
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonnamespace llvm {
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // Anything specified after the --args option are taken as arguments to the
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // program being debugged.
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  cl::list<std::string>
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            cl::ZeroOrMore);
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//===----------------------------------------------------------------------===//
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// BugDriver method implementation
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/// initializeExecutionEnvironment - This method is used to set up the
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/// environment for executing LLVM programs.
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson///
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonbool BugDriver::initializeExecutionEnvironment() {
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  std::cout << "Initializing execution environment: ";
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // Create an instance of the AbstractInterpreter interface as specified on
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // the command line
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  cbe = 0;
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  std::string Message;
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  switch (InterpreterSel) {
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  case AutoPick:
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    InterpreterSel = RunCBE;
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    Interpreter = cbe = AbstractInterpreter::createCBE(getToolName(), Message);
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    if (!Interpreter) {
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      InterpreterSel = RunJIT;
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      Interpreter = AbstractInterpreter::createJIT(getToolName(), Message);
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    if (!Interpreter) {
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      InterpreterSel = RunLLC;
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      Interpreter = AbstractInterpreter::createLLC(getToolName(), Message);
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    if (!Interpreter) {
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      InterpreterSel = RunLLI;
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      Interpreter = AbstractInterpreter::createLLI(getToolName(), Message);
104    }
105    if (!Interpreter) {
106      InterpreterSel = AutoPick;
107      Message = "Sorry, I can't automatically select an interpreter!\n";
108    }
109    break;
110  case RunLLI:
111    Interpreter = AbstractInterpreter::createLLI(getToolName(), Message);
112    break;
113  case RunLLC:
114    Interpreter = AbstractInterpreter::createLLC(getToolName(), Message);
115    break;
116  case RunJIT:
117    Interpreter = AbstractInterpreter::createJIT(getToolName(), Message);
118    break;
119  case RunCBE:
120    Interpreter = cbe = AbstractInterpreter::createCBE(getToolName(), Message);
121    break;
122  default:
123    Message = "Sorry, this back-end is not supported by bugpoint right now!\n";
124    break;
125  }
126  std::cerr << Message;
127
128  // Initialize auxiliary tools for debugging
129  if (!cbe) {
130    cbe = AbstractInterpreter::createCBE(getToolName(), Message);
131    if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
132  }
133  gcc = GCC::create(getToolName(), Message);
134  if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
135
136  // If there was an error creating the selected interpreter, quit with error.
137  return Interpreter == 0;
138}
139
140
141/// executeProgram - This method runs "Program", capturing the output of the
142/// program to a file, returning the filename of the file.  A recommended
143/// filename may be optionally specified.
144///
145std::string BugDriver::executeProgram(std::string OutputFile,
146                                      std::string BytecodeFile,
147                                      const std::string &SharedObj,
148                                      AbstractInterpreter *AI,
149                                      bool *ProgramExitedNonzero) {
150  if (AI == 0) AI = Interpreter;
151  assert(AI && "Interpreter should have been created already!");
152  bool CreatedBytecode = false;
153  if (BytecodeFile.empty()) {
154    // Emit the program to a bytecode file...
155    BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
156
157    if (writeProgramToFile(BytecodeFile, Program)) {
158      std::cerr << ToolName << ": Error emitting bytecode to file '"
159                << BytecodeFile << "'!\n";
160      exit(1);
161    }
162    CreatedBytecode = true;
163  }
164
165  if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
166
167  // Check to see if this is a valid output filename...
168  OutputFile = getUniqueFilename(OutputFile);
169
170  // Figure out which shared objects to run, if any.
171  std::vector<std::string> SharedObjs(AdditionalSOs);
172  if (!SharedObj.empty())
173    SharedObjs.push_back(SharedObj);
174
175  // Actually execute the program!
176  int RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
177                                  OutputFile, SharedObjs);
178
179  if (ProgramExitedNonzero != 0)
180    *ProgramExitedNonzero = (RetVal != 0);
181
182  // Remove the temporary bytecode file.
183  if (CreatedBytecode) removeFile(BytecodeFile);
184
185  // Return the filename we captured the output to.
186  return OutputFile;
187}
188
189/// executeProgramWithCBE - Used to create reference output with the C
190/// backend, if reference output is not provided.
191///
192std::string BugDriver::executeProgramWithCBE(std::string OutputFile) {
193  bool ProgramExitedNonzero;
194  std::string outFN = executeProgram(OutputFile, "", "",
195                                     (AbstractInterpreter*)cbe,
196                                     &ProgramExitedNonzero);
197  if (ProgramExitedNonzero) {
198    std::cerr
199      << "Warning: While generating reference output, program exited with\n"
200      << "non-zero exit code. This will NOT be treated as a failure.\n";
201    CheckProgramExitCode = false;
202  }
203  return outFN;
204}
205
206std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) {
207  assert(Interpreter && "Interpreter should have been created already!");
208  std::string OutputCFile;
209
210  // Using CBE
211  cbe->OutputC(BytecodeFile, OutputCFile);
212
213#if 0 /* This is an alternative, as yet unimplemented */
214  // Using LLC
215  std::string Message;
216  LLC *llc = createLLCtool(Message);
217  if (llc->OutputAsm(BytecodeFile, OutputFile)) {
218    std::cerr << "Could not generate asm code with `llc', exiting.\n";
219    exit(1);
220  }
221#endif
222
223  std::string SharedObjectFile;
224  if (gcc->MakeSharedObject(OutputCFile, GCC::CFile, SharedObjectFile))
225    exit(1);
226
227  // Remove the intermediate C file
228  removeFile(OutputCFile);
229
230  return "./" + SharedObjectFile;
231}
232
233
234/// diffProgram - This method executes the specified module and diffs the output
235/// against the file specified by ReferenceOutputFile.  If the output is
236/// different, true is returned.
237///
238bool BugDriver::diffProgram(const std::string &BytecodeFile,
239                            const std::string &SharedObject,
240                            bool RemoveBytecode) {
241  bool ProgramExitedNonzero;
242
243  // Execute the program, generating an output file...
244  std::string Output = executeProgram("", BytecodeFile, SharedObject, 0,
245                                      &ProgramExitedNonzero);
246
247  // If we're checking the program exit code, assume anything nonzero is bad.
248  if (CheckProgramExitCode && ProgramExitedNonzero)
249    return true;
250
251  std::string Error;
252  bool FilesDifferent = false;
253  if (DiffFiles(ReferenceOutputFile, Output, &Error)) {
254    if (!Error.empty()) {
255      std::cerr << "While diffing output: " << Error << "\n";
256      exit(1);
257    }
258    FilesDifferent = true;
259  }
260
261  // Remove the generated output.
262  removeFile(Output);
263
264  // Remove the bytecode file if we are supposed to.
265  if (RemoveBytecode) removeFile(BytecodeFile);
266  return FilesDifferent;
267}
268
269bool BugDriver::isExecutingJIT() {
270  return InterpreterSel == RunJIT;
271}
272
273