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