ExecutionDriver.cpp revision a0f5b15e1eb8642d92b3141a6b88a5729ea979dc
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===// 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// This file contains code used to execute the program utilizing one of the 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// various ways of running LLVM bytecode. 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// 6a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com//===----------------------------------------------------------------------===// 7a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 8a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com/* 9a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.comBUGPOINT NOTES: 10a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 11a0b40280a49a8a43af7929ead3b3489951c58501commit-bot@chromium.org1. Bugpoint should not leave any files behind if the program works properly 12a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com2. There should be an option to specify the program name, which specifies a 13a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com unique string to put into output files. This allows operation in the 14a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com SingleSource directory, e.g. default to the first input filename. 15a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com*/ 16a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 17a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "BugDriver.h" 18a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "Support/CommandLine.h" 19a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "Support/Debug.h" 20a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "Support/FileUtilities.h" 21a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "Support/SystemUtils.h" 22a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include "llvm/Support/ToolRunner.h" 23a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include <fstream> 24a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com#include <iostream> 25a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 26a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comnamespace { 27a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com // OutputType - Allow the user to specify the way code should be run, to test 28a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com // for miscompilation. 29a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com // 30a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com enum OutputType { 31a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com RunLLI, RunJIT, RunLLC, RunCBE 32a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com }; 33a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 34a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com cl::opt<OutputType> 35a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com InterpreterSel(cl::desc("Specify how LLVM code should be executed:"), 36a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com cl::values(clEnumValN(RunLLI, "run-lli", "Execute with LLI"), 37a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com clEnumValN(RunJIT, "run-jit", "Execute with JIT"), 38e3beb6bd7de7fa211681abbb0be58e80b19885e0commit-bot@chromium.org clEnumValN(RunLLC, "run-llc", "Compile with LLC"), 39a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com clEnumValN(RunCBE, "run-cbe", "Compile with CBE"), 40a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 0)); 41d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 42a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com cl::opt<std::string> 43a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com InputFile("input", cl::init("/dev/null"), 44a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com cl::desc("Filename to pipe in as stdin (default: /dev/null)")); 45a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com} 46a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 47a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com// Anything specified after the --args option are taken as arguments to the 48d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com// program being debugged. 49a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comcl::list<std::string> 50a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.comInputArgv("args", cl::Positional, cl::desc("<program arguments>..."), 51a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com cl::ZeroOrMore); 52a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 53a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com//===----------------------------------------------------------------------===// 54d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com// BugDriver method implementation 55a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com// 56a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com 57a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com/// initializeExecutionEnvironment - This method is used to set up the 58a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com/// environment for executing LLVM programs. 59a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com/// 60a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.combool BugDriver::initializeExecutionEnvironment() { 61a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com std::cout << "Initializing execution environment: "; 62a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 63a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com // FIXME: This should default to searching for the best interpreter to use on 64a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com // this platform, which would be JIT, then LLC, then CBE, then LLI. 65a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com 66a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com // Create an instance of the AbstractInterpreter interface as specified on 67a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com // the command line 6883747252b811c9f76bfec3c8ea4b48e30e46dd7fagl@chromium.org std::string Message; 69 switch (InterpreterSel) { 70 case RunLLI: Interpreter = createLLItool(getToolName(), Message); break; 71 case RunLLC: Interpreter = createLLCtool(getToolName(), Message); break; 72 case RunJIT: Interpreter = createJITtool(getToolName(), Message); break; 73 case RunCBE: Interpreter = createCBEtool(getToolName(), Message); break; 74 default: 75 Message = "Sorry, this back-end is not supported by bugpoint right now!\n"; 76 break; 77 } 78 std::cerr << Message; 79 80 // Initialize auxiliary tools for debugging 81 cbe = createCBEtool(getToolName(), Message); 82 if (!cbe) { std::cout << Message << "\nExiting.\n"; exit(1); } 83 gcc = createGCCtool(getToolName(), Message); 84 if (!gcc) { std::cout << Message << "\nExiting.\n"; exit(1); } 85 86 // If there was an error creating the selected interpreter, quit with error. 87 return Interpreter == 0; 88} 89 90 91/// executeProgram - This method runs "Program", capturing the output of the 92/// program to a file, returning the filename of the file. A recommended 93/// filename may be optionally specified. 94/// 95std::string BugDriver::executeProgram(std::string OutputFile, 96 std::string BytecodeFile, 97 std::string SharedObject, 98 AbstractInterpreter *AI) { 99 assert((Interpreter||AI) && "Interpreter should have been created already!"); 100 bool CreatedBytecode = false; 101 if (BytecodeFile.empty()) { 102 // Emit the program to a bytecode file... 103 BytecodeFile = getUniqueFilename("bugpoint-test-program.bc"); 104 105 if (writeProgramToFile(BytecodeFile, Program)) { 106 std::cerr << ToolName << ": Error emitting bytecode to file '" 107 << BytecodeFile << "'!\n"; 108 exit(1); 109 } 110 CreatedBytecode = true; 111 } 112 113 if (OutputFile.empty()) OutputFile = "bugpoint-execution-output"; 114 115 // Check to see if this is a valid output filename... 116 OutputFile = getUniqueFilename(OutputFile); 117 118 // Actually execute the program! 119 int RetVal = (AI != 0) ? 120 AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile, OutputFile, 121 SharedObject) : 122 Interpreter->ExecuteProgram(BytecodeFile, InputArgv, 123 InputFile, OutputFile, SharedObject); 124 125 // Remove the temporary bytecode file. 126 if (CreatedBytecode) removeFile(BytecodeFile); 127 128 // Return the filename we captured the output to. 129 return OutputFile; 130} 131 132std::string BugDriver::executeProgramWithCBE(std::string OutputFile, 133 std::string BytecodeFile, 134 std::string SharedObject) { 135 return executeProgram(OutputFile, BytecodeFile, SharedObject, cbe); 136} 137 138std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) { 139 assert(Interpreter && "Interpreter should have been created already!"); 140 std::string OutputCFile; 141 142 // Using CBE 143 cbe->OutputC(BytecodeFile, OutputCFile); 144 145#if 0 /* This is an alternative, as yet unimplemented */ 146 // Using LLC 147 std::string Message; 148 LLC *llc = createLLCtool(Message); 149 if (llc->OutputAsm(BytecodeFile, OutputFile)) { 150 std::cerr << "Could not generate asm code with `llc', exiting.\n"; 151 exit(1); 152 } 153#endif 154 155 std::string SharedObjectFile; 156 if (gcc->MakeSharedObject(OutputCFile, CFile, SharedObject)) 157 exit(1); 158 159 // Remove the intermediate C file 160 removeFile(OutputCFile); 161 162 return SharedObjectFile; 163} 164 165 166/// diffProgram - This method executes the specified module and diffs the output 167/// against the file specified by ReferenceOutputFile. If the output is 168/// different, true is returned. 169/// 170bool BugDriver::diffProgram(const std::string &BytecodeFile, 171 const std::string &SharedObject, 172 bool RemoveBytecode) { 173 // Execute the program, generating an output file... 174 std::string Output = executeProgram("", BytecodeFile, SharedObject); 175 176 std::string Error; 177 bool FilesDifferent = false; 178 if (DiffFiles(ReferenceOutputFile, Output, &Error)) { 179 if (!Error.empty()) { 180 std::cerr << "While diffing output: " << Error << "\n"; 181 exit(1); 182 } 183 FilesDifferent = true; 184 } 185 186 if (RemoveBytecode) removeFile(BytecodeFile); 187 return FilesDifferent; 188} 189 190bool BugDriver::isExecutingJIT() { 191 return InterpreterSel == RunJIT; 192} 193