//===- bolt/Passes/ThreeWayBranch.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the ThreeWayBranch class. // //===----------------------------------------------------------------------===// #include "bolt/Passes/ThreeWayBranch.h" using namespace llvm; namespace llvm { namespace bolt { bool ThreeWayBranch::shouldRunOnFunction(BinaryFunction &Function) { BinaryContext &BC = Function.getBinaryContext(); for (const BinaryBasicBlock &BB : Function) for (const MCInst &Inst : BB) if (BC.MIB->isPacked(Inst)) return false; return true; } void ThreeWayBranch::runOnFunction(BinaryFunction &Function) { BinaryContext &BC = Function.getBinaryContext(); MCContext *Ctx = BC.Ctx.get(); // New blocks will be added and layout will change, // so make a copy here to iterate over the original layout BinaryFunction::BasicBlockOrderType BlockLayout( Function.getLayout().block_begin(), Function.getLayout().block_end()); for (BinaryBasicBlock *BB : BlockLayout) { // The block must be hot if (BB->getExecutionCount() == 0 || BB->getExecutionCount() == BinaryBasicBlock::COUNT_NO_PROFILE) continue; // with two successors if (BB->succ_size() != 2) continue; // no jump table if (BB->hasJumpTable()) continue; BinaryBasicBlock *FalseSucc = BB->getConditionalSuccessor(false); BinaryBasicBlock *TrueSucc = BB->getConditionalSuccessor(true); // One of BB's successors must have only one instruction that is a // conditional jump if ((FalseSucc->succ_size() != 2 || FalseSucc->size() != 1) && (TrueSucc->succ_size() != 2 || TrueSucc->size() != 1)) continue; // SecondBranch has the second conditional jump BinaryBasicBlock *SecondBranch = FalseSucc; BinaryBasicBlock *FirstEndpoint = TrueSucc; if (FalseSucc->succ_size() != 2) { SecondBranch = TrueSucc; FirstEndpoint = FalseSucc; } BinaryBasicBlock *SecondEndpoint = SecondBranch->getConditionalSuccessor(false); BinaryBasicBlock *ThirdEndpoint = SecondBranch->getConditionalSuccessor(true); // Make sure we can modify the jump in SecondBranch without disturbing any // other paths if (SecondBranch->pred_size() != 1) continue; // Get Jump Instructions MCInst *FirstJump = BB->getLastNonPseudoInstr(); MCInst *SecondJump = SecondBranch->getLastNonPseudoInstr(); // Get condition codes unsigned FirstCC = BC.MIB->getCondCode(*FirstJump); if (SecondBranch != FalseSucc) FirstCC = BC.MIB->getInvertedCondCode(FirstCC); // ThirdCC = ThirdCond && !FirstCC = !(!ThirdCond || // !(!FirstCC)) = !(!ThirdCond || FirstCC) unsigned ThirdCC = BC.MIB->getInvertedCondCode(BC.MIB->getCondCodesLogicalOr( BC.MIB->getInvertedCondCode(BC.MIB->getCondCode(*SecondJump)), FirstCC)); // SecondCC = !ThirdCond && !FirstCC = !(!(!ThirdCond) || // !(!FirstCC)) = !(ThirdCond || FirstCC) unsigned SecondCC = BC.MIB->getInvertedCondCode(BC.MIB->getCondCodesLogicalOr( BC.MIB->getCondCode(*SecondJump), FirstCC)); if (!BC.MIB->isValidCondCode(FirstCC) || !BC.MIB->isValidCondCode(ThirdCC) || !BC.MIB->isValidCondCode(SecondCC)) continue; std::vector> Blocks; Blocks.push_back(std::make_pair(FirstEndpoint, FirstCC)); Blocks.push_back(std::make_pair(SecondEndpoint, SecondCC)); Blocks.push_back(std::make_pair(ThirdEndpoint, ThirdCC)); llvm::sort(Blocks, [&](const std::pair A, const std::pair B) { return A.first->getExecutionCount() < B.first->getExecutionCount(); }); uint64_t NewSecondBranchCount = Blocks[1].first->getExecutionCount() + Blocks[0].first->getExecutionCount(); bool SecondBranchBigger = NewSecondBranchCount > Blocks[2].first->getExecutionCount(); BB->removeAllSuccessors(); if (SecondBranchBigger) { BB->addSuccessor(Blocks[2].first, Blocks[2].first->getExecutionCount()); BB->addSuccessor(SecondBranch, NewSecondBranchCount); } else { BB->addSuccessor(SecondBranch, NewSecondBranchCount); BB->addSuccessor(Blocks[2].first, Blocks[2].first->getExecutionCount()); } // Remove and add so there is no duplicate successors SecondBranch->removeAllSuccessors(); SecondBranch->addSuccessor(Blocks[0].first, Blocks[0].first->getExecutionCount()); SecondBranch->addSuccessor(Blocks[1].first, Blocks[1].first->getExecutionCount()); SecondBranch->setExecutionCount(NewSecondBranchCount); // Replace the branch condition to fallthrough for the most common block if (SecondBranchBigger) BC.MIB->replaceBranchCondition(*FirstJump, Blocks[2].first->getLabel(), Ctx, Blocks[2].second); else BC.MIB->replaceBranchCondition( *FirstJump, SecondBranch->getLabel(), Ctx, BC.MIB->getInvertedCondCode(Blocks[2].second)); // Replace the branch condition to fallthrough for the second most common // block BC.MIB->replaceBranchCondition(*SecondJump, Blocks[0].first->getLabel(), Ctx, Blocks[0].second); ++BranchesAltered; } } Error ThreeWayBranch::runOnFunctions(BinaryContext &BC) { for (auto &It : BC.getBinaryFunctions()) { BinaryFunction &Function = It.second; if (!shouldRunOnFunction(Function)) continue; runOnFunction(Function); } BC.outs() << "BOLT-INFO: number of three way branches order changed: " << BranchesAltered << "\n"; return Error::success(); } } // end namespace bolt } // end namespace llvm