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