Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARM/ARMBlockPlacement.cpp
35266 views
//===-- ARMBlockPlacement.cpp - ARM block placement pass ------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This pass re-arranges machine basic blocks to suit target requirements.9// Currently it only moves blocks to fix backwards WLS branches.10//11//===----------------------------------------------------------------------===//1213#include "ARM.h"14#include "ARMBaseInstrInfo.h"15#include "ARMBasicBlockInfo.h"16#include "ARMSubtarget.h"17#include "MVETailPredUtils.h"18#include "llvm/CodeGen/LivePhysRegs.h"19#include "llvm/CodeGen/MachineFunctionPass.h"20#include "llvm/CodeGen/MachineInstrBuilder.h"21#include "llvm/CodeGen/MachineLoopInfo.h"2223using namespace llvm;2425#define DEBUG_TYPE "arm-block-placement"26#define DEBUG_PREFIX "ARM Block Placement: "2728namespace llvm {29class ARMBlockPlacement : public MachineFunctionPass {30private:31const ARMBaseInstrInfo *TII;32std::unique_ptr<ARMBasicBlockUtils> BBUtils = nullptr;33MachineLoopInfo *MLI = nullptr;34// A list of WLS instructions that need to be reverted to DLS.35SmallVector<MachineInstr *> RevertedWhileLoops;3637public:38static char ID;39ARMBlockPlacement() : MachineFunctionPass(ID) {}4041bool runOnMachineFunction(MachineFunction &MF) override;42void moveBasicBlock(MachineBasicBlock *BB, MachineBasicBlock *Before);43bool blockIsBefore(MachineBasicBlock *BB, MachineBasicBlock *Other);44bool fixBackwardsWLS(MachineLoop *ML);45bool processPostOrderLoops(MachineLoop *ML);46bool revertWhileToDoLoop(MachineInstr *WLS);4748void getAnalysisUsage(AnalysisUsage &AU) const override {49AU.addRequired<MachineLoopInfoWrapperPass>();50MachineFunctionPass::getAnalysisUsage(AU);51}52};5354} // namespace llvm5556FunctionPass *llvm::createARMBlockPlacementPass() {57return new ARMBlockPlacement();58}5960char ARMBlockPlacement::ID = 0;6162INITIALIZE_PASS(ARMBlockPlacement, DEBUG_TYPE, "ARM block placement", false,63false)6465static MachineInstr *findWLSInBlock(MachineBasicBlock *MBB) {66for (auto &Terminator : MBB->terminators()) {67if (isWhileLoopStart(Terminator))68return &Terminator;69}70return nullptr;71}7273/// Find WhileLoopStart in the loop predecessor BB or otherwise in its only74/// predecessor. If found, returns (BB, WLS Instr) pair, otherwise a null pair.75static MachineInstr *findWLS(MachineLoop *ML) {76MachineBasicBlock *Predecessor = ML->getLoopPredecessor();77if (!Predecessor)78return nullptr;79MachineInstr *WlsInstr = findWLSInBlock(Predecessor);80if (WlsInstr)81return WlsInstr;82if (Predecessor->pred_size() == 1)83return findWLSInBlock(*Predecessor->pred_begin());84return nullptr;85}8687// Revert a WhileLoopStart to an equivalent DoLoopStart and branch. Note that88// because of the branches this requires an extra block to be created.89bool ARMBlockPlacement::revertWhileToDoLoop(MachineInstr *WLS) {90// lr = t2WhileLoopStartTP r0, r1, TgtBB91// t2Br Ph92// ->93// cmp r0, 094// brcc TgtBB95// block2:96// LR = t2DoLoopStartTP r0, r197// t2Br Ph98MachineBasicBlock *Preheader = WLS->getParent();99assert(WLS != &Preheader->back());100assert(WLS->getNextNode() == &Preheader->back());101MachineInstr *Br = &Preheader->back();102assert(Br->getOpcode() == ARM::t2B);103assert(Br->getOperand(1).getImm() == 14);104105// Clear the kill flags, as the cmp/bcc will no longer kill any operands.106WLS->getOperand(1).setIsKill(false);107if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)108WLS->getOperand(2).setIsKill(false);109110// Create the new block111MachineBasicBlock *NewBlock = Preheader->getParent()->CreateMachineBasicBlock(112Preheader->getBasicBlock());113Preheader->getParent()->insert(++Preheader->getIterator(), NewBlock);114// Move the Br to it115Br->removeFromParent();116NewBlock->insert(NewBlock->end(), Br);117// And setup the successors correctly.118Preheader->replaceSuccessor(Br->getOperand(0).getMBB(), NewBlock);119NewBlock->addSuccessor(Br->getOperand(0).getMBB());120121// Create a new DLS to replace the WLS122MachineInstrBuilder MIB =123BuildMI(*NewBlock, Br, WLS->getDebugLoc(),124TII->get(WLS->getOpcode() == ARM::t2WhileLoopStartTP125? ARM::t2DoLoopStartTP126: ARM::t2DoLoopStart));127MIB.add(WLS->getOperand(0));128MIB.add(WLS->getOperand(1));129if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)130MIB.add(WLS->getOperand(2));131132LLVM_DEBUG(dbgs() << DEBUG_PREFIX133<< "Reverting While Loop to Do Loop: " << *WLS << "\n");134135RevertWhileLoopStartLR(WLS, TII, ARM::t2Bcc, true);136137LivePhysRegs LiveRegs;138computeAndAddLiveIns(LiveRegs, *NewBlock);139140Preheader->getParent()->RenumberBlocks();141BBUtils->computeAllBlockSizes();142BBUtils->adjustBBOffsetsAfter(Preheader);143144return true;145}146147/// Checks if loop has a backwards branching WLS, and if possible, fixes it.148/// This requires checking the predecessor (ie. preheader or it's predecessor)149/// for a WLS and if its loopExit/target is before it.150/// If moving the predecessor won't convert a WLS (to the predecessor) from151/// a forward to a backward branching WLS, then move the predecessor block152/// to before the loopExit/target.153bool ARMBlockPlacement::fixBackwardsWLS(MachineLoop *ML) {154MachineInstr *WlsInstr = findWLS(ML);155if (!WlsInstr)156return false;157158MachineBasicBlock *Predecessor = WlsInstr->getParent();159MachineBasicBlock *LoopExit = getWhileLoopStartTargetBB(*WlsInstr);160161// We don't want to move Preheader to before the function's entry block.162if (!LoopExit->getPrevNode())163return false;164if (blockIsBefore(Predecessor, LoopExit))165return false;166LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Found a backwards WLS from "167<< Predecessor->getFullName() << " to "168<< LoopExit->getFullName() << "\n");169170// Make sure no forward branching WLSs to the Predecessor become backwards171// branching. An example loop structure where the Predecessor can't be moved,172// since bb2's WLS will become forwards once bb3 is moved before/above bb1.173//174// bb1: - LoopExit175// bb2:176// WLS bb3177// bb3: - Predecessor178// WLS bb1179// bb4: - Header180for (auto It = ++LoopExit->getIterator(); It != Predecessor->getIterator();181++It) {182MachineBasicBlock *MBB = &*It;183for (auto &Terminator : MBB->terminators()) {184if (!isWhileLoopStart(Terminator))185continue;186MachineBasicBlock *WLSTarget = getWhileLoopStartTargetBB(Terminator);187// TODO: Analyse the blocks to make a decision if it would be worth188// moving Preheader even if we'd introduce a backwards WLS189if (WLSTarget == Predecessor) {190LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Can't move Predecessor block as "191<< "it would convert a WLS from forward to a "192<< "backwards branching WLS\n");193RevertedWhileLoops.push_back(WlsInstr);194return false;195}196}197}198199moveBasicBlock(Predecessor, LoopExit);200return true;201}202203/// Updates ordering (of WLS BB and their loopExits) in inner loops first204/// Returns true if any change was made in any of the loops205bool ARMBlockPlacement::processPostOrderLoops(MachineLoop *ML) {206bool Changed = false;207for (auto *InnerML : *ML)208Changed |= processPostOrderLoops(InnerML);209return Changed | fixBackwardsWLS(ML);210}211212bool ARMBlockPlacement::runOnMachineFunction(MachineFunction &MF) {213if (skipFunction(MF.getFunction()))214return false;215const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>();216if (!ST.hasLOB())217return false;218LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Running on " << MF.getName() << "\n");219MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();220TII = static_cast<const ARMBaseInstrInfo *>(ST.getInstrInfo());221BBUtils = std::make_unique<ARMBasicBlockUtils>(MF);222MF.RenumberBlocks();223BBUtils->computeAllBlockSizes();224BBUtils->adjustBBOffsetsAfter(&MF.front());225bool Changed = false;226RevertedWhileLoops.clear();227228// Find loops with a backwards branching WLS and fix if possible.229for (auto *ML : *MLI)230Changed |= processPostOrderLoops(ML);231232// Revert any While loops still out of range to DLS loops.233for (auto *WlsInstr : RevertedWhileLoops)234Changed |= revertWhileToDoLoop(WlsInstr);235236return Changed;237}238239bool ARMBlockPlacement::blockIsBefore(MachineBasicBlock *BB,240MachineBasicBlock *Other) {241return BBUtils->getOffsetOf(Other) > BBUtils->getOffsetOf(BB);242}243244// Moves a BasicBlock before another, without changing the control flow245void ARMBlockPlacement::moveBasicBlock(MachineBasicBlock *BB,246MachineBasicBlock *Before) {247LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Moving " << BB->getName() << " before "248<< Before->getName() << "\n");249MachineBasicBlock *BBPrevious = BB->getPrevNode();250assert(BBPrevious && "Cannot move the function entry basic block");251MachineBasicBlock *BBNext = BB->getNextNode();252253MachineBasicBlock *BeforePrev = Before->getPrevNode();254assert(BeforePrev &&255"Cannot move the given block to before the function entry block");256MachineFunction *F = BB->getParent();257BB->moveBefore(Before);258259// Since only the blocks are to be moved around (but the control flow must260// not change), if there were any fall-throughs (to/from adjacent blocks),261// replace with unconditional branch to the fall through block.262auto FixFallthrough = [&](MachineBasicBlock *From, MachineBasicBlock *To) {263LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Checking for fallthrough from "264<< From->getName() << " to " << To->getName() << "\n");265assert(From->isSuccessor(To) &&266"'To' is expected to be a successor of 'From'");267MachineInstr &Terminator = *(--From->terminators().end());268if (!TII->isPredicated(Terminator) &&269(isUncondBranchOpcode(Terminator.getOpcode()) ||270isIndirectBranchOpcode(Terminator.getOpcode()) ||271isJumpTableBranchOpcode(Terminator.getOpcode()) ||272Terminator.isReturn()))273return;274// The BB doesn't have an unconditional branch so it relied on275// fall-through. Fix by adding an unconditional branch to the moved BB.276MachineInstrBuilder MIB =277BuildMI(From, Terminator.getDebugLoc(), TII->get(ARM::t2B));278MIB.addMBB(To);279MIB.addImm(ARMCC::CondCodes::AL);280MIB.addReg(ARM::NoRegister);281LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Adding unconditional branch from "282<< From->getName() << " to " << To->getName() << ": "283<< *MIB.getInstr());284};285286// Fix fall-through to the moved BB from the one that used to be before it.287if (BBPrevious->isSuccessor(BB))288FixFallthrough(BBPrevious, BB);289// Fix fall through from the destination BB to the one that used to before it.290if (BeforePrev->isSuccessor(Before))291FixFallthrough(BeforePrev, Before);292// Fix fall through from the moved BB to the one that used to follow.293if (BBNext && BB->isSuccessor(BBNext))294FixFallthrough(BB, BBNext);295296F->RenumberBlocks();297BBUtils->computeAllBlockSizes();298BBUtils->adjustBBOffsetsAfter(BB);299}300301302