xref: /llvm-project/llvm/lib/Target/ARM/ARMBlockPlacement.cpp (revision 79d0de2ac37b6b7d66720611935d1dd7fc4fbd43)
160fda8ebSSam Tebbs //===-- ARMBlockPlacement.cpp - ARM block placement pass ------------===//
260fda8ebSSam Tebbs //
360fda8ebSSam Tebbs // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
460fda8ebSSam Tebbs // See https://llvm.org/LICENSE.txt for license information.
560fda8ebSSam Tebbs // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
660fda8ebSSam Tebbs //
760fda8ebSSam Tebbs //===----------------------------------------------------------------------===//
860fda8ebSSam Tebbs //
960fda8ebSSam Tebbs // This pass re-arranges machine basic blocks to suit target requirements.
1060fda8ebSSam Tebbs // Currently it only moves blocks to fix backwards WLS branches.
1160fda8ebSSam Tebbs //
1260fda8ebSSam Tebbs //===----------------------------------------------------------------------===//
1360fda8ebSSam Tebbs 
1460fda8ebSSam Tebbs #include "ARM.h"
1560fda8ebSSam Tebbs #include "ARMBaseInstrInfo.h"
1660fda8ebSSam Tebbs #include "ARMBasicBlockInfo.h"
1760fda8ebSSam Tebbs #include "ARMSubtarget.h"
18bee2f618SDavid Green #include "MVETailPredUtils.h"
19989f1c72Sserge-sans-paille #include "llvm/CodeGen/LivePhysRegs.h"
2060fda8ebSSam Tebbs #include "llvm/CodeGen/MachineFunctionPass.h"
2160fda8ebSSam Tebbs #include "llvm/CodeGen/MachineInstrBuilder.h"
2260fda8ebSSam Tebbs #include "llvm/CodeGen/MachineLoopInfo.h"
2360fda8ebSSam Tebbs 
2460fda8ebSSam Tebbs using namespace llvm;
2560fda8ebSSam Tebbs 
2660fda8ebSSam Tebbs #define DEBUG_TYPE "arm-block-placement"
2760fda8ebSSam Tebbs #define DEBUG_PREFIX "ARM Block Placement: "
2860fda8ebSSam Tebbs 
2960fda8ebSSam Tebbs namespace llvm {
3060fda8ebSSam Tebbs class ARMBlockPlacement : public MachineFunctionPass {
3160fda8ebSSam Tebbs private:
3260fda8ebSSam Tebbs   const ARMBaseInstrInfo *TII;
3360fda8ebSSam Tebbs   std::unique_ptr<ARMBasicBlockUtils> BBUtils = nullptr;
3460fda8ebSSam Tebbs   MachineLoopInfo *MLI = nullptr;
35fdd8c109SDavid Green   // A list of WLS instructions that need to be reverted to DLS.
36fdd8c109SDavid Green   SmallVector<MachineInstr *> RevertedWhileLoops;
3760fda8ebSSam Tebbs 
3860fda8ebSSam Tebbs public:
3960fda8ebSSam Tebbs   static char ID;
4060fda8ebSSam Tebbs   ARMBlockPlacement() : MachineFunctionPass(ID) {}
4160fda8ebSSam Tebbs 
4260fda8ebSSam Tebbs   bool runOnMachineFunction(MachineFunction &MF) override;
439ba5238cSMalhar Jajoo   void moveBasicBlock(MachineBasicBlock *BB, MachineBasicBlock *Before);
4460fda8ebSSam Tebbs   bool blockIsBefore(MachineBasicBlock *BB, MachineBasicBlock *Other);
4558f3201aSMalhar Jajoo   bool fixBackwardsWLS(MachineLoop *ML);
4658f3201aSMalhar Jajoo   bool processPostOrderLoops(MachineLoop *ML);
47fdd8c109SDavid Green   bool revertWhileToDoLoop(MachineInstr *WLS);
4860fda8ebSSam Tebbs 
4960fda8ebSSam Tebbs   void getAnalysisUsage(AnalysisUsage &AU) const override {
50*79d0de2aSpaperchalice     AU.addRequired<MachineLoopInfoWrapperPass>();
5160fda8ebSSam Tebbs     MachineFunctionPass::getAnalysisUsage(AU);
5260fda8ebSSam Tebbs   }
5360fda8ebSSam Tebbs };
5460fda8ebSSam Tebbs 
5560fda8ebSSam Tebbs } // namespace llvm
5660fda8ebSSam Tebbs 
5760fda8ebSSam Tebbs FunctionPass *llvm::createARMBlockPlacementPass() {
5860fda8ebSSam Tebbs   return new ARMBlockPlacement();
5960fda8ebSSam Tebbs }
6060fda8ebSSam Tebbs 
6160fda8ebSSam Tebbs char ARMBlockPlacement::ID = 0;
6260fda8ebSSam Tebbs 
6360fda8ebSSam Tebbs INITIALIZE_PASS(ARMBlockPlacement, DEBUG_TYPE, "ARM block placement", false,
6460fda8ebSSam Tebbs                 false)
6560fda8ebSSam Tebbs 
6658f3201aSMalhar Jajoo static MachineInstr *findWLSInBlock(MachineBasicBlock *MBB) {
6758f3201aSMalhar Jajoo   for (auto &Terminator : MBB->terminators()) {
68bee2f618SDavid Green     if (isWhileLoopStart(Terminator))
6958f3201aSMalhar Jajoo       return &Terminator;
7058f3201aSMalhar Jajoo   }
7158f3201aSMalhar Jajoo   return nullptr;
7258f3201aSMalhar Jajoo }
7360fda8ebSSam Tebbs 
74bee2f618SDavid Green /// Find WhileLoopStart in the loop predecessor BB or otherwise in its only
7558f3201aSMalhar Jajoo /// predecessor. If found, returns (BB, WLS Instr) pair, otherwise a null pair.
7658f3201aSMalhar Jajoo static MachineInstr *findWLS(MachineLoop *ML) {
7758f3201aSMalhar Jajoo   MachineBasicBlock *Predecessor = ML->getLoopPredecessor();
7858f3201aSMalhar Jajoo   if (!Predecessor)
7958f3201aSMalhar Jajoo     return nullptr;
8058f3201aSMalhar Jajoo   MachineInstr *WlsInstr = findWLSInBlock(Predecessor);
8158f3201aSMalhar Jajoo   if (WlsInstr)
8258f3201aSMalhar Jajoo     return WlsInstr;
8358f3201aSMalhar Jajoo   if (Predecessor->pred_size() == 1)
8458f3201aSMalhar Jajoo     return findWLSInBlock(*Predecessor->pred_begin());
8558f3201aSMalhar Jajoo   return nullptr;
8658f3201aSMalhar Jajoo }
8760fda8ebSSam Tebbs 
8828293918SDavid Green // Revert a WhileLoopStart to an equivalent DoLoopStart and branch. Note that
8928293918SDavid Green // because of the branches this requires an extra block to be created.
90fdd8c109SDavid Green bool ARMBlockPlacement::revertWhileToDoLoop(MachineInstr *WLS) {
9128293918SDavid Green   //   lr = t2WhileLoopStartTP r0, r1, TgtBB
9228293918SDavid Green   //   t2Br Ph
9328293918SDavid Green   // ->
9428293918SDavid Green   //   cmp r0, 0
9528293918SDavid Green   //   brcc TgtBB
9628293918SDavid Green   // block2:
9728293918SDavid Green   //   LR = t2DoLoopStartTP r0, r1
9828293918SDavid Green   //   t2Br Ph
9928293918SDavid Green   MachineBasicBlock *Preheader = WLS->getParent();
10028293918SDavid Green   assert(WLS != &Preheader->back());
10128293918SDavid Green   assert(WLS->getNextNode() == &Preheader->back());
10228293918SDavid Green   MachineInstr *Br = &Preheader->back();
10328293918SDavid Green   assert(Br->getOpcode() == ARM::t2B);
10428293918SDavid Green   assert(Br->getOperand(1).getImm() == 14);
10528293918SDavid Green 
10628293918SDavid Green   // Clear the kill flags, as the cmp/bcc will no longer kill any operands.
10728293918SDavid Green   WLS->getOperand(1).setIsKill(false);
10828293918SDavid Green   if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)
10928293918SDavid Green     WLS->getOperand(2).setIsKill(false);
11028293918SDavid Green 
11128293918SDavid Green   // Create the new block
11228293918SDavid Green   MachineBasicBlock *NewBlock = Preheader->getParent()->CreateMachineBasicBlock(
11328293918SDavid Green       Preheader->getBasicBlock());
11428293918SDavid Green   Preheader->getParent()->insert(++Preheader->getIterator(), NewBlock);
11528293918SDavid Green   // Move the Br to it
11628293918SDavid Green   Br->removeFromParent();
11728293918SDavid Green   NewBlock->insert(NewBlock->end(), Br);
11828293918SDavid Green   // And setup the successors correctly.
11928293918SDavid Green   Preheader->replaceSuccessor(Br->getOperand(0).getMBB(), NewBlock);
12028293918SDavid Green   NewBlock->addSuccessor(Br->getOperand(0).getMBB());
12128293918SDavid Green 
12228293918SDavid Green   // Create a new DLS to replace the WLS
12328293918SDavid Green   MachineInstrBuilder MIB =
12428293918SDavid Green       BuildMI(*NewBlock, Br, WLS->getDebugLoc(),
12528293918SDavid Green               TII->get(WLS->getOpcode() == ARM::t2WhileLoopStartTP
12628293918SDavid Green                            ? ARM::t2DoLoopStartTP
12728293918SDavid Green                            : ARM::t2DoLoopStart));
12828293918SDavid Green   MIB.add(WLS->getOperand(0));
12928293918SDavid Green   MIB.add(WLS->getOperand(1));
13028293918SDavid Green   if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)
13128293918SDavid Green     MIB.add(WLS->getOperand(2));
13228293918SDavid Green 
13328293918SDavid Green   LLVM_DEBUG(dbgs() << DEBUG_PREFIX
13428293918SDavid Green                     << "Reverting While Loop to Do Loop: " << *WLS << "\n");
13528293918SDavid Green 
13628293918SDavid Green   RevertWhileLoopStartLR(WLS, TII, ARM::t2Bcc, true);
13728293918SDavid Green 
13828293918SDavid Green   LivePhysRegs LiveRegs;
13928293918SDavid Green   computeAndAddLiveIns(LiveRegs, *NewBlock);
14028293918SDavid Green 
14128293918SDavid Green   Preheader->getParent()->RenumberBlocks();
14228293918SDavid Green   BBUtils->computeAllBlockSizes();
14328293918SDavid Green   BBUtils->adjustBBOffsetsAfter(Preheader);
14428293918SDavid Green 
14528293918SDavid Green   return true;
14628293918SDavid Green }
14728293918SDavid Green 
14858f3201aSMalhar Jajoo /// Checks if loop has a backwards branching WLS, and if possible, fixes it.
1499ba5238cSMalhar Jajoo /// This requires checking the predecessor (ie. preheader or it's predecessor)
1509ba5238cSMalhar Jajoo /// for a WLS and if its loopExit/target is before it.
1519ba5238cSMalhar Jajoo /// If moving the predecessor won't convert a WLS (to the predecessor) from
1529ba5238cSMalhar Jajoo /// a forward to a backward branching WLS, then move the predecessor block
1539ba5238cSMalhar Jajoo /// to before the loopExit/target.
15458f3201aSMalhar Jajoo bool ARMBlockPlacement::fixBackwardsWLS(MachineLoop *ML) {
15558f3201aSMalhar Jajoo   MachineInstr *WlsInstr = findWLS(ML);
15658f3201aSMalhar Jajoo   if (!WlsInstr)
15758f3201aSMalhar Jajoo     return false;
15858f3201aSMalhar Jajoo 
15958f3201aSMalhar Jajoo   MachineBasicBlock *Predecessor = WlsInstr->getParent();
160bee2f618SDavid Green   MachineBasicBlock *LoopExit = getWhileLoopStartTargetBB(*WlsInstr);
1619ba5238cSMalhar Jajoo 
1629ba5238cSMalhar Jajoo   // We don't want to move Preheader to before the function's entry block.
16360fda8ebSSam Tebbs   if (!LoopExit->getPrevNode())
16458f3201aSMalhar Jajoo     return false;
16558f3201aSMalhar Jajoo   if (blockIsBefore(Predecessor, LoopExit))
16658f3201aSMalhar Jajoo     return false;
16760fda8ebSSam Tebbs   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Found a backwards WLS from "
16858f3201aSMalhar Jajoo                     << Predecessor->getFullName() << " to "
16960fda8ebSSam Tebbs                     << LoopExit->getFullName() << "\n");
17060fda8ebSSam Tebbs 
1719ba5238cSMalhar Jajoo   // Make sure no forward branching WLSs to the Predecessor become backwards
1729ba5238cSMalhar Jajoo   // branching. An example loop structure where the Predecessor can't be moved,
1739ba5238cSMalhar Jajoo   // since bb2's WLS will become forwards once bb3 is moved before/above bb1.
1749ba5238cSMalhar Jajoo   //
17560fda8ebSSam Tebbs   // bb1:           - LoopExit
17660fda8ebSSam Tebbs   // bb2:
1779ba5238cSMalhar Jajoo   //      WLS  bb3
17858f3201aSMalhar Jajoo   // bb3:          - Predecessor
17960fda8ebSSam Tebbs   //      WLS bb1
18060fda8ebSSam Tebbs   // bb4:          - Header
1819ba5238cSMalhar Jajoo   for (auto It = ++LoopExit->getIterator(); It != Predecessor->getIterator();
1829ba5238cSMalhar Jajoo        ++It) {
18360fda8ebSSam Tebbs     MachineBasicBlock *MBB = &*It;
18460fda8ebSSam Tebbs     for (auto &Terminator : MBB->terminators()) {
185bee2f618SDavid Green       if (!isWhileLoopStart(Terminator))
18660fda8ebSSam Tebbs         continue;
187bee2f618SDavid Green       MachineBasicBlock *WLSTarget = getWhileLoopStartTargetBB(Terminator);
18860fda8ebSSam Tebbs       // TODO: Analyse the blocks to make a decision if it would be worth
1899ba5238cSMalhar Jajoo       // moving Preheader even if we'd introduce a backwards WLS
1909ba5238cSMalhar Jajoo       if (WLSTarget == Predecessor) {
191fdd8c109SDavid Green         LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Can't move Predecessor block as "
192fdd8c109SDavid Green                           << "it would convert a WLS from forward to a "
193fdd8c109SDavid Green                           << "backwards branching WLS\n");
194fdd8c109SDavid Green         RevertedWhileLoops.push_back(WlsInstr);
195fdd8c109SDavid Green         return false;
19660fda8ebSSam Tebbs       }
19760fda8ebSSam Tebbs     }
19860fda8ebSSam Tebbs   }
19960fda8ebSSam Tebbs 
2009ba5238cSMalhar Jajoo   moveBasicBlock(Predecessor, LoopExit);
2019ba5238cSMalhar Jajoo   return true;
20260fda8ebSSam Tebbs }
20358f3201aSMalhar Jajoo 
20458f3201aSMalhar Jajoo /// Updates ordering (of WLS BB and their loopExits) in inner loops first
20558f3201aSMalhar Jajoo /// Returns true if any change was made in any of the loops
20658f3201aSMalhar Jajoo bool ARMBlockPlacement::processPostOrderLoops(MachineLoop *ML) {
20758f3201aSMalhar Jajoo   bool Changed = false;
20858f3201aSMalhar Jajoo   for (auto *InnerML : *ML)
20958f3201aSMalhar Jajoo     Changed |= processPostOrderLoops(InnerML);
21058f3201aSMalhar Jajoo   return Changed | fixBackwardsWLS(ML);
21160fda8ebSSam Tebbs }
21258f3201aSMalhar Jajoo 
21358f3201aSMalhar Jajoo bool ARMBlockPlacement::runOnMachineFunction(MachineFunction &MF) {
21458f3201aSMalhar Jajoo   if (skipFunction(MF.getFunction()))
21558f3201aSMalhar Jajoo     return false;
216ad73ce31SZongwei Lan   const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>();
21758f3201aSMalhar Jajoo   if (!ST.hasLOB())
21858f3201aSMalhar Jajoo     return false;
21958f3201aSMalhar Jajoo   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Running on " << MF.getName() << "\n");
220*79d0de2aSpaperchalice   MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
22158f3201aSMalhar Jajoo   TII = static_cast<const ARMBaseInstrInfo *>(ST.getInstrInfo());
222ddaa93b0SKazu Hirata   BBUtils = std::make_unique<ARMBasicBlockUtils>(MF);
22358f3201aSMalhar Jajoo   MF.RenumberBlocks();
22458f3201aSMalhar Jajoo   BBUtils->computeAllBlockSizes();
22558f3201aSMalhar Jajoo   BBUtils->adjustBBOffsetsAfter(&MF.front());
22658f3201aSMalhar Jajoo   bool Changed = false;
227fdd8c109SDavid Green   RevertedWhileLoops.clear();
22858f3201aSMalhar Jajoo 
22958f3201aSMalhar Jajoo   // Find loops with a backwards branching WLS and fix if possible.
23058f3201aSMalhar Jajoo   for (auto *ML : *MLI)
23158f3201aSMalhar Jajoo     Changed |= processPostOrderLoops(ML);
23260fda8ebSSam Tebbs 
233fdd8c109SDavid Green   // Revert any While loops still out of range to DLS loops.
234fdd8c109SDavid Green   for (auto *WlsInstr : RevertedWhileLoops)
235fdd8c109SDavid Green     Changed |= revertWhileToDoLoop(WlsInstr);
236fdd8c109SDavid Green 
23760fda8ebSSam Tebbs   return Changed;
23860fda8ebSSam Tebbs }
23960fda8ebSSam Tebbs 
24060fda8ebSSam Tebbs bool ARMBlockPlacement::blockIsBefore(MachineBasicBlock *BB,
24160fda8ebSSam Tebbs                                       MachineBasicBlock *Other) {
24260fda8ebSSam Tebbs   return BBUtils->getOffsetOf(Other) > BBUtils->getOffsetOf(BB);
24360fda8ebSSam Tebbs }
24460fda8ebSSam Tebbs 
2459ba5238cSMalhar Jajoo // Moves a BasicBlock before another, without changing the control flow
24660fda8ebSSam Tebbs void ARMBlockPlacement::moveBasicBlock(MachineBasicBlock *BB,
2479ba5238cSMalhar Jajoo                                        MachineBasicBlock *Before) {
2489ba5238cSMalhar Jajoo   LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Moving " << BB->getName() << " before "
2499ba5238cSMalhar Jajoo                     << Before->getName() << "\n");
25060fda8ebSSam Tebbs   MachineBasicBlock *BBPrevious = BB->getPrevNode();
25160fda8ebSSam Tebbs   assert(BBPrevious && "Cannot move the function entry basic block");
25260fda8ebSSam Tebbs   MachineBasicBlock *BBNext = BB->getNextNode();
25360fda8ebSSam Tebbs 
2549ba5238cSMalhar Jajoo   MachineBasicBlock *BeforePrev = Before->getPrevNode();
2559ba5238cSMalhar Jajoo   assert(BeforePrev &&
2569ba5238cSMalhar Jajoo          "Cannot move the given block to before the function entry block");
2579ba5238cSMalhar Jajoo   MachineFunction *F = BB->getParent();
2589ba5238cSMalhar Jajoo   BB->moveBefore(Before);
25960fda8ebSSam Tebbs 
26058f3201aSMalhar Jajoo   // Since only the blocks are to be moved around (but the control flow must
26158f3201aSMalhar Jajoo   // not change), if there were any fall-throughs (to/from adjacent blocks),
26258f3201aSMalhar Jajoo   // replace with unconditional branch to the fall through block.
26360fda8ebSSam Tebbs   auto FixFallthrough = [&](MachineBasicBlock *From, MachineBasicBlock *To) {
26460fda8ebSSam Tebbs     LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Checking for fallthrough from "
26560fda8ebSSam Tebbs                       << From->getName() << " to " << To->getName() << "\n");
26660fda8ebSSam Tebbs     assert(From->isSuccessor(To) &&
26760fda8ebSSam Tebbs            "'To' is expected to be a successor of 'From'");
26860fda8ebSSam Tebbs     MachineInstr &Terminator = *(--From->terminators().end());
269883758edSDavid Green     if (!TII->isPredicated(Terminator) &&
270883758edSDavid Green         (isUncondBranchOpcode(Terminator.getOpcode()) ||
271883758edSDavid Green          isIndirectBranchOpcode(Terminator.getOpcode()) ||
272883758edSDavid Green          isJumpTableBranchOpcode(Terminator.getOpcode()) ||
273883758edSDavid Green          Terminator.isReturn()))
274883758edSDavid Green       return;
27560fda8ebSSam Tebbs     // The BB doesn't have an unconditional branch so it relied on
27660fda8ebSSam Tebbs     // fall-through. Fix by adding an unconditional branch to the moved BB.
27760fda8ebSSam Tebbs     MachineInstrBuilder MIB =
278465df353SDavid Green         BuildMI(From, Terminator.getDebugLoc(), TII->get(ARM::t2B));
27960fda8ebSSam Tebbs     MIB.addMBB(To);
28060fda8ebSSam Tebbs     MIB.addImm(ARMCC::CondCodes::AL);
28160fda8ebSSam Tebbs     MIB.addReg(ARM::NoRegister);
28260fda8ebSSam Tebbs     LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Adding unconditional branch from "
28360fda8ebSSam Tebbs                       << From->getName() << " to " << To->getName() << ": "
28460fda8ebSSam Tebbs                       << *MIB.getInstr());
28560fda8ebSSam Tebbs   };
28660fda8ebSSam Tebbs 
28760fda8ebSSam Tebbs   // Fix fall-through to the moved BB from the one that used to be before it.
28860fda8ebSSam Tebbs   if (BBPrevious->isSuccessor(BB))
28960fda8ebSSam Tebbs     FixFallthrough(BBPrevious, BB);
2909ba5238cSMalhar Jajoo   // Fix fall through from the destination BB to the one that used to before it.
2919ba5238cSMalhar Jajoo   if (BeforePrev->isSuccessor(Before))
2929ba5238cSMalhar Jajoo     FixFallthrough(BeforePrev, Before);
29360fda8ebSSam Tebbs   // Fix fall through from the moved BB to the one that used to follow.
29460fda8ebSSam Tebbs   if (BBNext && BB->isSuccessor(BBNext))
29560fda8ebSSam Tebbs     FixFallthrough(BB, BBNext);
29660fda8ebSSam Tebbs 
2979ba5238cSMalhar Jajoo   F->RenumberBlocks();
2989ba5238cSMalhar Jajoo   BBUtils->computeAllBlockSizes();
29928293918SDavid Green   BBUtils->adjustBBOffsetsAfter(BB);
30060fda8ebSSam Tebbs }
301