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