15f757f3fSDimitry Andric //===-- BasicBlockPathCloning.cpp ---=========-----------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric // 95f757f3fSDimitry Andric /// \file 105f757f3fSDimitry Andric /// BasicBlockPathCloning implementation. 115f757f3fSDimitry Andric /// 125f757f3fSDimitry Andric /// The purpose of this pass is to clone basic block paths based on information 135f757f3fSDimitry Andric /// provided by the -fbasic-block-sections=list option. 145f757f3fSDimitry Andric /// Please refer to BasicBlockSectionsProfileReader.cpp to see a path cloning 155f757f3fSDimitry Andric /// example. 165f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 175f757f3fSDimitry Andric // This pass clones the machine basic blocks alongs the given paths and sets up 185f757f3fSDimitry Andric // the CFG. It assigns BBIDs to the cloned blocks so that the 195f757f3fSDimitry Andric // `BasicBlockSections` pass can correctly map the cluster information to the 205f757f3fSDimitry Andric // blocks. The cloned block's BBID will have the same BaseID as the original 215f757f3fSDimitry Andric // block, but will get a unique non-zero CloneID (original blocks all have zero 225f757f3fSDimitry Andric // CloneIDs). This pass applies a path cloning if it satisfies the following 235f757f3fSDimitry Andric // conditions: 245f757f3fSDimitry Andric // 1. All BBIDs in the path should be mapped to existing blocks. 255f757f3fSDimitry Andric // 2. Each two consecutive BBIDs in the path must have a successor 265f757f3fSDimitry Andric // relationship in the CFG. 275f757f3fSDimitry Andric // 3. The path should not include a block with indirect branches, except for 285f757f3fSDimitry Andric // the last block. 295f757f3fSDimitry Andric // If a path does not satisfy all three conditions, it will be rejected, but the 305f757f3fSDimitry Andric // CloneIDs for its (supposed to be cloned) blocks will be bypassed to make sure 315f757f3fSDimitry Andric // that the `BasicBlockSections` pass can map cluster info correctly to the 325f757f3fSDimitry Andric // actually-cloned blocks. 335f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 345f757f3fSDimitry Andric 355f757f3fSDimitry Andric #include "llvm/ADT/SmallVector.h" 365f757f3fSDimitry Andric #include "llvm/ADT/StringRef.h" 375f757f3fSDimitry Andric #include "llvm/CodeGen/BasicBlockSectionUtils.h" 385f757f3fSDimitry Andric #include "llvm/CodeGen/BasicBlockSectionsProfileReader.h" 395f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 405f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 415f757f3fSDimitry Andric #include "llvm/CodeGen/Passes.h" 425f757f3fSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 435f757f3fSDimitry Andric #include "llvm/InitializePasses.h" 445f757f3fSDimitry Andric #include "llvm/Support/WithColor.h" 455f757f3fSDimitry Andric #include "llvm/Target/TargetMachine.h" 465f757f3fSDimitry Andric 475f757f3fSDimitry Andric using namespace llvm; 485f757f3fSDimitry Andric 495f757f3fSDimitry Andric namespace { 505f757f3fSDimitry Andric 515f757f3fSDimitry Andric // Clones the given block and assigns the given `CloneID` to its BBID. Copies 525f757f3fSDimitry Andric // the instructions into the new block and sets up its successors. 535f757f3fSDimitry Andric MachineBasicBlock *CloneMachineBasicBlock(MachineBasicBlock &OrigBB, 545f757f3fSDimitry Andric unsigned CloneID) { 555f757f3fSDimitry Andric auto &MF = *OrigBB.getParent(); 565f757f3fSDimitry Andric auto TII = MF.getSubtarget().getInstrInfo(); 575f757f3fSDimitry Andric // Create the clone block and set its BBID based on the original block. 585f757f3fSDimitry Andric MachineBasicBlock *CloneBB = MF.CreateMachineBasicBlock( 595f757f3fSDimitry Andric OrigBB.getBasicBlock(), UniqueBBID{OrigBB.getBBID()->BaseID, CloneID}); 605f757f3fSDimitry Andric MF.push_back(CloneBB); 615f757f3fSDimitry Andric 625f757f3fSDimitry Andric // Copy the instructions. 635f757f3fSDimitry Andric for (auto &I : OrigBB.instrs()) { 645f757f3fSDimitry Andric // Bundled instructions are duplicated together. 655f757f3fSDimitry Andric if (I.isBundledWithPred()) 665f757f3fSDimitry Andric continue; 675f757f3fSDimitry Andric TII->duplicate(*CloneBB, CloneBB->end(), I); 685f757f3fSDimitry Andric } 695f757f3fSDimitry Andric 705f757f3fSDimitry Andric // Add the successors of the original block as the new block's successors. 715f757f3fSDimitry Andric // We set the predecessor after returning from this call. 725f757f3fSDimitry Andric for (auto SI = OrigBB.succ_begin(), SE = OrigBB.succ_end(); SI != SE; ++SI) 735f757f3fSDimitry Andric CloneBB->copySuccessor(&OrigBB, SI); 745f757f3fSDimitry Andric 755f757f3fSDimitry Andric if (auto FT = OrigBB.getFallThrough(/*JumpToFallThrough=*/false)) { 765f757f3fSDimitry Andric // The original block has an implicit fall through. 775f757f3fSDimitry Andric // Insert an explicit unconditional jump from the cloned block to the 785f757f3fSDimitry Andric // fallthrough block. Technically, this is only needed for the last block 795f757f3fSDimitry Andric // of the path, but we do it for all clones for consistency. 805f757f3fSDimitry Andric TII->insertUnconditionalBranch(*CloneBB, FT, CloneBB->findBranchDebugLoc()); 815f757f3fSDimitry Andric } 825f757f3fSDimitry Andric return CloneBB; 835f757f3fSDimitry Andric } 845f757f3fSDimitry Andric 855f757f3fSDimitry Andric // Returns if we can legally apply the cloning represented by `ClonePath`. 865f757f3fSDimitry Andric // `BBIDToBlock` contains the original basic blocks in function `MF` keyed by 875f757f3fSDimitry Andric // their `BBID::BaseID`. 885f757f3fSDimitry Andric bool IsValidCloning(const MachineFunction &MF, 895f757f3fSDimitry Andric const DenseMap<unsigned, MachineBasicBlock *> &BBIDToBlock, 905f757f3fSDimitry Andric const SmallVector<unsigned> &ClonePath) { 915f757f3fSDimitry Andric const MachineBasicBlock *PrevBB = nullptr; 925f757f3fSDimitry Andric for (size_t I = 0; I < ClonePath.size(); ++I) { 935f757f3fSDimitry Andric unsigned BBID = ClonePath[I]; 945f757f3fSDimitry Andric const MachineBasicBlock *PathBB = BBIDToBlock.lookup(BBID); 955f757f3fSDimitry Andric if (!PathBB) { 965f757f3fSDimitry Andric WithColor::warning() << "no block with id " << BBID << " in function " 975f757f3fSDimitry Andric << MF.getName() << "\n"; 985f757f3fSDimitry Andric return false; 995f757f3fSDimitry Andric } 1005f757f3fSDimitry Andric 1015f757f3fSDimitry Andric if (PrevBB) { 1025f757f3fSDimitry Andric if (!PrevBB->isSuccessor(PathBB)) { 1035f757f3fSDimitry Andric WithColor::warning() 1045f757f3fSDimitry Andric << "block #" << BBID << " is not a successor of block #" 1055f757f3fSDimitry Andric << PrevBB->getBBID()->BaseID << " in function " << MF.getName() 1065f757f3fSDimitry Andric << "\n"; 1075f757f3fSDimitry Andric return false; 1085f757f3fSDimitry Andric } 1095f757f3fSDimitry Andric 1105f757f3fSDimitry Andric for (auto &MI : *PathBB) { 1115f757f3fSDimitry Andric // Avoid cloning when the block contains non-duplicable instructions. 1125f757f3fSDimitry Andric // CFI instructions are marked as non-duplicable only because of Darwin, 1135f757f3fSDimitry Andric // so we exclude them from this check. 1145f757f3fSDimitry Andric if (MI.isNotDuplicable() && !MI.isCFIInstruction()) { 1155f757f3fSDimitry Andric WithColor::warning() 1165f757f3fSDimitry Andric << "block #" << BBID 1175f757f3fSDimitry Andric << " has non-duplicable instructions in function " << MF.getName() 1185f757f3fSDimitry Andric << "\n"; 1195f757f3fSDimitry Andric return false; 1205f757f3fSDimitry Andric } 1215f757f3fSDimitry Andric } 122*0fca6ea1SDimitry Andric if (PathBB->isMachineBlockAddressTaken()) { 123*0fca6ea1SDimitry Andric // Avoid cloning blocks which have their address taken since we can't 124*0fca6ea1SDimitry Andric // rewire branches to those blocks as easily (e.g., branches within 125*0fca6ea1SDimitry Andric // inline assembly). 126*0fca6ea1SDimitry Andric WithColor::warning() 127*0fca6ea1SDimitry Andric << "block #" << BBID 128*0fca6ea1SDimitry Andric << " has its machine block address taken in function " 129*0fca6ea1SDimitry Andric << MF.getName() << "\n"; 130*0fca6ea1SDimitry Andric return false; 131*0fca6ea1SDimitry Andric } 1325f757f3fSDimitry Andric } 1335f757f3fSDimitry Andric 1345f757f3fSDimitry Andric if (I != ClonePath.size() - 1 && !PathBB->empty() && 1355f757f3fSDimitry Andric PathBB->back().isIndirectBranch()) { 1365f757f3fSDimitry Andric WithColor::warning() 1375f757f3fSDimitry Andric << "block #" << BBID 1385f757f3fSDimitry Andric << " has indirect branch and appears as the non-tail block of a " 1395f757f3fSDimitry Andric "path in function " 1405f757f3fSDimitry Andric << MF.getName() << "\n"; 1415f757f3fSDimitry Andric return false; 1425f757f3fSDimitry Andric } 1435f757f3fSDimitry Andric PrevBB = PathBB; 1445f757f3fSDimitry Andric } 1455f757f3fSDimitry Andric return true; 1465f757f3fSDimitry Andric } 1475f757f3fSDimitry Andric 1485f757f3fSDimitry Andric // Applies all clonings specified in `ClonePaths` to `MF`. Returns true 1495f757f3fSDimitry Andric // if any clonings have been applied. 1505f757f3fSDimitry Andric bool ApplyCloning(MachineFunction &MF, 1515f757f3fSDimitry Andric const SmallVector<SmallVector<unsigned>> &ClonePaths) { 1525f757f3fSDimitry Andric if (ClonePaths.empty()) 1535f757f3fSDimitry Andric return false; 1545f757f3fSDimitry Andric bool AnyPathsCloned = false; 1555f757f3fSDimitry Andric // Map from the final BB IDs to the `MachineBasicBlock`s. 1565f757f3fSDimitry Andric DenseMap<unsigned, MachineBasicBlock *> BBIDToBlock; 1575f757f3fSDimitry Andric for (auto &BB : MF) 1585f757f3fSDimitry Andric BBIDToBlock.try_emplace(BB.getBBID()->BaseID, &BB); 1595f757f3fSDimitry Andric 1605f757f3fSDimitry Andric DenseMap<unsigned, unsigned> NClonesForBBID; 1615f757f3fSDimitry Andric auto TII = MF.getSubtarget().getInstrInfo(); 1625f757f3fSDimitry Andric for (const auto &ClonePath : ClonePaths) { 1635f757f3fSDimitry Andric if (!IsValidCloning(MF, BBIDToBlock, ClonePath)) { 1645f757f3fSDimitry Andric // We still need to increment the number of clones so we can map 1655f757f3fSDimitry Andric // to the cluster info correctly. 1665f757f3fSDimitry Andric for (unsigned BBID : ClonePath) 1675f757f3fSDimitry Andric ++NClonesForBBID[BBID]; 1685f757f3fSDimitry Andric continue; 1695f757f3fSDimitry Andric } 1705f757f3fSDimitry Andric MachineBasicBlock *PrevBB = nullptr; 1715f757f3fSDimitry Andric for (unsigned BBID : ClonePath) { 1725f757f3fSDimitry Andric MachineBasicBlock *OrigBB = BBIDToBlock.at(BBID); 1735f757f3fSDimitry Andric if (PrevBB == nullptr) { 1745f757f3fSDimitry Andric // The first block in the path is not cloned. We only need to make it 1755f757f3fSDimitry Andric // branch to the next cloned block in the path. Here, we make its 1765f757f3fSDimitry Andric // fallthrough explicit so we can change it later. 1775f757f3fSDimitry Andric if (auto FT = OrigBB->getFallThrough(/*JumpToFallThrough=*/false)) { 1785f757f3fSDimitry Andric TII->insertUnconditionalBranch(*OrigBB, FT, 1795f757f3fSDimitry Andric OrigBB->findBranchDebugLoc()); 1805f757f3fSDimitry Andric } 1815f757f3fSDimitry Andric PrevBB = OrigBB; 1825f757f3fSDimitry Andric continue; 1835f757f3fSDimitry Andric } 1845f757f3fSDimitry Andric MachineBasicBlock *CloneBB = 1855f757f3fSDimitry Andric CloneMachineBasicBlock(*OrigBB, ++NClonesForBBID[BBID]); 1865f757f3fSDimitry Andric 1875f757f3fSDimitry Andric // Set up the previous block in the path to jump to the clone. This also 1885f757f3fSDimitry Andric // transfers the successor/predecessor relationship of PrevBB and OrigBB 1895f757f3fSDimitry Andric // to that of PrevBB and CloneBB. 1905f757f3fSDimitry Andric PrevBB->ReplaceUsesOfBlockWith(OrigBB, CloneBB); 1915f757f3fSDimitry Andric 1925f757f3fSDimitry Andric // Copy the livein set. 1935f757f3fSDimitry Andric for (auto &LiveIn : OrigBB->liveins()) 1945f757f3fSDimitry Andric CloneBB->addLiveIn(LiveIn); 1955f757f3fSDimitry Andric 1965f757f3fSDimitry Andric PrevBB = CloneBB; 1975f757f3fSDimitry Andric } 1985f757f3fSDimitry Andric AnyPathsCloned = true; 1995f757f3fSDimitry Andric } 2005f757f3fSDimitry Andric return AnyPathsCloned; 2015f757f3fSDimitry Andric } 2025f757f3fSDimitry Andric } // end anonymous namespace 2035f757f3fSDimitry Andric 2045f757f3fSDimitry Andric namespace llvm { 2055f757f3fSDimitry Andric class BasicBlockPathCloning : public MachineFunctionPass { 2065f757f3fSDimitry Andric public: 2075f757f3fSDimitry Andric static char ID; 2085f757f3fSDimitry Andric 2091db9f3b2SDimitry Andric BasicBlockSectionsProfileReaderWrapperPass *BBSectionsProfileReader = nullptr; 2105f757f3fSDimitry Andric 2115f757f3fSDimitry Andric BasicBlockPathCloning() : MachineFunctionPass(ID) { 2125f757f3fSDimitry Andric initializeBasicBlockPathCloningPass(*PassRegistry::getPassRegistry()); 2135f757f3fSDimitry Andric } 2145f757f3fSDimitry Andric 2155f757f3fSDimitry Andric StringRef getPassName() const override { return "Basic Block Path Cloning"; } 2165f757f3fSDimitry Andric 2175f757f3fSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 2185f757f3fSDimitry Andric 2195f757f3fSDimitry Andric /// Identify basic blocks that need separate sections and prepare to emit them 2205f757f3fSDimitry Andric /// accordingly. 2215f757f3fSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 2225f757f3fSDimitry Andric }; 2235f757f3fSDimitry Andric 2245f757f3fSDimitry Andric } // namespace llvm 2255f757f3fSDimitry Andric 2265f757f3fSDimitry Andric char BasicBlockPathCloning::ID = 0; 2275f757f3fSDimitry Andric INITIALIZE_PASS_BEGIN( 2285f757f3fSDimitry Andric BasicBlockPathCloning, "bb-path-cloning", 2295f757f3fSDimitry Andric "Applies path clonings for the -basic-block-sections=list option", false, 2305f757f3fSDimitry Andric false) 2311db9f3b2SDimitry Andric INITIALIZE_PASS_DEPENDENCY(BasicBlockSectionsProfileReaderWrapperPass) 2325f757f3fSDimitry Andric INITIALIZE_PASS_END( 2335f757f3fSDimitry Andric BasicBlockPathCloning, "bb-path-cloning", 2345f757f3fSDimitry Andric "Applies path clonings for the -basic-block-sections=list option", false, 2355f757f3fSDimitry Andric false) 2365f757f3fSDimitry Andric 2375f757f3fSDimitry Andric bool BasicBlockPathCloning::runOnMachineFunction(MachineFunction &MF) { 2385f757f3fSDimitry Andric assert(MF.getTarget().getBBSectionsType() == BasicBlockSection::List && 2395f757f3fSDimitry Andric "BB Sections list not enabled!"); 2405f757f3fSDimitry Andric if (hasInstrProfHashMismatch(MF)) 2415f757f3fSDimitry Andric return false; 2425f757f3fSDimitry Andric 2431db9f3b2SDimitry Andric return ApplyCloning(MF, 2441db9f3b2SDimitry Andric getAnalysis<BasicBlockSectionsProfileReaderWrapperPass>() 2455f757f3fSDimitry Andric .getClonePathsForFunction(MF.getName())); 2465f757f3fSDimitry Andric } 2475f757f3fSDimitry Andric 2485f757f3fSDimitry Andric void BasicBlockPathCloning::getAnalysisUsage(AnalysisUsage &AU) const { 2495f757f3fSDimitry Andric AU.setPreservesAll(); 2501db9f3b2SDimitry Andric AU.addRequired<BasicBlockSectionsProfileReaderWrapperPass>(); 2515f757f3fSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 2525f757f3fSDimitry Andric } 2535f757f3fSDimitry Andric 2545f757f3fSDimitry Andric MachineFunctionPass *llvm::createBasicBlockPathCloningPass() { 2555f757f3fSDimitry Andric return new BasicBlockPathCloning(); 2565f757f3fSDimitry Andric } 257