123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- //===-- ARMBlockPlacement.cpp - ARM block placement pass ------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This pass re-arranges machine basic blocks to suit target requirements.
- // Currently it only moves blocks to fix backwards WLS branches.
- //
- //===----------------------------------------------------------------------===//
- #include "ARM.h"
- #include "ARMBaseInstrInfo.h"
- #include "ARMBasicBlockInfo.h"
- #include "ARMSubtarget.h"
- #include "MVETailPredUtils.h"
- #include "llvm/CodeGen/LivePhysRegs.h"
- #include "llvm/CodeGen/MachineFunctionPass.h"
- #include "llvm/CodeGen/MachineInstrBuilder.h"
- #include "llvm/CodeGen/MachineLoopInfo.h"
- using namespace llvm;
- #define DEBUG_TYPE "arm-block-placement"
- #define DEBUG_PREFIX "ARM Block Placement: "
- namespace llvm {
- class ARMBlockPlacement : public MachineFunctionPass {
- private:
- const ARMBaseInstrInfo *TII;
- std::unique_ptr<ARMBasicBlockUtils> BBUtils = nullptr;
- MachineLoopInfo *MLI = nullptr;
- // A list of WLS instructions that need to be reverted to DLS.
- SmallVector<MachineInstr *> RevertedWhileLoops;
- public:
- static char ID;
- ARMBlockPlacement() : MachineFunctionPass(ID) {}
- bool runOnMachineFunction(MachineFunction &MF) override;
- void moveBasicBlock(MachineBasicBlock *BB, MachineBasicBlock *Before);
- bool blockIsBefore(MachineBasicBlock *BB, MachineBasicBlock *Other);
- bool fixBackwardsWLS(MachineLoop *ML);
- bool processPostOrderLoops(MachineLoop *ML);
- bool revertWhileToDoLoop(MachineInstr *WLS);
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addRequired<MachineLoopInfo>();
- MachineFunctionPass::getAnalysisUsage(AU);
- }
- };
- } // namespace llvm
- FunctionPass *llvm::createARMBlockPlacementPass() {
- return new ARMBlockPlacement();
- }
- char ARMBlockPlacement::ID = 0;
- INITIALIZE_PASS(ARMBlockPlacement, DEBUG_TYPE, "ARM block placement", false,
- false)
- static MachineInstr *findWLSInBlock(MachineBasicBlock *MBB) {
- for (auto &Terminator : MBB->terminators()) {
- if (isWhileLoopStart(Terminator))
- return &Terminator;
- }
- return nullptr;
- }
- /// Find WhileLoopStart in the loop predecessor BB or otherwise in its only
- /// predecessor. If found, returns (BB, WLS Instr) pair, otherwise a null pair.
- static MachineInstr *findWLS(MachineLoop *ML) {
- MachineBasicBlock *Predecessor = ML->getLoopPredecessor();
- if (!Predecessor)
- return nullptr;
- MachineInstr *WlsInstr = findWLSInBlock(Predecessor);
- if (WlsInstr)
- return WlsInstr;
- if (Predecessor->pred_size() == 1)
- return findWLSInBlock(*Predecessor->pred_begin());
- return nullptr;
- }
- // Revert a WhileLoopStart to an equivalent DoLoopStart and branch. Note that
- // because of the branches this requires an extra block to be created.
- bool ARMBlockPlacement::revertWhileToDoLoop(MachineInstr *WLS) {
- // lr = t2WhileLoopStartTP r0, r1, TgtBB
- // t2Br Ph
- // ->
- // cmp r0, 0
- // brcc TgtBB
- // block2:
- // LR = t2DoLoopStartTP r0, r1
- // t2Br Ph
- MachineBasicBlock *Preheader = WLS->getParent();
- assert(WLS != &Preheader->back());
- assert(WLS->getNextNode() == &Preheader->back());
- MachineInstr *Br = &Preheader->back();
- assert(Br->getOpcode() == ARM::t2B);
- assert(Br->getOperand(1).getImm() == 14);
- // Clear the kill flags, as the cmp/bcc will no longer kill any operands.
- WLS->getOperand(1).setIsKill(false);
- if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)
- WLS->getOperand(2).setIsKill(false);
- // Create the new block
- MachineBasicBlock *NewBlock = Preheader->getParent()->CreateMachineBasicBlock(
- Preheader->getBasicBlock());
- Preheader->getParent()->insert(++Preheader->getIterator(), NewBlock);
- // Move the Br to it
- Br->removeFromParent();
- NewBlock->insert(NewBlock->end(), Br);
- // And setup the successors correctly.
- Preheader->replaceSuccessor(Br->getOperand(0).getMBB(), NewBlock);
- NewBlock->addSuccessor(Br->getOperand(0).getMBB());
- // Create a new DLS to replace the WLS
- MachineInstrBuilder MIB =
- BuildMI(*NewBlock, Br, WLS->getDebugLoc(),
- TII->get(WLS->getOpcode() == ARM::t2WhileLoopStartTP
- ? ARM::t2DoLoopStartTP
- : ARM::t2DoLoopStart));
- MIB.add(WLS->getOperand(0));
- MIB.add(WLS->getOperand(1));
- if (WLS->getOpcode() == ARM::t2WhileLoopStartTP)
- MIB.add(WLS->getOperand(2));
- LLVM_DEBUG(dbgs() << DEBUG_PREFIX
- << "Reverting While Loop to Do Loop: " << *WLS << "\n");
- RevertWhileLoopStartLR(WLS, TII, ARM::t2Bcc, true);
- LivePhysRegs LiveRegs;
- computeAndAddLiveIns(LiveRegs, *NewBlock);
- Preheader->getParent()->RenumberBlocks();
- BBUtils->computeAllBlockSizes();
- BBUtils->adjustBBOffsetsAfter(Preheader);
- return true;
- }
- /// Checks if loop has a backwards branching WLS, and if possible, fixes it.
- /// This requires checking the predecessor (ie. preheader or it's predecessor)
- /// for a WLS and if its loopExit/target is before it.
- /// If moving the predecessor won't convert a WLS (to the predecessor) from
- /// a forward to a backward branching WLS, then move the predecessor block
- /// to before the loopExit/target.
- bool ARMBlockPlacement::fixBackwardsWLS(MachineLoop *ML) {
- MachineInstr *WlsInstr = findWLS(ML);
- if (!WlsInstr)
- return false;
- MachineBasicBlock *Predecessor = WlsInstr->getParent();
- MachineBasicBlock *LoopExit = getWhileLoopStartTargetBB(*WlsInstr);
- // We don't want to move Preheader to before the function's entry block.
- if (!LoopExit->getPrevNode())
- return false;
- if (blockIsBefore(Predecessor, LoopExit))
- return false;
- LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Found a backwards WLS from "
- << Predecessor->getFullName() << " to "
- << LoopExit->getFullName() << "\n");
- // Make sure no forward branching WLSs to the Predecessor become backwards
- // branching. An example loop structure where the Predecessor can't be moved,
- // since bb2's WLS will become forwards once bb3 is moved before/above bb1.
- //
- // bb1: - LoopExit
- // bb2:
- // WLS bb3
- // bb3: - Predecessor
- // WLS bb1
- // bb4: - Header
- for (auto It = ++LoopExit->getIterator(); It != Predecessor->getIterator();
- ++It) {
- MachineBasicBlock *MBB = &*It;
- for (auto &Terminator : MBB->terminators()) {
- if (!isWhileLoopStart(Terminator))
- continue;
- MachineBasicBlock *WLSTarget = getWhileLoopStartTargetBB(Terminator);
- // TODO: Analyse the blocks to make a decision if it would be worth
- // moving Preheader even if we'd introduce a backwards WLS
- if (WLSTarget == Predecessor) {
- LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Can't move Predecessor block as "
- << "it would convert a WLS from forward to a "
- << "backwards branching WLS\n");
- RevertedWhileLoops.push_back(WlsInstr);
- return false;
- }
- }
- }
- moveBasicBlock(Predecessor, LoopExit);
- return true;
- }
- /// Updates ordering (of WLS BB and their loopExits) in inner loops first
- /// Returns true if any change was made in any of the loops
- bool ARMBlockPlacement::processPostOrderLoops(MachineLoop *ML) {
- bool Changed = false;
- for (auto *InnerML : *ML)
- Changed |= processPostOrderLoops(InnerML);
- return Changed | fixBackwardsWLS(ML);
- }
- bool ARMBlockPlacement::runOnMachineFunction(MachineFunction &MF) {
- if (skipFunction(MF.getFunction()))
- return false;
- const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>();
- if (!ST.hasLOB())
- return false;
- LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Running on " << MF.getName() << "\n");
- MLI = &getAnalysis<MachineLoopInfo>();
- TII = static_cast<const ARMBaseInstrInfo *>(ST.getInstrInfo());
- BBUtils = std::unique_ptr<ARMBasicBlockUtils>(new ARMBasicBlockUtils(MF));
- MF.RenumberBlocks();
- BBUtils->computeAllBlockSizes();
- BBUtils->adjustBBOffsetsAfter(&MF.front());
- bool Changed = false;
- RevertedWhileLoops.clear();
- // Find loops with a backwards branching WLS and fix if possible.
- for (auto *ML : *MLI)
- Changed |= processPostOrderLoops(ML);
- // Revert any While loops still out of range to DLS loops.
- for (auto *WlsInstr : RevertedWhileLoops)
- Changed |= revertWhileToDoLoop(WlsInstr);
- return Changed;
- }
- bool ARMBlockPlacement::blockIsBefore(MachineBasicBlock *BB,
- MachineBasicBlock *Other) {
- return BBUtils->getOffsetOf(Other) > BBUtils->getOffsetOf(BB);
- }
- // Moves a BasicBlock before another, without changing the control flow
- void ARMBlockPlacement::moveBasicBlock(MachineBasicBlock *BB,
- MachineBasicBlock *Before) {
- LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Moving " << BB->getName() << " before "
- << Before->getName() << "\n");
- MachineBasicBlock *BBPrevious = BB->getPrevNode();
- assert(BBPrevious && "Cannot move the function entry basic block");
- MachineBasicBlock *BBNext = BB->getNextNode();
- MachineBasicBlock *BeforePrev = Before->getPrevNode();
- assert(BeforePrev &&
- "Cannot move the given block to before the function entry block");
- MachineFunction *F = BB->getParent();
- BB->moveBefore(Before);
- // Since only the blocks are to be moved around (but the control flow must
- // not change), if there were any fall-throughs (to/from adjacent blocks),
- // replace with unconditional branch to the fall through block.
- auto FixFallthrough = [&](MachineBasicBlock *From, MachineBasicBlock *To) {
- LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Checking for fallthrough from "
- << From->getName() << " to " << To->getName() << "\n");
- assert(From->isSuccessor(To) &&
- "'To' is expected to be a successor of 'From'");
- MachineInstr &Terminator = *(--From->terminators().end());
- if (!TII->isPredicated(Terminator) &&
- (isUncondBranchOpcode(Terminator.getOpcode()) ||
- isIndirectBranchOpcode(Terminator.getOpcode()) ||
- isJumpTableBranchOpcode(Terminator.getOpcode()) ||
- Terminator.isReturn()))
- return;
- // The BB doesn't have an unconditional branch so it relied on
- // fall-through. Fix by adding an unconditional branch to the moved BB.
- MachineInstrBuilder MIB =
- BuildMI(From, Terminator.getDebugLoc(), TII->get(ARM::t2B));
- MIB.addMBB(To);
- MIB.addImm(ARMCC::CondCodes::AL);
- MIB.addReg(ARM::NoRegister);
- LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Adding unconditional branch from "
- << From->getName() << " to " << To->getName() << ": "
- << *MIB.getInstr());
- };
- // Fix fall-through to the moved BB from the one that used to be before it.
- if (BBPrevious->isSuccessor(BB))
- FixFallthrough(BBPrevious, BB);
- // Fix fall through from the destination BB to the one that used to before it.
- if (BeforePrev->isSuccessor(Before))
- FixFallthrough(BeforePrev, Before);
- // Fix fall through from the moved BB to the one that used to follow.
- if (BBNext && BB->isSuccessor(BBNext))
- FixFallthrough(BB, BBNext);
- F->RenumberBlocks();
- BBUtils->computeAllBlockSizes();
- BBUtils->adjustBBOffsetsAfter(BB);
- }
|