1*5f757f3fSDimitry Andric //===-- BasicBlockPathCloning.cpp ---=========-----------------------------===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric // 9*5f757f3fSDimitry Andric /// \file 10*5f757f3fSDimitry Andric /// BasicBlockPathCloning implementation. 11*5f757f3fSDimitry Andric /// 12*5f757f3fSDimitry Andric /// The purpose of this pass is to clone basic block paths based on information 13*5f757f3fSDimitry Andric /// provided by the -fbasic-block-sections=list option. 14*5f757f3fSDimitry Andric /// Please refer to BasicBlockSectionsProfileReader.cpp to see a path cloning 15*5f757f3fSDimitry Andric /// example. 16*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 17*5f757f3fSDimitry Andric // This pass clones the machine basic blocks alongs the given paths and sets up 18*5f757f3fSDimitry Andric // the CFG. It assigns BBIDs to the cloned blocks so that the 19*5f757f3fSDimitry Andric // `BasicBlockSections` pass can correctly map the cluster information to the 20*5f757f3fSDimitry Andric // blocks. The cloned block's BBID will have the same BaseID as the original 21*5f757f3fSDimitry Andric // block, but will get a unique non-zero CloneID (original blocks all have zero 22*5f757f3fSDimitry Andric // CloneIDs). This pass applies a path cloning if it satisfies the following 23*5f757f3fSDimitry Andric // conditions: 24*5f757f3fSDimitry Andric // 1. All BBIDs in the path should be mapped to existing blocks. 25*5f757f3fSDimitry Andric // 2. Each two consecutive BBIDs in the path must have a successor 26*5f757f3fSDimitry Andric // relationship in the CFG. 27*5f757f3fSDimitry Andric // 3. The path should not include a block with indirect branches, except for 28*5f757f3fSDimitry Andric // the last block. 29*5f757f3fSDimitry Andric // If a path does not satisfy all three conditions, it will be rejected, but the 30*5f757f3fSDimitry Andric // CloneIDs for its (supposed to be cloned) blocks will be bypassed to make sure 31*5f757f3fSDimitry Andric // that the `BasicBlockSections` pass can map cluster info correctly to the 32*5f757f3fSDimitry Andric // actually-cloned blocks. 33*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 34*5f757f3fSDimitry Andric 35*5f757f3fSDimitry Andric #include "llvm/ADT/SmallVector.h" 36*5f757f3fSDimitry Andric #include "llvm/ADT/StringRef.h" 37*5f757f3fSDimitry Andric #include "llvm/CodeGen/BasicBlockSectionUtils.h" 38*5f757f3fSDimitry Andric #include "llvm/CodeGen/BasicBlockSectionsProfileReader.h" 39*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 40*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 41*5f757f3fSDimitry Andric #include "llvm/CodeGen/Passes.h" 42*5f757f3fSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 43*5f757f3fSDimitry Andric #include "llvm/InitializePasses.h" 44*5f757f3fSDimitry Andric #include "llvm/Support/WithColor.h" 45*5f757f3fSDimitry Andric #include "llvm/Target/TargetMachine.h" 46*5f757f3fSDimitry Andric 47*5f757f3fSDimitry Andric using namespace llvm; 48*5f757f3fSDimitry Andric 49*5f757f3fSDimitry Andric namespace { 50*5f757f3fSDimitry Andric 51*5f757f3fSDimitry Andric // Clones the given block and assigns the given `CloneID` to its BBID. Copies 52*5f757f3fSDimitry Andric // the instructions into the new block and sets up its successors. 53*5f757f3fSDimitry Andric MachineBasicBlock *CloneMachineBasicBlock(MachineBasicBlock &OrigBB, 54*5f757f3fSDimitry Andric unsigned CloneID) { 55*5f757f3fSDimitry Andric auto &MF = *OrigBB.getParent(); 56*5f757f3fSDimitry Andric auto TII = MF.getSubtarget().getInstrInfo(); 57*5f757f3fSDimitry Andric // Create the clone block and set its BBID based on the original block. 58*5f757f3fSDimitry Andric MachineBasicBlock *CloneBB = MF.CreateMachineBasicBlock( 59*5f757f3fSDimitry Andric OrigBB.getBasicBlock(), UniqueBBID{OrigBB.getBBID()->BaseID, CloneID}); 60*5f757f3fSDimitry Andric MF.push_back(CloneBB); 61*5f757f3fSDimitry Andric 62*5f757f3fSDimitry Andric // Copy the instructions. 63*5f757f3fSDimitry Andric for (auto &I : OrigBB.instrs()) { 64*5f757f3fSDimitry Andric // Bundled instructions are duplicated together. 65*5f757f3fSDimitry Andric if (I.isBundledWithPred()) 66*5f757f3fSDimitry Andric continue; 67*5f757f3fSDimitry Andric TII->duplicate(*CloneBB, CloneBB->end(), I); 68*5f757f3fSDimitry Andric } 69*5f757f3fSDimitry Andric 70*5f757f3fSDimitry Andric // Add the successors of the original block as the new block's successors. 71*5f757f3fSDimitry Andric // We set the predecessor after returning from this call. 72*5f757f3fSDimitry Andric for (auto SI = OrigBB.succ_begin(), SE = OrigBB.succ_end(); SI != SE; ++SI) 73*5f757f3fSDimitry Andric CloneBB->copySuccessor(&OrigBB, SI); 74*5f757f3fSDimitry Andric 75*5f757f3fSDimitry Andric if (auto FT = OrigBB.getFallThrough(/*JumpToFallThrough=*/false)) { 76*5f757f3fSDimitry Andric // The original block has an implicit fall through. 77*5f757f3fSDimitry Andric // Insert an explicit unconditional jump from the cloned block to the 78*5f757f3fSDimitry Andric // fallthrough block. Technically, this is only needed for the last block 79*5f757f3fSDimitry Andric // of the path, but we do it for all clones for consistency. 80*5f757f3fSDimitry Andric TII->insertUnconditionalBranch(*CloneBB, FT, CloneBB->findBranchDebugLoc()); 81*5f757f3fSDimitry Andric } 82*5f757f3fSDimitry Andric return CloneBB; 83*5f757f3fSDimitry Andric } 84*5f757f3fSDimitry Andric 85*5f757f3fSDimitry Andric // Returns if we can legally apply the cloning represented by `ClonePath`. 86*5f757f3fSDimitry Andric // `BBIDToBlock` contains the original basic blocks in function `MF` keyed by 87*5f757f3fSDimitry Andric // their `BBID::BaseID`. 88*5f757f3fSDimitry Andric bool IsValidCloning(const MachineFunction &MF, 89*5f757f3fSDimitry Andric const DenseMap<unsigned, MachineBasicBlock *> &BBIDToBlock, 90*5f757f3fSDimitry Andric const SmallVector<unsigned> &ClonePath) { 91*5f757f3fSDimitry Andric const MachineBasicBlock *PrevBB = nullptr; 92*5f757f3fSDimitry Andric for (size_t I = 0; I < ClonePath.size(); ++I) { 93*5f757f3fSDimitry Andric unsigned BBID = ClonePath[I]; 94*5f757f3fSDimitry Andric const MachineBasicBlock *PathBB = BBIDToBlock.lookup(BBID); 95*5f757f3fSDimitry Andric if (!PathBB) { 96*5f757f3fSDimitry Andric WithColor::warning() << "no block with id " << BBID << " in function " 97*5f757f3fSDimitry Andric << MF.getName() << "\n"; 98*5f757f3fSDimitry Andric return false; 99*5f757f3fSDimitry Andric } 100*5f757f3fSDimitry Andric 101*5f757f3fSDimitry Andric if (PrevBB) { 102*5f757f3fSDimitry Andric if (!PrevBB->isSuccessor(PathBB)) { 103*5f757f3fSDimitry Andric WithColor::warning() 104*5f757f3fSDimitry Andric << "block #" << BBID << " is not a successor of block #" 105*5f757f3fSDimitry Andric << PrevBB->getBBID()->BaseID << " in function " << MF.getName() 106*5f757f3fSDimitry Andric << "\n"; 107*5f757f3fSDimitry Andric return false; 108*5f757f3fSDimitry Andric } 109*5f757f3fSDimitry Andric 110*5f757f3fSDimitry Andric for (auto &MI : *PathBB) { 111*5f757f3fSDimitry Andric // Avoid cloning when the block contains non-duplicable instructions. 112*5f757f3fSDimitry Andric // CFI instructions are marked as non-duplicable only because of Darwin, 113*5f757f3fSDimitry Andric // so we exclude them from this check. 114*5f757f3fSDimitry Andric if (MI.isNotDuplicable() && !MI.isCFIInstruction()) { 115*5f757f3fSDimitry Andric WithColor::warning() 116*5f757f3fSDimitry Andric << "block #" << BBID 117*5f757f3fSDimitry Andric << " has non-duplicable instructions in function " << MF.getName() 118*5f757f3fSDimitry Andric << "\n"; 119*5f757f3fSDimitry Andric return false; 120*5f757f3fSDimitry Andric } 121*5f757f3fSDimitry Andric } 122*5f757f3fSDimitry Andric } 123*5f757f3fSDimitry Andric 124*5f757f3fSDimitry Andric if (I != ClonePath.size() - 1 && !PathBB->empty() && 125*5f757f3fSDimitry Andric PathBB->back().isIndirectBranch()) { 126*5f757f3fSDimitry Andric WithColor::warning() 127*5f757f3fSDimitry Andric << "block #" << BBID 128*5f757f3fSDimitry Andric << " has indirect branch and appears as the non-tail block of a " 129*5f757f3fSDimitry Andric "path in function " 130*5f757f3fSDimitry Andric << MF.getName() << "\n"; 131*5f757f3fSDimitry Andric return false; 132*5f757f3fSDimitry Andric } 133*5f757f3fSDimitry Andric PrevBB = PathBB; 134*5f757f3fSDimitry Andric } 135*5f757f3fSDimitry Andric return true; 136*5f757f3fSDimitry Andric } 137*5f757f3fSDimitry Andric 138*5f757f3fSDimitry Andric // Applies all clonings specified in `ClonePaths` to `MF`. Returns true 139*5f757f3fSDimitry Andric // if any clonings have been applied. 140*5f757f3fSDimitry Andric bool ApplyCloning(MachineFunction &MF, 141*5f757f3fSDimitry Andric const SmallVector<SmallVector<unsigned>> &ClonePaths) { 142*5f757f3fSDimitry Andric if (ClonePaths.empty()) 143*5f757f3fSDimitry Andric return false; 144*5f757f3fSDimitry Andric bool AnyPathsCloned = false; 145*5f757f3fSDimitry Andric // Map from the final BB IDs to the `MachineBasicBlock`s. 146*5f757f3fSDimitry Andric DenseMap<unsigned, MachineBasicBlock *> BBIDToBlock; 147*5f757f3fSDimitry Andric for (auto &BB : MF) 148*5f757f3fSDimitry Andric BBIDToBlock.try_emplace(BB.getBBID()->BaseID, &BB); 149*5f757f3fSDimitry Andric 150*5f757f3fSDimitry Andric DenseMap<unsigned, unsigned> NClonesForBBID; 151*5f757f3fSDimitry Andric auto TII = MF.getSubtarget().getInstrInfo(); 152*5f757f3fSDimitry Andric for (const auto &ClonePath : ClonePaths) { 153*5f757f3fSDimitry Andric if (!IsValidCloning(MF, BBIDToBlock, ClonePath)) { 154*5f757f3fSDimitry Andric // We still need to increment the number of clones so we can map 155*5f757f3fSDimitry Andric // to the cluster info correctly. 156*5f757f3fSDimitry Andric for (unsigned BBID : ClonePath) 157*5f757f3fSDimitry Andric ++NClonesForBBID[BBID]; 158*5f757f3fSDimitry Andric continue; 159*5f757f3fSDimitry Andric } 160*5f757f3fSDimitry Andric MachineBasicBlock *PrevBB = nullptr; 161*5f757f3fSDimitry Andric for (unsigned BBID : ClonePath) { 162*5f757f3fSDimitry Andric MachineBasicBlock *OrigBB = BBIDToBlock.at(BBID); 163*5f757f3fSDimitry Andric if (PrevBB == nullptr) { 164*5f757f3fSDimitry Andric // The first block in the path is not cloned. We only need to make it 165*5f757f3fSDimitry Andric // branch to the next cloned block in the path. Here, we make its 166*5f757f3fSDimitry Andric // fallthrough explicit so we can change it later. 167*5f757f3fSDimitry Andric if (auto FT = OrigBB->getFallThrough(/*JumpToFallThrough=*/false)) { 168*5f757f3fSDimitry Andric TII->insertUnconditionalBranch(*OrigBB, FT, 169*5f757f3fSDimitry Andric OrigBB->findBranchDebugLoc()); 170*5f757f3fSDimitry Andric } 171*5f757f3fSDimitry Andric PrevBB = OrigBB; 172*5f757f3fSDimitry Andric continue; 173*5f757f3fSDimitry Andric } 174*5f757f3fSDimitry Andric MachineBasicBlock *CloneBB = 175*5f757f3fSDimitry Andric CloneMachineBasicBlock(*OrigBB, ++NClonesForBBID[BBID]); 176*5f757f3fSDimitry Andric 177*5f757f3fSDimitry Andric // Set up the previous block in the path to jump to the clone. This also 178*5f757f3fSDimitry Andric // transfers the successor/predecessor relationship of PrevBB and OrigBB 179*5f757f3fSDimitry Andric // to that of PrevBB and CloneBB. 180*5f757f3fSDimitry Andric PrevBB->ReplaceUsesOfBlockWith(OrigBB, CloneBB); 181*5f757f3fSDimitry Andric 182*5f757f3fSDimitry Andric // Copy the livein set. 183*5f757f3fSDimitry Andric for (auto &LiveIn : OrigBB->liveins()) 184*5f757f3fSDimitry Andric CloneBB->addLiveIn(LiveIn); 185*5f757f3fSDimitry Andric 186*5f757f3fSDimitry Andric PrevBB = CloneBB; 187*5f757f3fSDimitry Andric } 188*5f757f3fSDimitry Andric AnyPathsCloned = true; 189*5f757f3fSDimitry Andric } 190*5f757f3fSDimitry Andric return AnyPathsCloned; 191*5f757f3fSDimitry Andric } 192*5f757f3fSDimitry Andric } // end anonymous namespace 193*5f757f3fSDimitry Andric 194*5f757f3fSDimitry Andric namespace llvm { 195*5f757f3fSDimitry Andric class BasicBlockPathCloning : public MachineFunctionPass { 196*5f757f3fSDimitry Andric public: 197*5f757f3fSDimitry Andric static char ID; 198*5f757f3fSDimitry Andric 199*5f757f3fSDimitry Andric BasicBlockSectionsProfileReader *BBSectionsProfileReader = nullptr; 200*5f757f3fSDimitry Andric 201*5f757f3fSDimitry Andric BasicBlockPathCloning() : MachineFunctionPass(ID) { 202*5f757f3fSDimitry Andric initializeBasicBlockPathCloningPass(*PassRegistry::getPassRegistry()); 203*5f757f3fSDimitry Andric } 204*5f757f3fSDimitry Andric 205*5f757f3fSDimitry Andric StringRef getPassName() const override { return "Basic Block Path Cloning"; } 206*5f757f3fSDimitry Andric 207*5f757f3fSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 208*5f757f3fSDimitry Andric 209*5f757f3fSDimitry Andric /// Identify basic blocks that need separate sections and prepare to emit them 210*5f757f3fSDimitry Andric /// accordingly. 211*5f757f3fSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 212*5f757f3fSDimitry Andric }; 213*5f757f3fSDimitry Andric 214*5f757f3fSDimitry Andric } // namespace llvm 215*5f757f3fSDimitry Andric 216*5f757f3fSDimitry Andric char BasicBlockPathCloning::ID = 0; 217*5f757f3fSDimitry Andric INITIALIZE_PASS_BEGIN( 218*5f757f3fSDimitry Andric BasicBlockPathCloning, "bb-path-cloning", 219*5f757f3fSDimitry Andric "Applies path clonings for the -basic-block-sections=list option", false, 220*5f757f3fSDimitry Andric false) 221*5f757f3fSDimitry Andric INITIALIZE_PASS_DEPENDENCY(BasicBlockSectionsProfileReader) 222*5f757f3fSDimitry Andric INITIALIZE_PASS_END( 223*5f757f3fSDimitry Andric BasicBlockPathCloning, "bb-path-cloning", 224*5f757f3fSDimitry Andric "Applies path clonings for the -basic-block-sections=list option", false, 225*5f757f3fSDimitry Andric false) 226*5f757f3fSDimitry Andric 227*5f757f3fSDimitry Andric bool BasicBlockPathCloning::runOnMachineFunction(MachineFunction &MF) { 228*5f757f3fSDimitry Andric assert(MF.getTarget().getBBSectionsType() == BasicBlockSection::List && 229*5f757f3fSDimitry Andric "BB Sections list not enabled!"); 230*5f757f3fSDimitry Andric if (hasInstrProfHashMismatch(MF)) 231*5f757f3fSDimitry Andric return false; 232*5f757f3fSDimitry Andric 233*5f757f3fSDimitry Andric return ApplyCloning(MF, getAnalysis<BasicBlockSectionsProfileReader>() 234*5f757f3fSDimitry Andric .getClonePathsForFunction(MF.getName())); 235*5f757f3fSDimitry Andric } 236*5f757f3fSDimitry Andric 237*5f757f3fSDimitry Andric void BasicBlockPathCloning::getAnalysisUsage(AnalysisUsage &AU) const { 238*5f757f3fSDimitry Andric AU.setPreservesAll(); 239*5f757f3fSDimitry Andric AU.addRequired<BasicBlockSectionsProfileReader>(); 240*5f757f3fSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 241*5f757f3fSDimitry Andric } 242*5f757f3fSDimitry Andric 243*5f757f3fSDimitry Andric MachineFunctionPass *llvm::createBasicBlockPathCloningPass() { 244*5f757f3fSDimitry Andric return new BasicBlockPathCloning(); 245*5f757f3fSDimitry Andric } 246