Implement support for bugpoint to identify which FUNCTION an optimization
[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   cl::opt<std::string>
39   InputFile("input", cl::init("/dev/null"),
40             cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
41 }
42
43 /// AbstractInterpreter Class - Subclasses of this class are used to execute
44 /// LLVM bytecode in a variety of ways.  This abstract interface hides this
45 /// complexity behind a simple interface.
46 ///
47 struct AbstractInterpreter {
48
49   virtual ~AbstractInterpreter() {}
50
51   /// ExecuteProgram - Run the specified bytecode file, emitting output to the
52   /// specified filename.  This returns the exit code of the program.
53   ///
54   virtual int ExecuteProgram(const std::string &Bytecode,
55                              const std::string &OutputFile) = 0;
56
57 };
58
59
60 //===----------------------------------------------------------------------===//
61 // LLI Implementation of AbstractIntepreter interface
62 //
63 class LLI : public AbstractInterpreter {
64   std::string LLIPath;          // The path to the LLI executable
65 public:
66   LLI(const std::string &Path) : LLIPath(Path) { }
67
68   // LLI create method - Try to find the LLI executable
69   static LLI *create(BugDriver *BD, std::string &Message) {
70     std::string LLIPath = FindExecutable("lli", BD->getToolName());
71     if (!LLIPath.empty()) {
72       Message = "Found lli: " + LLIPath + "\n";
73       return new LLI(LLIPath);
74     }
75
76     Message = "Cannot find 'lli' in bugpoint executable directory or PATH!\n";
77     return 0;
78   }
79   virtual int ExecuteProgram(const std::string &Bytecode,
80                              const std::string &OutputFile);
81 };
82
83 int LLI::ExecuteProgram(const std::string &Bytecode,
84                         const std::string &OutputFile) {
85   const char *Args[] = {
86     "-abort-on-exception",
87     "-quiet",
88     Bytecode.c_str(),
89     0
90   };
91   
92   return RunProgramWithTimeout(LLIPath, Args,
93                                InputFile, OutputFile, OutputFile);
94 }
95
96
97 //===----------------------------------------------------------------------===//
98 // BugDriver method implementation
99 //
100
101 /// initializeExecutionEnvironment - This method is used to set up the
102 /// environment for executing LLVM programs.
103 ///
104 bool BugDriver::initializeExecutionEnvironment() {
105   std::cout << "Initializing execution environment: ";
106
107   // FIXME: This should default to searching for the best interpreter to use on
108   // this platform, which would be JIT, then LLC, then CBE, then LLI.
109
110   // Create an instance of the AbstractInterpreter interface as specified on the
111   // command line
112   std::string Message;
113   if (InterpreterSel == RunLLI) {
114     Interpreter = LLI::create(this, Message);
115   } else {
116     Message = " Sorry, only LLI is supported right now!";
117   }
118
119   std::cout << Message;
120
121   // If there was an error creating the selected interpreter, quit with error.
122   return Interpreter == 0;
123 }
124
125
126 /// executeProgram - This method runs "Program", capturing the output of the
127 /// program to a file, returning the filename of the file.  A recommended
128 /// filename may be optionally specified.
129 ///
130 std::string BugDriver::executeProgram(std::string OutputFile,
131                                       std::string BytecodeFile) {
132   assert(Interpreter && "Interpreter should have been created already!");
133   bool CreatedBytecode = false;
134   if (BytecodeFile.empty()) {
135     // Emit the program to a bytecode file...
136     BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
137
138     if (writeProgramToFile(BytecodeFile, Program)) {
139       std::cerr << ToolName << ": Error emitting bytecode to file '"
140                 << BytecodeFile << "'!\n";
141       exit(1);
142     }
143     CreatedBytecode = true;
144   }
145
146   if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
147   
148   // Check to see if this is a valid output filename...
149   OutputFile = getUniqueFilename(OutputFile);
150
151   // Actually execute the program!
152   int RetVal = Interpreter->ExecuteProgram(BytecodeFile, OutputFile);
153
154   // Remove the temporary bytecode file.
155   if (CreatedBytecode)
156     removeFile(BytecodeFile);
157
158   // Return the filename we captured the output to.
159   return OutputFile;
160 }
161
162 /// diffProgram - This method executes the specified module and diffs the output
163 /// against the file specified by ReferenceOutputFile.  If the output is
164 /// different, true is returned.
165 ///
166 bool BugDriver::diffProgram(const std::string &ReferenceOutputFile,
167                             const std::string &BytecodeFile,
168                             bool RemoveBytecode) {
169   // Execute the program, generating an output file...
170   std::string Output = executeProgram("", BytecodeFile);
171
172   std::ifstream ReferenceFile(ReferenceOutputFile.c_str());
173   if (!ReferenceFile) {
174     std::cerr << "Couldn't open reference output file '"
175               << ReferenceOutputFile << "'\n";
176     exit(1);
177   }
178
179   std::ifstream OutputFile(Output.c_str());
180   if (!OutputFile) {
181     std::cerr << "Couldn't open output file: " << Output << "'!\n";
182     exit(1);
183   }
184
185   bool FilesDifferent = false;
186
187   // Compare the two files...
188   int C1, C2;
189   do {
190     C1 = ReferenceFile.get();
191     C2 = OutputFile.get();
192     if (C1 != C2) { FilesDifferent = true; break; }
193   } while (C1 != EOF);
194
195   removeFile(Output);
196   if (RemoveBytecode) removeFile(BytecodeFile);
197   return FilesDifferent;
198 }