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