summaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/lib/Target/ARM/ARMBlockPlacement.cpp
diff options
context:
space:
mode:
authorvvvv <[email protected]>2024-02-06 20:01:22 +0300
committerAlexander Smirnov <[email protected]>2024-02-09 19:18:27 +0300
commitee2b7fbda052aa09b6fdb83b8c6f0305fef3e193 (patch)
tree102765416c3866bde98a82facc7752d329ee0226 /contrib/libs/llvm16/lib/Target/ARM/ARMBlockPlacement.cpp
parent7494ca32d3a5aca00b7ac527b5f127989335102c (diff)
llvm16 targets
Diffstat (limited to 'contrib/libs/llvm16/lib/Target/ARM/ARMBlockPlacement.cpp')
-rw-r--r--contrib/libs/llvm16/lib/Target/ARM/ARMBlockPlacement.cpp300
1 files changed, 300 insertions, 0 deletions
diff --git a/contrib/libs/llvm16/lib/Target/ARM/ARMBlockPlacement.cpp b/contrib/libs/llvm16/lib/Target/ARM/ARMBlockPlacement.cpp
new file mode 100644
index 00000000000..b2d291bbe7f
--- /dev/null
+++ b/contrib/libs/llvm16/lib/Target/ARM/ARMBlockPlacement.cpp
@@ -0,0 +1,300 @@
+//===-- 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);
+}