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