DestBB->moveAfter(PredBB);
if (DT) {
- BasicBlock *PredBBIDom = DT->getNode(PredBB)->getIDom()->getBlock();
- DT->changeImmediateDominator(DestBB, PredBBIDom);
- DT->eraseNode(PredBB);
+ // For some irreducible CFG we end up having forward-unreachable blocks
+ // so check if getNode returns a valid node before updating the domtree.
+ if (DomTreeNode *DTN = DT->getNode(PredBB)) {
+ BasicBlock *PredBBIDom = DTN->getIDom()->getBlock();
+ DT->changeImmediateDominator(DestBB, PredBBIDom);
+ DT->eraseNode(PredBB);
+ }
}
// Nuke BB.
PredBB->eraseFromParent();
Declares++;
EXPECT_EQ(2, Declares);
}
+
+/// Build the dominator tree for the function and run the Test.
+static void runWithDomTree(
+ Module &M, StringRef FuncName,
+ function_ref<void(Function &F, DominatorTree *DT)> Test) {
+ auto *F = M.getFunction(FuncName);
+ ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
+ // Compute the dominator tree for the function.
+ DominatorTree DT(*F);
+ Test(*F, &DT);
+}
+
+TEST(Local, MergeBasicBlockIntoOnlyPred) {
+ LLVMContext C;
+
+ std::unique_ptr<Module> M = parseIR(
+ C,
+ "define i32 @f(i8* %str) {\n"
+ "entry:\n"
+ " br label %bb2.i\n"
+ "bb2.i: ; preds = %bb4.i, %entry\n"
+ " br i1 false, label %bb4.i, label %base2flt.exit204\n"
+ "bb4.i: ; preds = %bb2.i\n"
+ " br i1 false, label %base2flt.exit204, label %bb2.i\n"
+ "bb10.i196.bb7.i197_crit_edge: ; No predecessors!\n"
+ " br label %bb7.i197\n"
+ "bb7.i197: ; preds = %bb10.i196.bb7.i197_crit_edge\n"
+ " %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ]\n"
+ " br i1 undef, label %base2flt.exit204, label %base2flt.exit204\n"
+ "base2flt.exit204: ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i\n"
+ " ret i32 0\n"
+ "}\n");
+ runWithDomTree(
+ *M, "f", [&](Function &F, DominatorTree *DT) {
+ for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
+ BasicBlock *BB = &*I++;
+ BasicBlock *SinglePred = BB->getSinglePredecessor();
+ if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue;
+ BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
+ if (Term && !Term->isConditional())
+ MergeBasicBlockIntoOnlyPred(BB, DT);
+ }
+ EXPECT_TRUE(DT->verify());
+ });
+}