//===-- BasicBlockPathCloning.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 // //===----------------------------------------------------------------------===// // /// \file /// BasicBlockPathCloning implementation. /// /// The purpose of this pass is to clone basic block paths based on information /// provided by the -fbasic-block-sections=list option. /// Please refer to BasicBlockSectionsProfileReader.cpp to see a path cloning /// example. //===----------------------------------------------------------------------===// // This pass clones the machine basic blocks alongs the given paths and sets up // the CFG. It assigns BBIDs to the cloned blocks so that the // `BasicBlockSections` pass can correctly map the cluster information to the // blocks. The cloned block's BBID will have the same BaseID as the original // block, but will get a unique non-zero CloneID (original blocks all have zero // CloneIDs). This pass applies a path cloning if it satisfies the following // conditions: // 1. All BBIDs in the path should be mapped to existing blocks. // 2. Each two consecutive BBIDs in the path must have a successor // relationship in the CFG. // 3. The path should not include a block with indirect branches, except for // the last block. // If a path does not satisfy all three conditions, it will be rejected, but the // CloneIDs for its (supposed to be cloned) blocks will be bypassed to make sure // that the `BasicBlockSections` pass can map cluster info correctly to the // actually-cloned blocks. //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/BasicBlockSectionUtils.h" #include "llvm/CodeGen/BasicBlockSectionsProfileReader.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/InitializePasses.h" #include "llvm/Support/WithColor.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; namespace { // Clones the given block and assigns the given `CloneID` to its BBID. Copies // the instructions into the new block and sets up its successors. MachineBasicBlock *CloneMachineBasicBlock(MachineBasicBlock &OrigBB, unsigned CloneID) { auto &MF = *OrigBB.getParent(); auto TII = MF.getSubtarget().getInstrInfo(); // Create the clone block and set its BBID based on the original block. MachineBasicBlock *CloneBB = MF.CreateMachineBasicBlock( OrigBB.getBasicBlock(), UniqueBBID{OrigBB.getBBID()->BaseID, CloneID}); MF.push_back(CloneBB); // Copy the instructions. for (auto &I : OrigBB.instrs()) { // Bundled instructions are duplicated together. if (I.isBundledWithPred()) continue; TII->duplicate(*CloneBB, CloneBB->end(), I); } // Add the successors of the original block as the new block's successors. // We set the predecessor after returning from this call. for (auto SI = OrigBB.succ_begin(), SE = OrigBB.succ_end(); SI != SE; ++SI) CloneBB->copySuccessor(&OrigBB, SI); if (auto FT = OrigBB.getFallThrough(/*JumpToFallThrough=*/false)) { // The original block has an implicit fall through. // Insert an explicit unconditional jump from the cloned block to the // fallthrough block. Technically, this is only needed for the last block // of the path, but we do it for all clones for consistency. TII->insertUnconditionalBranch(*CloneBB, FT, CloneBB->findBranchDebugLoc()); } return CloneBB; } // Returns if we can legally apply the cloning represented by `ClonePath`. // `BBIDToBlock` contains the original basic blocks in function `MF` keyed by // their `BBID::BaseID`. bool IsValidCloning(const MachineFunction &MF, const DenseMap &BBIDToBlock, const SmallVector &ClonePath) { const MachineBasicBlock *PrevBB = nullptr; for (size_t I = 0; I < ClonePath.size(); ++I) { unsigned BBID = ClonePath[I]; const MachineBasicBlock *PathBB = BBIDToBlock.lookup(BBID); if (!PathBB) { WithColor::warning() << "no block with id " << BBID << " in function " << MF.getName() << "\n"; return false; } if (PrevBB) { if (!PrevBB->isSuccessor(PathBB)) { WithColor::warning() << "block #" << BBID << " is not a successor of block #" << PrevBB->getBBID()->BaseID << " in function " << MF.getName() << "\n"; return false; } for (auto &MI : *PathBB) { // Avoid cloning when the block contains non-duplicable instructions. // CFI instructions are marked as non-duplicable only because of Darwin, // so we exclude them from this check. if (MI.isNotDuplicable() && !MI.isCFIInstruction()) { WithColor::warning() << "block #" << BBID << " has non-duplicable instructions in function " << MF.getName() << "\n"; return false; } } if (PathBB->isMachineBlockAddressTaken()) { // Avoid cloning blocks which have their address taken since we can't // rewire branches to those blocks as easily (e.g., branches within // inline assembly). WithColor::warning() << "block #" << BBID << " has its machine block address taken in function " << MF.getName() << "\n"; return false; } } if (I != ClonePath.size() - 1 && !PathBB->empty() && PathBB->back().isIndirectBranch()) { WithColor::warning() << "block #" << BBID << " has indirect branch and appears as the non-tail block of a " "path in function " << MF.getName() << "\n"; return false; } PrevBB = PathBB; } return true; } // Applies all clonings specified in `ClonePaths` to `MF`. Returns true // if any clonings have been applied. bool ApplyCloning(MachineFunction &MF, const SmallVector> &ClonePaths) { if (ClonePaths.empty()) return false; bool AnyPathsCloned = false; // Map from the final BB IDs to the `MachineBasicBlock`s. DenseMap BBIDToBlock; for (auto &BB : MF) BBIDToBlock.try_emplace(BB.getBBID()->BaseID, &BB); DenseMap NClonesForBBID; auto TII = MF.getSubtarget().getInstrInfo(); for (const auto &ClonePath : ClonePaths) { if (!IsValidCloning(MF, BBIDToBlock, ClonePath)) { // We still need to increment the number of clones so we can map // to the cluster info correctly. for (unsigned BBID : ClonePath) ++NClonesForBBID[BBID]; continue; } MachineBasicBlock *PrevBB = nullptr; for (unsigned BBID : ClonePath) { MachineBasicBlock *OrigBB = BBIDToBlock.at(BBID); if (PrevBB == nullptr) { // The first block in the path is not cloned. We only need to make it // branch to the next cloned block in the path. Here, we make its // fallthrough explicit so we can change it later. if (auto FT = OrigBB->getFallThrough(/*JumpToFallThrough=*/false)) { TII->insertUnconditionalBranch(*OrigBB, FT, OrigBB->findBranchDebugLoc()); } PrevBB = OrigBB; continue; } MachineBasicBlock *CloneBB = CloneMachineBasicBlock(*OrigBB, ++NClonesForBBID[BBID]); // Set up the previous block in the path to jump to the clone. This also // transfers the successor/predecessor relationship of PrevBB and OrigBB // to that of PrevBB and CloneBB. PrevBB->ReplaceUsesOfBlockWith(OrigBB, CloneBB); // Copy the livein set. for (auto &LiveIn : OrigBB->liveins()) CloneBB->addLiveIn(LiveIn); PrevBB = CloneBB; } AnyPathsCloned = true; } return AnyPathsCloned; } } // end anonymous namespace namespace llvm { class BasicBlockPathCloning : public MachineFunctionPass { public: static char ID; BasicBlockSectionsProfileReaderWrapperPass *BBSectionsProfileReader = nullptr; BasicBlockPathCloning() : MachineFunctionPass(ID) { initializeBasicBlockPathCloningPass(*PassRegistry::getPassRegistry()); } StringRef getPassName() const override { return "Basic Block Path Cloning"; } void getAnalysisUsage(AnalysisUsage &AU) const override; /// Identify basic blocks that need separate sections and prepare to emit them /// accordingly. bool runOnMachineFunction(MachineFunction &MF) override; }; } // namespace llvm char BasicBlockPathCloning::ID = 0; INITIALIZE_PASS_BEGIN( BasicBlockPathCloning, "bb-path-cloning", "Applies path clonings for the -basic-block-sections=list option", false, false) INITIALIZE_PASS_DEPENDENCY(BasicBlockSectionsProfileReaderWrapperPass) INITIALIZE_PASS_END( BasicBlockPathCloning, "bb-path-cloning", "Applies path clonings for the -basic-block-sections=list option", false, false) bool BasicBlockPathCloning::runOnMachineFunction(MachineFunction &MF) { assert(MF.getTarget().getBBSectionsType() == BasicBlockSection::List && "BB Sections list not enabled!"); if (hasInstrProfHashMismatch(MF)) return false; return ApplyCloning(MF, getAnalysis() .getClonePathsForFunction(MF.getName())); } void BasicBlockPathCloning::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } MachineFunctionPass *llvm::createBasicBlockPathCloningPass() { return new BasicBlockPathCloning(); }