1 #include "llvm/Support/ToolRunner.h"
2 #include "Support/Debug.h"
3 #include "Support/FileUtilities.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("-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());
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];
48 return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
49 InputFile, OutputFile, OutputFile);
52 // LLI create method - Try to find the LLI executable
53 AbstractInterpreter *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);
61 Message = "Cannot find `lli' in executable directory or PATH!\n";
65 //===----------------------------------------------------------------------===//
66 // LLC Implementation of AbstractIntepreter interface
68 int LLC::OutputAsm(const std::string &Bytecode,
69 std::string &OutputAsmFile) {
70 OutputAsmFile = getUniqueFilename(Bytecode+".llc.s");
71 const char *LLCArgs[] = {
73 "-o", OutputAsmFile.c_str(), // Output to the Asm file
74 "-f", // Overwrite as necessary...
75 Bytecode.c_str(), // This is the input bytecode
79 std::cout << "<llc>" << std::flush;
80 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
82 // If LLC failed on the bytecode, print error...
83 std::cerr << "Error: `llc' failed!\n";
84 removeFile(OutputAsmFile);
91 int 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) {
97 std::string OutputAsmFile;
98 if (OutputAsm(Bytecode, OutputAsmFile)) {
99 std::cerr << "Could not generate asm code with `llc', exiting.\n";
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);
110 /// createLLCtool - Try to find the LLC executable
112 LLC *createLLCtool(const std::string &ProgramPath, std::string &Message)
114 std::string LLCPath = FindExecutable("llc", ProgramPath);
115 if (LLCPath.empty()) {
116 Message = "Cannot find `llc' in executable directory or PATH!\n";
120 Message = "Found llc: " + LLCPath + "\n";
121 GCC *gcc = createGCCtool(ProgramPath, Message);
123 std::cerr << Message << "\n";
126 return new LLC(LLCPath, gcc);
129 //===---------------------------------------------------------------------===//
130 // JIT Implementation of AbstractIntepreter interface
132 class JIT : public AbstractInterpreter {
133 std::string LLIPath; // The path to the LLI executable
135 JIT(const std::string &Path) : LLIPath(Path) { }
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 = "");
145 int 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());
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);
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];
171 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
172 return RunProgramWithTimeout(LLIPath, &JITArgs[0],
173 InputFile, OutputFile, OutputFile);
176 /// createJITtool - Try to find the LLI executable
178 AbstractInterpreter *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);
186 Message = "Cannot find `lli' in executable directory or PATH!\n";
190 int CBE::OutputC(const std::string &Bytecode,
191 std::string &OutputCFile) {
192 OutputCFile = getUniqueFilename(Bytecode+".cbe.c");
193 const char *DisArgs[] = {
195 "-o", OutputCFile.c_str(), // Output to the C file
197 "-f", // Overwrite as necessary...
198 Bytecode.c_str(), // This is the input bytecode
202 std::cout << "<cbe>" << std::flush;
203 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
205 // If dis failed on the bytecode, print error...
206 std::cerr << "Error: `llvm-dis -c' failed!\n";
213 int 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";
224 int Result = gcc->ExecuteProgram(OutputCFile, Args, CFile,
225 InputFile, OutputFile, SharedLib);
226 removeFile(OutputCFile);
231 /// createCBEtool - Try to find the 'dis' executable
233 CBE *createCBEtool(const std::string &ProgramPath, std::string &Message) {
234 std::string DISPath = FindExecutable("llvm-dis", ProgramPath);
235 if (DISPath.empty()) {
237 "Cannot find `llvm-dis' in executable directory or PATH!\n";
241 Message = "Found llvm-dis: " + DISPath + "\n";
242 GCC *gcc = createGCCtool(ProgramPath, Message);
244 std::cerr << Message << "\n";
247 return new CBE(DISPath, gcc);
250 //===---------------------------------------------------------------------===//
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
256 int GCC::ExecuteProgram(const std::string &ProgramFile,
257 const cl::list<std::string> &Args,
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;
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");
273 GCCArgs.push_back("assembler");
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
282 std::cout << "<gcc>" << std::flush;
283 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
285 ProcessFailure(&GCCArgs[0]);
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
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];
303 int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
304 InputFile, OutputFile, OutputFile);
305 removeFile(OutputBinary);
306 return ProgramResult;
309 int GCC::MakeSharedObject(const std::string &InputFile,
311 std::string &OutputFile) {
312 OutputFile = getUniqueFilename(InputFile+".so");
313 // Compile the C/asm file into a shared object
314 const char* GCCArgs[] = {
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
322 "-shared", // `-shared' for Linux/X86, maybe others
324 "-o", OutputFile.c_str(), // Output to the right filename...
325 "-O2", // Optimize the program a bit...
329 std::cout << "<gcc>" << std::flush;
330 if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
332 ProcessFailure(GCCArgs);
338 void 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;
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());
349 // Print out the error messages generated by GCC if possible...
350 std::ifstream ErrorFile(ErrorFilename.c_str());
352 std::copy(std::istreambuf_iterator<char>(ErrorFile),
353 std::istreambuf_iterator<char>(),
354 std::ostreambuf_iterator<char>(std::cerr));
359 removeFile(ErrorFilename);
362 /// createGCCtool - Try to find the `gcc' executable
364 GCC *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";
371 Message = "Found gcc: " + GCCPath + "\n";
372 return new GCC(GCCPath);