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