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