Implement PR5795 by merging duplicated return blocks. This could go further

by merging all returns in a function into a single one, but simplifycfg 
currently likes to duplicate the return (an unfortunate choice!)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91890 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2009-12-22 06:07:30 +00:00
parent 42385b03aa
commit 1a0e7081c3
2 changed files with 91 additions and 0 deletions

View File

@ -189,6 +189,77 @@ static bool RemoveUnreachableBlocksFromFn(Function &F) {
return true; return true;
} }
/// MergeEmptyReturnBlocks - 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) {
bool Changed = false;
BasicBlock *RetBlock = 0;
// Scan all the blocks in the function, looking for empty return blocks.
for (Function::iterator BBI = F.begin(), E = F.end(); BBI != E; ) {
BasicBlock &BB = *BBI++;
// Only look at return blocks.
ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator());
if (Ret == 0) continue;
// Only look at the block if it is empty or the only other thing in it is a
// single PHI node that is the operand to the return.
if (Ret != &BB.front()) {
// Check for something else in the block.
BasicBlock::iterator I = Ret;
--I;
if (!isa<PHINode>(I) || I != BB.begin() ||
Ret->getNumOperands() == 0 ||
Ret->getOperand(0) != I)
continue;
}
// If this is the first returning block, remember it and keep going.
if (RetBlock == 0) {
RetBlock = &BB;
continue;
}
// Otherwise, we found a duplicate return block. Merge the two.
Changed = true;
// Case when there is no input to the return or when the returned values
// agree is trivial. Note that they can't agree if there are phis in the
// blocks.
if (Ret->getNumOperands() == 0 ||
Ret->getOperand(0) ==
cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0)) {
BB.replaceAllUsesWith(RetBlock);
BB.eraseFromParent();
continue;
}
// If the canonical return block has no PHI node, create one now.
PHINode *RetBlockPHI = dyn_cast<PHINode>(RetBlock->begin());
if (RetBlockPHI == 0) {
Value *InVal = cast<ReturnInst>(RetBlock->begin())->getOperand(0);
RetBlockPHI = PHINode::Create(Ret->getOperand(0)->getType(), "merge",
&RetBlock->front());
for (pred_iterator PI = pred_begin(RetBlock), E = pred_end(RetBlock);
PI != E; ++PI)
RetBlockPHI->addIncoming(InVal, *PI);
RetBlock->getTerminator()->setOperand(0, RetBlockPHI);
}
// Turn BB into a block that just unconditionally branches to the return
// block. This handles the case when the two return blocks have a common
// predecessor but that return different things.
RetBlockPHI->addIncoming(Ret->getOperand(0), &BB);
BB.getTerminator()->eraseFromParent();
BranchInst::Create(RetBlock, &BB);
}
return Changed;
}
/// IterativeSimplifyCFG - Call SimplifyCFG on all the blocks in the function, /// IterativeSimplifyCFG - Call SimplifyCFG on all the blocks in the function,
/// iterating until no more changes are made. /// iterating until no more changes are made.
static bool IterativeSimplifyCFG(Function &F) { static bool IterativeSimplifyCFG(Function &F) {
@ -216,6 +287,7 @@ static bool IterativeSimplifyCFG(Function &F) {
// //
bool CFGSimplifyPass::runOnFunction(Function &F) { bool CFGSimplifyPass::runOnFunction(Function &F) {
bool EverChanged = RemoveUnreachableBlocksFromFn(F); bool EverChanged = RemoveUnreachableBlocksFromFn(F);
EverChanged |= MergeEmptyReturnBlocks(F);
EverChanged |= IterativeSimplifyCFG(F); EverChanged |= IterativeSimplifyCFG(F);
// If neither pass changed anything, we're done. // If neither pass changed anything, we're done.

View File

@ -38,3 +38,22 @@ return:
@test4g = global i8* blockaddress(@test4, %return) @test4g = global i8* blockaddress(@test4, %return)
; PR5795
define void @test5(i32 %A) {
switch i32 %A, label %return [
i32 2, label %bb
i32 10, label %bb1
]
bb: ; preds = %entry
ret void
bb1: ; preds = %entry
ret void
return: ; preds = %entry
ret void
; CHECK: @test5
; CHECK-NEXT: bb:
; CHECK-NEXT: ret void
}