Skip to content

Commit 271ca40

Browse files
committedJul 27, 2016
Make bugpoint transform conditional jumps into unconditional jumps.
Summary: Add a pass to bugpoint to make it transform conditional jumps into unconditional jumps. Often, bugpoint generates output that has large numbers of br undef jumps, where one side is dead. What is happening is two fold: 1. It never tries to just pick a direction for the jump, and just see what happens <<<< this patch 2. SimplifyCFG no longer is a good match for bugpoint's usecase. It does too much. Even things in SimplifyCFG, like removeUnreachableBlocks, go to great lengths to transform undefined behavior into blocks and kill large parts of the CFG. This is great for regular code, not so much for bugpoint, which often generates UB on purpose (store undef is a great example). <<<< a followup patch that is coming, to move simplifycfg into a separate reduction pass, and move the existing reduceCrashingBlocks pass to use simpleSimplifyCFG. Both of these patches significantly reduce the size and complexity of bugpoint generated testcases. Reviewers: chandlerc, majnemer Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D22841 llvm-svn: 276884
1 parent 46cb48c commit 271ca40

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed
 

‎llvm/tools/bugpoint/CrashDebugger.cpp

+168
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
#include "llvm/Support/CommandLine.h"
2929
#include "llvm/Support/FileUtilities.h"
3030
#include "llvm/Transforms/Scalar.h"
31+
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
3132
#include "llvm/Transforms/Utils/Cloning.h"
33+
#include "llvm/Transforms/Utils/Local.h"
3234
#include <set>
3335
using namespace llvm;
3436

@@ -430,6 +432,158 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) {
430432
return false;
431433
}
432434

435+
namespace {
436+
/// Simplify the CFG without completely destroying it.
437+
/// This is not well defined, but basically comes down to "try to eliminate
438+
/// unreachable blocks and constant fold terminators without deciding that
439+
/// certain undefined behavior cuts off the program at the legs".
440+
void simpleSimplifyCfg(Function &F, SmallVectorImpl<BasicBlock *> &BBs) {
441+
if (F.empty())
442+
return;
443+
444+
for (auto *BB : BBs) {
445+
ConstantFoldTerminator(BB);
446+
MergeBlockIntoPredecessor(BB);
447+
}
448+
449+
// Remove unreachable blocks
450+
// removeUnreachableBlocks can't be used here, it will turn various
451+
// undefined behavior into unreachables, but bugpoint was the thing that
452+
// generated the undefined behavior, and we don't want it to kill the entire
453+
// program.
454+
SmallPtrSet<BasicBlock *, 16> Visited;
455+
for (auto *BB : depth_first(&F.getEntryBlock()))
456+
Visited.insert(BB);
457+
458+
SmallVector<BasicBlock *, 16> Unreachable;
459+
for (auto &BB : F)
460+
if (!Visited.count(&BB))
461+
Unreachable.push_back(&BB);
462+
463+
// The dead BB's may be in a dead cycle or otherwise have references to each
464+
// other. Because of this, we have to drop all references first, then delete
465+
// them all at once.
466+
for (auto *BB : Unreachable) {
467+
for (BasicBlock *Successor : successors(&*BB))
468+
if (Visited.count(Successor))
469+
Successor->removePredecessor(&*BB);
470+
BB->dropAllReferences();
471+
}
472+
for (auto *BB : Unreachable)
473+
BB->eraseFromParent();
474+
}
475+
476+
/// ReduceCrashingConditionals reducer - This works by changing
477+
/// conditional branches to unconditional ones, then simplifying the CFG
478+
/// This has the effect of chopping up the CFG really fast which can reduce
479+
/// large functions quickly.
480+
///
481+
class ReduceCrashingConditionals : public ListReducer<const BasicBlock *> {
482+
BugDriver &BD;
483+
bool (*TestFn)(const BugDriver &, Module *);
484+
bool Direction;
485+
486+
public:
487+
ReduceCrashingConditionals(BugDriver &bd,
488+
bool (*testFn)(const BugDriver &, Module *),
489+
bool Direction)
490+
: BD(bd), TestFn(testFn), Direction(Direction) {}
491+
492+
TestResult doTest(std::vector<const BasicBlock *> &Prefix,
493+
std::vector<const BasicBlock *> &Kept,
494+
std::string &Error) override {
495+
if (!Kept.empty() && TestBlocks(Kept))
496+
return KeepSuffix;
497+
if (!Prefix.empty() && TestBlocks(Prefix))
498+
return KeepPrefix;
499+
return NoFailure;
500+
}
501+
502+
bool TestBlocks(std::vector<const BasicBlock *> &Prefix);
503+
};
504+
}
505+
506+
bool ReduceCrashingConditionals::TestBlocks(
507+
std::vector<const BasicBlock *> &BBs) {
508+
// Clone the program to try hacking it apart...
509+
ValueToValueMapTy VMap;
510+
Module *M = CloneModule(BD.getProgram(), VMap).release();
511+
512+
// Convert list to set for fast lookup...
513+
SmallPtrSet<const BasicBlock *, 8> Blocks;
514+
for (const auto *BB: BBs)
515+
Blocks.insert(cast<BasicBlock>(VMap[BB]));
516+
517+
outs() << "Checking for crash with changing conditionals to always jump to "
518+
<< (Direction ? "true" : "false") << ":";
519+
unsigned NumPrint = Blocks.size();
520+
if (NumPrint > 10)
521+
NumPrint = 10;
522+
for (unsigned i = 0, e = NumPrint; i != e; ++i)
523+
outs() << " " << BBs[i]->getName();
524+
if (NumPrint < Blocks.size())
525+
outs() << "... <" << Blocks.size() << " total>";
526+
outs() << ": ";
527+
528+
// Loop over and delete any hack up any blocks that are not listed...
529+
for (auto &F: *M)
530+
for (auto &BB : F)
531+
if (!Blocks.count(&BB)) {
532+
auto *BR = dyn_cast<BranchInst>(BB.getTerminator());
533+
if (!BR || !BR->isConditional())
534+
continue;
535+
if (Direction)
536+
BR->setCondition(ConstantInt::getTrue(BR->getContext()));
537+
else
538+
BR->setCondition(ConstantInt::getFalse(BR->getContext()));
539+
}
540+
541+
// The following may destroy some blocks, so we save them first
542+
std::vector<std::pair<std::string, std::string>> BlockInfo;
543+
544+
for (const BasicBlock *BB : Blocks)
545+
BlockInfo.emplace_back(BB->getParent()->getName(), BB->getName());
546+
547+
SmallVector<BasicBlock *, 16> ToProcess;
548+
for (auto &F :*M) {
549+
for (auto &BB : F)
550+
if (!Blocks.count(&BB))
551+
ToProcess.push_back(&BB);
552+
simpleSimplifyCfg(F, ToProcess);
553+
ToProcess.clear();
554+
}
555+
// Verify we didn't break anything
556+
std::vector<std::string> Passes;
557+
Passes.push_back("verify");
558+
std::unique_ptr<Module> New = BD.runPassesOn(M, Passes);
559+
delete M;
560+
if (!New) {
561+
errs() << "verify failed!\n";
562+
exit(1);
563+
}
564+
M = New.release();
565+
566+
// Try running on the hacked up program...
567+
if (TestFn(BD, M)) {
568+
BD.setNewProgram(M); // It crashed, keep the trimmed version...
569+
570+
// Make sure to use basic block pointers that point into the now-current
571+
// module, and that they don't include any deleted blocks.
572+
BBs.clear();
573+
const ValueSymbolTable &GST = M->getValueSymbolTable();
574+
for (auto &BI : BlockInfo) {
575+
auto *F = cast<Function>(GST.lookup(BI.first));
576+
ValueSymbolTable &ST = F->getValueSymbolTable();
577+
Value *V = ST.lookup(BI.second);
578+
if (V && V->getType() == Type::getLabelTy(V->getContext()))
579+
BBs.push_back(cast<BasicBlock>(V));
580+
}
581+
return true;
582+
}
583+
delete M; // It didn't crash, try something else.
584+
return false;
585+
}
586+
433587
namespace {
434588
/// ReduceCrashingInstructions reducer - This works by removing the specified
435589
/// non-terminator instructions and replacing them with undef.
@@ -813,6 +967,20 @@ static bool DebugACrash(BugDriver &BD,
813967
BD.EmitProgressBitcode(BD.getProgram(), "reduced-function");
814968
}
815969

970+
// Attempt to change conditional branches into unconditional branches to
971+
// eliminate blocks.
972+
if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
973+
std::vector<const BasicBlock*> Blocks;
974+
for (Function &F : *BD.getProgram())
975+
for (BasicBlock &BB : F)
976+
Blocks.push_back(&BB);
977+
unsigned OldSize = Blocks.size();
978+
ReduceCrashingConditionals(BD, TestFn, true).reduceList(Blocks, Error);
979+
ReduceCrashingConditionals(BD, TestFn, false).reduceList(Blocks, Error);
980+
if (Blocks.size() < OldSize)
981+
BD.EmitProgressBitcode(BD.getProgram(), "reduced-conditionals");
982+
}
983+
816984
// Attempt to delete entire basic blocks at a time to speed up
817985
// convergence... this actually works by setting the terminator of the blocks
818986
// to a return instruction then running simplifycfg, which can potentially

0 commit comments

Comments
 (0)
Please sign in to comment.