1*da58b97aSjoerg //===-- ARMBlockPlacement.cpp - ARM block placement pass ------------===//
2*da58b97aSjoerg //
3*da58b97aSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*da58b97aSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*da58b97aSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*da58b97aSjoerg //
7*da58b97aSjoerg //===----------------------------------------------------------------------===//
8*da58b97aSjoerg //
9*da58b97aSjoerg // This pass re-arranges machine basic blocks to suit target requirements.
10*da58b97aSjoerg // Currently it only moves blocks to fix backwards WLS branches.
11*da58b97aSjoerg //
12*da58b97aSjoerg //===----------------------------------------------------------------------===//
13*da58b97aSjoerg 
14*da58b97aSjoerg #include "ARM.h"
15*da58b97aSjoerg #include "ARMBaseInstrInfo.h"
16*da58b97aSjoerg #include "ARMBasicBlockInfo.h"
17*da58b97aSjoerg #include "ARMSubtarget.h"
18*da58b97aSjoerg #include "llvm/CodeGen/MachineFunctionPass.h"
19*da58b97aSjoerg #include "llvm/CodeGen/MachineInstrBuilder.h"
20*da58b97aSjoerg #include "llvm/CodeGen/MachineLoopInfo.h"
21*da58b97aSjoerg 
22*da58b97aSjoerg using namespace llvm;
23*da58b97aSjoerg 
24*da58b97aSjoerg #define DEBUG_TYPE "arm-block-placement"
25*da58b97aSjoerg #define DEBUG_PREFIX "ARM Block Placement: "
26*da58b97aSjoerg 
27*da58b97aSjoerg namespace llvm {
28*da58b97aSjoerg class ARMBlockPlacement : public MachineFunctionPass {
29*da58b97aSjoerg private:
30*da58b97aSjoerg   const ARMBaseInstrInfo *TII;
31*da58b97aSjoerg   std::unique_ptr<ARMBasicBlockUtils> BBUtils = nullptr;
32*da58b97aSjoerg   MachineLoopInfo *MLI = nullptr;
33*da58b97aSjoerg 
34*da58b97aSjoerg public:
35*da58b97aSjoerg   static char ID;
ARMBlockPlacement()36*da58b97aSjoerg   ARMBlockPlacement() : MachineFunctionPass(ID) {}
37*da58b97aSjoerg 
38*da58b97aSjoerg   bool runOnMachineFunction(MachineFunction &MF) override;
39*da58b97aSjoerg   void moveBasicBlock(MachineBasicBlock *BB, MachineBasicBlock *Before);
40*da58b97aSjoerg   bool blockIsBefore(MachineBasicBlock *BB, MachineBasicBlock *Other);
41*da58b97aSjoerg   bool fixBackwardsWLS(MachineLoop *ML);
42*da58b97aSjoerg   bool processPostOrderLoops(MachineLoop *ML);
43*da58b97aSjoerg 
getAnalysisUsage(AnalysisUsage & AU) const44*da58b97aSjoerg   void getAnalysisUsage(AnalysisUsage &AU) const override {
45*da58b97aSjoerg     AU.setPreservesCFG();
46*da58b97aSjoerg     AU.addRequired<MachineLoopInfo>();
47*da58b97aSjoerg     MachineFunctionPass::getAnalysisUsage(AU);
48*da58b97aSjoerg   }
49*da58b97aSjoerg };
50*da58b97aSjoerg 
51*da58b97aSjoerg } // namespace llvm
52*da58b97aSjoerg 
createARMBlockPlacementPass()53*da58b97aSjoerg FunctionPass *llvm::createARMBlockPlacementPass() {
54*da58b97aSjoerg   return new ARMBlockPlacement();
55*da58b97aSjoerg }
56*da58b97aSjoerg 
57*da58b97aSjoerg char ARMBlockPlacement::ID = 0;
58*da58b97aSjoerg 
59*da58b97aSjoerg INITIALIZE_PASS(ARMBlockPlacement, DEBUG_TYPE, "ARM block placement", false,
60*da58b97aSjoerg                 false)
61*da58b97aSjoerg 
findWLSInBlock(MachineBasicBlock * MBB)62*da58b97aSjoerg static MachineInstr *findWLSInBlock(MachineBasicBlock *MBB) {
63*da58b97aSjoerg   for (auto &Terminator : MBB->terminators()) {
64*da58b97aSjoerg     if (Terminator.getOpcode() == ARM::t2WhileLoopStartLR)
65*da58b97aSjoerg       return &Terminator;
66*da58b97aSjoerg   }
67*da58b97aSjoerg   return nullptr;
68*da58b97aSjoerg }
69*da58b97aSjoerg 
70*da58b97aSjoerg /// Find t2WhileLoopStartLR in the loop predecessor BB or otherwise in its only
71*da58b97aSjoerg /// predecessor. If found, returns (BB, WLS Instr) pair, otherwise a null pair.
findWLS(MachineLoop * ML)72*da58b97aSjoerg static MachineInstr *findWLS(MachineLoop *ML) {
73*da58b97aSjoerg   MachineBasicBlock *Predecessor = ML->getLoopPredecessor();
74*da58b97aSjoerg   if (!Predecessor)
75*da58b97aSjoerg     return nullptr;
76*da58b97aSjoerg   MachineInstr *WlsInstr = findWLSInBlock(Predecessor);
77*da58b97aSjoerg   if (WlsInstr)
78*da58b97aSjoerg     return WlsInstr;
79*da58b97aSjoerg   if (Predecessor->pred_size() == 1)
80*da58b97aSjoerg     return findWLSInBlock(*Predecessor->pred_begin());
81*da58b97aSjoerg   return nullptr;
82*da58b97aSjoerg }
83*da58b97aSjoerg 
84*da58b97aSjoerg /// Checks if loop has a backwards branching WLS, and if possible, fixes it.
85*da58b97aSjoerg /// This requires checking the predecessor (ie. preheader or it's predecessor)
86*da58b97aSjoerg /// for a WLS and if its loopExit/target is before it.
87*da58b97aSjoerg /// If moving the predecessor won't convert a WLS (to the predecessor) from
88*da58b97aSjoerg /// a forward to a backward branching WLS, then move the predecessor block
89*da58b97aSjoerg /// to before the loopExit/target.
fixBackwardsWLS(MachineLoop * ML)90*da58b97aSjoerg bool ARMBlockPlacement::fixBackwardsWLS(MachineLoop *ML) {
91*da58b97aSjoerg   MachineInstr *WlsInstr = findWLS(ML);
92*da58b97aSjoerg   if (!WlsInstr)
93*da58b97aSjoerg     return false;
94*da58b97aSjoerg 
95*da58b97aSjoerg   MachineBasicBlock *Predecessor = WlsInstr->getParent();
96*da58b97aSjoerg   MachineBasicBlock *LoopExit = WlsInstr->getOperand(2).getMBB();
97*da58b97aSjoerg 
98*da58b97aSjoerg   // We don't want to move Preheader to before the function's entry block.
99*da58b97aSjoerg   if (!LoopExit->getPrevNode())
100*da58b97aSjoerg     return false;
101*da58b97aSjoerg   if (blockIsBefore(Predecessor, LoopExit))
102*da58b97aSjoerg     return false;
103*da58b97aSjoerg   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Found a backwards WLS from "
104*da58b97aSjoerg                     << Predecessor->getFullName() << " to "
105*da58b97aSjoerg                     << LoopExit->getFullName() << "\n");
106*da58b97aSjoerg 
107*da58b97aSjoerg   // Make sure no forward branching WLSs to the Predecessor become backwards
108*da58b97aSjoerg   // branching. An example loop structure where the Predecessor can't be moved,
109*da58b97aSjoerg   // since bb2's WLS will become forwards once bb3 is moved before/above bb1.
110*da58b97aSjoerg   //
111*da58b97aSjoerg   // bb1:           - LoopExit
112*da58b97aSjoerg   // bb2:
113*da58b97aSjoerg   //      WLS  bb3
114*da58b97aSjoerg   // bb3:          - Predecessor
115*da58b97aSjoerg   //      WLS bb1
116*da58b97aSjoerg   // bb4:          - Header
117*da58b97aSjoerg   for (auto It = ++LoopExit->getIterator(); It != Predecessor->getIterator();
118*da58b97aSjoerg        ++It) {
119*da58b97aSjoerg     MachineBasicBlock *MBB = &*It;
120*da58b97aSjoerg     for (auto &Terminator : MBB->terminators()) {
121*da58b97aSjoerg       if (Terminator.getOpcode() != ARM::t2WhileLoopStartLR)
122*da58b97aSjoerg         continue;
123*da58b97aSjoerg       MachineBasicBlock *WLSTarget = Terminator.getOperand(2).getMBB();
124*da58b97aSjoerg       // TODO: Analyse the blocks to make a decision if it would be worth
125*da58b97aSjoerg       // moving Preheader even if we'd introduce a backwards WLS
126*da58b97aSjoerg       if (WLSTarget == Predecessor) {
127*da58b97aSjoerg         LLVM_DEBUG(
128*da58b97aSjoerg             dbgs() << DEBUG_PREFIX
129*da58b97aSjoerg                    << "Can't move Predecessor"
130*da58b97aSjoerg                       "block as it would convert a WLS from forward to a "
131*da58b97aSjoerg                       "backwards branching WLS\n");
132*da58b97aSjoerg         return false;
133*da58b97aSjoerg       }
134*da58b97aSjoerg     }
135*da58b97aSjoerg   }
136*da58b97aSjoerg 
137*da58b97aSjoerg   moveBasicBlock(Predecessor, LoopExit);
138*da58b97aSjoerg   return true;
139*da58b97aSjoerg }
140*da58b97aSjoerg 
141*da58b97aSjoerg /// Updates ordering (of WLS BB and their loopExits) in inner loops first
142*da58b97aSjoerg /// Returns true if any change was made in any of the loops
processPostOrderLoops(MachineLoop * ML)143*da58b97aSjoerg bool ARMBlockPlacement::processPostOrderLoops(MachineLoop *ML) {
144*da58b97aSjoerg   bool Changed = false;
145*da58b97aSjoerg   for (auto *InnerML : *ML)
146*da58b97aSjoerg     Changed |= processPostOrderLoops(InnerML);
147*da58b97aSjoerg   return Changed | fixBackwardsWLS(ML);
148*da58b97aSjoerg }
149*da58b97aSjoerg 
runOnMachineFunction(MachineFunction & MF)150*da58b97aSjoerg bool ARMBlockPlacement::runOnMachineFunction(MachineFunction &MF) {
151*da58b97aSjoerg   if (skipFunction(MF.getFunction()))
152*da58b97aSjoerg     return false;
153*da58b97aSjoerg   const ARMSubtarget &ST = static_cast<const ARMSubtarget &>(MF.getSubtarget());
154*da58b97aSjoerg   if (!ST.hasLOB())
155*da58b97aSjoerg     return false;
156*da58b97aSjoerg   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Running on " << MF.getName() << "\n");
157*da58b97aSjoerg   MLI = &getAnalysis<MachineLoopInfo>();
158*da58b97aSjoerg   TII = static_cast<const ARMBaseInstrInfo *>(ST.getInstrInfo());
159*da58b97aSjoerg   BBUtils = std::unique_ptr<ARMBasicBlockUtils>(new ARMBasicBlockUtils(MF));
160*da58b97aSjoerg   MF.RenumberBlocks();
161*da58b97aSjoerg   BBUtils->computeAllBlockSizes();
162*da58b97aSjoerg   BBUtils->adjustBBOffsetsAfter(&MF.front());
163*da58b97aSjoerg   bool Changed = false;
164*da58b97aSjoerg 
165*da58b97aSjoerg   // Find loops with a backwards branching WLS and fix if possible.
166*da58b97aSjoerg   for (auto *ML : *MLI)
167*da58b97aSjoerg     Changed |= processPostOrderLoops(ML);
168*da58b97aSjoerg 
169*da58b97aSjoerg   return Changed;
170*da58b97aSjoerg }
171*da58b97aSjoerg 
blockIsBefore(MachineBasicBlock * BB,MachineBasicBlock * Other)172*da58b97aSjoerg bool ARMBlockPlacement::blockIsBefore(MachineBasicBlock *BB,
173*da58b97aSjoerg                                       MachineBasicBlock *Other) {
174*da58b97aSjoerg   return BBUtils->getOffsetOf(Other) > BBUtils->getOffsetOf(BB);
175*da58b97aSjoerg }
176*da58b97aSjoerg 
177*da58b97aSjoerg // Moves a BasicBlock before another, without changing the control flow
moveBasicBlock(MachineBasicBlock * BB,MachineBasicBlock * Before)178*da58b97aSjoerg void ARMBlockPlacement::moveBasicBlock(MachineBasicBlock *BB,
179*da58b97aSjoerg                                        MachineBasicBlock *Before) {
180*da58b97aSjoerg   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Moving " << BB->getName() << " before "
181*da58b97aSjoerg                     << Before->getName() << "\n");
182*da58b97aSjoerg   MachineBasicBlock *BBPrevious = BB->getPrevNode();
183*da58b97aSjoerg   assert(BBPrevious && "Cannot move the function entry basic block");
184*da58b97aSjoerg   MachineBasicBlock *BBNext = BB->getNextNode();
185*da58b97aSjoerg 
186*da58b97aSjoerg   MachineBasicBlock *BeforePrev = Before->getPrevNode();
187*da58b97aSjoerg   assert(BeforePrev &&
188*da58b97aSjoerg          "Cannot move the given block to before the function entry block");
189*da58b97aSjoerg   MachineFunction *F = BB->getParent();
190*da58b97aSjoerg   BB->moveBefore(Before);
191*da58b97aSjoerg 
192*da58b97aSjoerg   // Since only the blocks are to be moved around (but the control flow must
193*da58b97aSjoerg   // not change), if there were any fall-throughs (to/from adjacent blocks),
194*da58b97aSjoerg   // replace with unconditional branch to the fall through block.
195*da58b97aSjoerg   auto FixFallthrough = [&](MachineBasicBlock *From, MachineBasicBlock *To) {
196*da58b97aSjoerg     LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Checking for fallthrough from "
197*da58b97aSjoerg                       << From->getName() << " to " << To->getName() << "\n");
198*da58b97aSjoerg     assert(From->isSuccessor(To) &&
199*da58b97aSjoerg            "'To' is expected to be a successor of 'From'");
200*da58b97aSjoerg     MachineInstr &Terminator = *(--From->terminators().end());
201*da58b97aSjoerg     if (!Terminator.isUnconditionalBranch()) {
202*da58b97aSjoerg       // The BB doesn't have an unconditional branch so it relied on
203*da58b97aSjoerg       // fall-through. Fix by adding an unconditional branch to the moved BB.
204*da58b97aSjoerg       MachineInstrBuilder MIB =
205*da58b97aSjoerg           BuildMI(From, Terminator.getDebugLoc(), TII->get(ARM::t2B));
206*da58b97aSjoerg       MIB.addMBB(To);
207*da58b97aSjoerg       MIB.addImm(ARMCC::CondCodes::AL);
208*da58b97aSjoerg       MIB.addReg(ARM::NoRegister);
209*da58b97aSjoerg       LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Adding unconditional branch from "
210*da58b97aSjoerg                         << From->getName() << " to " << To->getName() << ": "
211*da58b97aSjoerg                         << *MIB.getInstr());
212*da58b97aSjoerg     }
213*da58b97aSjoerg   };
214*da58b97aSjoerg 
215*da58b97aSjoerg   // Fix fall-through to the moved BB from the one that used to be before it.
216*da58b97aSjoerg   if (BBPrevious->isSuccessor(BB))
217*da58b97aSjoerg     FixFallthrough(BBPrevious, BB);
218*da58b97aSjoerg   // Fix fall through from the destination BB to the one that used to before it.
219*da58b97aSjoerg   if (BeforePrev->isSuccessor(Before))
220*da58b97aSjoerg     FixFallthrough(BeforePrev, Before);
221*da58b97aSjoerg   // Fix fall through from the moved BB to the one that used to follow.
222*da58b97aSjoerg   if (BBNext && BB->isSuccessor(BBNext))
223*da58b97aSjoerg     FixFallthrough(BB, BBNext);
224*da58b97aSjoerg 
225*da58b97aSjoerg   F->RenumberBlocks();
226*da58b97aSjoerg   BBUtils->computeAllBlockSizes();
227*da58b97aSjoerg   BBUtils->adjustBBOffsetsAfter(&F->front());
228*da58b97aSjoerg }
229