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