BugDriver.cpp revision 0bd75bb92d25591b89f5dee08fb343709d792d5b
1//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===// 2// 3// This class contains all of the shared state and information that is used by 4// the BugPoint tool to track down errors in optimizations. This class is the 5// main driver class that invokes all sub-functionality. 6// 7//===----------------------------------------------------------------------===// 8 9#include "BugDriver.h" 10#include "Support/SystemUtils.h" 11#include "llvm/Module.h" 12#include "llvm/Bytecode/Reader.h" 13#include "llvm/Assembly/Parser.h" 14#include "llvm/Transforms/Utils/Linker.h" 15#include "llvm/Pass.h" 16#include "Support/CommandLine.h" 17#include <memory> 18 19// Anonymous namespace to define command line options for debugging. 20// 21namespace { 22 // Output - The user can specify a file containing the expected output of the 23 // program. If this filename is set, it is used as the reference diff source, 24 // otherwise the raw input run through an interpreter is used as the reference 25 // source. 26 // 27 cl::opt<std::string> 28 OutputFile("output", cl::desc("Specify a reference program output " 29 "(for miscompilation detection)")); 30 31 enum DebugType { DebugCompile, DebugCodegen }; 32 cl::opt<DebugType> 33 DebugMode("mode", cl::desc("Debug mode for bugpoint:"), cl::Prefix, 34 cl::values(clEnumValN(DebugCompile, "compile", " Compilation"), 35 clEnumValN(DebugCodegen, "codegen", " Code generation"), 36 0), 37 cl::init(DebugCompile)); 38} 39 40/// getPassesString - Turn a list of passes into a string which indicates the 41/// command line options that must be passed to add the passes. 42/// 43std::string getPassesString(const std::vector<const PassInfo*> &Passes) { 44 std::string Result; 45 for (unsigned i = 0, e = Passes.size(); i != e; ++i) { 46 if (i) Result += " "; 47 Result += "-"; 48 Result += Passes[i]->getPassArgument(); 49 } 50 return Result; 51} 52 53// DeleteFunctionBody - "Remove" the function by deleting all of its basic 54// blocks, making it external. 55// 56void DeleteFunctionBody(Function *F) { 57 // First, break circular use/def chain references... 58 for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) 59 I->dropAllReferences(); 60 61 // Next, delete all of the basic blocks. 62 F->getBasicBlockList().clear(); 63 F->setLinkage(GlobalValue::ExternalLinkage); 64 assert(F->isExternal() && "This didn't make the function external!"); 65} 66 67BugDriver::BugDriver(const char *toolname) 68 : ToolName(toolname), ReferenceOutputFile(OutputFile), 69 Program(0), Interpreter(0), cbe(0), gcc(0) {} 70 71 72/// ParseInputFile - Given a bytecode or assembly input filename, parse and 73/// return it, or return null if not possible. 74/// 75Module *BugDriver::ParseInputFile(const std::string &InputFilename) const { 76 Module *Result = 0; 77 try { 78 Result = ParseBytecodeFile(InputFilename); 79 if (!Result && !(Result = ParseAssemblyFile(InputFilename))){ 80 std::cerr << ToolName << ": could not read input file '" 81 << InputFilename << "'!\n"; 82 } 83 } catch (const ParseException &E) { 84 std::cerr << ToolName << ": " << E.getMessage() << "\n"; 85 Result = 0; 86 } 87 return Result; 88} 89 90// This method takes the specified list of LLVM input files, attempts to load 91// them, either as assembly or bytecode, then link them together. It returns 92// true on failure (if, for example, an input bytecode file could not be 93// parsed), and false on success. 94// 95bool BugDriver::addSources(const std::vector<std::string> &Filenames) { 96 assert(Program == 0 && "Cannot call addSources multiple times!"); 97 assert(!Filenames.empty() && "Must specify at least on input filename!"); 98 99 // Load the first input file... 100 Program = ParseInputFile(Filenames[0]); 101 if (Program == 0) return true; 102 std::cout << "Read input file : '" << Filenames[0] << "'\n"; 103 104 for (unsigned i = 1, e = Filenames.size(); i != e; ++i) { 105 std::auto_ptr<Module> M(ParseInputFile(Filenames[i])); 106 if (M.get() == 0) return true; 107 108 std::cout << "Linking in input file: '" << Filenames[i] << "'\n"; 109 std::string ErrorMessage; 110 if (LinkModules(Program, M.get(), &ErrorMessage)) { 111 std::cerr << ToolName << ": error linking in '" << Filenames[i] << "': " 112 << ErrorMessage << "\n"; 113 return true; 114 } 115 } 116 117 std::cout << "*** All input ok\n"; 118 119 // All input files read successfully! 120 return false; 121} 122 123 124 125/// run - The top level method that is invoked after all of the instance 126/// variables are set up from command line arguments. 127/// 128bool BugDriver::run() { 129 // The first thing that we must do is determine what the problem is. Does the 130 // optimization series crash the compiler, or does it produce illegal code? We 131 // make the top-level decision by trying to run all of the passes on the the 132 // input program, which should generate a bytecode file. If it does generate 133 // a bytecode file, then we know the compiler didn't crash, so try to diagnose 134 // a miscompilation. 135 // 136 std::cout << "Running selected passes on program to test for crash: "; 137 if (runPasses(PassesToRun)) 138 return debugCrash(); 139 140 std::cout << "Checking for a miscompilation...\n"; 141 142 // Set up the execution environment, selecting a method to run LLVM bytecode. 143 if (initializeExecutionEnvironment()) return true; 144 145 // Run the raw input to see where we are coming from. If a reference output 146 // was specified, make sure that the raw output matches it. If not, it's a 147 // problem in the front-end or the code generator. 148 // 149 bool CreatedOutput = false, Result; 150 if (ReferenceOutputFile.empty()) { 151 std::cout << "Generating reference output from raw program..."; 152 if (DebugCodegen) { 153 ReferenceOutputFile = executeProgramWithCBE("bugpoint.reference.out"); 154 } else { 155 ReferenceOutputFile = executeProgram("bugpoint.reference.out"); 156 } 157 CreatedOutput = true; 158 std::cout << "Reference output is: " << ReferenceOutputFile << "\n"; 159 } 160 161 if (DebugMode == DebugCompile) { 162 std::cout << "\n*** Debugging miscompilation!\n"; 163 Result = debugMiscompilation(); 164 } else if (DebugMode == DebugCodegen) { 165 std::cout << "Debugging code generator problem!\n"; 166 Result = debugCodeGenerator(); 167 } 168 169 if (CreatedOutput) removeFile(ReferenceOutputFile); 170 return Result; 171} 172 173void BugDriver::PrintFunctionList(const std::vector<Function*> &Funcs) 174{ 175 for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { 176 if (i) std::cout << ", "; 177 std::cout << Funcs[i]->getName(); 178 } 179} 180