xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/ARMBlockPlacement.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===-- ARMBlockPlacement.cpp - ARM block placement pass ------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass re-arranges machine basic blocks to suit target requirements.
10 // Currently it only moves blocks to fix backwards WLS branches.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "ARM.h"
15 #include "ARMBaseInstrInfo.h"
16 #include "ARMBasicBlockInfo.h"
17 #include "ARMSubtarget.h"
18 #include "MVETailPredUtils.h"
19 #include "llvm/CodeGen/LivePhysRegs.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/MachineLoopInfo.h"
23 
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "arm-block-placement"
27 #define DEBUG_PREFIX "ARM Block Placement: "
28 
29 namespace llvm {
30 class ARMBlockPlacement : public MachineFunctionPass {
31 private:
32   const ARMBaseInstrInfo *TII;
33   std::unique_ptr<ARMBasicBlockUtils> BBUtils = nullptr;
34   MachineLoopInfo *MLI = nullptr;
35   // A list of WLS instructions that need to be reverted to DLS.
36   SmallVector<MachineInstr *> RevertedWhileLoops;
37 
38 public:
39   static char ID;
ARMBlockPlacement()40   ARMBlockPlacement() : MachineFunctionPass(ID) {}
41 
42   bool runOnMachineFunction(MachineFunction &MF) override;
43   void moveBasicBlock(MachineBasicBlock *BB, MachineBasicBlock *Before);
44   bool blockIsBefore(MachineBasicBlock *BB, MachineBasicBlock *Other);
45   bool fixBackwardsWLS(MachineLoop *ML);
46   bool processPostOrderLoops(MachineLoop *ML);
47   bool revertWhileToDoLoop(MachineInstr *WLS);
48 
getAnalysisUsage(AnalysisUsage & AU) const49   void getAnalysisUsage(AnalysisUsage &AU) const override {
50     AU.addRequired<MachineLoopInfoWrapperPass>();
51     MachineFunctionPass::getAnalysisUsage(AU);
52   }
53 };
54 
55 } // namespace llvm
56 
createARMBlockPlacementPass()57 FunctionPass *llvm::createARMBlockPlacementPass() {
58   return new ARMBlockPlacement();
59 }
60 
61 char ARMBlockPlacement::ID = 0;
62 
63 INITIALIZE_PASS(ARMBlockPlacement, DEBUG_TYPE, "ARM block placement", false,
64                 false)
65 
findWLSInBlock(MachineBasicBlock * MBB)66 static MachineInstr *findWLSInBlock(MachineBasicBlock *MBB) {
67   for (auto &Terminator : MBB->terminators()) {
68     if (isWhileLoopStart(Terminator))
69       return &Terminator;
70   }
71   return nullptr;
72 }
73 
74 /// Find WhileLoopStart in the loop predecessor BB or otherwise in its only
75 /// predecessor. If found, returns (BB, WLS Instr) pair, otherwise a null pair.
findWLS(MachineLoop * ML)76 static MachineInstr *findWLS(MachineLoop *ML) {
77   MachineBasicBlock *Predecessor = ML->getLoopPredecessor();
78   if (!Predecessor)
79     return nullptr;
80   MachineInstr *WlsInstr = findWLSInBlock(Predecessor);
81   if (WlsInstr)
82     return WlsInstr;
83   if (Predecessor->pred_size() == 1)
84     return findWLSInBlock(*Predecessor->pred_begin());
85   return nullptr;
86 }
87 
88 // Revert a WhileLoopStart to an equivalent DoLoopStart and branch. Note that
89 // because of the branches this requires an extra block to be created.
revertWhileToDoLoop(MachineInstr * WLS)90 bool ARMBlockPlacement::revertWhileToDoLoop(MachineInstr *WLS) {
91   //   lr = t2WhileLoopStartTP r0, r1, TgtBB
92   //   t2Br Ph
93   // ->
94   //   cmp r0, 0
95   //   brcc TgtBB
96   // block2:
97   //   LR = t2DoLoopStartTP r0, r1
98   //   t2Br Ph
99   MachineBasicBlock *Preheader = WLS->getParent();
100   assert(WLS != &Preheader->back());
101   assert(WLS->getNextNode() == &Preheader->back());
102   MachineInstr *Br = &Preheader->back();
103   assert(Br->getOpcode() == ARM::t2B);
104   assert(Br->getOperand(1).getImm() == 14);
105 
106   // Clear the kill flags, as the cmp/bcc will no longer kill any operands.
107   WLS->getOperand(1).setIsKill(false);
108   if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)
109     WLS->getOperand(2).setIsKill(false);
110 
111   // Create the new block
112   MachineBasicBlock *NewBlock = Preheader->getParent()->CreateMachineBasicBlock(
113       Preheader->getBasicBlock());
114   Preheader->getParent()->insert(++Preheader->getIterator(), NewBlock);
115   // Move the Br to it
116   Br->removeFromParent();
117   NewBlock->insert(NewBlock->end(), Br);
118   // And setup the successors correctly.
119   Preheader->replaceSuccessor(Br->getOperand(0).getMBB(), NewBlock);
120   NewBlock->addSuccessor(Br->getOperand(0).getMBB());
121 
122   // Create a new DLS to replace the WLS
123   MachineInstrBuilder MIB =
124       BuildMI(*NewBlock, Br, WLS->getDebugLoc(),
125               TII->get(WLS->getOpcode() == ARM::t2WhileLoopStartTP
126                            ? ARM::t2DoLoopStartTP
127                            : ARM::t2DoLoopStart));
128   MIB.add(WLS->getOperand(0));
129   MIB.add(WLS->getOperand(1));
130   if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)
131     MIB.add(WLS->getOperand(2));
132 
133   LLVM_DEBUG(dbgs() << DEBUG_PREFIX
134                     << "Reverting While Loop to Do Loop: " << *WLS << "\n");
135 
136   RevertWhileLoopStartLR(WLS, TII, ARM::t2Bcc, true);
137 
138   LivePhysRegs LiveRegs;
139   computeAndAddLiveIns(LiveRegs, *NewBlock);
140 
141   Preheader->getParent()->RenumberBlocks();
142   BBUtils->computeAllBlockSizes();
143   BBUtils->adjustBBOffsetsAfter(Preheader);
144 
145   return true;
146 }
147 
148 /// Checks if loop has a backwards branching WLS, and if possible, fixes it.
149 /// This requires checking the predecessor (ie. preheader or it's predecessor)
150 /// for a WLS and if its loopExit/target is before it.
151 /// If moving the predecessor won't convert a WLS (to the predecessor) from
152 /// a forward to a backward branching WLS, then move the predecessor block
153 /// to before the loopExit/target.
fixBackwardsWLS(MachineLoop * ML)154 bool ARMBlockPlacement::fixBackwardsWLS(MachineLoop *ML) {
155   MachineInstr *WlsInstr = findWLS(ML);
156   if (!WlsInstr)
157     return false;
158 
159   MachineBasicBlock *Predecessor = WlsInstr->getParent();
160   MachineBasicBlock *LoopExit = getWhileLoopStartTargetBB(*WlsInstr);
161 
162   // We don't want to move Preheader to before the function's entry block.
163   if (!LoopExit->getPrevNode())
164     return false;
165   if (blockIsBefore(Predecessor, LoopExit))
166     return false;
167   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Found a backwards WLS from "
168                     << Predecessor->getFullName() << " to "
169                     << LoopExit->getFullName() << "\n");
170 
171   // Make sure no forward branching WLSs to the Predecessor become backwards
172   // branching. An example loop structure where the Predecessor can't be moved,
173   // since bb2's WLS will become forwards once bb3 is moved before/above bb1.
174   //
175   // bb1:           - LoopExit
176   // bb2:
177   //      WLS  bb3
178   // bb3:          - Predecessor
179   //      WLS bb1
180   // bb4:          - Header
181   for (auto It = ++LoopExit->getIterator(); It != Predecessor->getIterator();
182        ++It) {
183     MachineBasicBlock *MBB = &*It;
184     for (auto &Terminator : MBB->terminators()) {
185       if (!isWhileLoopStart(Terminator))
186         continue;
187       MachineBasicBlock *WLSTarget = getWhileLoopStartTargetBB(Terminator);
188       // TODO: Analyse the blocks to make a decision if it would be worth
189       // moving Preheader even if we'd introduce a backwards WLS
190       if (WLSTarget == Predecessor) {
191         LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Can't move Predecessor block as "
192                           << "it would convert a WLS from forward to a "
193                           << "backwards branching WLS\n");
194         RevertedWhileLoops.push_back(WlsInstr);
195         return false;
196       }
197     }
198   }
199 
200   moveBasicBlock(Predecessor, LoopExit);
201   return true;
202 }
203 
204 /// Updates ordering (of WLS BB and their loopExits) in inner loops first
205 /// Returns true if any change was made in any of the loops
processPostOrderLoops(MachineLoop * ML)206 bool ARMBlockPlacement::processPostOrderLoops(MachineLoop *ML) {
207   bool Changed = false;
208   for (auto *InnerML : *ML)
209     Changed |= processPostOrderLoops(InnerML);
210   return Changed | fixBackwardsWLS(ML);
211 }
212 
runOnMachineFunction(MachineFunction & MF)213 bool ARMBlockPlacement::runOnMachineFunction(MachineFunction &MF) {
214   if (skipFunction(MF.getFunction()))
215     return false;
216   const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>();
217   if (!ST.hasLOB())
218     return false;
219   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Running on " << MF.getName() << "\n");
220   MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
221   TII = static_cast<const ARMBaseInstrInfo *>(ST.getInstrInfo());
222   BBUtils = std::make_unique<ARMBasicBlockUtils>(MF);
223   MF.RenumberBlocks();
224   BBUtils->computeAllBlockSizes();
225   BBUtils->adjustBBOffsetsAfter(&MF.front());
226   bool Changed = false;
227   RevertedWhileLoops.clear();
228 
229   // Find loops with a backwards branching WLS and fix if possible.
230   for (auto *ML : *MLI)
231     Changed |= processPostOrderLoops(ML);
232 
233   // Revert any While loops still out of range to DLS loops.
234   for (auto *WlsInstr : RevertedWhileLoops)
235     Changed |= revertWhileToDoLoop(WlsInstr);
236 
237   return Changed;
238 }
239 
blockIsBefore(MachineBasicBlock * BB,MachineBasicBlock * Other)240 bool ARMBlockPlacement::blockIsBefore(MachineBasicBlock *BB,
241                                       MachineBasicBlock *Other) {
242   return BBUtils->getOffsetOf(Other) > BBUtils->getOffsetOf(BB);
243 }
244 
245 // Moves a BasicBlock before another, without changing the control flow
moveBasicBlock(MachineBasicBlock * BB,MachineBasicBlock * Before)246 void ARMBlockPlacement::moveBasicBlock(MachineBasicBlock *BB,
247                                        MachineBasicBlock *Before) {
248   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Moving " << BB->getName() << " before "
249                     << Before->getName() << "\n");
250   MachineBasicBlock *BBPrevious = BB->getPrevNode();
251   assert(BBPrevious && "Cannot move the function entry basic block");
252   MachineBasicBlock *BBNext = BB->getNextNode();
253 
254   MachineBasicBlock *BeforePrev = Before->getPrevNode();
255   assert(BeforePrev &&
256          "Cannot move the given block to before the function entry block");
257   MachineFunction *F = BB->getParent();
258   BB->moveBefore(Before);
259 
260   // Since only the blocks are to be moved around (but the control flow must
261   // not change), if there were any fall-throughs (to/from adjacent blocks),
262   // replace with unconditional branch to the fall through block.
263   auto FixFallthrough = [&](MachineBasicBlock *From, MachineBasicBlock *To) {
264     LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Checking for fallthrough from "
265                       << From->getName() << " to " << To->getName() << "\n");
266     assert(From->isSuccessor(To) &&
267            "'To' is expected to be a successor of 'From'");
268     MachineInstr &Terminator = *(--From->terminators().end());
269     if (!TII->isPredicated(Terminator) &&
270         (isUncondBranchOpcode(Terminator.getOpcode()) ||
271          isIndirectBranchOpcode(Terminator.getOpcode()) ||
272          isJumpTableBranchOpcode(Terminator.getOpcode()) ||
273          Terminator.isReturn()))
274       return;
275     // The BB doesn't have an unconditional branch so it relied on
276     // fall-through. Fix by adding an unconditional branch to the moved BB.
277     MachineInstrBuilder MIB =
278         BuildMI(From, Terminator.getDebugLoc(), TII->get(ARM::t2B));
279     MIB.addMBB(To);
280     MIB.addImm(ARMCC::CondCodes::AL);
281     MIB.addReg(ARM::NoRegister);
282     LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Adding unconditional branch from "
283                       << From->getName() << " to " << To->getName() << ": "
284                       << *MIB.getInstr());
285   };
286 
287   // Fix fall-through to the moved BB from the one that used to be before it.
288   if (BBPrevious->isSuccessor(BB))
289     FixFallthrough(BBPrevious, BB);
290   // Fix fall through from the destination BB to the one that used to before it.
291   if (BeforePrev->isSuccessor(Before))
292     FixFallthrough(BeforePrev, Before);
293   // Fix fall through from the moved BB to the one that used to follow.
294   if (BBNext && BB->isSuccessor(BBNext))
295     FixFallthrough(BB, BBNext);
296 
297   F->RenumberBlocks();
298   BBUtils->computeAllBlockSizes();
299   BBUtils->adjustBBOffsetsAfter(BB);
300 }
301