ExecutionDriver.cpp revision a0f5b15e1eb8642d92b3141a6b88a5729ea979dc
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// This file contains code used to execute the program utilizing one of the
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// various ways of running LLVM bytecode.
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//
6a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com//===----------------------------------------------------------------------===//
7a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
8a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com/*
9a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.comBUGPOINT NOTES:
10a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
11a0b40280a49a8a43af7929ead3b3489951c58501commit-bot@chromium.org1. Bugpoint should not leave any files behind if the program works properly
12a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com2. There should be an option to specify the program name, which specifies a
13a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com   unique string to put into output files.  This allows operation in the
14a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com   SingleSource directory, e.g. default to the first input filename.
15a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com*/
16a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
17a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "BugDriver.h"
18a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "Support/CommandLine.h"
19a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "Support/Debug.h"
20a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "Support/FileUtilities.h"
21a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "Support/SystemUtils.h"
22a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "llvm/Support/ToolRunner.h"
23a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include <fstream>
24a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include <iostream>
25a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
26a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comnamespace {
27a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com  // OutputType - Allow the user to specify the way code should be run, to test
28a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  // for miscompilation.
29a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  //
30a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com  enum OutputType {
31a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com    RunLLI, RunJIT, RunLLC, RunCBE
32a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com  };
33a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
34a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  cl::opt<OutputType>
35a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
36a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com                 cl::values(clEnumValN(RunLLI, "run-lli", "Execute with LLI"),
37a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com                            clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
38e3beb6bd7de7fa211681abbb0be58e80b19885e0commit-bot@chromium.org                            clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
39a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com                            clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
40a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                            0));
41d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
42a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com  cl::opt<std::string>
43a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  InputFile("input", cl::init("/dev/null"),
44a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com            cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
45a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com}
46a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
47a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com// Anything specified after the --args option are taken as arguments to the
48d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com// program being debugged.
49a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comcl::list<std::string>
50a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.comInputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
51a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com          cl::ZeroOrMore);
52a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
53a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com//===----------------------------------------------------------------------===//
54d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com// BugDriver method implementation
55a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com//
56a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
57a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com/// initializeExecutionEnvironment - This method is used to set up the
58a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com/// environment for executing LLVM programs.
59a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com///
60a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.combool BugDriver::initializeExecutionEnvironment() {
61a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  std::cout << "Initializing execution environment: ";
62a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
63a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  // FIXME: This should default to searching for the best interpreter to use on
64a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  // this platform, which would be JIT, then LLC, then CBE, then LLI.
65a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
66a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  // Create an instance of the AbstractInterpreter interface as specified on
67a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com  // the command line
6883747252b811c9f76bfec3c8ea4b48e30e46dd7fagl@chromium.org  std::string Message;
69  switch (InterpreterSel) {
70  case RunLLI: Interpreter = createLLItool(getToolName(), Message); break;
71  case RunLLC: Interpreter = createLLCtool(getToolName(), Message); break;
72  case RunJIT: Interpreter = createJITtool(getToolName(), Message); break;
73  case RunCBE: Interpreter = createCBEtool(getToolName(), Message); break;
74  default:
75    Message = "Sorry, this back-end is not supported by bugpoint right now!\n";
76    break;
77  }
78  std::cerr << Message;
79
80  // Initialize auxiliary tools for debugging
81  cbe = createCBEtool(getToolName(), Message);
82  if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
83  gcc = createGCCtool(getToolName(), Message);
84  if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
85
86  // If there was an error creating the selected interpreter, quit with error.
87  return Interpreter == 0;
88}
89
90
91/// executeProgram - This method runs "Program", capturing the output of the
92/// program to a file, returning the filename of the file.  A recommended
93/// filename may be optionally specified.
94///
95std::string BugDriver::executeProgram(std::string OutputFile,
96                                      std::string BytecodeFile,
97                                      std::string SharedObject,
98                                      AbstractInterpreter *AI) {
99  assert((Interpreter||AI) && "Interpreter should have been created already!");
100  bool CreatedBytecode = false;
101  if (BytecodeFile.empty()) {
102    // Emit the program to a bytecode file...
103    BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
104
105    if (writeProgramToFile(BytecodeFile, Program)) {
106      std::cerr << ToolName << ": Error emitting bytecode to file '"
107                << BytecodeFile << "'!\n";
108      exit(1);
109    }
110    CreatedBytecode = true;
111  }
112
113  if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
114
115  // Check to see if this is a valid output filename...
116  OutputFile = getUniqueFilename(OutputFile);
117
118  // Actually execute the program!
119  int RetVal = (AI != 0) ?
120    AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile, OutputFile,
121                       SharedObject) :
122    Interpreter->ExecuteProgram(BytecodeFile, InputArgv,
123                                InputFile, OutputFile, SharedObject);
124
125  // Remove the temporary bytecode file.
126  if (CreatedBytecode) removeFile(BytecodeFile);
127
128  // Return the filename we captured the output to.
129  return OutputFile;
130}
131
132std::string BugDriver::executeProgramWithCBE(std::string OutputFile,
133                                             std::string BytecodeFile,
134                                             std::string SharedObject) {
135  return executeProgram(OutputFile, BytecodeFile, SharedObject, cbe);
136}
137
138std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) {
139  assert(Interpreter && "Interpreter should have been created already!");
140  std::string OutputCFile;
141
142  // Using CBE
143  cbe->OutputC(BytecodeFile, OutputCFile);
144
145#if 0 /* This is an alternative, as yet unimplemented */
146  // Using LLC
147  std::string Message;
148  LLC *llc = createLLCtool(Message);
149  if (llc->OutputAsm(BytecodeFile, OutputFile)) {
150    std::cerr << "Could not generate asm code with `llc', exiting.\n";
151    exit(1);
152  }
153#endif
154
155  std::string SharedObjectFile;
156  if (gcc->MakeSharedObject(OutputCFile, CFile, SharedObject))
157    exit(1);
158
159  // Remove the intermediate C file
160  removeFile(OutputCFile);
161
162  return SharedObjectFile;
163}
164
165
166/// diffProgram - This method executes the specified module and diffs the output
167/// against the file specified by ReferenceOutputFile.  If the output is
168/// different, true is returned.
169///
170bool BugDriver::diffProgram(const std::string &BytecodeFile,
171                            const std::string &SharedObject,
172                            bool RemoveBytecode) {
173  // Execute the program, generating an output file...
174  std::string Output = executeProgram("", BytecodeFile, SharedObject);
175
176  std::string Error;
177  bool FilesDifferent = false;
178  if (DiffFiles(ReferenceOutputFile, Output, &Error)) {
179    if (!Error.empty()) {
180      std::cerr << "While diffing output: " << Error << "\n";
181      exit(1);
182    }
183    FilesDifferent = true;
184  }
185
186  if (RemoveBytecode) removeFile(BytecodeFile);
187  return FilesDifferent;
188}
189
190bool BugDriver::isExecutingJIT() {
191  return InterpreterSel == RunJIT;
192}
193