From a7bef4a4e49f461984c04ef6be6eef3f1c023558 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 18 Nov 2006 20:47:54 +0000 Subject: [PATCH] Minor code layout tweak: if we have something like this: if (cond) goto BB2 BB1: ... return; BB2: ... Move BB1 to the end of the function so that the code falls through in the non-return case. This has the effect of moving assert (and other no-return call) bodies and return blocks out of loops. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@31855 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/BranchFolding.cpp | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/lib/CodeGen/BranchFolding.cpp b/lib/CodeGen/BranchFolding.cpp index ddd3bca03b9..04bed9c8a5b 100644 --- a/lib/CodeGen/BranchFolding.cpp +++ b/lib/CodeGen/BranchFolding.cpp @@ -586,6 +586,24 @@ bool BranchFolder::CanFallThrough(MachineBasicBlock *CurBB) { return CanFallThrough(CurBB, CurUnAnalyzable, TBB, FBB, Cond); } +/// IsBetterFallthrough - Return true if it would be clearly better to +/// fall-through to MBB1 than to fall through into MBB2. This has to return +/// a strict ordering, returning true for both (MBB1,MBB2) and (MBB2,MBB1) will +/// result in infinite loops. +static bool IsBetterFallthrough(MachineBasicBlock *MBB1, + MachineBasicBlock *MBB2, + const TargetInstrInfo &TII) { + // Right now, we use a simple heuristic. If MBB ends with a return, and + // MBB2 doesn't, we prefer to fall through into MBB1. This allows us to + // optimize branches that branch to either a return block or an assert block + // into a fallthrough to the return. + if (MBB1->empty() || MBB2->empty()) return false; + + MachineInstr *MBB1I = --MBB1->end(); + MachineInstr *MBB2I = --MBB2->end(); + return TII.isReturn(MBB1I->getOpcode()) && !TII.isReturn(MBB2I->getOpcode()); +} + /// OptimizeBlock - Analyze and optimize control flow related to the specified /// block. This is never called on the entry block. void BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) { @@ -675,6 +693,38 @@ void BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) { return OptimizeBlock(MBB); } } + + // If this block has no successors (e.g. it is a return block or ends with + // a call to a no-return function like abort or __cxa_throw) and if the pred + // falls through into this block, and if it would otherwise fall through + // into the block after this, move this block to the end of the function. + // We consider it more likely that execution will stay in the function (e.g. + // due to loops) than it is to exit it. This asserts in loops etc, moving + // the assert condition out of the loop body. + if (MBB->succ_empty() && !PriorCond.empty() && PriorFBB == 0 && + MachineFunction::iterator(PriorTBB) == FallThrough) { + // We have to be careful that the succs of PredBB aren't both no-successor + // blocks. If neither have successors and if PredBB is the second from + // last block in the function, we'd just keep swapping the two blocks for + // last. Only do the swap if one is clearly better to fall through than + // the other. + if (FallThrough != --MBB->getParent()->end() || + IsBetterFallthrough(PriorTBB, MBB, *TII)) { + + // Reverse the branch so we will fall through on the previous true cond. + std::vector NewPriorCond(PriorCond); + if (!TII->ReverseBranchCondition(NewPriorCond)) { + TII->RemoveBranch(PrevBB); + TII->InsertBranch(PrevBB, MBB, 0, NewPriorCond); + + // Move this block to the end of the function. + MBB->moveAfter(--MBB->getParent()->end()); + MadeChange = true; + ++NumBranchOpts; + return; + } + } + } } // Analyze the branch in the current block.