blob: 985c6854b8a953f7d3886693ec515489e6153d5c [file] [log] [blame]
Misha Brukman68734502003-10-06 18:37:24 +00001#include "llvm/Support/ToolRunner.h"
Misha Brukman9558c6a2003-09-29 22:39:25 +00002#include "Support/Debug.h"
3#include "Support/FileUtilities.h"
Misha Brukman9558c6a2003-09-29 22:39:25 +00004
5//===---------------------------------------------------------------------===//
6// LLI Implementation of AbstractIntepreter interface
7//
8class LLI : public AbstractInterpreter {
9 std::string LLIPath; // The path to the LLI executable
10public:
11 LLI(const std::string &Path) : LLIPath(Path) { }
12
13
14 virtual int ExecuteProgram(const std::string &Bytecode,
15 const cl::list<std::string> &Args,
16 const std::string &InputFile,
17 const std::string &OutputFile,
18 const std::string &SharedLib = "");
19};
20
21int LLI::ExecuteProgram(const std::string &Bytecode,
22 const cl::list<std::string> &Args,
23 const std::string &InputFile,
24 const std::string &OutputFile,
25 const std::string &SharedLib) {
26 if (!SharedLib.empty()) {
27 std::cerr << "LLI currently does not support loading shared libraries.\n"
28 << "Exiting.\n";
29 exit(1);
30 }
31
32 std::vector<const char*> LLIArgs;
33 LLIArgs.push_back(LLIPath.c_str());
34 LLIArgs.push_back("-abort-on-exception");
35 LLIArgs.push_back("-quiet");
36 LLIArgs.push_back("-force-interpreter=true");
37 LLIArgs.push_back(Bytecode.c_str());
38 // Add optional parameters to the running program from Argv
39 for (unsigned i=0, e = Args.size(); i != e; ++i)
40 LLIArgs.push_back(Args[i].c_str());
41 LLIArgs.push_back(0);
42
43 std::cout << "<lli>" << std::flush;
44 DEBUG(std::cerr << "\nAbout to run:\n\t";
45 for (unsigned i=0, e = LLIArgs.size(); i != e; ++i)
46 std::cerr << " " << LLIArgs[i];
47 std::cerr << "\n";
48 );
49 return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
50 InputFile, OutputFile, OutputFile);
51}
52
53// LLI create method - Try to find the LLI executable
54AbstractInterpreter *createLLItool(const std::string &ProgramPath,
55 std::string &Message) {
56 std::string LLIPath = FindExecutable("lli", ProgramPath);
57 if (!LLIPath.empty()) {
58 Message = "Found lli: " + LLIPath + "\n";
59 return new LLI(LLIPath);
60 }
61
62 Message = "Cannot find `lli' in executable directory or PATH!\n";
63 return 0;
64}
65
66//===----------------------------------------------------------------------===//
67// LLC Implementation of AbstractIntepreter interface
68//
69int LLC::OutputAsm(const std::string &Bytecode,
70 std::string &OutputAsmFile) {
71 OutputAsmFile = getUniqueFilename(Bytecode+".llc.s");
72 const char *LLCArgs[] = {
73 LLCPath.c_str(),
74 "-o", OutputAsmFile.c_str(), // Output to the Asm file
75 "-f", // Overwrite as necessary...
76 Bytecode.c_str(), // This is the input bytecode
77 0
78 };
79
80 std::cout << "<llc>" << std::flush;
81 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
82 "/dev/null")) {
83 // If LLC failed on the bytecode, print error...
84 std::cerr << "Error: `llc' failed!\n";
85 removeFile(OutputAsmFile);
86 return 1;
87 }
88
89 return 0;
90}
91
92int LLC::ExecuteProgram(const std::string &Bytecode,
93 const cl::list<std::string> &Args,
94 const std::string &InputFile,
95 const std::string &OutputFile,
96 const std::string &SharedLib) {
97
98 std::string OutputAsmFile;
99 if (OutputAsm(Bytecode, OutputAsmFile)) {
100 std::cerr << "Could not generate asm code with `llc', exiting.\n";
101 exit(1);
102 }
103
104 // Assuming LLC worked, compile the result with GCC and run it.
105 int Result = gcc->ExecuteProgram(OutputAsmFile, Args, AsmFile,
106 InputFile, OutputFile, SharedLib);
107 removeFile(OutputAsmFile);
108 return Result;
109}
110
111/// createLLCtool - Try to find the LLC executable
112///
113LLC *createLLCtool(const std::string &ProgramPath, std::string &Message)
114{
115 std::string LLCPath = FindExecutable("llc", ProgramPath);
116 if (LLCPath.empty()) {
117 Message = "Cannot find `llc' in executable directory or PATH!\n";
118 return 0;
119 }
120
121 Message = "Found llc: " + LLCPath + "\n";
122 GCC *gcc = createGCCtool(ProgramPath, Message);
123 if (!gcc) {
124 std::cerr << Message << "\n";
125 exit(1);
126 }
127 return new LLC(LLCPath, gcc);
128}
129
130//===---------------------------------------------------------------------===//
131// JIT Implementation of AbstractIntepreter interface
132//
133class JIT : public AbstractInterpreter {
134 std::string LLIPath; // The path to the LLI executable
135public:
136 JIT(const std::string &Path) : LLIPath(Path) { }
137
138
139 virtual int ExecuteProgram(const std::string &Bytecode,
140 const cl::list<std::string> &Args,
141 const std::string &InputFile,
142 const std::string &OutputFile,
143 const std::string &SharedLib = "");
144};
145
146int JIT::ExecuteProgram(const std::string &Bytecode,
147 const cl::list<std::string> &Args,
148 const std::string &InputFile,
149 const std::string &OutputFile,
150 const std::string &SharedLib) {
151 // Construct a vector of parameters, incorporating those from the command-line
152 std::vector<const char*> JITArgs;
153 JITArgs.push_back(LLIPath.c_str());
154 JITArgs.push_back("-quiet");
155 JITArgs.push_back("-force-interpreter=false");
156 if (!SharedLib.empty()) {
157 JITArgs.push_back("-load");
158 JITArgs.push_back(SharedLib.c_str());
159 }
160 JITArgs.push_back(Bytecode.c_str());
161 // Add optional parameters to the running program from Argv
162 for (unsigned i=0, e = Args.size(); i != e; ++i)
163 JITArgs.push_back(Args[i].c_str());
164 JITArgs.push_back(0);
165
166 std::cout << "<jit>" << std::flush;
167 DEBUG(std::cerr << "\nAbout to run:\n\t";
168 for (unsigned i=0, e = JITArgs.size(); i != e; ++i)
169 std::cerr << " " << JITArgs[i];
170 std::cerr << "\n";
171 );
172 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
173 return RunProgramWithTimeout(LLIPath, &JITArgs[0],
174 InputFile, OutputFile, OutputFile);
175}
176
177/// createJITtool - Try to find the LLI executable
178///
179AbstractInterpreter *createJITtool(const std::string &ProgramPath,
180 std::string &Message) {
181 std::string LLIPath = FindExecutable("lli", ProgramPath);
182 if (!LLIPath.empty()) {
183 Message = "Found lli: " + LLIPath + "\n";
184 return new JIT(LLIPath);
185 }
186
187 Message = "Cannot find `lli' in executable directory or PATH!\n";
188 return 0;
189}
190
191int CBE::OutputC(const std::string &Bytecode,
192 std::string &OutputCFile) {
193 OutputCFile = getUniqueFilename(Bytecode+".cbe.c");
194 const char *DisArgs[] = {
195 DISPath.c_str(),
196 "-o", OutputCFile.c_str(), // Output to the C file
197 "-c", // Output to C
198 "-f", // Overwrite as necessary...
199 Bytecode.c_str(), // This is the input bytecode
200 0
201 };
202
203 std::cout << "<cbe>" << std::flush;
204 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
205 "/dev/null")) {
206 // If dis failed on the bytecode, print error...
207 std::cerr << "Error: `llvm-dis -c' failed!\n";
208 return 1;
209 }
210
211 return 0;
212}
213
214int CBE::ExecuteProgram(const std::string &Bytecode,
215 const cl::list<std::string> &Args,
216 const std::string &InputFile,
217 const std::string &OutputFile,
218 const std::string &SharedLib) {
219 std::string OutputCFile;
220 if (OutputC(Bytecode, OutputCFile)) {
221 std::cerr << "Could not generate C code with `llvm-dis', exiting.\n";
222 exit(1);
223 }
224
225 int Result = gcc->ExecuteProgram(OutputCFile, Args, CFile,
226 InputFile, OutputFile, SharedLib);
227 removeFile(OutputCFile);
228
229 return Result;
230}
231
232/// createCBEtool - Try to find the 'dis' executable
233///
234CBE *createCBEtool(const std::string &ProgramPath, std::string &Message) {
235 std::string DISPath = FindExecutable("llvm-dis", ProgramPath);
236 if (DISPath.empty()) {
237 Message =
238 "Cannot find `llvm-dis' in executable directory or PATH!\n";
239 return 0;
240 }
241
242 Message = "Found llvm-dis: " + DISPath + "\n";
243 GCC *gcc = createGCCtool(ProgramPath, Message);
244 if (!gcc) {
245 std::cerr << Message << "\n";
246 exit(1);
247 }
248 return new CBE(DISPath, gcc);
249}
250
251//===---------------------------------------------------------------------===//
252// GCC abstraction
253//
254// This is not a *real* AbstractInterpreter as it does not accept bytecode
255// files, but only input acceptable to GCC, i.e. C, C++, and assembly files
256//
257int GCC::ExecuteProgram(const std::string &ProgramFile,
258 const cl::list<std::string> &Args,
259 FileType fileType,
260 const std::string &InputFile,
261 const std::string &OutputFile,
262 const std::string &SharedLib) {
263 std::string OutputBinary = getUniqueFilename(ProgramFile+".gcc.exe");
264 std::vector<const char*> GCCArgs;
265
266 GCCArgs.push_back(GCCPath.c_str());
267 if (!SharedLib.empty()) // Specify the shared library to link in...
268 GCCArgs.push_back(SharedLib.c_str());
269 GCCArgs.push_back("-x");
270 if (fileType == CFile) {
271 GCCArgs.push_back("c");
272 GCCArgs.push_back("-fno-strict-aliasing");
273 } else {
274 GCCArgs.push_back("assembler");
275 }
276 GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename...
277 GCCArgs.push_back("-o");
278 GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
279 GCCArgs.push_back("-lm"); // Hard-code the math library...
280 GCCArgs.push_back("-O2"); // Optimize the program a bit...
281 GCCArgs.push_back(0); // NULL terminator
282
283 std::cout << "<gcc>" << std::flush;
284 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
285 "/dev/null")) {
286 ProcessFailure(&GCCArgs[0]);
287 exit(1);
288 }
289
290 std::vector<const char*> ProgramArgs;
291 ProgramArgs.push_back(OutputBinary.c_str());
292 // Add optional parameters to the running program from Argv
293 for (unsigned i=0, e = Args.size(); i != e; ++i)
294 ProgramArgs.push_back(Args[i].c_str());
295 ProgramArgs.push_back(0); // NULL terminator
296
297 // Now that we have a binary, run it!
298 std::cout << "<program>" << std::flush;
299 DEBUG(std::cerr << "\nAbout to run:\n\t";
300 for (unsigned i=0, e = ProgramArgs.size(); i != e; ++i)
301 std::cerr << " " << ProgramArgs[i];
302 std::cerr << "\n";
303 );
304 int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
305 InputFile, OutputFile, OutputFile);
306 removeFile(OutputBinary);
307 return ProgramResult;
308}
309
310int GCC::MakeSharedObject(const std::string &InputFile,
311 FileType fileType,
312 std::string &OutputFile) {
313 OutputFile = getUniqueFilename(InputFile+".so");
314 // Compile the C/asm file into a shared object
315 const char* GCCArgs[] = {
316 GCCPath.c_str(),
317 "-x", (fileType == AsmFile) ? "assembler" : "c",
318 "-fno-strict-aliasing",
319 InputFile.c_str(), // Specify the input filename...
320#if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
321 "-G", // Compile a shared library, `-G' for Sparc
322#else
323 "-shared", // `-shared' for Linux/X86, maybe others
324#endif
325 "-o", OutputFile.c_str(), // Output to the right filename...
326 "-O2", // Optimize the program a bit...
327 0
328 };
329
330 std::cout << "<gcc>" << std::flush;
331 if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
332 "/dev/null")) {
333 ProcessFailure(GCCArgs);
334 exit(1);
335 }
336 return 0;
337}
338
339void GCC::ProcessFailure(const char** GCCArgs) {
340 std::cerr << "\n*** Error: invocation of the C compiler failed!\n";
341 for (const char **Arg = GCCArgs; *Arg; ++Arg)
342 std::cerr << " " << *Arg;
343 std::cerr << "\n";
344
345 // Rerun the compiler, capturing any error messages to print them.
346 std::string ErrorFilename = getUniqueFilename("gcc.errors");
347 RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
348 ErrorFilename.c_str());
349
350 // Print out the error messages generated by GCC if possible...
351 std::ifstream ErrorFile(ErrorFilename.c_str());
352 if (ErrorFile) {
353 std::copy(std::istreambuf_iterator<char>(ErrorFile),
354 std::istreambuf_iterator<char>(),
355 std::ostreambuf_iterator<char>(std::cerr));
356 ErrorFile.close();
357 std::cerr << "\n";
358 }
359
360 removeFile(ErrorFilename);
361}
362
363/// createGCCtool - Try to find the `gcc' executable
364///
365GCC *createGCCtool(const std::string &ProgramPath, std::string &Message) {
366 std::string GCCPath = FindExecutable("gcc", ProgramPath);
367 if (GCCPath.empty()) {
368 Message = "Cannot find `gcc' in executable directory or PATH!\n";
369 return 0;
370 }
371
372 Message = "Found gcc: " + GCCPath + "\n";
373 return new GCC(GCCPath);
374}