blob: 01f7be89e35a8465e9bd4413f53a1a58f6c7be71 [file] [log] [blame]
Chris Lattnerde4aa4c2002-12-23 23:50:16 +00001//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
John Criswell09344dc2003-10-20 17:47:21 +00002//
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//===----------------------------------------------------------------------===//
Chris Lattnerde4aa4c2002-12-23 23:50:16 +00009//
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/*
16BUGPOINT NOTES:
17
181. Bugpoint should not leave any files behind if the program works properly
192. There should be an option to specify the program name, which specifies a
20 unique string to put into output files. This allows operation in the
Misha Brukmand792c9b2003-07-24 18:17:43 +000021 SingleSource directory, e.g. default to the first input filename.
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000022*/
23
24#include "BugDriver.h"
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000025#include "Support/CommandLine.h"
Chris Lattnerf0c69642003-08-01 22:13:59 +000026#include "Support/Debug.h"
Chris Lattneraa997fb2003-08-01 20:29:45 +000027#include "Support/FileUtilities.h"
Misha Brukman0c2305b2003-08-07 21:19:30 +000028#include "Support/SystemUtils.h"
Chris Lattner10bd1c22003-10-07 13:45:51 +000029#include "llvm/Support/ToolRunner.h"
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000030#include <fstream>
Chris Lattner7c0f8622002-12-24 00:44:34 +000031#include <iostream>
Brian Gaeke960707c2003-11-11 22:41:34 +000032using namespace llvm;
33
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000034namespace {
35 // OutputType - Allow the user to specify the way code should be run, to test
36 // for miscompilation.
37 //
38 enum OutputType {
Brian Gaeke9a0bdb12003-10-21 17:41:35 +000039 AutoPick, RunLLI, RunJIT, RunLLC, RunCBE
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000040 };
Misha Brukman5bc6a8f2003-09-29 22:40:52 +000041
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000042 cl::opt<OutputType>
43 InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
Brian Gaeke9a0bdb12003-10-21 17:41:35 +000044 cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
45 clEnumValN(RunLLI, "run-int", "Execute with the interpreter"),
Misha Brukmand792c9b2003-07-24 18:17:43 +000046 clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
47 clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
48 clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
Chris Lattner16d36a12003-10-18 20:18:20 +000049 0),
Brian Gaeke9a0bdb12003-10-21 17:41:35 +000050 cl::init(AutoPick));
Chris Lattner68efaa72003-04-23 20:31:37 +000051
Brian Gaeke35145be2004-02-11 18:37:32 +000052 cl::opt<bool>
53 CheckProgramExitCode("check-exit-code",
54 cl::desc("Assume nonzero exit code is failure (default on)"),
55 cl::init(true));
56
Chris Lattner68efaa72003-04-23 20:31:37 +000057 cl::opt<std::string>
58 InputFile("input", cl::init("/dev/null"),
59 cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
Chris Lattnerdc92fa62003-10-14 22:24:31 +000060
61 cl::list<std::string>
62 AdditionalSOs("additional-so",
63 cl::desc("Additional shared objects to load "
64 "into executing programs"));
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000065}
66
Brian Gaeke960707c2003-11-11 22:41:34 +000067namespace llvm {
Chris Lattner2f1aa112004-01-14 03:38:37 +000068 // Anything specified after the --args option are taken as arguments to the
69 // program being debugged.
70 cl::list<std::string>
71 InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
72 cl::ZeroOrMore);
73}
Misha Brukman40feb362003-07-30 20:15:44 +000074
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000075//===----------------------------------------------------------------------===//
76// BugDriver method implementation
77//
78
79/// initializeExecutionEnvironment - This method is used to set up the
80/// environment for executing LLVM programs.
81///
82bool BugDriver::initializeExecutionEnvironment() {
83 std::cout << "Initializing execution environment: ";
84
Misha Brukman5bc6a8f2003-09-29 22:40:52 +000085 // Create an instance of the AbstractInterpreter interface as specified on
86 // the command line
Chris Lattner898de4a2004-02-18 20:52:02 +000087 cbe = 0;
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000088 std::string Message;
Chris Lattner7709ec52003-05-03 03:19:41 +000089 switch (InterpreterSel) {
Brian Gaeke9a0bdb12003-10-21 17:41:35 +000090 case AutoPick:
91 InterpreterSel = RunCBE;
Chris Lattner898de4a2004-02-18 20:52:02 +000092 Interpreter = cbe = AbstractInterpreter::createCBE(getToolName(), Message);
Brian Gaeke9a0bdb12003-10-21 17:41:35 +000093 if (!Interpreter) {
94 InterpreterSel = RunJIT;
95 Interpreter = AbstractInterpreter::createJIT(getToolName(), Message);
96 }
97 if (!Interpreter) {
98 InterpreterSel = RunLLC;
99 Interpreter = AbstractInterpreter::createLLC(getToolName(), Message);
100 }
101 if (!Interpreter) {
102 InterpreterSel = RunLLI;
103 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;
Chris Lattner3f6e5222003-10-14 21:59:36 +0000110 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:
Chris Lattner898de4a2004-02-18 20:52:02 +0000120 Interpreter = cbe = AbstractInterpreter::createCBE(getToolName(), Message);
Chris Lattner3f6e5222003-10-14 21:59:36 +0000121 break;
Chris Lattner7709ec52003-05-03 03:19:41 +0000122 default:
Misha Brukman5bc6a8f2003-09-29 22:40:52 +0000123 Message = "Sorry, this back-end is not supported by bugpoint right now!\n";
Chris Lattner7709ec52003-05-03 03:19:41 +0000124 break;
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000125 }
Misha Brukman5bc6a8f2003-09-29 22:40:52 +0000126 std::cerr << Message;
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000127
Misha Brukman0fd31722003-07-24 21:59:10 +0000128 // Initialize auxiliary tools for debugging
Chris Lattner898de4a2004-02-18 20:52:02 +0000129 if (!cbe) {
130 cbe = AbstractInterpreter::createCBE(getToolName(), Message);
131 if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
132 }
Chris Lattner3f6e5222003-10-14 21:59:36 +0000133 gcc = GCC::create(getToolName(), Message);
Misha Brukman0fd31722003-07-24 21:59:10 +0000134 if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
135
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000136 // 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,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000146 std::string BytecodeFile,
Chris Lattner3f6e5222003-10-14 21:59:36 +0000147 const std::string &SharedObj,
Brian Gaeke35145be2004-02-11 18:37:32 +0000148 AbstractInterpreter *AI,
149 bool *ProgramExitedNonzero) {
Chris Lattner3f6e5222003-10-14 21:59:36 +0000150 if (AI == 0) AI = Interpreter;
151 assert(AI && "Interpreter should have been created already!");
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000152 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 '"
Misha Brukmand792c9b2003-07-24 18:17:43 +0000159 << BytecodeFile << "'!\n";
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000160 exit(1);
161 }
162 CreatedBytecode = true;
163 }
164
Chris Lattner1f80a922004-02-18 22:01:21 +0000165 // Remove the temporary bytecode file when we are done.
166 FileRemover BytecodeFileRemover(BytecodeFile, CreatedBytecode);
167
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000168 if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
Misha Brukmand792c9b2003-07-24 18:17:43 +0000169
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000170 // Check to see if this is a valid output filename...
171 OutputFile = getUniqueFilename(OutputFile);
172
Chris Lattner3f6e5222003-10-14 21:59:36 +0000173 // Figure out which shared objects to run, if any.
Chris Lattnerdc92fa62003-10-14 22:24:31 +0000174 std::vector<std::string> SharedObjs(AdditionalSOs);
Chris Lattner3f6e5222003-10-14 21:59:36 +0000175 if (!SharedObj.empty())
176 SharedObjs.push_back(SharedObj);
177
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000178 // Actually execute the program!
Chris Lattner3f6e5222003-10-14 21:59:36 +0000179 int RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
180 OutputFile, SharedObjs);
181
Brian Gaeke35145be2004-02-11 18:37:32 +0000182 if (ProgramExitedNonzero != 0)
183 *ProgramExitedNonzero = (RetVal != 0);
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000184
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000185 // Return the filename we captured the output to.
186 return OutputFile;
187}
188
Brian Gaeke35145be2004-02-11 18:37:32 +0000189/// 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}
Misha Brukmand792c9b2003-07-24 18:17:43 +0000205
Chris Lattnerf8a84db2003-10-14 21:09:11 +0000206std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) {
Misha Brukmand792c9b2003-07-24 18:17:43 +0000207 assert(Interpreter && "Interpreter should have been created already!");
Chris Lattnerf8a84db2003-10-14 21:09:11 +0000208 std::string OutputCFile;
Misha Brukmand792c9b2003-07-24 18:17:43 +0000209
210 // Using CBE
Misha Brukmand792c9b2003-07-24 18:17:43 +0000211 cbe->OutputC(BytecodeFile, OutputCFile);
212
213#if 0 /* This is an alternative, as yet unimplemented */
214 // Using LLC
Chris Lattnerf8a84db2003-10-14 21:09:11 +0000215 std::string Message;
Misha Brukman5bc6a8f2003-09-29 22:40:52 +0000216 LLC *llc = createLLCtool(Message);
Misha Brukmand792c9b2003-07-24 18:17:43 +0000217 if (llc->OutputAsm(BytecodeFile, OutputFile)) {
218 std::cerr << "Could not generate asm code with `llc', exiting.\n";
219 exit(1);
220 }
221#endif
222
Chris Lattnerf8a84db2003-10-14 21:09:11 +0000223 std::string SharedObjectFile;
Chris Lattner3f6e5222003-10-14 21:59:36 +0000224 if (gcc->MakeSharedObject(OutputCFile, GCC::CFile, SharedObjectFile))
Chris Lattnerf8a84db2003-10-14 21:09:11 +0000225 exit(1);
Misha Brukmand792c9b2003-07-24 18:17:43 +0000226
227 // Remove the intermediate C file
228 removeFile(OutputCFile);
229
Chris Lattner2b97d6e2003-10-19 21:54:13 +0000230 return "./" + SharedObjectFile;
Misha Brukmand792c9b2003-07-24 18:17:43 +0000231}
232
233
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000234/// 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///
Misha Brukmand792c9b2003-07-24 18:17:43 +0000238bool BugDriver::diffProgram(const std::string &BytecodeFile,
239 const std::string &SharedObject,
Chris Lattner16a41312003-04-24 17:02:17 +0000240 bool RemoveBytecode) {
Brian Gaeke35145be2004-02-11 18:37:32 +0000241 bool ProgramExitedNonzero;
242
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000243 // Execute the program, generating an output file...
Brian Gaeke35145be2004-02-11 18:37:32 +0000244 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;
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000250
Chris Lattneraa997fb2003-08-01 20:29:45 +0000251 std::string Error;
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000252 bool FilesDifferent = false;
Chris Lattneraa997fb2003-08-01 20:29:45 +0000253 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 }
Chris Lattner759b9932003-10-18 21:02:51 +0000260
261 // Remove the generated output.
262 removeFile(Output);
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000263
Chris Lattner759b9932003-10-18 21:02:51 +0000264 // Remove the bytecode file if we are supposed to.
Chris Lattner16a41312003-04-24 17:02:17 +0000265 if (RemoveBytecode) removeFile(BytecodeFile);
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000266 return FilesDifferent;
267}
Misha Brukman539f9592003-07-28 19:16:14 +0000268
269bool BugDriver::isExecutingJIT() {
270 return InterpreterSel == RunJIT;
271}
Brian Gaeke960707c2003-11-11 22:41:34 +0000272