1 #include "Support/Debug.h"
2 #include "Support/FileUtilities.h"
3 #include "Support/ToolRunner.h"
5 //===---------------------------------------------------------------------===//
6 // LLI Implementation of AbstractIntepreter interface
8 class LLI : public AbstractInterpreter {
9 std::string LLIPath; // The path to the LLI executable
11 LLI(const std::string &Path) : LLIPath(Path) { }
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 = "");
21 int 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"
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());
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];
49 return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
50 InputFile, OutputFile, OutputFile);
53 // LLI create method - Try to find the LLI executable
54 AbstractInterpreter *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);
62 Message = "Cannot find `lli' in executable directory or PATH!\n";
66 //===----------------------------------------------------------------------===//
67 // LLC Implementation of AbstractIntepreter interface
69 int LLC::OutputAsm(const std::string &Bytecode,
70 std::string &OutputAsmFile) {
71 OutputAsmFile = getUniqueFilename(Bytecode+".llc.s");
72 const char *LLCArgs[] = {
74 "-o", OutputAsmFile.c_str(), // Output to the Asm file
75 "-f", // Overwrite as necessary...
76 Bytecode.c_str(), // This is the input bytecode
80 std::cout << "<llc>" << std::flush;
81 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
83 // If LLC failed on the bytecode, print error...
84 std::cerr << "Error: `llc' failed!\n";
85 removeFile(OutputAsmFile);
92 int 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) {
98 std::string OutputAsmFile;
99 if (OutputAsm(Bytecode, OutputAsmFile)) {
100 std::cerr << "Could not generate asm code with `llc', exiting.\n";
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);
111 /// createLLCtool - Try to find the LLC executable
113 LLC *createLLCtool(const std::string &ProgramPath, std::string &Message)
115 std::string LLCPath = FindExecutable("llc", ProgramPath);
116 if (LLCPath.empty()) {
117 Message = "Cannot find `llc' in executable directory or PATH!\n";
121 Message = "Found llc: " + LLCPath + "\n";
122 GCC *gcc = createGCCtool(ProgramPath, Message);
124 std::cerr << Message << "\n";
127 return new LLC(LLCPath, gcc);
130 //===---------------------------------------------------------------------===//
131 // JIT Implementation of AbstractIntepreter interface
133 class JIT : public AbstractInterpreter {
134 std::string LLIPath; // The path to the LLI executable
136 JIT(const std::string &Path) : LLIPath(Path) { }
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 = "");
146 int 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());
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);
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];
172 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
173 return RunProgramWithTimeout(LLIPath, &JITArgs[0],
174 InputFile, OutputFile, OutputFile);
177 /// createJITtool - Try to find the LLI executable
179 AbstractInterpreter *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);
187 Message = "Cannot find `lli' in executable directory or PATH!\n";
191 int CBE::OutputC(const std::string &Bytecode,
192 std::string &OutputCFile) {
193 OutputCFile = getUniqueFilename(Bytecode+".cbe.c");
194 const char *DisArgs[] = {
196 "-o", OutputCFile.c_str(), // Output to the C file
198 "-f", // Overwrite as necessary...
199 Bytecode.c_str(), // This is the input bytecode
203 std::cout << "<cbe>" << std::flush;
204 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
206 // If dis failed on the bytecode, print error...
207 std::cerr << "Error: `llvm-dis -c' failed!\n";
214 int 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";
225 int Result = gcc->ExecuteProgram(OutputCFile, Args, CFile,
226 InputFile, OutputFile, SharedLib);
227 removeFile(OutputCFile);
232 /// createCBEtool - Try to find the 'dis' executable
234 CBE *createCBEtool(const std::string &ProgramPath, std::string &Message) {
235 std::string DISPath = FindExecutable("llvm-dis", ProgramPath);
236 if (DISPath.empty()) {
238 "Cannot find `llvm-dis' in executable directory or PATH!\n";
242 Message = "Found llvm-dis: " + DISPath + "\n";
243 GCC *gcc = createGCCtool(ProgramPath, Message);
245 std::cerr << Message << "\n";
248 return new CBE(DISPath, gcc);
251 //===---------------------------------------------------------------------===//
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
257 int GCC::ExecuteProgram(const std::string &ProgramFile,
258 const cl::list<std::string> &Args,
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;
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");
274 GCCArgs.push_back("assembler");
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
283 std::cout << "<gcc>" << std::flush;
284 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
286 ProcessFailure(&GCCArgs[0]);
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
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];
304 int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
305 InputFile, OutputFile, OutputFile);
306 removeFile(OutputBinary);
307 return ProgramResult;
310 int GCC::MakeSharedObject(const std::string &InputFile,
312 std::string &OutputFile) {
313 OutputFile = getUniqueFilename(InputFile+".so");
314 // Compile the C/asm file into a shared object
315 const char* GCCArgs[] = {
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
323 "-shared", // `-shared' for Linux/X86, maybe others
325 "-o", OutputFile.c_str(), // Output to the right filename...
326 "-O2", // Optimize the program a bit...
330 std::cout << "<gcc>" << std::flush;
331 if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
333 ProcessFailure(GCCArgs);
339 void 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;
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());
350 // Print out the error messages generated by GCC if possible...
351 std::ifstream ErrorFile(ErrorFilename.c_str());
353 std::copy(std::istreambuf_iterator<char>(ErrorFile),
354 std::istreambuf_iterator<char>(),
355 std::ostreambuf_iterator<char>(std::cerr));
360 removeFile(ErrorFilename);
363 /// createGCCtool - Try to find the `gcc' executable
365 GCC *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";
372 Message = "Found gcc: " + GCCPath + "\n";
373 return new GCC(GCCPath);