232 lines
9.1 KiB
C++
232 lines
9.1 KiB
C++
//===-- 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 "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;
|
|
|
|
public:
|
|
static char ID;
|
|
ARMBlockPlacement() : MachineFunctionPass(ID) {}
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
void moveBasicBlock(MachineBasicBlock *BB, MachineBasicBlock *After);
|
|
bool blockIsBefore(MachineBasicBlock *BB, MachineBasicBlock *Other);
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
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)
|
|
|
|
bool ARMBlockPlacement::runOnMachineFunction(MachineFunction &MF) {
|
|
if (skipFunction(MF.getFunction()))
|
|
return false;
|
|
const ARMSubtarget &ST = static_cast<const ARMSubtarget &>(MF.getSubtarget());
|
|
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;
|
|
|
|
// Find loops with a backwards branching WLS.
|
|
// This requires looping over the loops in the function, checking each
|
|
// preheader for a WLS and if its target is before the preheader. If moving
|
|
// the target block wouldn't produce another backwards WLS or a new forwards
|
|
// LE branch then move the target block after the preheader.
|
|
for (auto *ML : *MLI) {
|
|
MachineBasicBlock *Preheader = ML->getLoopPredecessor();
|
|
if (!Preheader)
|
|
continue;
|
|
|
|
for (auto &Terminator : Preheader->terminators()) {
|
|
if (Terminator.getOpcode() != ARM::t2WhileLoopStart)
|
|
continue;
|
|
MachineBasicBlock *LoopExit = Terminator.getOperand(1).getMBB();
|
|
// We don't want to move the function's entry block.
|
|
if (!LoopExit->getPrevNode())
|
|
continue;
|
|
if (blockIsBefore(Preheader, LoopExit))
|
|
continue;
|
|
LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Found a backwards WLS from "
|
|
<< Preheader->getFullName() << " to "
|
|
<< LoopExit->getFullName() << "\n");
|
|
|
|
// Make sure that moving the target block doesn't cause any of its WLSs
|
|
// that were previously not backwards to become backwards
|
|
bool CanMove = true;
|
|
for (auto &LoopExitTerminator : LoopExit->terminators()) {
|
|
if (LoopExitTerminator.getOpcode() != ARM::t2WhileLoopStart)
|
|
continue;
|
|
// An example loop structure where the LoopExit can't be moved, since
|
|
// bb1's WLS will become backwards once it's moved after bb3 bb1: -
|
|
// LoopExit
|
|
// WLS bb2 - LoopExit2
|
|
// bb2:
|
|
// ...
|
|
// bb3: - Preheader
|
|
// WLS bb1
|
|
// bb4: - Header
|
|
MachineBasicBlock *LoopExit2 =
|
|
LoopExitTerminator.getOperand(1).getMBB();
|
|
// If the WLS from LoopExit to LoopExit2 is already backwards then
|
|
// moving LoopExit won't affect it, so it can be moved. If LoopExit2 is
|
|
// after the Preheader then moving will keep it as a forward branch, so
|
|
// it can be moved. If LoopExit2 is between the Preheader and LoopExit
|
|
// then moving LoopExit will make it a backwards branch, so it can't be
|
|
// moved since we'd fix one and introduce one backwards branch.
|
|
// TODO: Analyse the blocks to make a decision if it would be worth
|
|
// moving LoopExit even if LoopExit2 is between the Preheader and
|
|
// LoopExit.
|
|
if (!blockIsBefore(LoopExit2, LoopExit) &&
|
|
(LoopExit2 == Preheader || blockIsBefore(LoopExit2, Preheader))) {
|
|
LLVM_DEBUG(dbgs() << DEBUG_PREFIX
|
|
<< "Can't move the target block as it would "
|
|
"introduce a new backwards WLS branch\n");
|
|
CanMove = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CanMove) {
|
|
// Make sure no LEs become forwards.
|
|
// An example loop structure where the LoopExit can't be moved, since
|
|
// bb2's LE will become forwards once bb1 is moved after bb3.
|
|
// bb1: - LoopExit
|
|
// bb2:
|
|
// LE bb1 - Terminator
|
|
// bb3: - Preheader
|
|
// WLS bb1
|
|
// bb4: - Header
|
|
for (auto It = LoopExit->getIterator(); It != Preheader->getIterator();
|
|
It++) {
|
|
MachineBasicBlock *MBB = &*It;
|
|
for (auto &Terminator : MBB->terminators()) {
|
|
if (Terminator.getOpcode() != ARM::t2LoopEnd &&
|
|
Terminator.getOpcode() != ARM::t2LoopEndDec)
|
|
continue;
|
|
MachineBasicBlock *LETarget = Terminator.getOperand(2).getMBB();
|
|
// The LE will become forwards branching if it branches to LoopExit
|
|
// which isn't allowed by the architecture, so we should avoid
|
|
// introducing these.
|
|
// TODO: Analyse the blocks to make a decision if it would be worth
|
|
// moving LoopExit even if we'd introduce a forwards LE
|
|
if (LETarget == LoopExit) {
|
|
LLVM_DEBUG(dbgs() << DEBUG_PREFIX
|
|
<< "Can't move the target block as it would "
|
|
"introduce a new forwards LE branch\n");
|
|
CanMove = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!CanMove)
|
|
break;
|
|
}
|
|
|
|
if (CanMove) {
|
|
moveBasicBlock(LoopExit, Preheader);
|
|
Changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
bool ARMBlockPlacement::blockIsBefore(MachineBasicBlock *BB,
|
|
MachineBasicBlock *Other) {
|
|
return BBUtils->getOffsetOf(Other) > BBUtils->getOffsetOf(BB);
|
|
}
|
|
|
|
void ARMBlockPlacement::moveBasicBlock(MachineBasicBlock *BB,
|
|
MachineBasicBlock *After) {
|
|
LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Moving " << BB->getName() << " after "
|
|
<< After->getName() << "\n");
|
|
MachineBasicBlock *BBPrevious = BB->getPrevNode();
|
|
assert(BBPrevious && "Cannot move the function entry basic block");
|
|
MachineBasicBlock *AfterNext = After->getNextNode();
|
|
MachineBasicBlock *BBNext = BB->getNextNode();
|
|
|
|
BB->moveAfter(After);
|
|
|
|
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 (!Terminator.isUnconditionalBranch()) {
|
|
// The BB doesn't have an unconditional branch so it relied on
|
|
// fall-through. Fix by adding an unconditional branch to the moved BB.
|
|
unsigned BrOpc =
|
|
BBUtils->isBBInRange(&Terminator, To, 254) ? ARM::tB : ARM::t2B;
|
|
MachineInstrBuilder MIB =
|
|
BuildMI(From, Terminator.getDebugLoc(), TII->get(BrOpc));
|
|
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 follow.
|
|
if (AfterNext && After->isSuccessor(AfterNext))
|
|
FixFallthrough(After, AfterNext);
|
|
// Fix fall through from the moved BB to the one that used to follow.
|
|
if (BBNext && BB->isSuccessor(BBNext))
|
|
FixFallthrough(BB, BBNext);
|
|
|
|
BBUtils->adjustBBOffsetsAfter(After);
|
|
}
|