brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · a7e93f6 Raw
256 lines · cpp
1//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This class contains all of the shared state and information that is used by10// the BugPoint tool to track down errors in optimizations.  This class is the11// main driver class that invokes all sub-functionality.12//13//===----------------------------------------------------------------------===//14 15#include "BugDriver.h"16#include "ToolRunner.h"17#include "llvm/IR/Module.h"18#include "llvm/IR/Verifier.h"19#include "llvm/IRReader/IRReader.h"20#include "llvm/Linker/Linker.h"21#include "llvm/Pass.h"22#include "llvm/Support/CommandLine.h"23#include "llvm/Support/FileUtilities.h"24#include "llvm/Support/SourceMgr.h"25#include "llvm/Support/raw_ostream.h"26#include "llvm/TargetParser/Host.h"27#include <memory>28using namespace llvm;29 30Triple llvm::TargetTriple;31 32DiscardTemp::~DiscardTemp() {33  if (SaveTemps) {34    if (Error E = File.keep())35      errs() << "Failed to keep temp file " << toString(std::move(E)) << '\n';36    return;37  }38  if (Error E = File.discard())39    errs() << "Failed to delete temp file " << toString(std::move(E)) << '\n';40}41 42// Output - The user can specify a file containing the expected output of the43// program.  If this filename is set, it is used as the reference diff source,44// otherwise the raw input run through an interpreter is used as the reference45// source.46//47static cl::opt<std::string>48    OutputFile("output", cl::desc("Specify a reference program output "49                                  "(for miscompilation detection)"));50 51/// If we reduce or update the program somehow, call this method to update52/// bugdriver with it.  This deletes the old module and sets the specified one53/// as the current program.54void BugDriver::setNewProgram(std::unique_ptr<Module> M) {55  Program = std::move(M);56}57 58/// getPassesString - Turn a list of passes into a string which indicates the59/// command line options that must be passed to add the passes.60///61std::string llvm::getPassesString(const std::vector<std::string> &Passes) {62  std::string Result;63  for (unsigned i = 0, e = Passes.size(); i != e; ++i) {64    if (i)65      Result += " ";66    Result += "-";67    Result += Passes[i];68  }69  return Result;70}71 72BugDriver::BugDriver(const char *toolname, bool find_bugs, unsigned timeout,73                     unsigned memlimit, bool use_valgrind, LLVMContext &ctxt)74    : Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile),75      Program(nullptr), Interpreter(nullptr), SafeInterpreter(nullptr),76      cc(nullptr), run_find_bugs(find_bugs), Timeout(timeout),77      MemoryLimit(memlimit), UseValgrind(use_valgrind) {}78 79BugDriver::~BugDriver() {80  if (Interpreter != SafeInterpreter)81    delete Interpreter;82  delete SafeInterpreter;83  delete cc;84}85 86std::unique_ptr<Module> llvm::parseInputFile(StringRef Filename,87                                             LLVMContext &Ctxt) {88  SMDiagnostic Err;89  std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);90  if (!Result) {91    Err.print("bugpoint", errs());92    return Result;93  }94 95  if (verifyModule(*Result, &errs())) {96    errs() << "bugpoint: " << Filename << ": error: input module is broken!\n";97    return std::unique_ptr<Module>();98  }99 100  // If we don't have an override triple, use the first one to configure101  // bugpoint, or use the host triple if none provided.102  if (TargetTriple.getTriple().empty()) {103    Triple TheTriple(Result->getTargetTriple());104 105    if (TheTriple.getTriple().empty())106      TheTriple.setTriple(sys::getDefaultTargetTriple());107 108    TargetTriple.setTriple(TheTriple.getTriple());109  }110 111  // override the triple112  Result->setTargetTriple(TargetTriple);113  return Result;114}115 116std::unique_ptr<Module> BugDriver::swapProgramIn(std::unique_ptr<Module> M) {117  std::unique_ptr<Module> OldProgram = std::move(Program);118  Program = std::move(M);119  return OldProgram;120}121 122// This method takes the specified list of LLVM input files, attempts to load123// them, either as assembly or bitcode, then link them together. It returns124// true on failure (if, for example, an input bitcode file could not be125// parsed), and false on success.126//127bool BugDriver::addSources(const std::vector<std::string> &Filenames) {128  assert(!Program && "Cannot call addSources multiple times!");129  assert(!Filenames.empty() && "Must specify at least on input filename!");130 131  // Load the first input file.132  Program = parseInputFile(Filenames[0], Context);133  if (!Program)134    return true;135 136  outs() << "Read input file      : '" << Filenames[0] << "'\n";137 138  for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {139    std::unique_ptr<Module> M = parseInputFile(Filenames[i], Context);140    if (!M)141      return true;142 143    outs() << "Linking in input file: '" << Filenames[i] << "'\n";144    if (Linker::linkModules(*Program, std::move(M)))145      return true;146  }147 148  outs() << "*** All input ok\n";149 150  // All input files read successfully!151  return false;152}153 154/// run - The top level method that is invoked after all of the instance155/// variables are set up from command line arguments.156///157Error BugDriver::run() {158  if (run_find_bugs) {159    // Rearrange the passes and apply them to the program. Repeat this process160    // until the user kills the program or we find a bug.161    return runManyPasses(PassesToRun);162  }163 164  // If we're not running as a child, the first thing that we must do is165  // determine what the problem is. Does the optimization series crash the166  // compiler, or does it produce illegal code?  We make the top-level167  // decision by trying to run all of the passes on the input program,168  // which should generate a bitcode file.  If it does generate a bitcode169  // file, then we know the compiler didn't crash, so try to diagnose a170  // miscompilation.171  if (!PassesToRun.empty()) {172    outs() << "Running selected passes on program to test for crash: ";173    if (runPasses(*Program, PassesToRun))174      return debugOptimizerCrash();175  }176 177  // Set up the execution environment, selecting a method to run LLVM bitcode.178  if (Error E = initializeExecutionEnvironment())179    return E;180 181  // Test to see if we have a code generator crash.182  outs() << "Running the code generator to test for a crash: ";183  if (Error E = compileProgram(*Program)) {184    outs() << toString(std::move(E));185    return debugCodeGeneratorCrash();186  }187  outs() << '\n';188 189  // Run the raw input to see where we are coming from.  If a reference output190  // was specified, make sure that the raw output matches it.  If not, it's a191  // problem in the front-end or the code generator.192  //193  bool CreatedOutput = false;194  if (ReferenceOutputFile.empty()) {195    outs() << "Generating reference output from raw program: ";196    if (Error E = createReferenceFile(*Program)) {197      errs() << toString(std::move(E));198      return debugCodeGeneratorCrash();199    }200    CreatedOutput = true;201  }202 203  // Make sure the reference output file gets deleted on exit from this204  // function, if appropriate.205  std::string ROF(ReferenceOutputFile);206  FileRemover RemoverInstance(ROF, CreatedOutput && !SaveTemps);207 208  // Diff the output of the raw program against the reference output.  If it209  // matches, then we assume there is a miscompilation bug and try to210  // diagnose it.211  outs() << "*** Checking the code generator...\n";212  Expected<bool> Diff = diffProgram(*Program, "", "", false);213  if (Error E = Diff.takeError()) {214    errs() << toString(std::move(E));215    return debugCodeGeneratorCrash();216  }217  if (!*Diff) {218    outs() << "\n*** Output matches: Debugging miscompilation!\n";219    if (Error E = debugMiscompilation()) {220      errs() << toString(std::move(E));221      return debugCodeGeneratorCrash();222    }223    return Error::success();224  }225 226  outs() << "\n*** Input program does not match reference diff!\n";227  outs() << "Debugging code generator problem!\n";228  if (Error E = debugCodeGenerator()) {229    errs() << toString(std::move(E));230    return debugCodeGeneratorCrash();231  }232  return Error::success();233}234 235void llvm::printFunctionList(const std::vector<Function *> &Funcs) {236  unsigned NumPrint = Funcs.size();237  if (NumPrint > 10)238    NumPrint = 10;239  for (unsigned i = 0; i != NumPrint; ++i)240    outs() << " " << Funcs[i]->getName();241  if (NumPrint < Funcs.size())242    outs() << "... <" << Funcs.size() << " total>";243  outs().flush();244}245 246void llvm::printGlobalVariableList(const std::vector<GlobalVariable *> &GVs) {247  unsigned NumPrint = GVs.size();248  if (NumPrint > 10)249    NumPrint = 10;250  for (unsigned i = 0; i != NumPrint; ++i)251    outs() << " " << GVs[i]->getName();252  if (NumPrint < GVs.size())253    outs() << "... <" << GVs.size() << " total>";254  outs().flush();255}256