diff options
Diffstat (limited to 'tools/bugpoint/CrashDebugger.cpp')
-rw-r--r-- | tools/bugpoint/CrashDebugger.cpp | 153 |
1 files changed, 88 insertions, 65 deletions
diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index 6cdc43ab8699..b25e6ecec19b 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -54,6 +54,9 @@ namespace { cl::opt<bool> NoNamedMDRM("disable-namedmd-remove", cl::desc("Do not remove global named metadata"), cl::init(false)); + cl::opt<bool> VerboseErrors("verbose-errors", + cl::desc("Print the output of crashing program"), + cl::init(false)); } namespace llvm { @@ -164,6 +167,7 @@ ReduceCrashingGlobalVariables::TestGlobalVariables( if (I.hasInitializer() && !GVSet.count(&I)) { DeleteGlobalInitializer(&I); I.setLinkage(GlobalValue::ExternalLinkage); + I.setComdat(nullptr); } // Try running the hacked up program... @@ -264,8 +268,8 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { std::vector<GlobalValue*> ToRemove; // First, remove aliases to functions we're about to purge. for (GlobalAlias &Alias : M->aliases()) { - Constant *Root = Alias.getAliasee()->stripPointerCasts(); - Function *F = dyn_cast<Function>(Root); + GlobalObject *Root = Alias.getBaseObject(); + Function *F = dyn_cast_or_null<Function>(Root); if (F) { if (Functions.count(F)) // We're keeping this function. @@ -373,9 +377,9 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { (*SI)->removePredecessor(&*BB); TerminatorInst *BBTerm = BB->getTerminator(); - if (BBTerm->isEHPad()) + if (BBTerm->isEHPad() || BBTerm->getType()->isTokenTy()) continue; - if (!BBTerm->getType()->isVoidTy() && !BBTerm->getType()->isTokenTy()) + if (!BBTerm->getType()->isVoidTy()) BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType())); // Replace the old terminator instruction. @@ -459,7 +463,7 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> Module *M = CloneModule(BD.getProgram(), VMap).release(); // Convert list to set for fast lookup... - SmallPtrSet<Instruction*, 64> Instructions; + SmallPtrSet<Instruction*, 32> Instructions; for (unsigned i = 0, e = Insts.size(); i != e; ++i) { assert(!isa<TerminatorInst>(Insts[i])); Instructions.insert(cast<Instruction>(VMap[Insts[i]])); @@ -476,8 +480,8 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) { Instruction *Inst = &*I++; if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst) && - !Inst->isEHPad()) { - if (!Inst->getType()->isVoidTy() && !Inst->getType()->isTokenTy()) + !Inst->isEHPad() && !Inst->getType()->isTokenTy()) { + if (!Inst->getType()->isVoidTy()) Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); Inst->eraseFromParent(); } @@ -552,7 +556,9 @@ bool ReduceCrashingNamedMD::TestNamedMDs(std::vector<std::string> &NamedMDs) { std::vector<NamedMDNode *> ToDelete; ToDelete.reserve(M->named_metadata_size() - Names.size()); for (auto &NamedMD : M->named_metadata()) - if (!Names.count(NamedMD.getName())) + // Always keep a nonempty llvm.dbg.cu because the Verifier would complain. + if (!Names.count(NamedMD.getName()) && + (!(NamedMD.getName() == "llvm.dbg.cu" && NamedMD.getNumOperands() > 0))) ToDelete.push_back(&NamedMD); for (auto *NamedMD : ToDelete) @@ -600,7 +606,7 @@ public: bool ReduceCrashingNamedMDOps::TestNamedMDOps( std::vector<const MDNode *> &NamedMDOps) { // Convert list to set for fast lookup... - SmallPtrSet<const MDNode *, 64> OldMDNodeOps; + SmallPtrSet<const MDNode *, 32> OldMDNodeOps; for (unsigned i = 0, e = NamedMDOps.size(); i != e; ++i) { OldMDNodeOps.insert(NamedMDOps[i]); } @@ -637,7 +643,7 @@ bool ReduceCrashingNamedMDOps::TestNamedMDOps( // module, and that they don't include any deleted blocks. NamedMDOps.clear(); for (const MDNode *Node : OldMDNodeOps) - NamedMDOps.push_back(cast<MDNode>(VMap.MD()[Node].get())); + NamedMDOps.push_back(cast<MDNode>(*VMap.getMappedMD(Node))); BD.setNewProgram(M); // It crashed, keep the trimmed version... return true; @@ -646,16 +652,10 @@ bool ReduceCrashingNamedMDOps::TestNamedMDOps( return false; } -/// DebugACrash - Given a predicate that determines whether a component crashes -/// on a program, try to destructively reduce the program while still keeping -/// the predicate true. -static bool DebugACrash(BugDriver &BD, - bool (*TestFn)(const BugDriver &, Module *), - std::string &Error) { - // See if we can get away with nuking some of the global variable initializers - // in the program... - if (!NoGlobalRM && - BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { +static void ReduceGlobalInitializers(BugDriver &BD, + bool (*TestFn)(const BugDriver &, Module *), + std::string &Error) { + if (BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { // Now try to reduce the number of global variable initializers in the // module to something small. Module *M = CloneModule(BD.getProgram()).release(); @@ -666,6 +666,7 @@ static bool DebugACrash(BugDriver &BD, if (I->hasInitializer()) { DeleteGlobalInitializer(&*I); I->setLinkage(GlobalValue::ExternalLinkage); + I->setComdat(nullptr); DeletedInit = true; } @@ -695,8 +696,7 @@ static bool DebugACrash(BugDriver &BD, unsigned OldSize = GVs.size(); ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error); - if (!Error.empty()) - return true; + assert(!Error.empty()); if (GVs.size() < OldSize) BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables"); @@ -704,40 +704,11 @@ static bool DebugACrash(BugDriver &BD, } } } +} - // Now try to reduce the number of functions in the module to something small. - std::vector<Function*> Functions; - for (Function &F : *BD.getProgram()) - if (!F.isDeclaration()) - Functions.push_back(&F); - - if (Functions.size() > 1 && !BugpointIsInterrupted) { - outs() << "\n*** Attempting to reduce the number of functions " - "in the testcase\n"; - - unsigned OldSize = Functions.size(); - ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error); - - if (Functions.size() < OldSize) - BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); - } - - // Attempt to delete entire basic blocks at a time to speed up - // convergence... this actually works by setting the terminator of the blocks - // to a return instruction then running simplifycfg, which can potentially - // shrinks the code dramatically quickly - // - if (!DisableSimplifyCFG && !BugpointIsInterrupted) { - std::vector<const BasicBlock*> Blocks; - for (Function &F : *BD.getProgram()) - for (BasicBlock &BB : F) - Blocks.push_back(&BB); - unsigned OldSize = Blocks.size(); - ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); - if (Blocks.size() < OldSize) - BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks"); - } - +static void ReduceInsts(BugDriver &BD, + bool (*TestFn)(const BugDriver &, Module *), + std::string &Error) { // 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) { @@ -751,11 +722,10 @@ static bool DebugACrash(BugDriver &BD, ReduceCrashingInstructions(BD, TestFn).reduceList(Insts, Error); } - // FIXME: This should use the list reducer to converge faster by deleting - // larger chunks of instructions at a time! unsigned Simplification = 2; do { - if (BugpointIsInterrupted) break; + if (BugpointIsInterrupted) + return; --Simplification; outs() << "\n*** Attempting to reduce testcase by deleting instruc" << "tions: Simplification Level #" << Simplification << '\n'; @@ -784,7 +754,8 @@ static bool DebugACrash(BugDriver &BD, if (InstructionsToSkipBeforeDeleting) { --InstructionsToSkipBeforeDeleting; } else { - if (BugpointIsInterrupted) goto ExitLoops; + if (BugpointIsInterrupted) + return; if (I->isEHPad() || I->getType()->isTokenTy()) continue; @@ -810,10 +781,60 @@ static bool DebugACrash(BugDriver &BD, } } while (Simplification); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions"); +} - if (!NoNamedMDRM) { - BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions"); +/// DebugACrash - Given a predicate that determines whether a component crashes +/// on a program, try to destructively reduce the program while still keeping +/// the predicate true. +static bool DebugACrash(BugDriver &BD, + bool (*TestFn)(const BugDriver &, Module *), + std::string &Error) { + // See if we can get away with nuking some of the global variable initializers + // in the program... + if (!NoGlobalRM) + ReduceGlobalInitializers(BD, TestFn, Error); + + // Now try to reduce the number of functions in the module to something small. + std::vector<Function*> Functions; + for (Function &F : *BD.getProgram()) + if (!F.isDeclaration()) + Functions.push_back(&F); + + if (Functions.size() > 1 && !BugpointIsInterrupted) { + outs() << "\n*** Attempting to reduce the number of functions " + "in the testcase\n"; + + unsigned OldSize = Functions.size(); + ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error); + + if (Functions.size() < OldSize) + BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); + } + + // Attempt to delete entire basic blocks at a time to speed up + // convergence... this actually works by setting the terminator of the blocks + // to a return instruction then running simplifycfg, which can potentially + // shrinks the code dramatically quickly + // + if (!DisableSimplifyCFG && !BugpointIsInterrupted) { + std::vector<const BasicBlock*> Blocks; + for (Function &F : *BD.getProgram()) + for (BasicBlock &BB : F) + Blocks.push_back(&BB); + unsigned OldSize = Blocks.size(); + ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); + if (Blocks.size() < OldSize) + BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks"); + } + + // 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) + ReduceInsts(BD, TestFn, Error); + + if (!NoNamedMDRM) { if (!BugpointIsInterrupted) { // Try to reduce the amount of global metadata (particularly debug info), // by dropping global named metadata that anchors them @@ -833,10 +854,9 @@ static bool DebugACrash(BugDriver &BD, NamedMDOps.push_back(op); ReduceCrashingNamedMDOps(BD, TestFn).reduceList(NamedMDOps, Error); } + BD.EmitProgressBitcode(BD.getProgram(), "reduced-named-md"); } -ExitLoops: - // Try to clean up the testcase by running funcresolve and globaldce... if (!BugpointIsInterrupted) { outs() << "\n*** Attempting to perform final cleanups: "; @@ -857,7 +877,7 @@ ExitLoops: } static bool TestForOptimizerCrash(const BugDriver &BD, Module *M) { - return BD.runPasses(M); + return BD.runPasses(M, BD.getPassesToRun()); } /// debugOptimizerCrash - This method is called when some pass crashes on input. @@ -888,7 +908,10 @@ static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) { std::string Error; BD.compileProgram(M, &Error); if (!Error.empty()) { - errs() << "<crash>\n"; + if (VerboseErrors) + errs() << Error << "\n"; + else + errs() << "<crash>\n"; return true; // Tool is still crashing. } errs() << '\n'; |