Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/BasicBlockPathCloning.cpp
35232 views
//===-- BasicBlockPathCloning.cpp ---=========-----------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file9/// BasicBlockPathCloning implementation.10///11/// The purpose of this pass is to clone basic block paths based on information12/// provided by the -fbasic-block-sections=list option.13/// Please refer to BasicBlockSectionsProfileReader.cpp to see a path cloning14/// example.15//===----------------------------------------------------------------------===//16// This pass clones the machine basic blocks alongs the given paths and sets up17// the CFG. It assigns BBIDs to the cloned blocks so that the18// `BasicBlockSections` pass can correctly map the cluster information to the19// blocks. The cloned block's BBID will have the same BaseID as the original20// block, but will get a unique non-zero CloneID (original blocks all have zero21// CloneIDs). This pass applies a path cloning if it satisfies the following22// conditions:23// 1. All BBIDs in the path should be mapped to existing blocks.24// 2. Each two consecutive BBIDs in the path must have a successor25// relationship in the CFG.26// 3. The path should not include a block with indirect branches, except for27// the last block.28// If a path does not satisfy all three conditions, it will be rejected, but the29// CloneIDs for its (supposed to be cloned) blocks will be bypassed to make sure30// that the `BasicBlockSections` pass can map cluster info correctly to the31// actually-cloned blocks.32//===----------------------------------------------------------------------===//3334#include "llvm/ADT/SmallVector.h"35#include "llvm/ADT/StringRef.h"36#include "llvm/CodeGen/BasicBlockSectionUtils.h"37#include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"38#include "llvm/CodeGen/MachineFunction.h"39#include "llvm/CodeGen/MachineFunctionPass.h"40#include "llvm/CodeGen/Passes.h"41#include "llvm/CodeGen/TargetInstrInfo.h"42#include "llvm/InitializePasses.h"43#include "llvm/Support/WithColor.h"44#include "llvm/Target/TargetMachine.h"4546using namespace llvm;4748namespace {4950// Clones the given block and assigns the given `CloneID` to its BBID. Copies51// the instructions into the new block and sets up its successors.52MachineBasicBlock *CloneMachineBasicBlock(MachineBasicBlock &OrigBB,53unsigned CloneID) {54auto &MF = *OrigBB.getParent();55auto TII = MF.getSubtarget().getInstrInfo();56// Create the clone block and set its BBID based on the original block.57MachineBasicBlock *CloneBB = MF.CreateMachineBasicBlock(58OrigBB.getBasicBlock(), UniqueBBID{OrigBB.getBBID()->BaseID, CloneID});59MF.push_back(CloneBB);6061// Copy the instructions.62for (auto &I : OrigBB.instrs()) {63// Bundled instructions are duplicated together.64if (I.isBundledWithPred())65continue;66TII->duplicate(*CloneBB, CloneBB->end(), I);67}6869// Add the successors of the original block as the new block's successors.70// We set the predecessor after returning from this call.71for (auto SI = OrigBB.succ_begin(), SE = OrigBB.succ_end(); SI != SE; ++SI)72CloneBB->copySuccessor(&OrigBB, SI);7374if (auto FT = OrigBB.getFallThrough(/*JumpToFallThrough=*/false)) {75// The original block has an implicit fall through.76// Insert an explicit unconditional jump from the cloned block to the77// fallthrough block. Technically, this is only needed for the last block78// of the path, but we do it for all clones for consistency.79TII->insertUnconditionalBranch(*CloneBB, FT, CloneBB->findBranchDebugLoc());80}81return CloneBB;82}8384// Returns if we can legally apply the cloning represented by `ClonePath`.85// `BBIDToBlock` contains the original basic blocks in function `MF` keyed by86// their `BBID::BaseID`.87bool IsValidCloning(const MachineFunction &MF,88const DenseMap<unsigned, MachineBasicBlock *> &BBIDToBlock,89const SmallVector<unsigned> &ClonePath) {90const MachineBasicBlock *PrevBB = nullptr;91for (size_t I = 0; I < ClonePath.size(); ++I) {92unsigned BBID = ClonePath[I];93const MachineBasicBlock *PathBB = BBIDToBlock.lookup(BBID);94if (!PathBB) {95WithColor::warning() << "no block with id " << BBID << " in function "96<< MF.getName() << "\n";97return false;98}99100if (PrevBB) {101if (!PrevBB->isSuccessor(PathBB)) {102WithColor::warning()103<< "block #" << BBID << " is not a successor of block #"104<< PrevBB->getBBID()->BaseID << " in function " << MF.getName()105<< "\n";106return false;107}108109for (auto &MI : *PathBB) {110// Avoid cloning when the block contains non-duplicable instructions.111// CFI instructions are marked as non-duplicable only because of Darwin,112// so we exclude them from this check.113if (MI.isNotDuplicable() && !MI.isCFIInstruction()) {114WithColor::warning()115<< "block #" << BBID116<< " has non-duplicable instructions in function " << MF.getName()117<< "\n";118return false;119}120}121if (PathBB->isMachineBlockAddressTaken()) {122// Avoid cloning blocks which have their address taken since we can't123// rewire branches to those blocks as easily (e.g., branches within124// inline assembly).125WithColor::warning()126<< "block #" << BBID127<< " has its machine block address taken in function "128<< MF.getName() << "\n";129return false;130}131}132133if (I != ClonePath.size() - 1 && !PathBB->empty() &&134PathBB->back().isIndirectBranch()) {135WithColor::warning()136<< "block #" << BBID137<< " has indirect branch and appears as the non-tail block of a "138"path in function "139<< MF.getName() << "\n";140return false;141}142PrevBB = PathBB;143}144return true;145}146147// Applies all clonings specified in `ClonePaths` to `MF`. Returns true148// if any clonings have been applied.149bool ApplyCloning(MachineFunction &MF,150const SmallVector<SmallVector<unsigned>> &ClonePaths) {151if (ClonePaths.empty())152return false;153bool AnyPathsCloned = false;154// Map from the final BB IDs to the `MachineBasicBlock`s.155DenseMap<unsigned, MachineBasicBlock *> BBIDToBlock;156for (auto &BB : MF)157BBIDToBlock.try_emplace(BB.getBBID()->BaseID, &BB);158159DenseMap<unsigned, unsigned> NClonesForBBID;160auto TII = MF.getSubtarget().getInstrInfo();161for (const auto &ClonePath : ClonePaths) {162if (!IsValidCloning(MF, BBIDToBlock, ClonePath)) {163// We still need to increment the number of clones so we can map164// to the cluster info correctly.165for (unsigned BBID : ClonePath)166++NClonesForBBID[BBID];167continue;168}169MachineBasicBlock *PrevBB = nullptr;170for (unsigned BBID : ClonePath) {171MachineBasicBlock *OrigBB = BBIDToBlock.at(BBID);172if (PrevBB == nullptr) {173// The first block in the path is not cloned. We only need to make it174// branch to the next cloned block in the path. Here, we make its175// fallthrough explicit so we can change it later.176if (auto FT = OrigBB->getFallThrough(/*JumpToFallThrough=*/false)) {177TII->insertUnconditionalBranch(*OrigBB, FT,178OrigBB->findBranchDebugLoc());179}180PrevBB = OrigBB;181continue;182}183MachineBasicBlock *CloneBB =184CloneMachineBasicBlock(*OrigBB, ++NClonesForBBID[BBID]);185186// Set up the previous block in the path to jump to the clone. This also187// transfers the successor/predecessor relationship of PrevBB and OrigBB188// to that of PrevBB and CloneBB.189PrevBB->ReplaceUsesOfBlockWith(OrigBB, CloneBB);190191// Copy the livein set.192for (auto &LiveIn : OrigBB->liveins())193CloneBB->addLiveIn(LiveIn);194195PrevBB = CloneBB;196}197AnyPathsCloned = true;198}199return AnyPathsCloned;200}201} // end anonymous namespace202203namespace llvm {204class BasicBlockPathCloning : public MachineFunctionPass {205public:206static char ID;207208BasicBlockSectionsProfileReaderWrapperPass *BBSectionsProfileReader = nullptr;209210BasicBlockPathCloning() : MachineFunctionPass(ID) {211initializeBasicBlockPathCloningPass(*PassRegistry::getPassRegistry());212}213214StringRef getPassName() const override { return "Basic Block Path Cloning"; }215216void getAnalysisUsage(AnalysisUsage &AU) const override;217218/// Identify basic blocks that need separate sections and prepare to emit them219/// accordingly.220bool runOnMachineFunction(MachineFunction &MF) override;221};222223} // namespace llvm224225char BasicBlockPathCloning::ID = 0;226INITIALIZE_PASS_BEGIN(227BasicBlockPathCloning, "bb-path-cloning",228"Applies path clonings for the -basic-block-sections=list option", false,229false)230INITIALIZE_PASS_DEPENDENCY(BasicBlockSectionsProfileReaderWrapperPass)231INITIALIZE_PASS_END(232BasicBlockPathCloning, "bb-path-cloning",233"Applies path clonings for the -basic-block-sections=list option", false,234false)235236bool BasicBlockPathCloning::runOnMachineFunction(MachineFunction &MF) {237assert(MF.getTarget().getBBSectionsType() == BasicBlockSection::List &&238"BB Sections list not enabled!");239if (hasInstrProfHashMismatch(MF))240return false;241242return ApplyCloning(MF,243getAnalysis<BasicBlockSectionsProfileReaderWrapperPass>()244.getClonePathsForFunction(MF.getName()));245}246247void BasicBlockPathCloning::getAnalysisUsage(AnalysisUsage &AU) const {248AU.setPreservesAll();249AU.addRequired<BasicBlockSectionsProfileReaderWrapperPass>();250MachineFunctionPass::getAnalysisUsage(AU);251}252253MachineFunctionPass *llvm::createBasicBlockPathCloningPass() {254return new BasicBlockPathCloning();255}256257258