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