xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/ARM/ARMBlockPlacement.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1e8d8bef9SDimitry Andric //===-- ARMBlockPlacement.cpp - ARM block placement pass ------------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric //
9e8d8bef9SDimitry Andric // This pass re-arranges machine basic blocks to suit target requirements.
10e8d8bef9SDimitry Andric // Currently it only moves blocks to fix backwards WLS branches.
11e8d8bef9SDimitry Andric //
12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
13e8d8bef9SDimitry Andric 
14e8d8bef9SDimitry Andric #include "ARM.h"
15e8d8bef9SDimitry Andric #include "ARMBaseInstrInfo.h"
16e8d8bef9SDimitry Andric #include "ARMBasicBlockInfo.h"
17e8d8bef9SDimitry Andric #include "ARMSubtarget.h"
18fe6060f1SDimitry Andric #include "MVETailPredUtils.h"
1981ad6265SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
20e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
21e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
22e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
23e8d8bef9SDimitry Andric 
24e8d8bef9SDimitry Andric using namespace llvm;
25e8d8bef9SDimitry Andric 
26e8d8bef9SDimitry Andric #define DEBUG_TYPE "arm-block-placement"
27e8d8bef9SDimitry Andric #define DEBUG_PREFIX "ARM Block Placement: "
28e8d8bef9SDimitry Andric 
29e8d8bef9SDimitry Andric namespace llvm {
30e8d8bef9SDimitry Andric class ARMBlockPlacement : public MachineFunctionPass {
31e8d8bef9SDimitry Andric private:
32e8d8bef9SDimitry Andric   const ARMBaseInstrInfo *TII;
33e8d8bef9SDimitry Andric   std::unique_ptr<ARMBasicBlockUtils> BBUtils = nullptr;
34e8d8bef9SDimitry Andric   MachineLoopInfo *MLI = nullptr;
35349cc55cSDimitry Andric   // A list of WLS instructions that need to be reverted to DLS.
36349cc55cSDimitry Andric   SmallVector<MachineInstr *> RevertedWhileLoops;
37e8d8bef9SDimitry Andric 
38e8d8bef9SDimitry Andric public:
39e8d8bef9SDimitry Andric   static char ID;
40e8d8bef9SDimitry Andric   ARMBlockPlacement() : MachineFunctionPass(ID) {}
41e8d8bef9SDimitry Andric 
42e8d8bef9SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
43fe6060f1SDimitry Andric   void moveBasicBlock(MachineBasicBlock *BB, MachineBasicBlock *Before);
44e8d8bef9SDimitry Andric   bool blockIsBefore(MachineBasicBlock *BB, MachineBasicBlock *Other);
45fe6060f1SDimitry Andric   bool fixBackwardsWLS(MachineLoop *ML);
46fe6060f1SDimitry Andric   bool processPostOrderLoops(MachineLoop *ML);
47349cc55cSDimitry Andric   bool revertWhileToDoLoop(MachineInstr *WLS);
48e8d8bef9SDimitry Andric 
49e8d8bef9SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
50*0fca6ea1SDimitry Andric     AU.addRequired<MachineLoopInfoWrapperPass>();
51e8d8bef9SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
52e8d8bef9SDimitry Andric   }
53e8d8bef9SDimitry Andric };
54e8d8bef9SDimitry Andric 
55e8d8bef9SDimitry Andric } // namespace llvm
56e8d8bef9SDimitry Andric 
57e8d8bef9SDimitry Andric FunctionPass *llvm::createARMBlockPlacementPass() {
58e8d8bef9SDimitry Andric   return new ARMBlockPlacement();
59e8d8bef9SDimitry Andric }
60e8d8bef9SDimitry Andric 
61e8d8bef9SDimitry Andric char ARMBlockPlacement::ID = 0;
62e8d8bef9SDimitry Andric 
63e8d8bef9SDimitry Andric INITIALIZE_PASS(ARMBlockPlacement, DEBUG_TYPE, "ARM block placement", false,
64e8d8bef9SDimitry Andric                 false)
65e8d8bef9SDimitry Andric 
66fe6060f1SDimitry Andric static MachineInstr *findWLSInBlock(MachineBasicBlock *MBB) {
67fe6060f1SDimitry Andric   for (auto &Terminator : MBB->terminators()) {
68fe6060f1SDimitry Andric     if (isWhileLoopStart(Terminator))
69fe6060f1SDimitry Andric       return &Terminator;
70fe6060f1SDimitry Andric   }
71fe6060f1SDimitry Andric   return nullptr;
72fe6060f1SDimitry Andric }
73fe6060f1SDimitry Andric 
74fe6060f1SDimitry Andric /// Find WhileLoopStart in the loop predecessor BB or otherwise in its only
75fe6060f1SDimitry Andric /// predecessor. If found, returns (BB, WLS Instr) pair, otherwise a null pair.
76fe6060f1SDimitry Andric static MachineInstr *findWLS(MachineLoop *ML) {
77fe6060f1SDimitry Andric   MachineBasicBlock *Predecessor = ML->getLoopPredecessor();
78fe6060f1SDimitry Andric   if (!Predecessor)
79fe6060f1SDimitry Andric     return nullptr;
80fe6060f1SDimitry Andric   MachineInstr *WlsInstr = findWLSInBlock(Predecessor);
81fe6060f1SDimitry Andric   if (WlsInstr)
82fe6060f1SDimitry Andric     return WlsInstr;
83fe6060f1SDimitry Andric   if (Predecessor->pred_size() == 1)
84fe6060f1SDimitry Andric     return findWLSInBlock(*Predecessor->pred_begin());
85fe6060f1SDimitry Andric   return nullptr;
86fe6060f1SDimitry Andric }
87fe6060f1SDimitry Andric 
88349cc55cSDimitry Andric // Revert a WhileLoopStart to an equivalent DoLoopStart and branch. Note that
89349cc55cSDimitry Andric // because of the branches this requires an extra block to be created.
90349cc55cSDimitry Andric bool ARMBlockPlacement::revertWhileToDoLoop(MachineInstr *WLS) {
91349cc55cSDimitry Andric   //   lr = t2WhileLoopStartTP r0, r1, TgtBB
92349cc55cSDimitry Andric   //   t2Br Ph
93349cc55cSDimitry Andric   // ->
94349cc55cSDimitry Andric   //   cmp r0, 0
95349cc55cSDimitry Andric   //   brcc TgtBB
96349cc55cSDimitry Andric   // block2:
97349cc55cSDimitry Andric   //   LR = t2DoLoopStartTP r0, r1
98349cc55cSDimitry Andric   //   t2Br Ph
99349cc55cSDimitry Andric   MachineBasicBlock *Preheader = WLS->getParent();
100349cc55cSDimitry Andric   assert(WLS != &Preheader->back());
101349cc55cSDimitry Andric   assert(WLS->getNextNode() == &Preheader->back());
102349cc55cSDimitry Andric   MachineInstr *Br = &Preheader->back();
103349cc55cSDimitry Andric   assert(Br->getOpcode() == ARM::t2B);
104349cc55cSDimitry Andric   assert(Br->getOperand(1).getImm() == 14);
105349cc55cSDimitry Andric 
106349cc55cSDimitry Andric   // Clear the kill flags, as the cmp/bcc will no longer kill any operands.
107349cc55cSDimitry Andric   WLS->getOperand(1).setIsKill(false);
108349cc55cSDimitry Andric   if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)
109349cc55cSDimitry Andric     WLS->getOperand(2).setIsKill(false);
110349cc55cSDimitry Andric 
111349cc55cSDimitry Andric   // Create the new block
112349cc55cSDimitry Andric   MachineBasicBlock *NewBlock = Preheader->getParent()->CreateMachineBasicBlock(
113349cc55cSDimitry Andric       Preheader->getBasicBlock());
114349cc55cSDimitry Andric   Preheader->getParent()->insert(++Preheader->getIterator(), NewBlock);
115349cc55cSDimitry Andric   // Move the Br to it
116349cc55cSDimitry Andric   Br->removeFromParent();
117349cc55cSDimitry Andric   NewBlock->insert(NewBlock->end(), Br);
118349cc55cSDimitry Andric   // And setup the successors correctly.
119349cc55cSDimitry Andric   Preheader->replaceSuccessor(Br->getOperand(0).getMBB(), NewBlock);
120349cc55cSDimitry Andric   NewBlock->addSuccessor(Br->getOperand(0).getMBB());
121349cc55cSDimitry Andric 
122349cc55cSDimitry Andric   // Create a new DLS to replace the WLS
123349cc55cSDimitry Andric   MachineInstrBuilder MIB =
124349cc55cSDimitry Andric       BuildMI(*NewBlock, Br, WLS->getDebugLoc(),
125349cc55cSDimitry Andric               TII->get(WLS->getOpcode() == ARM::t2WhileLoopStartTP
126349cc55cSDimitry Andric                            ? ARM::t2DoLoopStartTP
127349cc55cSDimitry Andric                            : ARM::t2DoLoopStart));
128349cc55cSDimitry Andric   MIB.add(WLS->getOperand(0));
129349cc55cSDimitry Andric   MIB.add(WLS->getOperand(1));
130349cc55cSDimitry Andric   if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)
131349cc55cSDimitry Andric     MIB.add(WLS->getOperand(2));
132349cc55cSDimitry Andric 
133349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << DEBUG_PREFIX
134349cc55cSDimitry Andric                     << "Reverting While Loop to Do Loop: " << *WLS << "\n");
135349cc55cSDimitry Andric 
136349cc55cSDimitry Andric   RevertWhileLoopStartLR(WLS, TII, ARM::t2Bcc, true);
137349cc55cSDimitry Andric 
138349cc55cSDimitry Andric   LivePhysRegs LiveRegs;
139349cc55cSDimitry Andric   computeAndAddLiveIns(LiveRegs, *NewBlock);
140349cc55cSDimitry Andric 
141349cc55cSDimitry Andric   Preheader->getParent()->RenumberBlocks();
142349cc55cSDimitry Andric   BBUtils->computeAllBlockSizes();
143349cc55cSDimitry Andric   BBUtils->adjustBBOffsetsAfter(Preheader);
144349cc55cSDimitry Andric 
145349cc55cSDimitry Andric   return true;
146349cc55cSDimitry Andric }
147349cc55cSDimitry Andric 
148fe6060f1SDimitry Andric /// Checks if loop has a backwards branching WLS, and if possible, fixes it.
149fe6060f1SDimitry Andric /// This requires checking the predecessor (ie. preheader or it's predecessor)
150fe6060f1SDimitry Andric /// for a WLS and if its loopExit/target is before it.
151fe6060f1SDimitry Andric /// If moving the predecessor won't convert a WLS (to the predecessor) from
152fe6060f1SDimitry Andric /// a forward to a backward branching WLS, then move the predecessor block
153fe6060f1SDimitry Andric /// to before the loopExit/target.
154fe6060f1SDimitry Andric bool ARMBlockPlacement::fixBackwardsWLS(MachineLoop *ML) {
155fe6060f1SDimitry Andric   MachineInstr *WlsInstr = findWLS(ML);
156fe6060f1SDimitry Andric   if (!WlsInstr)
157fe6060f1SDimitry Andric     return false;
158fe6060f1SDimitry Andric 
159fe6060f1SDimitry Andric   MachineBasicBlock *Predecessor = WlsInstr->getParent();
160fe6060f1SDimitry Andric   MachineBasicBlock *LoopExit = getWhileLoopStartTargetBB(*WlsInstr);
161fe6060f1SDimitry Andric 
162fe6060f1SDimitry Andric   // We don't want to move Preheader to before the function's entry block.
163fe6060f1SDimitry Andric   if (!LoopExit->getPrevNode())
164fe6060f1SDimitry Andric     return false;
165fe6060f1SDimitry Andric   if (blockIsBefore(Predecessor, LoopExit))
166fe6060f1SDimitry Andric     return false;
167fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Found a backwards WLS from "
168fe6060f1SDimitry Andric                     << Predecessor->getFullName() << " to "
169fe6060f1SDimitry Andric                     << LoopExit->getFullName() << "\n");
170fe6060f1SDimitry Andric 
171fe6060f1SDimitry Andric   // Make sure no forward branching WLSs to the Predecessor become backwards
172fe6060f1SDimitry Andric   // branching. An example loop structure where the Predecessor can't be moved,
173fe6060f1SDimitry Andric   // since bb2's WLS will become forwards once bb3 is moved before/above bb1.
174fe6060f1SDimitry Andric   //
175fe6060f1SDimitry Andric   // bb1:           - LoopExit
176fe6060f1SDimitry Andric   // bb2:
177fe6060f1SDimitry Andric   //      WLS  bb3
178fe6060f1SDimitry Andric   // bb3:          - Predecessor
179fe6060f1SDimitry Andric   //      WLS bb1
180fe6060f1SDimitry Andric   // bb4:          - Header
181fe6060f1SDimitry Andric   for (auto It = ++LoopExit->getIterator(); It != Predecessor->getIterator();
182fe6060f1SDimitry Andric        ++It) {
183fe6060f1SDimitry Andric     MachineBasicBlock *MBB = &*It;
184fe6060f1SDimitry Andric     for (auto &Terminator : MBB->terminators()) {
185fe6060f1SDimitry Andric       if (!isWhileLoopStart(Terminator))
186fe6060f1SDimitry Andric         continue;
187fe6060f1SDimitry Andric       MachineBasicBlock *WLSTarget = getWhileLoopStartTargetBB(Terminator);
188fe6060f1SDimitry Andric       // TODO: Analyse the blocks to make a decision if it would be worth
189fe6060f1SDimitry Andric       // moving Preheader even if we'd introduce a backwards WLS
190fe6060f1SDimitry Andric       if (WLSTarget == Predecessor) {
191349cc55cSDimitry Andric         LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Can't move Predecessor block as "
192349cc55cSDimitry Andric                           << "it would convert a WLS from forward to a "
193349cc55cSDimitry Andric                           << "backwards branching WLS\n");
194349cc55cSDimitry Andric         RevertedWhileLoops.push_back(WlsInstr);
195fe6060f1SDimitry Andric         return false;
196fe6060f1SDimitry Andric       }
197fe6060f1SDimitry Andric     }
198fe6060f1SDimitry Andric   }
199fe6060f1SDimitry Andric 
200fe6060f1SDimitry Andric   moveBasicBlock(Predecessor, LoopExit);
201fe6060f1SDimitry Andric   return true;
202fe6060f1SDimitry Andric }
203fe6060f1SDimitry Andric 
204fe6060f1SDimitry Andric /// Updates ordering (of WLS BB and their loopExits) in inner loops first
205fe6060f1SDimitry Andric /// Returns true if any change was made in any of the loops
206fe6060f1SDimitry Andric bool ARMBlockPlacement::processPostOrderLoops(MachineLoop *ML) {
207fe6060f1SDimitry Andric   bool Changed = false;
208fe6060f1SDimitry Andric   for (auto *InnerML : *ML)
209fe6060f1SDimitry Andric     Changed |= processPostOrderLoops(InnerML);
210fe6060f1SDimitry Andric   return Changed | fixBackwardsWLS(ML);
211fe6060f1SDimitry Andric }
212fe6060f1SDimitry Andric 
213e8d8bef9SDimitry Andric bool ARMBlockPlacement::runOnMachineFunction(MachineFunction &MF) {
214e8d8bef9SDimitry Andric   if (skipFunction(MF.getFunction()))
215e8d8bef9SDimitry Andric     return false;
21681ad6265SDimitry Andric   const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>();
217e8d8bef9SDimitry Andric   if (!ST.hasLOB())
218e8d8bef9SDimitry Andric     return false;
219e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Running on " << MF.getName() << "\n");
220*0fca6ea1SDimitry Andric   MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
221e8d8bef9SDimitry Andric   TII = static_cast<const ARMBaseInstrInfo *>(ST.getInstrInfo());
222*0fca6ea1SDimitry Andric   BBUtils = std::make_unique<ARMBasicBlockUtils>(MF);
223e8d8bef9SDimitry Andric   MF.RenumberBlocks();
224e8d8bef9SDimitry Andric   BBUtils->computeAllBlockSizes();
225e8d8bef9SDimitry Andric   BBUtils->adjustBBOffsetsAfter(&MF.front());
226e8d8bef9SDimitry Andric   bool Changed = false;
227349cc55cSDimitry Andric   RevertedWhileLoops.clear();
228e8d8bef9SDimitry Andric 
229fe6060f1SDimitry Andric   // Find loops with a backwards branching WLS and fix if possible.
230fe6060f1SDimitry Andric   for (auto *ML : *MLI)
231fe6060f1SDimitry Andric     Changed |= processPostOrderLoops(ML);
232e8d8bef9SDimitry Andric 
233349cc55cSDimitry Andric   // Revert any While loops still out of range to DLS loops.
234349cc55cSDimitry Andric   for (auto *WlsInstr : RevertedWhileLoops)
235349cc55cSDimitry Andric     Changed |= revertWhileToDoLoop(WlsInstr);
236349cc55cSDimitry Andric 
237e8d8bef9SDimitry Andric   return Changed;
238e8d8bef9SDimitry Andric }
239e8d8bef9SDimitry Andric 
240e8d8bef9SDimitry Andric bool ARMBlockPlacement::blockIsBefore(MachineBasicBlock *BB,
241e8d8bef9SDimitry Andric                                       MachineBasicBlock *Other) {
242e8d8bef9SDimitry Andric   return BBUtils->getOffsetOf(Other) > BBUtils->getOffsetOf(BB);
243e8d8bef9SDimitry Andric }
244e8d8bef9SDimitry Andric 
245fe6060f1SDimitry Andric // Moves a BasicBlock before another, without changing the control flow
246e8d8bef9SDimitry Andric void ARMBlockPlacement::moveBasicBlock(MachineBasicBlock *BB,
247fe6060f1SDimitry Andric                                        MachineBasicBlock *Before) {
248fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Moving " << BB->getName() << " before "
249fe6060f1SDimitry Andric                     << Before->getName() << "\n");
250e8d8bef9SDimitry Andric   MachineBasicBlock *BBPrevious = BB->getPrevNode();
251e8d8bef9SDimitry Andric   assert(BBPrevious && "Cannot move the function entry basic block");
252e8d8bef9SDimitry Andric   MachineBasicBlock *BBNext = BB->getNextNode();
253e8d8bef9SDimitry Andric 
254fe6060f1SDimitry Andric   MachineBasicBlock *BeforePrev = Before->getPrevNode();
255fe6060f1SDimitry Andric   assert(BeforePrev &&
256fe6060f1SDimitry Andric          "Cannot move the given block to before the function entry block");
257fe6060f1SDimitry Andric   MachineFunction *F = BB->getParent();
258fe6060f1SDimitry Andric   BB->moveBefore(Before);
259e8d8bef9SDimitry Andric 
260fe6060f1SDimitry Andric   // Since only the blocks are to be moved around (but the control flow must
261fe6060f1SDimitry Andric   // not change), if there were any fall-throughs (to/from adjacent blocks),
262fe6060f1SDimitry Andric   // replace with unconditional branch to the fall through block.
263e8d8bef9SDimitry Andric   auto FixFallthrough = [&](MachineBasicBlock *From, MachineBasicBlock *To) {
264e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Checking for fallthrough from "
265e8d8bef9SDimitry Andric                       << From->getName() << " to " << To->getName() << "\n");
266e8d8bef9SDimitry Andric     assert(From->isSuccessor(To) &&
267e8d8bef9SDimitry Andric            "'To' is expected to be a successor of 'From'");
268e8d8bef9SDimitry Andric     MachineInstr &Terminator = *(--From->terminators().end());
269349cc55cSDimitry Andric     if (!TII->isPredicated(Terminator) &&
270349cc55cSDimitry Andric         (isUncondBranchOpcode(Terminator.getOpcode()) ||
271349cc55cSDimitry Andric          isIndirectBranchOpcode(Terminator.getOpcode()) ||
272349cc55cSDimitry Andric          isJumpTableBranchOpcode(Terminator.getOpcode()) ||
273349cc55cSDimitry Andric          Terminator.isReturn()))
274349cc55cSDimitry Andric       return;
275e8d8bef9SDimitry Andric     // The BB doesn't have an unconditional branch so it relied on
276e8d8bef9SDimitry Andric     // fall-through. Fix by adding an unconditional branch to the moved BB.
277e8d8bef9SDimitry Andric     MachineInstrBuilder MIB =
2784652422eSDimitry Andric         BuildMI(From, Terminator.getDebugLoc(), TII->get(ARM::t2B));
279e8d8bef9SDimitry Andric     MIB.addMBB(To);
280e8d8bef9SDimitry Andric     MIB.addImm(ARMCC::CondCodes::AL);
281e8d8bef9SDimitry Andric     MIB.addReg(ARM::NoRegister);
282e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Adding unconditional branch from "
283e8d8bef9SDimitry Andric                       << From->getName() << " to " << To->getName() << ": "
284e8d8bef9SDimitry Andric                       << *MIB.getInstr());
285e8d8bef9SDimitry Andric   };
286e8d8bef9SDimitry Andric 
287e8d8bef9SDimitry Andric   // Fix fall-through to the moved BB from the one that used to be before it.
288e8d8bef9SDimitry Andric   if (BBPrevious->isSuccessor(BB))
289e8d8bef9SDimitry Andric     FixFallthrough(BBPrevious, BB);
290fe6060f1SDimitry Andric   // Fix fall through from the destination BB to the one that used to before it.
291fe6060f1SDimitry Andric   if (BeforePrev->isSuccessor(Before))
292fe6060f1SDimitry Andric     FixFallthrough(BeforePrev, Before);
293e8d8bef9SDimitry Andric   // Fix fall through from the moved BB to the one that used to follow.
294e8d8bef9SDimitry Andric   if (BBNext && BB->isSuccessor(BBNext))
295e8d8bef9SDimitry Andric     FixFallthrough(BB, BBNext);
296e8d8bef9SDimitry Andric 
297fe6060f1SDimitry Andric   F->RenumberBlocks();
298fe6060f1SDimitry Andric   BBUtils->computeAllBlockSizes();
299349cc55cSDimitry Andric   BBUtils->adjustBBOffsetsAfter(BB);
300e8d8bef9SDimitry Andric }
301