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