1 //===-- ToolRunner.cpp ----------------------------------------------------===//
3 // This file implements the interfaces described in the ToolRunner.h file.
5 //===----------------------------------------------------------------------===//
7 #include "llvm/Support/ToolRunner.h"
8 #include "Support/Debug.h"
9 #include "Support/FileUtilities.h"
13 //===---------------------------------------------------------------------===//
14 // LLI Implementation of AbstractIntepreter interface
16 class LLI : public AbstractInterpreter {
17 std::string LLIPath; // The path to the LLI executable
19 LLI(const std::string &Path) : LLIPath(Path) { }
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>());
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"
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());
51 std::cout << "<lli>" << std::flush;
52 DEBUG(std::cerr << "\nAbout to run:\n\t";
53 for (unsigned i=0, e = LLIArgs.size(); i != e; ++i)
54 std::cerr << " " << LLIArgs[i];
57 return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
58 InputFile, OutputFile, OutputFile);
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);
70 Message = "Cannot find `lli' in executable directory or PATH!\n";
74 //===----------------------------------------------------------------------===//
75 // LLC Implementation of AbstractIntepreter interface
77 int LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) {
78 OutputAsmFile = getUniqueFilename(Bytecode+".llc.s");
79 const char *LLCArgs[] = {
81 "-o", OutputAsmFile.c_str(), // Output to the Asm file
82 "-f", // Overwrite as necessary...
83 Bytecode.c_str(), // This is the input bytecode
87 std::cout << "<llc>" << std::flush;
88 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
90 // If LLC failed on the bytecode, print error...
91 std::cerr << "Error: `llc' failed!\n";
92 removeFile(OutputAsmFile);
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) {
105 std::string OutputAsmFile;
106 if (OutputAsm(Bytecode, OutputAsmFile)) {
107 std::cerr << "Could not generate asm code with `llc', exiting.\n";
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);
118 /// createLLC - Try to find the LLC executable
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";
128 Message = "Found llc: " + LLCPath + "\n";
129 GCC *gcc = GCC::create(ProgramPath, Message);
131 std::cerr << Message << "\n";
134 return new LLC(LLCPath, gcc);
137 //===---------------------------------------------------------------------===//
138 // JIT Implementation of AbstractIntepreter interface
140 class JIT : public AbstractInterpreter {
141 std::string LLIPath; // The path to the LLI executable
143 JIT(const std::string &Path) : LLIPath(Path) { }
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>());
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");
165 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
166 JITArgs.push_back("-load");
167 JITArgs.push_back(SharedLibs[i].c_str());
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);
175 std::cout << "<jit>" << std::flush;
176 DEBUG(std::cerr << "\nAbout to run:\n\t";
177 for (unsigned i=0, e = JITArgs.size(); i != e; ++i)
178 std::cerr << " " << JITArgs[i];
181 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
182 return RunProgramWithTimeout(LLIPath, &JITArgs[0],
183 InputFile, OutputFile, OutputFile);
186 /// createJIT - Try to find the LLI executable
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);
196 Message = "Cannot find `lli' in executable directory or PATH!\n";
200 int CBE::OutputC(const std::string &Bytecode,
201 std::string &OutputCFile) {
202 OutputCFile = getUniqueFilename(Bytecode+".cbe.c");
203 const char *DisArgs[] = {
205 "-o", OutputCFile.c_str(), // Output to the C file
207 "-f", // Overwrite as necessary...
208 Bytecode.c_str(), // This is the input bytecode
212 std::cout << "<cbe>" << std::flush;
213 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
215 // If dis failed on the bytecode, print error...
216 std::cerr << "Error: `llvm-dis -c' failed!\n";
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";
234 int Result = gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile,
235 InputFile, OutputFile, SharedLibs);
236 removeFile(OutputCFile);
241 /// createCBE - Try to find the 'llvm-dis' executable
243 CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath,
244 std::string &Message) {
245 std::string DISPath = FindExecutable("llvm-dis", ProgramPath);
246 if (DISPath.empty()) {
248 "Cannot find `llvm-dis' in executable directory or PATH!\n";
252 Message = "Found llvm-dis: " + DISPath + "\n";
253 GCC *gcc = GCC::create(ProgramPath, Message);
255 std::cerr << Message << "\n";
258 return new CBE(DISPath, gcc);
261 //===---------------------------------------------------------------------===//
264 int GCC::ExecuteProgram(const std::string &ProgramFile,
265 const std::vector<std::string> &Args,
267 const std::string &InputFile,
268 const std::string &OutputFile,
269 const std::vector<std::string> &SharedLibs) {
270 std::vector<const char*> GCCArgs;
272 GCCArgs.push_back(GCCPath.c_str());
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());
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");
284 GCCArgs.push_back("assembler");
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(0); // NULL terminator
294 std::cout << "<gcc>" << std::flush;
295 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
297 ProcessFailure(&GCCArgs[0]);
301 std::vector<const char*> ProgramArgs;
302 ProgramArgs.push_back(OutputBinary.c_str());
303 // Add optional parameters to the running program from Argv
304 for (unsigned i=0, e = Args.size(); i != e; ++i)
305 ProgramArgs.push_back(Args[i].c_str());
306 ProgramArgs.push_back(0); // NULL terminator
308 // Now that we have a binary, run it!
309 std::cout << "<program>" << std::flush;
310 DEBUG(std::cerr << "\nAbout to run:\n\t";
311 for (unsigned i=0, e = ProgramArgs.size(); i != e; ++i)
312 std::cerr << " " << ProgramArgs[i];
315 int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
316 InputFile, OutputFile, OutputFile);
317 removeFile(OutputBinary);
318 return ProgramResult;
321 int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
322 std::string &OutputFile) {
323 OutputFile = getUniqueFilename(InputFile+".so");
324 // Compile the C/asm file into a shared object
325 const char* GCCArgs[] = {
327 "-x", (fileType == AsmFile) ? "assembler" : "c",
328 "-fno-strict-aliasing",
329 InputFile.c_str(), // Specify the input filename...
330 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
331 "-G", // Compile a shared library, `-G' for Sparc
333 "-shared", // `-shared' for Linux/X86, maybe others
335 "-o", OutputFile.c_str(), // Output to the right filename...
336 "-O2", // Optimize the program a bit...
340 std::cout << "<gcc>" << std::flush;
341 if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
343 ProcessFailure(GCCArgs);
349 void GCC::ProcessFailure(const char** GCCArgs) {
350 std::cerr << "\n*** Error: invocation of the C compiler failed!\n";
351 for (const char **Arg = GCCArgs; *Arg; ++Arg)
352 std::cerr << " " << *Arg;
355 // Rerun the compiler, capturing any error messages to print them.
356 std::string ErrorFilename = getUniqueFilename("gcc.errors");
357 RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
358 ErrorFilename.c_str());
360 // Print out the error messages generated by GCC if possible...
361 std::ifstream ErrorFile(ErrorFilename.c_str());
363 std::copy(std::istreambuf_iterator<char>(ErrorFile),
364 std::istreambuf_iterator<char>(),
365 std::ostreambuf_iterator<char>(std::cerr));
370 removeFile(ErrorFilename);
373 /// create - Try to find the `gcc' executable
375 GCC *GCC::create(const std::string &ProgramPath, std::string &Message) {
376 std::string GCCPath = FindExecutable("gcc", ProgramPath);
377 if (GCCPath.empty()) {
378 Message = "Cannot find `gcc' in executable directory or PATH!\n";
382 Message = "Found gcc: " + GCCPath + "\n";
383 return new GCC(GCCPath);