BugDriver.cpp revision fa76183e8e28985dfd17b1d6291c939dab4cbe1d
1//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file was developed by the LLVM research group and is distributed under 6// the University of Illinois Open Source License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This class contains all of the shared state and information that is used by 11// the BugPoint tool to track down errors in optimizations. This class is the 12// main driver class that invokes all sub-functionality. 13// 14//===----------------------------------------------------------------------===// 15 16#include "BugDriver.h" 17#include "llvm/Module.h" 18#include "llvm/Pass.h" 19#include "llvm/Assembly/Parser.h" 20#include "llvm/Bytecode/Reader.h" 21#include "llvm/Transforms/Utils/Linker.h" 22#include "Support/CommandLine.h" 23#include "Support/FileUtilities.h" 24#include <memory> 25using namespace llvm; 26 27// Anonymous namespace to define command line options for debugging. 28// 29namespace { 30 // Output - The user can specify a file containing the expected output of the 31 // program. If this filename is set, it is used as the reference diff source, 32 // otherwise the raw input run through an interpreter is used as the reference 33 // source. 34 // 35 cl::opt<std::string> 36 OutputFile("output", cl::desc("Specify a reference program output " 37 "(for miscompilation detection)")); 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 llvm::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 llvm::DeleteFunctionBody(Function *F) { 57 // delete the body of the function... 58 F->deleteBody(); 59 assert(F->isExternal() && "This didn't make the function external!"); 60} 61 62BugDriver::BugDriver(const char *toolname) 63 : ToolName(toolname), ReferenceOutputFile(OutputFile), 64 Program(0), Interpreter(0), cbe(0), gcc(0) {} 65 66 67/// ParseInputFile - Given a bytecode or assembly input filename, parse and 68/// return it, or return null if not possible. 69/// 70Module *BugDriver::ParseInputFile(const std::string &InputFilename) const { 71 Module *Result = 0; 72 try { 73 Result = ParseBytecodeFile(InputFilename); 74 if (!Result && !(Result = ParseAssemblyFile(InputFilename))){ 75 std::cerr << ToolName << ": could not read input file '" 76 << InputFilename << "'!\n"; 77 } 78 } catch (const ParseException &E) { 79 std::cerr << ToolName << ": " << E.getMessage() << "\n"; 80 Result = 0; 81 } 82 return Result; 83} 84 85// This method takes the specified list of LLVM input files, attempts to load 86// them, either as assembly or bytecode, then link them together. It returns 87// true on failure (if, for example, an input bytecode file could not be 88// parsed), and false on success. 89// 90bool BugDriver::addSources(const std::vector<std::string> &Filenames) { 91 assert(Program == 0 && "Cannot call addSources multiple times!"); 92 assert(!Filenames.empty() && "Must specify at least on input filename!"); 93 94 // Load the first input file... 95 Program = ParseInputFile(Filenames[0]); 96 if (Program == 0) return true; 97 std::cout << "Read input file : '" << Filenames[0] << "'\n"; 98 99 for (unsigned i = 1, e = Filenames.size(); i != e; ++i) { 100 std::auto_ptr<Module> M(ParseInputFile(Filenames[i])); 101 if (M.get() == 0) return true; 102 103 std::cout << "Linking in input file: '" << Filenames[i] << "'\n"; 104 std::string ErrorMessage; 105 if (LinkModules(Program, M.get(), &ErrorMessage)) { 106 std::cerr << ToolName << ": error linking in '" << Filenames[i] << "': " 107 << ErrorMessage << "\n"; 108 return true; 109 } 110 } 111 112 std::cout << "*** All input ok\n"; 113 114 // All input files read successfully! 115 return false; 116} 117 118 119 120/// run - The top level method that is invoked after all of the instance 121/// variables are set up from command line arguments. 122/// 123bool BugDriver::run() { 124 // The first thing that we must do is determine what the problem is. Does the 125 // optimization series crash the compiler, or does it produce illegal code? We 126 // make the top-level decision by trying to run all of the passes on the the 127 // input program, which should generate a bytecode file. If it does generate 128 // a bytecode file, then we know the compiler didn't crash, so try to diagnose 129 // a miscompilation. 130 // 131 if (!PassesToRun.empty()) { 132 std::cout << "Running selected passes on program to test for crash: "; 133 if (runPasses(PassesToRun)) 134 return debugCrash(); 135 } 136 137 // Set up the execution environment, selecting a method to run LLVM bytecode. 138 if (initializeExecutionEnvironment()) return true; 139 140 // Run the raw input to see where we are coming from. If a reference output 141 // was specified, make sure that the raw output matches it. If not, it's a 142 // problem in the front-end or the code generator. 143 // 144 bool CreatedOutput = false; 145 if (ReferenceOutputFile.empty()) { 146 std::cout << "Generating reference output from raw program..."; 147 ReferenceOutputFile = executeProgramWithCBE("bugpoint.reference.out"); 148 CreatedOutput = true; 149 std::cout << "Reference output is: " << ReferenceOutputFile << "\n"; 150 } 151 152 // Make sure the reference output file gets deleted on exit from this 153 // function, if appropriate. 154 struct Remover { 155 bool DeleteIt; const std::string &Filename; 156 Remover(bool deleteIt, const std::string &filename) 157 : DeleteIt(deleteIt), Filename(filename) {} 158 ~Remover() { 159 if (DeleteIt) removeFile(Filename); 160 } 161 } RemoverInstance(CreatedOutput, ReferenceOutputFile); 162 163 // Diff the output of the raw program against the reference output. If it 164 // matches, then we have a miscompilation bug. 165 std::cout << "*** Checking the code generator...\n"; 166 if (!diffProgram()) { 167 std::cout << "\n*** Debugging miscompilation!\n"; 168 return debugMiscompilation(); 169 } 170 171 std::cout << "\n*** Input program does not match reference diff!\n"; 172 std::cout << "Debugging code generator problem!\n"; 173 return debugCodeGenerator(); 174} 175 176void BugDriver::PrintFunctionList(const std::vector<Function*> &Funcs) { 177 for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { 178 if (i) std::cout << ", "; 179 std::cout << Funcs[i]->getName(); 180 } 181 std::cout << std::flush; 182} 183 184