xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/BasicBlockPathCloning.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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