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