Fix compilation on GCC 3.2
[oota-llvm.git] / tools / bugpoint / ExecutionDriver.cpp
1 //===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
2 //
3 // This file contains code used to execute the program utilizing one of the
4 // various ways of running LLVM bytecode.
5 //
6 //===----------------------------------------------------------------------===//
7
8 /*
9 BUGPOINT NOTES:
10
11 1. Bugpoint should not leave any files behind if the program works properly
12 2. There should be an option to specify the program name, which specifies a
13    unique string to put into output files.  This allows operation in the
14    SingleSource directory f.e.  Default to the first input filename.
15 */
16
17 #include "BugDriver.h"
18 #include "SystemUtils.h"
19 #include "Support/CommandLine.h"
20 #include <fstream>
21 #include <iostream>
22
23 namespace {
24   // OutputType - Allow the user to specify the way code should be run, to test
25   // for miscompilation.
26   //
27   enum OutputType {
28     RunLLI, RunJIT, RunLLC, RunCBE
29   };
30   cl::opt<OutputType>
31   InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
32                  cl::values(clEnumValN(RunLLI, "run-lli", "Execute with LLI"),
33                             clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
34                             clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
35                             clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
36                             0));
37 }
38
39 /// AbstractInterpreter Class - Subclasses of this class are used to execute
40 /// LLVM bytecode in a variety of ways.  This abstract interface hides this
41 /// complexity behind a simple interface.
42 ///
43 struct AbstractInterpreter {
44
45   virtual ~AbstractInterpreter() {}
46
47   /// ExecuteProgram - Run the specified bytecode file, emitting output to the
48   /// specified filename.  This returns the exit code of the program.
49   ///
50   virtual int ExecuteProgram(const std::string &Bytecode,
51                              const std::string &OutputFile) = 0;
52
53 };
54
55
56 //===----------------------------------------------------------------------===//
57 // LLI Implementation of AbstractIntepreter interface
58 //
59 class LLI : public AbstractInterpreter {
60   std::string LLIPath;          // The path to the LLI executable
61 public:
62   LLI(const std::string &Path) : LLIPath(Path) { }
63
64   // LLI create method - Try to find the LLI executable
65   static LLI *create(BugDriver *BD, std::string &Message) {
66     std::string LLIPath = FindExecutable("lli", BD->getToolName());
67     if (!LLIPath.empty()) {
68       Message = "Found lli: " + LLIPath + "\n";
69       return new LLI(LLIPath);
70     }
71
72     Message = "Cannot find 'lli' in bugpoint executable directory or PATH!\n";
73     return 0;
74   }
75   virtual int ExecuteProgram(const std::string &Bytecode,
76                              const std::string &OutputFile);
77 };
78
79 int LLI::ExecuteProgram(const std::string &Bytecode,
80                         const std::string &OutputFile) {
81   const char *Args[] = {
82     "-abort-on-exception",
83     "-quiet",
84     Bytecode.c_str(),
85     0
86   };
87   
88   return RunProgramWithTimeout(LLIPath, Args,
89                                "/dev/null", OutputFile, OutputFile);
90 }
91
92
93 //===----------------------------------------------------------------------===//
94 // BugDriver method implementation
95 //
96
97 /// initializeExecutionEnvironment - This method is used to set up the
98 /// environment for executing LLVM programs.
99 ///
100 bool BugDriver::initializeExecutionEnvironment() {
101   std::cout << "Initializing execution environment: ";
102
103   // FIXME: This should default to searching for the best interpreter to use on
104   // this platform, which would be JIT, then LLC, then CBE, then LLI.
105
106   // Create an instance of the AbstractInterpreter interface as specified on the
107   // command line
108   std::string Message;
109   if (InterpreterSel == RunLLI) {
110     Interpreter = LLI::create(this, Message);
111   } else {
112     Message = " Sorry, only LLI is supported right now!";
113   }
114
115   std::cout << Message;
116
117   // If there was an error creating the selected interpreter, quit with error.
118   return Interpreter == 0;
119 }
120
121
122 /// executeProgram - This method runs "Program", capturing the output of the
123 /// program to a file, returning the filename of the file.  A recommended
124 /// filename may be optionally specified.
125 ///
126 std::string BugDriver::executeProgram(std::string OutputFile,
127                                       std::string BytecodeFile) {
128   assert(Interpreter && "Interpreter should have been created already!");
129   bool CreatedBytecode = false;
130   if (BytecodeFile.empty()) {
131     // Emit the program to a bytecode file...
132     BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
133
134     if (writeProgramToFile(BytecodeFile, Program)) {
135       std::cerr << ToolName << ": Error emitting bytecode to file '"
136                 << BytecodeFile << "'!\n";
137       exit(1);
138     }
139     CreatedBytecode = true;
140   }
141
142   if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
143   
144   // Check to see if this is a valid output filename...
145   OutputFile = getUniqueFilename(OutputFile);
146
147   // Actually execute the program!
148   int RetVal = Interpreter->ExecuteProgram(BytecodeFile, OutputFile);
149
150   // Remove the temporary bytecode file.
151   if (CreatedBytecode)
152     removeFile(BytecodeFile);
153
154   // Return the filename we captured the output to.
155   return OutputFile;
156 }
157
158 /// diffProgram - This method executes the specified module and diffs the output
159 /// against the file specified by ReferenceOutputFile.  If the output is
160 /// different, true is returned.
161 ///
162 bool BugDriver::diffProgram(const std::string &ReferenceOutputFile,
163                             const std::string &BytecodeFile) {
164   // Execute the program, generating an output file...
165   std::string Output = executeProgram("", BytecodeFile);
166
167   std::ifstream ReferenceFile(ReferenceOutputFile.c_str());
168   if (!ReferenceFile) {
169     std::cerr << "Couldn't open reference output file '"
170               << ReferenceOutputFile << "'\n";
171     exit(1);
172   }
173
174   std::ifstream OutputFile(Output.c_str());
175   if (!OutputFile) {
176     std::cerr << "Couldn't open output file: " << Output << "'!\n";
177     exit(1);
178   }
179
180   bool FilesDifferent = false;
181
182   // Compare the two files...
183   int C1, C2;
184   do {
185     C1 = ReferenceFile.get();
186     C2 = OutputFile.get();
187     if (C1 != C2) { FilesDifferent = true; break; }
188   } while (C1 != EOF);
189
190   removeFile(Output);
191   return FilesDifferent;
192 }