blob: 50a9ad21c8598bdf1993adfed2e25d6d7e087f1a [file] [log] [blame]
Chris Lattner7915a1e2003-10-14 21:34:11 +00001//===-- ToolRunner.cpp ----------------------------------------------------===//
John Criswellb576c942003-10-20 19:43:21 +00002//
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//===----------------------------------------------------------------------===//
Chris Lattner7915a1e2003-10-14 21:34:11 +00009//
10// This file implements the interfaces described in the ToolRunner.h file.
11//
12//===----------------------------------------------------------------------===//
13
Chris Lattner0b1fe842003-10-19 02:27:40 +000014#define DEBUG_TYPE "toolrunner"
Misha Brukman68734502003-10-06 18:37:24 +000015#include "llvm/Support/ToolRunner.h"
Misha Brukman9558c6a2003-09-29 22:39:25 +000016#include "Support/Debug.h"
17#include "Support/FileUtilities.h"
Chris Lattner7915a1e2003-10-14 21:34:11 +000018#include <iostream>
19#include <fstream>
Misha Brukman9558c6a2003-09-29 22:39:25 +000020
Brian Gaeked0fde302003-11-11 22:41:34 +000021namespace llvm {
22
Misha Brukman9558c6a2003-09-29 22:39:25 +000023//===---------------------------------------------------------------------===//
24// LLI Implementation of AbstractIntepreter interface
25//
26class LLI : public AbstractInterpreter {
27 std::string LLIPath; // The path to the LLI executable
28public:
29 LLI(const std::string &Path) : LLIPath(Path) { }
30
31
32 virtual int ExecuteProgram(const std::string &Bytecode,
Chris Lattner7915a1e2003-10-14 21:34:11 +000033 const std::vector<std::string> &Args,
Misha Brukman9558c6a2003-09-29 22:39:25 +000034 const std::string &InputFile,
35 const std::string &OutputFile,
Chris Lattnereeed9832003-10-14 21:52:52 +000036 const std::vector<std::string> &SharedLibs =
37 std::vector<std::string>());
Misha Brukman9558c6a2003-09-29 22:39:25 +000038};
39
40int LLI::ExecuteProgram(const std::string &Bytecode,
Chris Lattner7915a1e2003-10-14 21:34:11 +000041 const std::vector<std::string> &Args,
Misha Brukman9558c6a2003-09-29 22:39:25 +000042 const std::string &InputFile,
43 const std::string &OutputFile,
Chris Lattnereeed9832003-10-14 21:52:52 +000044 const std::vector<std::string> &SharedLibs) {
45 if (!SharedLibs.empty()) {
Misha Brukman9558c6a2003-09-29 22:39:25 +000046 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());
Misha Brukman9558c6a2003-09-29 22:39:25 +000053 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;
Chris Lattner0b1fe842003-10-19 02:27:40 +000062 DEBUG(std::cerr << "\nAbout to run:\t";
Chris Lattner7b2ccff2003-10-19 02:14:58 +000063 for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i)
Misha Brukman9558c6a2003-09-29 22:39:25 +000064 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
Chris Lattner7915a1e2003-10-14 21:34:11 +000072AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath,
73 std::string &Message) {
74 std::string LLIPath = FindExecutable("lli", ProgPath);
Misha Brukman9558c6a2003-09-29 22:39:25 +000075 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//
Chris Lattner7915a1e2003-10-14 21:34:11 +000087int LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) {
Misha Brukman9558c6a2003-09-29 22:39:25 +000088 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
109int LLC::ExecuteProgram(const std::string &Bytecode,
Chris Lattner7915a1e2003-10-14 21:34:11 +0000110 const std::vector<std::string> &Args,
Misha Brukman9558c6a2003-09-29 22:39:25 +0000111 const std::string &InputFile,
112 const std::string &OutputFile,
Chris Lattnereeed9832003-10-14 21:52:52 +0000113 const std::vector<std::string> &SharedLibs) {
114
Misha Brukman9558c6a2003-09-29 22:39:25 +0000115 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.
Chris Lattner7915a1e2003-10-14 21:34:11 +0000122 int Result = gcc->ExecuteProgram(OutputAsmFile, Args, GCC::AsmFile,
Chris Lattnereeed9832003-10-14 21:52:52 +0000123 InputFile, OutputFile, SharedLibs);
Misha Brukman9558c6a2003-09-29 22:39:25 +0000124 removeFile(OutputAsmFile);
125 return Result;
126}
127
Chris Lattner7915a1e2003-10-14 21:34:11 +0000128/// createLLC - Try to find the LLC executable
Misha Brukman9558c6a2003-09-29 22:39:25 +0000129///
Chris Lattner7915a1e2003-10-14 21:34:11 +0000130LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath,
131 std::string &Message) {
Misha Brukman9558c6a2003-09-29 22:39:25 +0000132 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";
Chris Lattner7915a1e2003-10-14 21:34:11 +0000139 GCC *gcc = GCC::create(ProgramPath, Message);
Misha Brukman9558c6a2003-09-29 22:39:25 +0000140 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//
150class JIT : public AbstractInterpreter {
151 std::string LLIPath; // The path to the LLI executable
152public:
153 JIT(const std::string &Path) : LLIPath(Path) { }
154
155
156 virtual int ExecuteProgram(const std::string &Bytecode,
Chris Lattner7915a1e2003-10-14 21:34:11 +0000157 const std::vector<std::string> &Args,
Misha Brukman9558c6a2003-09-29 22:39:25 +0000158 const std::string &InputFile,
159 const std::string &OutputFile,
Chris Lattnereeed9832003-10-14 21:52:52 +0000160 const std::vector<std::string> &SharedLibs =
161 std::vector<std::string>());
Misha Brukman9558c6a2003-09-29 22:39:25 +0000162};
163
164int JIT::ExecuteProgram(const std::string &Bytecode,
Chris Lattner7915a1e2003-10-14 21:34:11 +0000165 const std::vector<std::string> &Args,
Misha Brukman9558c6a2003-09-29 22:39:25 +0000166 const std::string &InputFile,
167 const std::string &OutputFile,
Chris Lattnereeed9832003-10-14 21:52:52 +0000168 const std::vector<std::string> &SharedLibs) {
Misha Brukman9558c6a2003-09-29 22:39:25 +0000169 // 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");
Chris Lattnereeed9832003-10-14 21:52:52 +0000174
175 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
Misha Brukman9558c6a2003-09-29 22:39:25 +0000176 JITArgs.push_back("-load");
Chris Lattnereeed9832003-10-14 21:52:52 +0000177 JITArgs.push_back(SharedLibs[i].c_str());
Misha Brukman9558c6a2003-09-29 22:39:25 +0000178 }
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;
Chris Lattner0b1fe842003-10-19 02:27:40 +0000186 DEBUG(std::cerr << "\nAbout to run:\t";
Chris Lattner7b2ccff2003-10-19 02:14:58 +0000187 for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i)
Misha Brukman9558c6a2003-09-29 22:39:25 +0000188 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
Chris Lattner7915a1e2003-10-14 21:34:11 +0000196/// createJIT - Try to find the LLI executable
Misha Brukman9558c6a2003-09-29 22:39:25 +0000197///
Chris Lattner7915a1e2003-10-14 21:34:11 +0000198AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath,
199 std::string &Message) {
200 std::string LLIPath = FindExecutable("lli", ProgPath);
Misha Brukman9558c6a2003-09-29 22:39:25 +0000201 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
210int 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
233int CBE::ExecuteProgram(const std::string &Bytecode,
Chris Lattner7915a1e2003-10-14 21:34:11 +0000234 const std::vector<std::string> &Args,
Misha Brukman9558c6a2003-09-29 22:39:25 +0000235 const std::string &InputFile,
236 const std::string &OutputFile,
Chris Lattnereeed9832003-10-14 21:52:52 +0000237 const std::vector<std::string> &SharedLibs) {
Misha Brukman9558c6a2003-09-29 22:39:25 +0000238 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
Chris Lattner7915a1e2003-10-14 21:34:11 +0000244 int Result = gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile,
Chris Lattnereeed9832003-10-14 21:52:52 +0000245 InputFile, OutputFile, SharedLibs);
Misha Brukman9558c6a2003-09-29 22:39:25 +0000246 removeFile(OutputCFile);
247
248 return Result;
249}
250
Chris Lattner7915a1e2003-10-14 21:34:11 +0000251/// createCBE - Try to find the 'llvm-dis' executable
Misha Brukman9558c6a2003-09-29 22:39:25 +0000252///
Chris Lattner7915a1e2003-10-14 21:34:11 +0000253CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath,
254 std::string &Message) {
Misha Brukman9558c6a2003-09-29 22:39:25 +0000255 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";
Chris Lattner7915a1e2003-10-14 21:34:11 +0000263 GCC *gcc = GCC::create(ProgramPath, Message);
Misha Brukman9558c6a2003-09-29 22:39:25 +0000264 if (!gcc) {
265 std::cerr << Message << "\n";
266 exit(1);
267 }
268 return new CBE(DISPath, gcc);
269}
270
271//===---------------------------------------------------------------------===//
272// GCC abstraction
273//
Misha Brukman9558c6a2003-09-29 22:39:25 +0000274int GCC::ExecuteProgram(const std::string &ProgramFile,
Chris Lattner7915a1e2003-10-14 21:34:11 +0000275 const std::vector<std::string> &Args,
Misha Brukman9558c6a2003-09-29 22:39:25 +0000276 FileType fileType,
277 const std::string &InputFile,
278 const std::string &OutputFile,
Chris Lattnereeed9832003-10-14 21:52:52 +0000279 const std::vector<std::string> &SharedLibs) {
Misha Brukman9558c6a2003-09-29 22:39:25 +0000280 std::vector<const char*> GCCArgs;
281
282 GCCArgs.push_back(GCCPath.c_str());
Chris Lattnereeed9832003-10-14 21:52:52 +0000283
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
Misha Brukman9558c6a2003-09-29 22:39:25 +0000289 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");
Chris Lattnereeed9832003-10-14 21:52:52 +0000298 std::string OutputBinary = getUniqueFilename(ProgramFile+".gcc.exe");
Misha Brukman9558c6a2003-09-29 22:39:25 +0000299 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...
Chris Lattner1f0f1622003-10-18 21:54:47 +0000302 GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files
Misha Brukman9558c6a2003-09-29 22:39:25 +0000303 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;
Chris Lattner0b1fe842003-10-19 02:27:40 +0000321 DEBUG(std::cerr << "\nAbout to run:\t";
Chris Lattner7b2ccff2003-10-19 02:14:58 +0000322 for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i)
Misha Brukman9558c6a2003-09-29 22:39:25 +0000323 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
Chris Lattner1798e4a2003-10-14 21:07:25 +0000332int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
Misha Brukman9558c6a2003-09-29 22:39:25 +0000333 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;
Chris Lattner1798e4a2003-10-14 21:07:25 +0000352 if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
353 "/dev/null")) {
Misha Brukman9558c6a2003-09-29 22:39:25 +0000354 ProcessFailure(GCCArgs);
Chris Lattner1798e4a2003-10-14 21:07:25 +0000355 return 1;
Misha Brukman9558c6a2003-09-29 22:39:25 +0000356 }
357 return 0;
358}
359
360void 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
Chris Lattner7915a1e2003-10-14 21:34:11 +0000384/// create - Try to find the `gcc' executable
Misha Brukman9558c6a2003-09-29 22:39:25 +0000385///
Chris Lattner7915a1e2003-10-14 21:34:11 +0000386GCC *GCC::create(const std::string &ProgramPath, std::string &Message) {
Misha Brukman9558c6a2003-09-29 22:39:25 +0000387 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}
Brian Gaeked0fde302003-11-11 22:41:34 +0000396
397} // End llvm namespace