blob: adca572075e533adad9d06bf3ac4b6eed6efd99f [file] [log] [blame]
Chris Lattnerde4aa4c2002-12-23 23:50:16 +00001//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
2//
3// This file contains code used to execute the program utilizing one of the
4// various ways of running LLVM bytecode.
5//
6//===----------------------------------------------------------------------===//
7
8/*
9BUGPOINT NOTES:
10
111. Bugpoint should not leave any files behind if the program works properly
122. There should be an option to specify the program name, which specifies a
13 unique string to put into output files. This allows operation in the
Misha Brukmand792c9b2003-07-24 18:17:43 +000014 SingleSource directory, e.g. default to the first input filename.
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000015*/
16
17#include "BugDriver.h"
18#include "SystemUtils.h"
19#include "Support/CommandLine.h"
Misha Brukman539f9592003-07-28 19:16:14 +000020#include "Support/Statistic.h"
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000021#include <fstream>
Chris Lattner7c0f8622002-12-24 00:44:34 +000022#include <iostream>
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000023
24namespace {
25 // OutputType - Allow the user to specify the way code should be run, to test
26 // for miscompilation.
27 //
28 enum OutputType {
29 RunLLI, RunJIT, RunLLC, RunCBE
30 };
31 cl::opt<OutputType>
32 InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
Misha Brukmand792c9b2003-07-24 18:17:43 +000033 cl::values(clEnumValN(RunLLI, "run-lli", "Execute with LLI"),
34 clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
35 clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
36 clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
37 0));
Chris Lattner68efaa72003-04-23 20:31:37 +000038
39 cl::opt<std::string>
40 InputFile("input", cl::init("/dev/null"),
41 cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
Misha Brukman0fd31722003-07-24 21:59:10 +000042
43 enum FileType { AsmFile, CFile };
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000044}
45
46/// AbstractInterpreter Class - Subclasses of this class are used to execute
47/// LLVM bytecode in a variety of ways. This abstract interface hides this
48/// complexity behind a simple interface.
49///
50struct AbstractInterpreter {
51
52 virtual ~AbstractInterpreter() {}
53
54 /// ExecuteProgram - Run the specified bytecode file, emitting output to the
55 /// specified filename. This returns the exit code of the program.
56 ///
57 virtual int ExecuteProgram(const std::string &Bytecode,
Misha Brukmand792c9b2003-07-24 18:17:43 +000058 const std::string &OutputFile,
59 const std::string &SharedLib = "") = 0;
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000060};
61
62
63//===----------------------------------------------------------------------===//
64// LLI Implementation of AbstractIntepreter interface
65//
66class LLI : public AbstractInterpreter {
67 std::string LLIPath; // The path to the LLI executable
68public:
69 LLI(const std::string &Path) : LLIPath(Path) { }
70
71 // LLI create method - Try to find the LLI executable
72 static LLI *create(BugDriver *BD, std::string &Message) {
73 std::string LLIPath = FindExecutable("lli", BD->getToolName());
74 if (!LLIPath.empty()) {
75 Message = "Found lli: " + LLIPath + "\n";
76 return new LLI(LLIPath);
77 }
78
Misha Brukmand792c9b2003-07-24 18:17:43 +000079 Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000080 return 0;
81 }
82 virtual int ExecuteProgram(const std::string &Bytecode,
Misha Brukmand792c9b2003-07-24 18:17:43 +000083 const std::string &OutputFile,
84 const std::string &SharedLib = "");
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000085};
86
87int LLI::ExecuteProgram(const std::string &Bytecode,
Misha Brukmand792c9b2003-07-24 18:17:43 +000088 const std::string &OutputFile,
89 const std::string &SharedLib) {
Misha Brukman0fd31722003-07-24 21:59:10 +000090 if (!SharedLib.empty()) {
Misha Brukmand792c9b2003-07-24 18:17:43 +000091 std::cerr << "LLI currently does not support loading shared libraries.\n"
92 << "Exiting.\n";
93 exit(1);
94 }
95
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000096 const char *Args[] = {
Misha Brukmand792c9b2003-07-24 18:17:43 +000097 LLIPath.c_str(),
Chris Lattnerde4aa4c2002-12-23 23:50:16 +000098 "-abort-on-exception",
99 "-quiet",
Chris Lattner7709ec52003-05-03 03:19:41 +0000100 "-force-interpreter=true",
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000101 Bytecode.c_str(),
102 0
103 };
Misha Brukmand792c9b2003-07-24 18:17:43 +0000104
Misha Brukman539f9592003-07-28 19:16:14 +0000105 std::cout << "<lli>";
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000106 return RunProgramWithTimeout(LLIPath, Args,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000107 InputFile, OutputFile, OutputFile);
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000108}
109
Chris Lattner7709ec52003-05-03 03:19:41 +0000110//===----------------------------------------------------------------------===//
Misha Brukman539f9592003-07-28 19:16:14 +0000111// GCC abstraction
Misha Brukmand792c9b2003-07-24 18:17:43 +0000112//
113// This is not a *real* AbstractInterpreter as it does not accept bytecode
114// files, but only input acceptable to GCC, i.e. C, C++, and assembly files
115//
Misha Brukman0fd31722003-07-24 21:59:10 +0000116class GCC {
Misha Brukmand792c9b2003-07-24 18:17:43 +0000117 std::string GCCPath; // The path to the gcc executable
118public:
119 GCC(const std::string &gccPath) : GCCPath(gccPath) { }
Misha Brukman0fd31722003-07-24 21:59:10 +0000120 virtual ~GCC() {}
Misha Brukmand792c9b2003-07-24 18:17:43 +0000121
122 // GCC create method - Try to find the `gcc' executable
123 static GCC *create(BugDriver *BD, std::string &Message) {
124 std::string GCCPath = FindExecutable("gcc", BD->getToolName());
125 if (GCCPath.empty()) {
126 Message = "Cannot find `gcc' in bugpoint executable directory or PATH!\n";
127 return 0;
128 }
129
130 Message = "Found gcc: " + GCCPath + "\n";
131 return new GCC(GCCPath);
132 }
133
134 virtual int ExecuteProgram(const std::string &ProgramFile,
Misha Brukman0fd31722003-07-24 21:59:10 +0000135 FileType fileType,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000136 const std::string &OutputFile,
137 const std::string &SharedLib = "");
138
139 int MakeSharedObject(const std::string &InputFile,
Misha Brukman0fd31722003-07-24 21:59:10 +0000140 FileType fileType,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000141 std::string &OutputFile);
142
143 void ProcessFailure(const char **Args);
144};
145
146int GCC::ExecuteProgram(const std::string &ProgramFile,
Misha Brukman0fd31722003-07-24 21:59:10 +0000147 FileType fileType,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000148 const std::string &OutputFile,
149 const std::string &SharedLib) {
Misha Brukman539f9592003-07-28 19:16:14 +0000150 std::string OutputBinary = getUniqueFilename("bugpoint.gcc.exe");
Misha Brukmand792c9b2003-07-24 18:17:43 +0000151 const char **GCCArgs;
152
153 const char *ArgsWithoutSO[] = {
154 GCCPath.c_str(),
Misha Brukman0fd31722003-07-24 21:59:10 +0000155 "-x", (fileType == AsmFile) ? "assembler" : "c",
Misha Brukmand792c9b2003-07-24 18:17:43 +0000156 ProgramFile.c_str(), // Specify the input filename...
157 "-o", OutputBinary.c_str(), // Output to the right filename...
158 "-lm", // Hard-code the math library...
159 "-O2", // Optimize the program a bit...
160 0
161 };
162 const char *ArgsWithSO[] = {
163 GCCPath.c_str(),
Misha Brukman539f9592003-07-28 19:16:14 +0000164 SharedLib.c_str(), // Specify the shared library to link in...
Misha Brukman0fd31722003-07-24 21:59:10 +0000165 "-x", (fileType == AsmFile) ? "assembler" : "c",
Misha Brukmand792c9b2003-07-24 18:17:43 +0000166 ProgramFile.c_str(), // Specify the input filename...
Misha Brukmand792c9b2003-07-24 18:17:43 +0000167 "-o", OutputBinary.c_str(), // Output to the right filename...
168 "-lm", // Hard-code the math library...
169 "-O2", // Optimize the program a bit...
170 0
171 };
172
Misha Brukman0fd31722003-07-24 21:59:10 +0000173 GCCArgs = (SharedLib.empty()) ? ArgsWithoutSO : ArgsWithSO;
Misha Brukmand792c9b2003-07-24 18:17:43 +0000174 std::cout << "<gcc>";
Misha Brukman0fd31722003-07-24 21:59:10 +0000175 if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
176 "/dev/null")) {
Misha Brukmand792c9b2003-07-24 18:17:43 +0000177 ProcessFailure(GCCArgs);
Misha Brukman0fd31722003-07-24 21:59:10 +0000178 exit(1);
Misha Brukmand792c9b2003-07-24 18:17:43 +0000179 }
180
181 const char *ProgramArgs[] = {
182 OutputBinary.c_str(),
183 0
184 };
185
Misha Brukmand792c9b2003-07-24 18:17:43 +0000186 // Now that we have a binary, run it!
Misha Brukman539f9592003-07-28 19:16:14 +0000187 std::cout << "<program>";
Misha Brukmand792c9b2003-07-24 18:17:43 +0000188 int ProgramResult = RunProgramWithTimeout(OutputBinary, ProgramArgs,
189 InputFile, OutputFile, OutputFile);
190 std::cout << "\n";
191 removeFile(OutputBinary);
192 return ProgramResult;
193}
194
195int GCC::MakeSharedObject(const std::string &InputFile,
Misha Brukman0fd31722003-07-24 21:59:10 +0000196 FileType fileType,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000197 std::string &OutputFile) {
Misha Brukman539f9592003-07-28 19:16:14 +0000198 OutputFile = getUniqueFilename("./bugpoint.so");
Misha Brukmand792c9b2003-07-24 18:17:43 +0000199 // Compile the C/asm file into a shared object
200 const char* GCCArgs[] = {
201 GCCPath.c_str(),
Misha Brukman0fd31722003-07-24 21:59:10 +0000202 "-x", (fileType == AsmFile) ? "assembler" : "c",
Misha Brukmand792c9b2003-07-24 18:17:43 +0000203 InputFile.c_str(), // Specify the input filename...
204#if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
205 "-G", // Compile a shared library, `-G' for Sparc
206#else
207 "-shared", // `-shared' for Linux/X86, maybe others
208#endif
209 "-o", OutputFile.c_str(), // Output to the right filename...
210 "-O2", // Optimize the program a bit...
211 0
212 };
213
214 std::cout << "<gcc>";
215 if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
216 "/dev/null")) {
217 ProcessFailure(GCCArgs);
218 exit(1);
219 }
220 return 0;
221}
222
223void GCC::ProcessFailure(const char** GCCArgs) {
224 std::cerr << "\n*** bugpoint error: invocation of the C compiler failed!\n";
225 for (const char **Arg = GCCArgs; *Arg; ++Arg)
226 std::cerr << " " << *Arg;
227 std::cerr << "\n";
228
229 // Rerun the compiler, capturing any error messages to print them.
230 std::string ErrorFilename = getUniqueFilename("bugpoint.gcc.errors");
231 RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
232 ErrorFilename.c_str());
233
234 // Print out the error messages generated by GCC if possible...
235 std::ifstream ErrorFile(ErrorFilename.c_str());
236 if (ErrorFile) {
237 std::copy(std::istreambuf_iterator<char>(ErrorFile),
238 std::istreambuf_iterator<char>(),
239 std::ostreambuf_iterator<char>(std::cerr));
240 ErrorFile.close();
241 std::cerr << "\n";
242 }
243
244 removeFile(ErrorFilename);
245}
246
247//===----------------------------------------------------------------------===//
248// LLC Implementation of AbstractIntepreter interface
249//
250class LLC : public AbstractInterpreter {
251 std::string LLCPath; // The path to the LLC executable
252 GCC *gcc;
253public:
254 LLC(const std::string &llcPath, GCC *Gcc)
255 : LLCPath(llcPath), gcc(Gcc) { }
256 ~LLC() { delete gcc; }
257
258 // LLC create method - Try to find the LLC executable
259 static LLC *create(BugDriver *BD, std::string &Message) {
260 std::string LLCPath = FindExecutable("llc", BD->getToolName());
261 if (LLCPath.empty()) {
262 Message = "Cannot find `llc' in bugpoint executable directory or PATH!\n";
263 return 0;
264 }
265
266 Message = "Found llc: " + LLCPath + "\n";
267 GCC *gcc = GCC::create(BD, Message);
Misha Brukman0fd31722003-07-24 21:59:10 +0000268 if (!gcc) {
269 std::cerr << Message << "\n";
270 exit(1);
271 }
Misha Brukmand792c9b2003-07-24 18:17:43 +0000272 return new LLC(LLCPath, gcc);
273 }
274
275 virtual int ExecuteProgram(const std::string &Bytecode,
276 const std::string &OutputFile,
277 const std::string &SharedLib = "");
278
279 int OutputAsm(const std::string &Bytecode,
280 std::string &OutputAsmFile);
Misha Brukmand792c9b2003-07-24 18:17:43 +0000281};
282
283int LLC::OutputAsm(const std::string &Bytecode,
284 std::string &OutputAsmFile) {
285 OutputAsmFile = "bugpoint.llc.s";
286 const char *LLCArgs[] = {
287 LLCPath.c_str(),
288 "-o", OutputAsmFile.c_str(), // Output to the Asm file
289 "-f", // Overwrite as necessary...
290 Bytecode.c_str(), // This is the input bytecode
291 0
292 };
293
294 std::cout << "<llc>";
295 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
296 "/dev/null")) {
297 // If LLC failed on the bytecode, print error...
298 std::cerr << "bugpoint error: `llc' failed!\n";
299 removeFile(OutputAsmFile);
300 return 1;
301 }
302
303 return 0;
304}
305
306int LLC::ExecuteProgram(const std::string &Bytecode,
307 const std::string &OutputFile,
308 const std::string &SharedLib) {
309
310 std::string OutputAsmFile;
311 if (OutputAsm(Bytecode, OutputAsmFile)) {
312 std::cerr << "Could not generate asm code with `llc', exiting.\n";
313 exit(1);
314 }
315
316 // Assuming LLC worked, compile the result with GCC and run it.
Misha Brukman0fd31722003-07-24 21:59:10 +0000317 int Result = gcc->ExecuteProgram(OutputAsmFile,AsmFile,OutputFile,SharedLib);
Misha Brukmand792c9b2003-07-24 18:17:43 +0000318 removeFile(OutputAsmFile);
319 return Result;
320}
321
322
323//===----------------------------------------------------------------------===//
Chris Lattner7709ec52003-05-03 03:19:41 +0000324// JIT Implementation of AbstractIntepreter interface
325//
326class JIT : public AbstractInterpreter {
327 std::string LLIPath; // The path to the LLI executable
328public:
329 JIT(const std::string &Path) : LLIPath(Path) { }
330
331 // JIT create method - Try to find the LLI executable
332 static JIT *create(BugDriver *BD, std::string &Message) {
333 std::string LLIPath = FindExecutable("lli", BD->getToolName());
334 if (!LLIPath.empty()) {
335 Message = "Found lli: " + LLIPath + "\n";
336 return new JIT(LLIPath);
337 }
338
Misha Brukmand792c9b2003-07-24 18:17:43 +0000339 Message = "Cannot find `lli' in bugpoint executable directory or PATH!\n";
Chris Lattner7709ec52003-05-03 03:19:41 +0000340 return 0;
341 }
342 virtual int ExecuteProgram(const std::string &Bytecode,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000343 const std::string &OutputFile,
344 const std::string &SharedLib = "");
Chris Lattner7709ec52003-05-03 03:19:41 +0000345};
346
347int JIT::ExecuteProgram(const std::string &Bytecode,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000348 const std::string &OutputFile,
349 const std::string &SharedLib) {
Misha Brukman539f9592003-07-28 19:16:14 +0000350 const char* ArgsWithoutSO[] = {
351 LLIPath.c_str(), "-quiet", "-force-interpreter=false",
352 Bytecode.c_str(),
353 0
354 };
355
356 const char* ArgsWithSO[] = {
357 LLIPath.c_str(), "-quiet", "-force-interpreter=false",
358 "-load", SharedLib.c_str(),
359 Bytecode.c_str(),
360 0
361 };
362
363 const char** JITArgs = SharedLib.empty() ? ArgsWithoutSO : ArgsWithSO;
364
365 std::cout << "<jit>";
366 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
367 return RunProgramWithTimeout(LLIPath, JITArgs,
368 InputFile, OutputFile, OutputFile);
Chris Lattner7709ec52003-05-03 03:19:41 +0000369}
370
371//===----------------------------------------------------------------------===//
372// CBE Implementation of AbstractIntepreter interface
373//
374class CBE : public AbstractInterpreter {
375 std::string DISPath; // The path to the LLVM 'dis' executable
Misha Brukmand792c9b2003-07-24 18:17:43 +0000376 GCC *gcc;
Chris Lattner7709ec52003-05-03 03:19:41 +0000377public:
Misha Brukmand792c9b2003-07-24 18:17:43 +0000378 CBE(const std::string &disPath, GCC *Gcc) : DISPath(disPath), gcc(Gcc) { }
379 ~CBE() { delete gcc; }
Chris Lattner7709ec52003-05-03 03:19:41 +0000380
381 // CBE create method - Try to find the 'dis' executable
382 static CBE *create(BugDriver *BD, std::string &Message) {
383 std::string DISPath = FindExecutable("dis", BD->getToolName());
384 if (DISPath.empty()) {
Misha Brukmand792c9b2003-07-24 18:17:43 +0000385 Message = "Cannot find `dis' in bugpoint executable directory or PATH!\n";
Chris Lattner7709ec52003-05-03 03:19:41 +0000386 return 0;
387 }
388
389 Message = "Found dis: " + DISPath + "\n";
390
Misha Brukmand792c9b2003-07-24 18:17:43 +0000391 GCC *gcc = GCC::create(BD, Message);
Misha Brukman0fd31722003-07-24 21:59:10 +0000392 if (!gcc) {
393 std::cerr << Message << "\n";
394 exit(1);
395 }
Misha Brukmand792c9b2003-07-24 18:17:43 +0000396 return new CBE(DISPath, gcc);
Chris Lattner7709ec52003-05-03 03:19:41 +0000397 }
Misha Brukmand792c9b2003-07-24 18:17:43 +0000398
Chris Lattner7709ec52003-05-03 03:19:41 +0000399 virtual int ExecuteProgram(const std::string &Bytecode,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000400 const std::string &OutputFile,
401 const std::string &SharedLib = "");
402
403 // Sometimes we just want to go half-way and only generate the C file,
404 // not necessarily compile it with GCC and run the program
405 virtual int OutputC(const std::string &Bytecode,
406 std::string &OutputCFile);
407
Chris Lattner7709ec52003-05-03 03:19:41 +0000408};
409
Misha Brukmand792c9b2003-07-24 18:17:43 +0000410int CBE::OutputC(const std::string &Bytecode,
411 std::string &OutputCFile) {
412 OutputCFile = "bugpoint.cbe.c";
Chris Lattner7709ec52003-05-03 03:19:41 +0000413 const char *DisArgs[] = {
414 DISPath.c_str(),
415 "-o", OutputCFile.c_str(), // Output to the C file
416 "-c", // Output to C
417 "-f", // Overwrite as necessary...
418 Bytecode.c_str(), // This is the input bytecode
419 0
420 };
421
422 std::cout << "<cbe>";
423 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
424 "/dev/null")) {
425 // If dis failed on the bytecode, print error...
Misha Brukmand792c9b2003-07-24 18:17:43 +0000426 std::cerr << "bugpoint error: `dis -c' failed!\n";
Chris Lattner7709ec52003-05-03 03:19:41 +0000427 return 1;
428 }
429
Misha Brukmand792c9b2003-07-24 18:17:43 +0000430 return 0;
431}
Chris Lattner7709ec52003-05-03 03:19:41 +0000432
Chris Lattner7709ec52003-05-03 03:19:41 +0000433
Misha Brukmand792c9b2003-07-24 18:17:43 +0000434int CBE::ExecuteProgram(const std::string &Bytecode,
435 const std::string &OutputFile,
436 const std::string &SharedLib) {
437 std::string OutputCFile;
438 if (OutputC(Bytecode, OutputCFile)) {
439 std::cerr << "Could not generate C code with `dis', exiting.\n";
440 exit(1);
Chris Lattner7709ec52003-05-03 03:19:41 +0000441 }
442
Misha Brukman0fd31722003-07-24 21:59:10 +0000443 int Result = gcc->ExecuteProgram(OutputCFile, CFile, OutputFile, SharedLib);
Chris Lattner7709ec52003-05-03 03:19:41 +0000444 removeFile(OutputCFile);
Misha Brukmand792c9b2003-07-24 18:17:43 +0000445
Chris Lattner7709ec52003-05-03 03:19:41 +0000446 return Result;
447}
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000448
Misha Brukmand792c9b2003-07-24 18:17:43 +0000449
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000450//===----------------------------------------------------------------------===//
451// BugDriver method implementation
452//
453
454/// initializeExecutionEnvironment - This method is used to set up the
455/// environment for executing LLVM programs.
456///
457bool BugDriver::initializeExecutionEnvironment() {
458 std::cout << "Initializing execution environment: ";
459
460 // FIXME: This should default to searching for the best interpreter to use on
461 // this platform, which would be JIT, then LLC, then CBE, then LLI.
462
463 // Create an instance of the AbstractInterpreter interface as specified on the
464 // command line
465 std::string Message;
Chris Lattner7709ec52003-05-03 03:19:41 +0000466 switch (InterpreterSel) {
467 case RunLLI: Interpreter = LLI::create(this, Message); break;
Misha Brukmand792c9b2003-07-24 18:17:43 +0000468 case RunLLC: Interpreter = LLC::create(this, Message); break;
Chris Lattner7709ec52003-05-03 03:19:41 +0000469 case RunJIT: Interpreter = JIT::create(this, Message); break;
470 case RunCBE: Interpreter = CBE::create(this, Message); break;
471 default:
472 Message = " Sorry, this back-end is not supported by bugpoint right now!\n";
473 break;
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000474 }
475
476 std::cout << Message;
477
Misha Brukman0fd31722003-07-24 21:59:10 +0000478 // Initialize auxiliary tools for debugging
479 cbe = CBE::create(this, Message);
480 if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); }
481 gcc = GCC::create(this, Message);
482 if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); }
483
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000484 // If there was an error creating the selected interpreter, quit with error.
485 return Interpreter == 0;
486}
487
488
489/// executeProgram - This method runs "Program", capturing the output of the
490/// program to a file, returning the filename of the file. A recommended
491/// filename may be optionally specified.
492///
493std::string BugDriver::executeProgram(std::string OutputFile,
Misha Brukmand792c9b2003-07-24 18:17:43 +0000494 std::string BytecodeFile,
495 std::string SharedObject,
496 AbstractInterpreter *AI) {
497 assert((Interpreter || AI) &&"Interpreter should have been created already!");
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000498 bool CreatedBytecode = false;
499 if (BytecodeFile.empty()) {
500 // Emit the program to a bytecode file...
501 BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
502
503 if (writeProgramToFile(BytecodeFile, Program)) {
504 std::cerr << ToolName << ": Error emitting bytecode to file '"
Misha Brukmand792c9b2003-07-24 18:17:43 +0000505 << BytecodeFile << "'!\n";
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000506 exit(1);
507 }
508 CreatedBytecode = true;
509 }
510
511 if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
Misha Brukmand792c9b2003-07-24 18:17:43 +0000512
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000513 // Check to see if this is a valid output filename...
514 OutputFile = getUniqueFilename(OutputFile);
515
516 // Actually execute the program!
Misha Brukmand792c9b2003-07-24 18:17:43 +0000517 int RetVal = (AI != 0) ?
518 AI->ExecuteProgram(BytecodeFile, OutputFile, SharedObject) :
519 Interpreter->ExecuteProgram(BytecodeFile, OutputFile, SharedObject);
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000520
521 // Remove the temporary bytecode file.
Misha Brukmand792c9b2003-07-24 18:17:43 +0000522 if (CreatedBytecode) removeFile(BytecodeFile);
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000523
524 // Return the filename we captured the output to.
525 return OutputFile;
526}
527
Misha Brukmand792c9b2003-07-24 18:17:43 +0000528std::string BugDriver::executeProgramWithCBE(std::string OutputFile,
529 std::string BytecodeFile,
530 std::string SharedObject) {
Misha Brukman0fd31722003-07-24 21:59:10 +0000531 return executeProgram(OutputFile, BytecodeFile, SharedObject, cbe);
Misha Brukmand792c9b2003-07-24 18:17:43 +0000532}
533
534int BugDriver::compileSharedObject(const std::string &BytecodeFile,
535 std::string &SharedObject) {
536 assert(Interpreter && "Interpreter should have been created already!");
537 std::string Message, OutputCFile;
538
539 // Using CBE
Misha Brukmand792c9b2003-07-24 18:17:43 +0000540 cbe->OutputC(BytecodeFile, OutputCFile);
541
542#if 0 /* This is an alternative, as yet unimplemented */
543 // Using LLC
544 LLC *llc = LLC::create(this, Message);
545 if (llc->OutputAsm(BytecodeFile, OutputFile)) {
546 std::cerr << "Could not generate asm code with `llc', exiting.\n";
547 exit(1);
548 }
549#endif
550
Misha Brukman0fd31722003-07-24 21:59:10 +0000551 gcc->MakeSharedObject(OutputCFile, CFile, SharedObject);
Misha Brukmand792c9b2003-07-24 18:17:43 +0000552
553 // Remove the intermediate C file
554 removeFile(OutputCFile);
555
Misha Brukmand792c9b2003-07-24 18:17:43 +0000556 return 0;
557}
558
559
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000560/// diffProgram - This method executes the specified module and diffs the output
561/// against the file specified by ReferenceOutputFile. If the output is
562/// different, true is returned.
563///
Misha Brukmand792c9b2003-07-24 18:17:43 +0000564bool BugDriver::diffProgram(const std::string &BytecodeFile,
565 const std::string &SharedObject,
Chris Lattner16a41312003-04-24 17:02:17 +0000566 bool RemoveBytecode) {
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000567 // Execute the program, generating an output file...
Misha Brukmand792c9b2003-07-24 18:17:43 +0000568 std::string Output = executeProgram("", BytecodeFile, SharedObject);
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000569
570 std::ifstream ReferenceFile(ReferenceOutputFile.c_str());
571 if (!ReferenceFile) {
572 std::cerr << "Couldn't open reference output file '"
Misha Brukmand792c9b2003-07-24 18:17:43 +0000573 << ReferenceOutputFile << "'\n";
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000574 exit(1);
575 }
576
577 std::ifstream OutputFile(Output.c_str());
578 if (!OutputFile) {
579 std::cerr << "Couldn't open output file: " << Output << "'!\n";
580 exit(1);
581 }
582
583 bool FilesDifferent = false;
584
585 // Compare the two files...
586 int C1, C2;
587 do {
588 C1 = ReferenceFile.get();
589 C2 = OutputFile.get();
590 if (C1 != C2) { FilesDifferent = true; break; }
591 } while (C1 != EOF);
592
Misha Brukman539f9592003-07-28 19:16:14 +0000593 //removeFile(Output);
Chris Lattner16a41312003-04-24 17:02:17 +0000594 if (RemoveBytecode) removeFile(BytecodeFile);
Chris Lattnerde4aa4c2002-12-23 23:50:16 +0000595 return FilesDifferent;
596}
Misha Brukman539f9592003-07-28 19:16:14 +0000597
598bool BugDriver::isExecutingJIT() {
599 return InterpreterSel == RunJIT;
600}