| 1 | //===- bolt/Passes/ThreeWayBranch.cpp -------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file implements the ThreeWayBranch class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "bolt/Passes/ThreeWayBranch.h" |
| 14 | |
| 15 | using namespace llvm; |
| 16 | |
| 17 | namespace llvm { |
| 18 | namespace bolt { |
| 19 | |
| 20 | bool ThreeWayBranch::shouldRunOnFunction(BinaryFunction &Function) { |
| 21 | BinaryContext &BC = Function.getBinaryContext(); |
| 22 | for (const BinaryBasicBlock &BB : Function) |
| 23 | for (const MCInst &Inst : BB) |
| 24 | if (BC.MIB->isPacked(Inst)) |
| 25 | return false; |
| 26 | return true; |
| 27 | } |
| 28 | |
| 29 | void ThreeWayBranch::runOnFunction(BinaryFunction &Function) { |
| 30 | BinaryContext &BC = Function.getBinaryContext(); |
| 31 | MCContext *Ctx = BC.Ctx.get(); |
| 32 | // New blocks will be added and layout will change, |
| 33 | // so make a copy here to iterate over the original layout |
| 34 | BinaryFunction::BasicBlockOrderType BlockLayout( |
| 35 | Function.getLayout().block_begin(), Function.getLayout().block_end()); |
| 36 | for (BinaryBasicBlock *BB : BlockLayout) { |
| 37 | // The block must be hot |
| 38 | if (BB->getExecutionCount() == 0 || |
| 39 | BB->getExecutionCount() == BinaryBasicBlock::COUNT_NO_PROFILE) |
| 40 | continue; |
| 41 | // with two successors |
| 42 | if (BB->succ_size() != 2) |
| 43 | continue; |
| 44 | // no jump table |
| 45 | if (BB->hasJumpTable()) |
| 46 | continue; |
| 47 | |
| 48 | BinaryBasicBlock *FalseSucc = BB->getConditionalSuccessor(Condition: false); |
| 49 | BinaryBasicBlock *TrueSucc = BB->getConditionalSuccessor(Condition: true); |
| 50 | |
| 51 | // One of BB's successors must have only one instruction that is a |
| 52 | // conditional jump |
| 53 | if ((FalseSucc->succ_size() != 2 || FalseSucc->size() != 1) && |
| 54 | (TrueSucc->succ_size() != 2 || TrueSucc->size() != 1)) |
| 55 | continue; |
| 56 | |
| 57 | // SecondBranch has the second conditional jump |
| 58 | BinaryBasicBlock *SecondBranch = FalseSucc; |
| 59 | BinaryBasicBlock *FirstEndpoint = TrueSucc; |
| 60 | if (FalseSucc->succ_size() != 2) { |
| 61 | SecondBranch = TrueSucc; |
| 62 | FirstEndpoint = FalseSucc; |
| 63 | } |
| 64 | |
| 65 | BinaryBasicBlock *SecondEndpoint = |
| 66 | SecondBranch->getConditionalSuccessor(Condition: false); |
| 67 | BinaryBasicBlock *ThirdEndpoint = |
| 68 | SecondBranch->getConditionalSuccessor(Condition: true); |
| 69 | |
| 70 | // Make sure we can modify the jump in SecondBranch without disturbing any |
| 71 | // other paths |
| 72 | if (SecondBranch->pred_size() != 1) |
| 73 | continue; |
| 74 | |
| 75 | // Get Jump Instructions |
| 76 | MCInst *FirstJump = BB->getLastNonPseudoInstr(); |
| 77 | MCInst *SecondJump = SecondBranch->getLastNonPseudoInstr(); |
| 78 | |
| 79 | // Get condition codes |
| 80 | unsigned FirstCC = BC.MIB->getCondCode(Inst: *FirstJump); |
| 81 | if (SecondBranch != FalseSucc) |
| 82 | FirstCC = BC.MIB->getInvertedCondCode(CC: FirstCC); |
| 83 | // ThirdCC = ThirdCond && !FirstCC = !(!ThirdCond || |
| 84 | // !(!FirstCC)) = !(!ThirdCond || FirstCC) |
| 85 | unsigned ThirdCC = |
| 86 | BC.MIB->getInvertedCondCode(CC: BC.MIB->getCondCodesLogicalOr( |
| 87 | CC1: BC.MIB->getInvertedCondCode(CC: BC.MIB->getCondCode(Inst: *SecondJump)), |
| 88 | CC2: FirstCC)); |
| 89 | // SecondCC = !ThirdCond && !FirstCC = !(!(!ThirdCond) || |
| 90 | // !(!FirstCC)) = !(ThirdCond || FirstCC) |
| 91 | unsigned SecondCC = |
| 92 | BC.MIB->getInvertedCondCode(CC: BC.MIB->getCondCodesLogicalOr( |
| 93 | CC1: BC.MIB->getCondCode(Inst: *SecondJump), CC2: FirstCC)); |
| 94 | |
| 95 | if (!BC.MIB->isValidCondCode(CC: FirstCC) || |
| 96 | !BC.MIB->isValidCondCode(CC: ThirdCC) || !BC.MIB->isValidCondCode(CC: SecondCC)) |
| 97 | continue; |
| 98 | |
| 99 | std::vector<std::pair<BinaryBasicBlock *, unsigned>> Blocks; |
| 100 | Blocks.push_back(x: std::make_pair(x&: FirstEndpoint, y&: FirstCC)); |
| 101 | Blocks.push_back(x: std::make_pair(x&: SecondEndpoint, y&: SecondCC)); |
| 102 | Blocks.push_back(x: std::make_pair(x&: ThirdEndpoint, y&: ThirdCC)); |
| 103 | |
| 104 | llvm::sort(C&: Blocks, Comp: [&](const std::pair<BinaryBasicBlock *, unsigned> A, |
| 105 | const std::pair<BinaryBasicBlock *, unsigned> B) { |
| 106 | return A.first->getExecutionCount() < B.first->getExecutionCount(); |
| 107 | }); |
| 108 | |
| 109 | uint64_t NewSecondBranchCount = Blocks[1].first->getExecutionCount() + |
| 110 | Blocks[0].first->getExecutionCount(); |
| 111 | bool SecondBranchBigger = |
| 112 | NewSecondBranchCount > Blocks[2].first->getExecutionCount(); |
| 113 | |
| 114 | BB->removeAllSuccessors(); |
| 115 | if (SecondBranchBigger) { |
| 116 | BB->addSuccessor(Succ: Blocks[2].first, Count: Blocks[2].first->getExecutionCount()); |
| 117 | BB->addSuccessor(Succ: SecondBranch, Count: NewSecondBranchCount); |
| 118 | } else { |
| 119 | BB->addSuccessor(Succ: SecondBranch, Count: NewSecondBranchCount); |
| 120 | BB->addSuccessor(Succ: Blocks[2].first, Count: Blocks[2].first->getExecutionCount()); |
| 121 | } |
| 122 | |
| 123 | // Remove and add so there is no duplicate successors |
| 124 | SecondBranch->removeAllSuccessors(); |
| 125 | SecondBranch->addSuccessor(Succ: Blocks[0].first, |
| 126 | Count: Blocks[0].first->getExecutionCount()); |
| 127 | SecondBranch->addSuccessor(Succ: Blocks[1].first, |
| 128 | Count: Blocks[1].first->getExecutionCount()); |
| 129 | |
| 130 | SecondBranch->setExecutionCount(NewSecondBranchCount); |
| 131 | |
| 132 | // Replace the branch condition to fallthrough for the most common block |
| 133 | if (SecondBranchBigger) |
| 134 | BC.MIB->replaceBranchCondition(Inst&: *FirstJump, TBB: Blocks[2].first->getLabel(), |
| 135 | Ctx, CC: Blocks[2].second); |
| 136 | else |
| 137 | BC.MIB->replaceBranchCondition( |
| 138 | Inst&: *FirstJump, TBB: SecondBranch->getLabel(), Ctx, |
| 139 | CC: BC.MIB->getInvertedCondCode(CC: Blocks[2].second)); |
| 140 | |
| 141 | // Replace the branch condition to fallthrough for the second most common |
| 142 | // block |
| 143 | BC.MIB->replaceBranchCondition(Inst&: *SecondJump, TBB: Blocks[0].first->getLabel(), |
| 144 | Ctx, CC: Blocks[0].second); |
| 145 | |
| 146 | ++BranchesAltered; |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | Error ThreeWayBranch::runOnFunctions(BinaryContext &BC) { |
| 151 | for (auto &It : BC.getBinaryFunctions()) { |
| 152 | BinaryFunction &Function = It.second; |
| 153 | if (!shouldRunOnFunction(Function)) |
| 154 | continue; |
| 155 | runOnFunction(Function); |
| 156 | } |
| 157 | |
| 158 | BC.outs() << "BOLT-INFO: number of three way branches order changed: " |
| 159 | << BranchesAltered << "\n" ; |
| 160 | return Error::success(); |
| 161 | } |
| 162 | |
| 163 | } // end namespace bolt |
| 164 | } // end namespace llvm |
| 165 | |