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" 18e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 19e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 20e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h" 21e8d8bef9SDimitry Andric 22e8d8bef9SDimitry Andric using namespace llvm; 23e8d8bef9SDimitry Andric 24e8d8bef9SDimitry Andric #define DEBUG_TYPE "arm-block-placement" 25e8d8bef9SDimitry Andric #define DEBUG_PREFIX "ARM Block Placement: " 26e8d8bef9SDimitry Andric 27e8d8bef9SDimitry Andric namespace llvm { 28e8d8bef9SDimitry Andric class ARMBlockPlacement : public MachineFunctionPass { 29e8d8bef9SDimitry Andric private: 30e8d8bef9SDimitry Andric const ARMBaseInstrInfo *TII; 31e8d8bef9SDimitry Andric std::unique_ptr<ARMBasicBlockUtils> BBUtils = nullptr; 32e8d8bef9SDimitry Andric MachineLoopInfo *MLI = nullptr; 33e8d8bef9SDimitry Andric 34e8d8bef9SDimitry Andric public: 35e8d8bef9SDimitry Andric static char ID; 36e8d8bef9SDimitry Andric ARMBlockPlacement() : MachineFunctionPass(ID) {} 37e8d8bef9SDimitry Andric 38e8d8bef9SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 39e8d8bef9SDimitry Andric void moveBasicBlock(MachineBasicBlock *BB, MachineBasicBlock *After); 40e8d8bef9SDimitry Andric bool blockIsBefore(MachineBasicBlock *BB, MachineBasicBlock *Other); 41e8d8bef9SDimitry Andric 42e8d8bef9SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 43e8d8bef9SDimitry Andric AU.setPreservesCFG(); 44e8d8bef9SDimitry Andric AU.addRequired<MachineLoopInfo>(); 45e8d8bef9SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 46e8d8bef9SDimitry Andric } 47e8d8bef9SDimitry Andric }; 48e8d8bef9SDimitry Andric 49e8d8bef9SDimitry Andric } // namespace llvm 50e8d8bef9SDimitry Andric 51e8d8bef9SDimitry Andric FunctionPass *llvm::createARMBlockPlacementPass() { 52e8d8bef9SDimitry Andric return new ARMBlockPlacement(); 53e8d8bef9SDimitry Andric } 54e8d8bef9SDimitry Andric 55e8d8bef9SDimitry Andric char ARMBlockPlacement::ID = 0; 56e8d8bef9SDimitry Andric 57e8d8bef9SDimitry Andric INITIALIZE_PASS(ARMBlockPlacement, DEBUG_TYPE, "ARM block placement", false, 58e8d8bef9SDimitry Andric false) 59e8d8bef9SDimitry Andric 60e8d8bef9SDimitry Andric bool ARMBlockPlacement::runOnMachineFunction(MachineFunction &MF) { 61e8d8bef9SDimitry Andric if (skipFunction(MF.getFunction())) 62e8d8bef9SDimitry Andric return false; 63e8d8bef9SDimitry Andric const ARMSubtarget &ST = static_cast<const ARMSubtarget &>(MF.getSubtarget()); 64e8d8bef9SDimitry Andric if (!ST.hasLOB()) 65e8d8bef9SDimitry Andric return false; 66e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Running on " << MF.getName() << "\n"); 67e8d8bef9SDimitry Andric MLI = &getAnalysis<MachineLoopInfo>(); 68e8d8bef9SDimitry Andric TII = static_cast<const ARMBaseInstrInfo *>(ST.getInstrInfo()); 69e8d8bef9SDimitry Andric BBUtils = std::unique_ptr<ARMBasicBlockUtils>(new ARMBasicBlockUtils(MF)); 70e8d8bef9SDimitry Andric MF.RenumberBlocks(); 71e8d8bef9SDimitry Andric BBUtils->computeAllBlockSizes(); 72e8d8bef9SDimitry Andric BBUtils->adjustBBOffsetsAfter(&MF.front()); 73e8d8bef9SDimitry Andric bool Changed = false; 74e8d8bef9SDimitry Andric 75e8d8bef9SDimitry Andric // Find loops with a backwards branching WLS. 76e8d8bef9SDimitry Andric // This requires looping over the loops in the function, checking each 77e8d8bef9SDimitry Andric // preheader for a WLS and if its target is before the preheader. If moving 78e8d8bef9SDimitry Andric // the target block wouldn't produce another backwards WLS or a new forwards 79e8d8bef9SDimitry Andric // LE branch then move the target block after the preheader. 80e8d8bef9SDimitry Andric for (auto *ML : *MLI) { 81e8d8bef9SDimitry Andric MachineBasicBlock *Preheader = ML->getLoopPredecessor(); 82e8d8bef9SDimitry Andric if (!Preheader) 83e8d8bef9SDimitry Andric continue; 84e8d8bef9SDimitry Andric 85e8d8bef9SDimitry Andric for (auto &Terminator : Preheader->terminators()) { 86e8d8bef9SDimitry Andric if (Terminator.getOpcode() != ARM::t2WhileLoopStart) 87e8d8bef9SDimitry Andric continue; 88e8d8bef9SDimitry Andric MachineBasicBlock *LoopExit = Terminator.getOperand(1).getMBB(); 89e8d8bef9SDimitry Andric // We don't want to move the function's entry block. 90e8d8bef9SDimitry Andric if (!LoopExit->getPrevNode()) 91e8d8bef9SDimitry Andric continue; 92e8d8bef9SDimitry Andric if (blockIsBefore(Preheader, LoopExit)) 93e8d8bef9SDimitry Andric continue; 94e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Found a backwards WLS from " 95e8d8bef9SDimitry Andric << Preheader->getFullName() << " to " 96e8d8bef9SDimitry Andric << LoopExit->getFullName() << "\n"); 97e8d8bef9SDimitry Andric 98e8d8bef9SDimitry Andric // Make sure that moving the target block doesn't cause any of its WLSs 99e8d8bef9SDimitry Andric // that were previously not backwards to become backwards 100e8d8bef9SDimitry Andric bool CanMove = true; 101e8d8bef9SDimitry Andric for (auto &LoopExitTerminator : LoopExit->terminators()) { 102e8d8bef9SDimitry Andric if (LoopExitTerminator.getOpcode() != ARM::t2WhileLoopStart) 103e8d8bef9SDimitry Andric continue; 104e8d8bef9SDimitry Andric // An example loop structure where the LoopExit can't be moved, since 105e8d8bef9SDimitry Andric // bb1's WLS will become backwards once it's moved after bb3 bb1: - 106e8d8bef9SDimitry Andric // LoopExit 107e8d8bef9SDimitry Andric // WLS bb2 - LoopExit2 108e8d8bef9SDimitry Andric // bb2: 109e8d8bef9SDimitry Andric // ... 110e8d8bef9SDimitry Andric // bb3: - Preheader 111e8d8bef9SDimitry Andric // WLS bb1 112e8d8bef9SDimitry Andric // bb4: - Header 113e8d8bef9SDimitry Andric MachineBasicBlock *LoopExit2 = 114e8d8bef9SDimitry Andric LoopExitTerminator.getOperand(1).getMBB(); 115e8d8bef9SDimitry Andric // If the WLS from LoopExit to LoopExit2 is already backwards then 116e8d8bef9SDimitry Andric // moving LoopExit won't affect it, so it can be moved. If LoopExit2 is 117e8d8bef9SDimitry Andric // after the Preheader then moving will keep it as a forward branch, so 118e8d8bef9SDimitry Andric // it can be moved. If LoopExit2 is between the Preheader and LoopExit 119e8d8bef9SDimitry Andric // then moving LoopExit will make it a backwards branch, so it can't be 120e8d8bef9SDimitry Andric // moved since we'd fix one and introduce one backwards branch. 121e8d8bef9SDimitry Andric // TODO: Analyse the blocks to make a decision if it would be worth 122e8d8bef9SDimitry Andric // moving LoopExit even if LoopExit2 is between the Preheader and 123e8d8bef9SDimitry Andric // LoopExit. 124e8d8bef9SDimitry Andric if (!blockIsBefore(LoopExit2, LoopExit) && 125e8d8bef9SDimitry Andric (LoopExit2 == Preheader || blockIsBefore(LoopExit2, Preheader))) { 126e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << DEBUG_PREFIX 127e8d8bef9SDimitry Andric << "Can't move the target block as it would " 128e8d8bef9SDimitry Andric "introduce a new backwards WLS branch\n"); 129e8d8bef9SDimitry Andric CanMove = false; 130e8d8bef9SDimitry Andric break; 131e8d8bef9SDimitry Andric } 132e8d8bef9SDimitry Andric } 133e8d8bef9SDimitry Andric 134e8d8bef9SDimitry Andric if (CanMove) { 135e8d8bef9SDimitry Andric // Make sure no LEs become forwards. 136e8d8bef9SDimitry Andric // An example loop structure where the LoopExit can't be moved, since 137e8d8bef9SDimitry Andric // bb2's LE will become forwards once bb1 is moved after bb3. 138e8d8bef9SDimitry Andric // bb1: - LoopExit 139e8d8bef9SDimitry Andric // bb2: 140e8d8bef9SDimitry Andric // LE bb1 - Terminator 141e8d8bef9SDimitry Andric // bb3: - Preheader 142e8d8bef9SDimitry Andric // WLS bb1 143e8d8bef9SDimitry Andric // bb4: - Header 144e8d8bef9SDimitry Andric for (auto It = LoopExit->getIterator(); It != Preheader->getIterator(); 145e8d8bef9SDimitry Andric It++) { 146e8d8bef9SDimitry Andric MachineBasicBlock *MBB = &*It; 147e8d8bef9SDimitry Andric for (auto &Terminator : MBB->terminators()) { 148*4652422eSDimitry Andric if (Terminator.getOpcode() != ARM::t2LoopEndDec) 149e8d8bef9SDimitry Andric continue; 150e8d8bef9SDimitry Andric MachineBasicBlock *LETarget = Terminator.getOperand(2).getMBB(); 151e8d8bef9SDimitry Andric // The LE will become forwards branching if it branches to LoopExit 152e8d8bef9SDimitry Andric // which isn't allowed by the architecture, so we should avoid 153e8d8bef9SDimitry Andric // introducing these. 154e8d8bef9SDimitry Andric // TODO: Analyse the blocks to make a decision if it would be worth 155e8d8bef9SDimitry Andric // moving LoopExit even if we'd introduce a forwards LE 156e8d8bef9SDimitry Andric if (LETarget == LoopExit) { 157e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << DEBUG_PREFIX 158e8d8bef9SDimitry Andric << "Can't move the target block as it would " 159e8d8bef9SDimitry Andric "introduce a new forwards LE branch\n"); 160e8d8bef9SDimitry Andric CanMove = false; 161e8d8bef9SDimitry Andric break; 162e8d8bef9SDimitry Andric } 163e8d8bef9SDimitry Andric } 164e8d8bef9SDimitry Andric } 165e8d8bef9SDimitry Andric 166e8d8bef9SDimitry Andric if (!CanMove) 167e8d8bef9SDimitry Andric break; 168e8d8bef9SDimitry Andric } 169e8d8bef9SDimitry Andric 170e8d8bef9SDimitry Andric if (CanMove) { 171e8d8bef9SDimitry Andric moveBasicBlock(LoopExit, Preheader); 172e8d8bef9SDimitry Andric Changed = true; 173e8d8bef9SDimitry Andric break; 174e8d8bef9SDimitry Andric } 175e8d8bef9SDimitry Andric } 176e8d8bef9SDimitry Andric } 177e8d8bef9SDimitry Andric 178e8d8bef9SDimitry Andric return Changed; 179e8d8bef9SDimitry Andric } 180e8d8bef9SDimitry Andric 181e8d8bef9SDimitry Andric bool ARMBlockPlacement::blockIsBefore(MachineBasicBlock *BB, 182e8d8bef9SDimitry Andric MachineBasicBlock *Other) { 183e8d8bef9SDimitry Andric return BBUtils->getOffsetOf(Other) > BBUtils->getOffsetOf(BB); 184e8d8bef9SDimitry Andric } 185e8d8bef9SDimitry Andric 186e8d8bef9SDimitry Andric void ARMBlockPlacement::moveBasicBlock(MachineBasicBlock *BB, 187e8d8bef9SDimitry Andric MachineBasicBlock *After) { 188e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Moving " << BB->getName() << " after " 189e8d8bef9SDimitry Andric << After->getName() << "\n"); 190e8d8bef9SDimitry Andric MachineBasicBlock *BBPrevious = BB->getPrevNode(); 191e8d8bef9SDimitry Andric assert(BBPrevious && "Cannot move the function entry basic block"); 192e8d8bef9SDimitry Andric MachineBasicBlock *AfterNext = After->getNextNode(); 193e8d8bef9SDimitry Andric MachineBasicBlock *BBNext = BB->getNextNode(); 194e8d8bef9SDimitry Andric 195e8d8bef9SDimitry Andric BB->moveAfter(After); 196e8d8bef9SDimitry Andric 197e8d8bef9SDimitry Andric auto FixFallthrough = [&](MachineBasicBlock *From, MachineBasicBlock *To) { 198e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Checking for fallthrough from " 199e8d8bef9SDimitry Andric << From->getName() << " to " << To->getName() << "\n"); 200e8d8bef9SDimitry Andric assert(From->isSuccessor(To) && 201e8d8bef9SDimitry Andric "'To' is expected to be a successor of 'From'"); 202e8d8bef9SDimitry Andric MachineInstr &Terminator = *(--From->terminators().end()); 203e8d8bef9SDimitry Andric if (!Terminator.isUnconditionalBranch()) { 204e8d8bef9SDimitry Andric // The BB doesn't have an unconditional branch so it relied on 205e8d8bef9SDimitry Andric // fall-through. Fix by adding an unconditional branch to the moved BB. 206e8d8bef9SDimitry Andric MachineInstrBuilder MIB = 207*4652422eSDimitry Andric BuildMI(From, Terminator.getDebugLoc(), TII->get(ARM::t2B)); 208e8d8bef9SDimitry Andric MIB.addMBB(To); 209e8d8bef9SDimitry Andric MIB.addImm(ARMCC::CondCodes::AL); 210e8d8bef9SDimitry Andric MIB.addReg(ARM::NoRegister); 211e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Adding unconditional branch from " 212e8d8bef9SDimitry Andric << From->getName() << " to " << To->getName() << ": " 213e8d8bef9SDimitry Andric << *MIB.getInstr()); 214e8d8bef9SDimitry Andric } 215e8d8bef9SDimitry Andric }; 216e8d8bef9SDimitry Andric 217e8d8bef9SDimitry Andric // Fix fall-through to the moved BB from the one that used to be before it. 218e8d8bef9SDimitry Andric if (BBPrevious->isSuccessor(BB)) 219e8d8bef9SDimitry Andric FixFallthrough(BBPrevious, BB); 220e8d8bef9SDimitry Andric // Fix fall through from the destination BB to the one that used to follow. 221e8d8bef9SDimitry Andric if (AfterNext && After->isSuccessor(AfterNext)) 222e8d8bef9SDimitry Andric FixFallthrough(After, AfterNext); 223e8d8bef9SDimitry Andric // Fix fall through from the moved BB to the one that used to follow. 224e8d8bef9SDimitry Andric if (BBNext && BB->isSuccessor(BBNext)) 225e8d8bef9SDimitry Andric FixFallthrough(BB, BBNext); 226e8d8bef9SDimitry Andric 227e8d8bef9SDimitry Andric BBUtils->adjustBBOffsetsAfter(After); 228e8d8bef9SDimitry Andric } 229