diff options
Diffstat (limited to 'contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp | 163 | 
1 files changed, 138 insertions, 25 deletions
diff --git a/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp index aab9debf9b59..aa88a06a6df0 100644 --- a/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp +++ b/contrib/llvm-project/llvm/tools/bugpoint/CrashDebugger.cpp @@ -16,11 +16,11 @@  #include "llvm/ADT/SmallPtrSet.h"  #include "llvm/ADT/StringSet.h"  #include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Transforms/Utils/Local.h"  #include "llvm/IR/CFG.h"  #include "llvm/IR/Constants.h"  #include "llvm/IR/DebugInfo.h"  #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/InstIterator.h"  #include "llvm/IR/Instructions.h"  #include "llvm/IR/LegacyPassManager.h"  #include "llvm/IR/Module.h" @@ -32,6 +32,7 @@  #include "llvm/Transforms/Scalar.h"  #include "llvm/Transforms/Utils/BasicBlockUtils.h"  #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/Local.h"  #include <set>  using namespace llvm; @@ -43,6 +44,10 @@ cl::opt<bool> NoGlobalRM("disable-global-remove",                           cl::desc("Do not remove global variables"),                           cl::init(false)); +cl::opt<bool> NoAttributeRM("disable-attribute-remove", +                         cl::desc("Do not remove function attributes"), +                         cl::init(false)); +  cl::opt<bool> ReplaceFuncsWithNull(      "replace-funcs-with-null",      cl::desc("When stubbing functions, replace all uses will null"), @@ -359,6 +364,11 @@ bool ReduceCrashingFunctionAttributes::TestFuncAttrs(    // Set this new list of attributes on the function.    F->setAttributes(NewAttrs); +  // If the attribute list includes "optnone" we need to make sure it also +  // includes "noinline" otherwise we will get a verifier failure. +  if (F->hasFnAttribute(Attribute::OptimizeNone)) +    F->addFnAttr(Attribute::NoInline); +    // Try running on the hacked up program...    if (TestFn(BD, M.get())) {      BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... @@ -806,6 +816,78 @@ bool ReduceCrashingInstructions::TestInsts(  }  namespace { +/// ReduceCrashingMetadata reducer - This works by removing all metadata from +/// the specified instructions. +/// +class ReduceCrashingMetadata : public ListReducer<Instruction *> { +  BugDriver &BD; +  BugTester TestFn; + +public: +  ReduceCrashingMetadata(BugDriver &bd, BugTester testFn) +      : BD(bd), TestFn(testFn) {} + +  Expected<TestResult> doTest(std::vector<Instruction *> &Prefix, +                              std::vector<Instruction *> &Kept) override { +    if (!Kept.empty() && TestInsts(Kept)) +      return KeepSuffix; +    if (!Prefix.empty() && TestInsts(Prefix)) +      return KeepPrefix; +    return NoFailure; +  } + +  bool TestInsts(std::vector<Instruction *> &Prefix); +}; +} // namespace + +bool ReduceCrashingMetadata::TestInsts(std::vector<Instruction *> &Insts) { +  // Clone the program to try hacking it apart... +  ValueToValueMapTy VMap; +  std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap); + +  // Convert list to set for fast lookup... +  SmallPtrSet<Instruction *, 32> Instructions; +  for (Instruction *I : Insts) +    Instructions.insert(cast<Instruction>(VMap[I])); + +  outs() << "Checking for crash with metadata retained from " +         << Instructions.size(); +  if (Instructions.size() == 1) +    outs() << " instruction: "; +  else +    outs() << " instructions: "; + +  // Try to drop instruction metadata from all instructions, except the ones +  // selected in Instructions. +  for (Function &F : *M) +    for (Instruction &Inst : instructions(F)) { +      if (Instructions.find(&Inst) == Instructions.end()) { +        Inst.dropUnknownNonDebugMetadata(); +        Inst.setDebugLoc({}); +      } +    } + +  // Verify that this is still valid. +  legacy::PassManager Passes; +  Passes.add(createVerifierPass(/*FatalErrors=*/false)); +  Passes.run(*M); + +  // Try running on the hacked up program... +  if (TestFn(BD, M.get())) { +    BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... + +    // Make sure to use instruction pointers that point into the now-current +    // module, and that they don't include any deleted blocks. +    Insts.clear(); +    for (Instruction *I : Instructions) +      Insts.push_back(I); +    return true; +  } +  // It didn't crash, try something else. +  return false; +} + +namespace {  // Reduce the list of Named Metadata nodes. We keep this as a list of  // names to avoid having to convert back and forth every time.  class ReduceCrashingNamedMD : public ListReducer<std::string> { @@ -1081,6 +1163,21 @@ static Error ReduceInsts(BugDriver &BD, BugTester TestFn) {      }    } while (Simplification); + +  // Attempt to drop metadata from instructions that does not contribute to the +  // crash. +  if (!BugpointIsInterrupted) { +    std::vector<Instruction *> Insts; +    for (Function &F : BD.getProgram()) +      for (Instruction &I : instructions(F)) +        Insts.push_back(&I); + +    Expected<bool> Result = +        ReduceCrashingMetadata(BD, TestFn).reduceList(Insts); +    if (Error E = Result.takeError()) +      return E; +  } +    BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");    return Error::success();  } @@ -1115,36 +1212,38 @@ static Error DebugACrash(BugDriver &BD, BugTester TestFn) {        BD.EmitProgressBitcode(BD.getProgram(), "reduced-function");    } -  // For each remaining function, try to reduce that function's attributes. -  std::vector<std::string> FunctionNames; -  for (Function &F : BD.getProgram()) -    FunctionNames.push_back(F.getName()); +  if (!NoAttributeRM) { +    // For each remaining function, try to reduce that function's attributes. +    std::vector<std::string> FunctionNames; +    for (Function &F : BD.getProgram()) +      FunctionNames.push_back(F.getName()); -  if (!FunctionNames.empty() && !BugpointIsInterrupted) { -    outs() << "\n*** Attempting to reduce the number of function attributes in " -              "the testcase\n"; +    if (!FunctionNames.empty() && !BugpointIsInterrupted) { +      outs() << "\n*** Attempting to reduce the number of function attributes" +                " in the testcase\n"; -    unsigned OldSize = 0; -    unsigned NewSize = 0; -    for (std::string &Name : FunctionNames) { -      Function *Fn = BD.getProgram().getFunction(Name); -      assert(Fn && "Could not find funcion?"); +      unsigned OldSize = 0; +      unsigned NewSize = 0; +      for (std::string &Name : FunctionNames) { +        Function *Fn = BD.getProgram().getFunction(Name); +        assert(Fn && "Could not find funcion?"); -      std::vector<Attribute> Attrs; -      for (Attribute A : Fn->getAttributes().getFnAttributes()) -        Attrs.push_back(A); +        std::vector<Attribute> Attrs; +        for (Attribute A : Fn->getAttributes().getFnAttributes()) +          Attrs.push_back(A); -      OldSize += Attrs.size(); -      Expected<bool> Result = +        OldSize += Attrs.size(); +        Expected<bool> Result =            ReduceCrashingFunctionAttributes(BD, Name, TestFn).reduceList(Attrs); -      if (Error E = Result.takeError()) -        return E; +        if (Error E = Result.takeError()) +          return E; -      NewSize += Attrs.size(); -    } +        NewSize += Attrs.size(); +      } -    if (OldSize < NewSize) -      BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes"); +      if (OldSize < NewSize) +        BD.EmitProgressBitcode(BD.getProgram(), "reduced-function-attributes"); +    }    }    // Attempt to change conditional branches into unconditional branches to @@ -1289,7 +1388,21 @@ Error BugDriver::debugOptimizerCrash(const std::string &ID) {    EmitProgressBitcode(*Program, ID); -  return DebugACrash(*this, TestForOptimizerCrash); +  auto Res = DebugACrash(*this, TestForOptimizerCrash); +  if (Res || DontReducePassList) +    return Res; +  // Try to reduce the pass list again. This covers additional cases +  // we failed to reduce earlier, because of more complex pass dependencies +  // triggering the crash. +  auto SecondRes = ReducePassList(*this).reduceList(PassesToRun); +  if (Error E = SecondRes.takeError()) +    return E; +  outs() << "\n*** Found crashing pass" +         << (PassesToRun.size() == 1 ? ": " : "es: ") +         << getPassesString(PassesToRun) << '\n'; + +  EmitProgressBitcode(getProgram(), "reduced-simplified"); +  return Res;  }  static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) {  | 
