Example #1
0
static Error ReduceInsts(BugDriver &BD,
                        bool (*TestFn)(const BugDriver &, Module *)) {
  // Attempt to delete instructions using bisection. This should help out nasty
  // cases with large basic blocks where the problem is at one end.
  if (!BugpointIsInterrupted) {
    std::vector<const Instruction *> Insts;
    for (const Function &F : *BD.getProgram())
      for (const BasicBlock &BB : F)
        for (const Instruction &I : BB)
          if (!isa<TerminatorInst>(&I))
            Insts.push_back(&I);

    Expected<bool> Result =
        ReduceCrashingInstructions(BD, TestFn).reduceList(Insts);
    if (Error E = Result.takeError())
      return E;
  }

  unsigned Simplification = 2;
  do {
    if (BugpointIsInterrupted)
      // TODO: Should we distinguish this with an "interrupted error"?
      return Error::success();
    --Simplification;
    outs() << "\n*** Attempting to reduce testcase by deleting instruc"
           << "tions: Simplification Level #" << Simplification << '\n';

    // Now that we have deleted the functions that are unnecessary for the
    // program, try to remove instructions that are not necessary to cause the
    // crash.  To do this, we loop through all of the instructions in the
    // remaining functions, deleting them (replacing any values produced with
    // nulls), and then running ADCE and SimplifyCFG.  If the transformed input
    // still triggers failure, keep deleting until we cannot trigger failure
    // anymore.
    //
    unsigned InstructionsToSkipBeforeDeleting = 0;
  TryAgain:

    // Loop over all of the (non-terminator) instructions remaining in the
    // function, attempting to delete them.
    unsigned CurInstructionNum = 0;
    for (Module::const_iterator FI = BD.getProgram()->begin(),
                                E = BD.getProgram()->end();
         FI != E; ++FI)
      if (!FI->isDeclaration())
        for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E;
             ++BI)
          for (BasicBlock::const_iterator I = BI->begin(), E = --BI->end();
               I != E; ++I, ++CurInstructionNum) {
            if (InstructionsToSkipBeforeDeleting) {
              --InstructionsToSkipBeforeDeleting;
            } else {
              if (BugpointIsInterrupted)
                // TODO: Should this be some kind of interrupted error?
                return Error::success();

              if (I->isEHPad() || I->getType()->isTokenTy() ||
                  I->isSwiftError())
                continue;

              outs() << "Checking instruction: " << *I;
              std::unique_ptr<Module> M =
                  BD.deleteInstructionFromProgram(&*I, Simplification);

              // Find out if the pass still crashes on this pass...
              if (TestFn(BD, M.get())) {
                // Yup, it does, we delete the old module, and continue trying
                // to reduce the testcase...
                BD.setNewProgram(M.release());
                InstructionsToSkipBeforeDeleting = CurInstructionNum;
                goto TryAgain; // I wish I had a multi-level break here!
              }
            }
          }

    if (InstructionsToSkipBeforeDeleting) {
      InstructionsToSkipBeforeDeleting = 0;
      goto TryAgain;
    }

  } while (Simplification);
  BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");
  return Error::success();
}