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