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 } 193