Path: blob/main/contrib/llvm-project/llvm/tools/bugpoint/BugDriver.cpp
35231 views
//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This class contains all of the shared state and information that is used by9// the BugPoint tool to track down errors in optimizations. This class is the10// main driver class that invokes all sub-functionality.11//12//===----------------------------------------------------------------------===//1314#include "BugDriver.h"15#include "ToolRunner.h"16#include "llvm/IR/Module.h"17#include "llvm/IR/Verifier.h"18#include "llvm/IRReader/IRReader.h"19#include "llvm/Linker/Linker.h"20#include "llvm/Pass.h"21#include "llvm/Support/CommandLine.h"22#include "llvm/Support/FileUtilities.h"23#include "llvm/Support/SourceMgr.h"24#include "llvm/Support/raw_ostream.h"25#include "llvm/TargetParser/Host.h"26#include <memory>27using namespace llvm;2829namespace llvm {30Triple TargetTriple;31}3233DiscardTemp::~DiscardTemp() {34if (SaveTemps) {35if (Error E = File.keep())36errs() << "Failed to keep temp file " << toString(std::move(E)) << '\n';37return;38}39if (Error E = File.discard())40errs() << "Failed to delete temp file " << toString(std::move(E)) << '\n';41}4243// Anonymous namespace to define command line options for debugging.44//45namespace {46// Output - The user can specify a file containing the expected output of the47// program. If this filename is set, it is used as the reference diff source,48// otherwise the raw input run through an interpreter is used as the reference49// source.50//51cl::opt<std::string> OutputFile("output",52cl::desc("Specify a reference program output "53"(for miscompilation detection)"));54}5556/// If we reduce or update the program somehow, call this method to update57/// bugdriver with it. This deletes the old module and sets the specified one58/// as the current program.59void BugDriver::setNewProgram(std::unique_ptr<Module> M) {60Program = std::move(M);61}6263/// getPassesString - Turn a list of passes into a string which indicates the64/// command line options that must be passed to add the passes.65///66std::string llvm::getPassesString(const std::vector<std::string> &Passes) {67std::string Result;68for (unsigned i = 0, e = Passes.size(); i != e; ++i) {69if (i)70Result += " ";71Result += "-";72Result += Passes[i];73}74return Result;75}7677BugDriver::BugDriver(const char *toolname, bool find_bugs, unsigned timeout,78unsigned memlimit, bool use_valgrind, LLVMContext &ctxt)79: Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile),80Program(nullptr), Interpreter(nullptr), SafeInterpreter(nullptr),81cc(nullptr), run_find_bugs(find_bugs), Timeout(timeout),82MemoryLimit(memlimit), UseValgrind(use_valgrind) {}8384BugDriver::~BugDriver() {85if (Interpreter != SafeInterpreter)86delete Interpreter;87delete SafeInterpreter;88delete cc;89}9091std::unique_ptr<Module> llvm::parseInputFile(StringRef Filename,92LLVMContext &Ctxt) {93SMDiagnostic Err;94std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);95if (!Result) {96Err.print("bugpoint", errs());97return Result;98}99100if (verifyModule(*Result, &errs())) {101errs() << "bugpoint: " << Filename << ": error: input module is broken!\n";102return std::unique_ptr<Module>();103}104105// If we don't have an override triple, use the first one to configure106// bugpoint, or use the host triple if none provided.107if (TargetTriple.getTriple().empty()) {108Triple TheTriple(Result->getTargetTriple());109110if (TheTriple.getTriple().empty())111TheTriple.setTriple(sys::getDefaultTargetTriple());112113TargetTriple.setTriple(TheTriple.getTriple());114}115116Result->setTargetTriple(TargetTriple.getTriple()); // override the triple117return Result;118}119120std::unique_ptr<Module> BugDriver::swapProgramIn(std::unique_ptr<Module> M) {121std::unique_ptr<Module> OldProgram = std::move(Program);122Program = std::move(M);123return OldProgram;124}125126// This method takes the specified list of LLVM input files, attempts to load127// them, either as assembly or bitcode, then link them together. It returns128// true on failure (if, for example, an input bitcode file could not be129// parsed), and false on success.130//131bool BugDriver::addSources(const std::vector<std::string> &Filenames) {132assert(!Program && "Cannot call addSources multiple times!");133assert(!Filenames.empty() && "Must specify at least on input filename!");134135// Load the first input file.136Program = parseInputFile(Filenames[0], Context);137if (!Program)138return true;139140outs() << "Read input file : '" << Filenames[0] << "'\n";141142for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {143std::unique_ptr<Module> M = parseInputFile(Filenames[i], Context);144if (!M)145return true;146147outs() << "Linking in input file: '" << Filenames[i] << "'\n";148if (Linker::linkModules(*Program, std::move(M)))149return true;150}151152outs() << "*** All input ok\n";153154// All input files read successfully!155return false;156}157158/// run - The top level method that is invoked after all of the instance159/// variables are set up from command line arguments.160///161Error BugDriver::run() {162if (run_find_bugs) {163// Rearrange the passes and apply them to the program. Repeat this process164// until the user kills the program or we find a bug.165return runManyPasses(PassesToRun);166}167168// If we're not running as a child, the first thing that we must do is169// determine what the problem is. Does the optimization series crash the170// compiler, or does it produce illegal code? We make the top-level171// decision by trying to run all of the passes on the input program,172// which should generate a bitcode file. If it does generate a bitcode173// file, then we know the compiler didn't crash, so try to diagnose a174// miscompilation.175if (!PassesToRun.empty()) {176outs() << "Running selected passes on program to test for crash: ";177if (runPasses(*Program, PassesToRun))178return debugOptimizerCrash();179}180181// Set up the execution environment, selecting a method to run LLVM bitcode.182if (Error E = initializeExecutionEnvironment())183return E;184185// Test to see if we have a code generator crash.186outs() << "Running the code generator to test for a crash: ";187if (Error E = compileProgram(*Program)) {188outs() << toString(std::move(E));189return debugCodeGeneratorCrash();190}191outs() << '\n';192193// Run the raw input to see where we are coming from. If a reference output194// was specified, make sure that the raw output matches it. If not, it's a195// problem in the front-end or the code generator.196//197bool CreatedOutput = false;198if (ReferenceOutputFile.empty()) {199outs() << "Generating reference output from raw program: ";200if (Error E = createReferenceFile(*Program)) {201errs() << toString(std::move(E));202return debugCodeGeneratorCrash();203}204CreatedOutput = true;205}206207// Make sure the reference output file gets deleted on exit from this208// function, if appropriate.209std::string ROF(ReferenceOutputFile);210FileRemover RemoverInstance(ROF, CreatedOutput && !SaveTemps);211212// Diff the output of the raw program against the reference output. If it213// matches, then we assume there is a miscompilation bug and try to214// diagnose it.215outs() << "*** Checking the code generator...\n";216Expected<bool> Diff = diffProgram(*Program, "", "", false);217if (Error E = Diff.takeError()) {218errs() << toString(std::move(E));219return debugCodeGeneratorCrash();220}221if (!*Diff) {222outs() << "\n*** Output matches: Debugging miscompilation!\n";223if (Error E = debugMiscompilation()) {224errs() << toString(std::move(E));225return debugCodeGeneratorCrash();226}227return Error::success();228}229230outs() << "\n*** Input program does not match reference diff!\n";231outs() << "Debugging code generator problem!\n";232if (Error E = debugCodeGenerator()) {233errs() << toString(std::move(E));234return debugCodeGeneratorCrash();235}236return Error::success();237}238239void llvm::PrintFunctionList(const std::vector<Function *> &Funcs) {240unsigned NumPrint = Funcs.size();241if (NumPrint > 10)242NumPrint = 10;243for (unsigned i = 0; i != NumPrint; ++i)244outs() << " " << Funcs[i]->getName();245if (NumPrint < Funcs.size())246outs() << "... <" << Funcs.size() << " total>";247outs().flush();248}249250void llvm::PrintGlobalVariableList(const std::vector<GlobalVariable *> &GVs) {251unsigned NumPrint = GVs.size();252if (NumPrint > 10)253NumPrint = 10;254for (unsigned i = 0; i != NumPrint; ++i)255outs() << " " << GVs[i]->getName();256if (NumPrint < GVs.size())257outs() << "... <" << GVs.size() << " total>";258outs().flush();259}260261262