mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
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:
parent
42385b03aa
commit
1a0e7081c3
@ -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.
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user