blob: 913fee850b960b90fcc1352f0bd28bc680806a84 [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
14 SingleSource directory f.e. Default to the first input filename.
15*/
16
17#include "BugDriver.h"
18#include "SystemUtils.h"
19#include "Support/CommandLine.h"
20#include <fstream>
21
22namespace {
23 // OutputType - Allow the user to specify the way code should be run, to test
24 // for miscompilation.
25 //
26 enum OutputType {
27 RunLLI, RunJIT, RunLLC, RunCBE
28 };
29 cl::opt<OutputType>
30 InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
31 cl::values(clEnumValN(RunLLI, "run-lli", "Execute with LLI"),
32 clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
33 clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
34 clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
35 0));
36}
37
38/// AbstractInterpreter Class - Subclasses of this class are used to execute
39/// LLVM bytecode in a variety of ways. This abstract interface hides this
40/// complexity behind a simple interface.
41///
42struct AbstractInterpreter {
43
44 virtual ~AbstractInterpreter() {}
45
46 /// ExecuteProgram - Run the specified bytecode file, emitting output to the
47 /// specified filename. This returns the exit code of the program.
48 ///
49 virtual int ExecuteProgram(const std::string &Bytecode,
50 const std::string &OutputFile) = 0;
51
52};
53
54
55//===----------------------------------------------------------------------===//
56// LLI Implementation of AbstractIntepreter interface
57//
58class LLI : public AbstractInterpreter {
59 std::string LLIPath; // The path to the LLI executable
60public:
61 LLI(const std::string &Path) : LLIPath(Path) { }
62
63 // LLI create method - Try to find the LLI executable
64 static LLI *create(BugDriver *BD, std::string &Message) {
65 std::string LLIPath = FindExecutable("lli", BD->getToolName());
66 if (!LLIPath.empty()) {
67 Message = "Found lli: " + LLIPath + "\n";
68 return new LLI(LLIPath);
69 }
70
71 Message = "Cannot find 'lli' in bugpoint executable directory or PATH!\n";
72 return 0;
73 }
74 virtual int ExecuteProgram(const std::string &Bytecode,
75 const std::string &OutputFile);
76};
77
78int LLI::ExecuteProgram(const std::string &Bytecode,
79 const std::string &OutputFile) {
80 const char *Args[] = {
81 "-abort-on-exception",
82 "-quiet",
83 Bytecode.c_str(),
84 0
85 };
86
87 return RunProgramWithTimeout(LLIPath, Args,
88 "/dev/null", OutputFile, OutputFile);
89}
90
91
92//===----------------------------------------------------------------------===//
93// BugDriver method implementation
94//
95
96/// initializeExecutionEnvironment - This method is used to set up the
97/// environment for executing LLVM programs.
98///
99bool BugDriver::initializeExecutionEnvironment() {
100 std::cout << "Initializing execution environment: ";
101
102 // FIXME: This should default to searching for the best interpreter to use on
103 // this platform, which would be JIT, then LLC, then CBE, then LLI.
104
105 // Create an instance of the AbstractInterpreter interface as specified on the
106 // command line
107 std::string Message;
108 if (InterpreterSel == RunLLI) {
109 Interpreter = LLI::create(this, Message);
110 } else {
111 Message = " Sorry, only LLI is supported right now!";
112 }
113
114 std::cout << Message;
115
116 // If there was an error creating the selected interpreter, quit with error.
117 return Interpreter == 0;
118}
119
120
121/// executeProgram - This method runs "Program", capturing the output of the
122/// program to a file, returning the filename of the file. A recommended
123/// filename may be optionally specified.
124///
125std::string BugDriver::executeProgram(std::string OutputFile,
126 std::string BytecodeFile) {
127 assert(Interpreter && "Interpreter should have been created already!");
128 bool CreatedBytecode = false;
129 if (BytecodeFile.empty()) {
130 // Emit the program to a bytecode file...
131 BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
132
133 if (writeProgramToFile(BytecodeFile, Program)) {
134 std::cerr << ToolName << ": Error emitting bytecode to file '"
135 << BytecodeFile << "'!\n";
136 exit(1);
137 }
138 CreatedBytecode = true;
139 }
140
141 if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
142
143 // Check to see if this is a valid output filename...
144 OutputFile = getUniqueFilename(OutputFile);
145
146 // Actually execute the program!
147 int RetVal = Interpreter->ExecuteProgram(BytecodeFile, OutputFile);
148
149 // Remove the temporary bytecode file.
150 if (CreatedBytecode)
151 removeFile(BytecodeFile);
152
153 // Return the filename we captured the output to.
154 return OutputFile;
155}
156
157/// diffProgram - This method executes the specified module and diffs the output
158/// against the file specified by ReferenceOutputFile. If the output is
159/// different, true is returned.
160///
161bool BugDriver::diffProgram(const std::string &ReferenceOutputFile,
162 const std::string &BytecodeFile) {
163 // Execute the program, generating an output file...
164 std::string Output = executeProgram("", BytecodeFile);
165
166 std::ifstream ReferenceFile(ReferenceOutputFile.c_str());
167 if (!ReferenceFile) {
168 std::cerr << "Couldn't open reference output file '"
169 << ReferenceOutputFile << "'\n";
170 exit(1);
171 }
172
173 std::ifstream OutputFile(Output.c_str());
174 if (!OutputFile) {
175 std::cerr << "Couldn't open output file: " << Output << "'!\n";
176 exit(1);
177 }
178
179 bool FilesDifferent = false;
180
181 // Compare the two files...
182 int C1, C2;
183 do {
184 C1 = ReferenceFile.get();
185 C2 = OutputFile.get();
186 if (C1 != C2) { FilesDifferent = true; break; }
187 } while (C1 != EOF);
188
189 removeFile(Output);
190 return FilesDifferent;
191}