Skip to content

Commit

Permalink
[SimplifyCFG] Teach mergeEmptyReturnBlocks() to preserve DomTree
Browse files Browse the repository at this point in the history
A first real transformation that didn't already knew how to do that,
but it's pretty tame - either change successor of all the predecessors
of a block and carefully delay deletion of the block until afterwards
the DomTree updates are appled, or add a successor to the block.

There wasn't a great test coverage for this, so i added extra, to be sure.
  • Loading branch information
LebedevRI committed Dec 16, 2020
1 parent 5cce4af commit d22a47e
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 5 deletions.
27 changes: 24 additions & 3 deletions llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,12 @@ STATISTIC(NumSimpl, "Number of blocks simplified");

/// If we have more than one empty (other than phi node) return blocks,
/// merge them together to promote recursive block merging.
static bool mergeEmptyReturnBlocks(Function &F) {
static bool mergeEmptyReturnBlocks(Function &F, DomTreeUpdater *DTU) {
bool Changed = false;

std::vector<DominatorTree::UpdateType> Updates;
SmallVector<BasicBlock *, 8> DeadBlocks;

BasicBlock *RetBlock = nullptr;

// Scan all the blocks in the function, looking for empty return blocks.
Expand Down Expand Up @@ -135,8 +138,15 @@ static bool mergeEmptyReturnBlocks(Function &F) {
if (Ret->getNumOperands() == 0 ||
Ret->getOperand(0) ==
cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0)) {
// All predecessors of BB should now branch to RetBlock instead.
if (DTU) {
for (auto *Predecessor : predecessors(&BB)) {
Updates.push_back({DominatorTree::Delete, Predecessor, &BB});
Updates.push_back({DominatorTree::Insert, Predecessor, RetBlock});
}
}
BB.replaceAllUsesWith(RetBlock);
BB.eraseFromParent();
DeadBlocks.emplace_back(&BB);
continue;
}

Expand All @@ -160,6 +170,17 @@ static bool mergeEmptyReturnBlocks(Function &F) {
RetBlockPHI->addIncoming(Ret->getOperand(0), &BB);
BB.getTerminator()->eraseFromParent();
BranchInst::Create(RetBlock, &BB);
if (DTU)
Updates.push_back({DominatorTree::Insert, &BB, RetBlock});
}

if (DTU) {
DTU->applyUpdatesPermissive(Updates);
for (auto *BB : DeadBlocks)
DTU->deleteBB(BB);
} else {
for (auto *BB : DeadBlocks)
BB->eraseFromParent();
}

return Changed;
Expand Down Expand Up @@ -200,7 +221,7 @@ static bool simplifyFunctionCFGImpl(Function &F, const TargetTransformInfo &TTI,
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);

bool EverChanged = removeUnreachableBlocks(F, DT ? &DTU : nullptr);
EverChanged |= mergeEmptyReturnBlocks(F);
EverChanged |= mergeEmptyReturnBlocks(F, DT ? &DTU : nullptr);
EverChanged |= iterativelySimplifyCFG(F, TTI, DT ? &DTU : nullptr, Options);

// If neither pass changed anything, we're done.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: opt < %s -simplifycfg -disable-output
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -disable-output

define i1 @foo() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
%X = invoke i1 @foo( )
Expand Down
48 changes: 48 additions & 0 deletions llvm/test/Transforms/SimplifyCFG/merge-empty-return-blocks.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s | FileCheck %s

define void @t0(i1 %c) {
; CHECK-LABEL: @t0(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;
entry:
br i1 %c, label %end0, label %end1

end0:
ret void

end1:
ret void
}

define i8 @t1(i1 %c, i8 %v) {
; CHECK-LABEL: @t1(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i8 [[V:%.*]]
;
entry:
br i1 %c, label %end0, label %end1

end0:
ret i8 %v

end1:
ret i8 %v
}

define i8 @t2(i1 %c, i8 %v0, i8 %v1) {
; CHECK-LABEL: @t2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], i8 [[V0:%.*]], i8 [[V1:%.*]]
; CHECK-NEXT: ret i8 [[SPEC_SELECT]]
;
entry:
br i1 %c, label %end0, label %end1

end0:
ret i8 %v0

end1:
ret i8 %v1
}
2 changes: 1 addition & 1 deletion llvm/test/Transforms/SimplifyCFG/return-merge.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: opt < %s -simplifycfg -S | not grep br
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | not grep br

define i32 @test1(i1 %C) {
entry:
Expand Down

0 comments on commit d22a47e

Please sign in to comment.