107#define DEBUG_TYPE "mips-branch-expansion"
119 bool HasLongBranch =
false;
129 MipsBranchExpansionLegacy() : MachineFunctionPass(ID) {}
131 StringRef getPassName()
const override {
132 return "Mips Branch Expansion Pass";
137 MachineFunctionProperties getRequiredProperties()
const override {
138 return MachineFunctionProperties().setNoVRegs();
142class MipsBranchExpansionImpl {
145 int64_t computeOffset(
const MachineInstr *Br);
147 void replaceBranch(MachineBasicBlock &
MBB, Iter Br,
const DebugLoc &
DL,
148 MachineBasicBlock *MBBOpnd);
149 bool buildProperJumpMI(MachineBasicBlock *
MBB,
151 void expandToLongBranch(MBBInfo &Info);
152 template <
typename Pred,
typename Safe>
153 bool handleSlot(
Pred Predicate, Safe SafeInSlot);
154 bool handleForbiddenSlot();
155 bool handleFPUDelaySlot();
156 bool handleLoadDelaySlot();
157 bool handlePossibleLongBranch();
159 template <
typename Pred,
typename Safe>
160 bool handleMFLOSlot(
Pred Predicate, Safe SafeInSlot);
162 const MipsSubtarget *STI;
163 const MipsInstrInfo *TII;
169 bool ForceLongBranchFirstPass =
false;
177char MipsBranchExpansionLegacy::ID = 0;
180 "Expand out of range branch instructions and fix forbidden"
186 return new MipsBranchExpansionLegacy();
192 Iter
I = Position,
E = Position->getParent()->end();
193 I = std::find_if_not(
I,
E,
194 [](
const Iter &Insn) {
return Insn->isTransient(); });
203 if (Position == Parent->
end()) {
206 if (Succ !=
nullptr && Parent->
isSuccessor(Succ)) {
207 Position = Succ->
begin();
210 return std::make_pair(Position,
true);
212 }
while (Parent->
empty());
216 if (Instr == Parent->
end()) {
219 return std::make_pair(Instr,
false);
239 if (!
B->isDebugInstr())
251 if ((LastBr ==
End) ||
252 (!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch()))
259 if ((FirstBr ==
End) ||
260 (!FirstBr->isConditionalBranch() && !FirstBr->isUnconditionalBranch()))
263 assert(!FirstBr->isIndirectBranch() &&
"Unexpected indirect branch found.");
266 MachineBasicBlock *NewMBB =
282void MipsBranchExpansionImpl::initMBBInfo() {
285 for (
auto &
MBB : *MFp)
288 MFp->RenumberBlocks();
290 MBBInfos.resize(MFp->size());
292 for (
unsigned I = 0,
E = MBBInfos.size();
I <
E; ++
I) {
293 MachineBasicBlock *
MBB = MFp->getBlockNumbered(
I);
296 for (MachineInstr &
MI : *
MBB)
297 MBBInfos[
I].Size +=
TII->getInstSizeInBytes(
MI);
302int64_t MipsBranchExpansionImpl::computeOffset(
const MachineInstr *Br) {
308 if (ThisMBB < TargetMBB) {
309 for (
int N = ThisMBB + 1;
N < TargetMBB; ++
N)
316 for (
int N = ThisMBB;
N >= TargetMBB; --
N)
323uint64_t MipsBranchExpansionImpl::computeOffsetFromTheBeginning(
int MBB) {
325 for (
int N = 0;
N <
MBB; ++
N)
332void MipsBranchExpansionImpl::replaceBranch(MachineBasicBlock &
MBB, Iter Br,
334 MachineBasicBlock *MBBOpnd) {
335 unsigned NewOpc =
TII->getOppositeBranchOpc(Br->getOpcode());
336 const MCInstrDesc &NewDesc =
TII->get(NewOpc);
338 MachineInstrBuilder MIB =
BuildMI(
MBB, Br,
DL, NewDesc);
340 for (
unsigned I = 0,
E = Br->getDesc().getNumOperands();
I <
E; ++
I) {
341 MachineOperand &MO = Br->getOperand(
I);
350 if (!
TII->isBranchWithImm(Br->getOpcode()))
362 if (Br->hasDelaySlot()) {
365 assert(Br->isBundledWithSucc());
367 MIBundleBuilder(&*MIB).append((++
II)->removeFromBundle());
369 Br->eraseFromParent();
372bool MipsBranchExpansionImpl::buildProperJumpMI(MachineBasicBlock *
MBB,
378 unsigned JR = ABI.
IsN64() ? Mips::JR64 : Mips::JR;
379 unsigned JIC = ABI.
IsN64() ? Mips::JIC64 : Mips::JIC;
380 unsigned JR_HB = ABI.
IsN64() ? Mips::JR_HB64 : Mips::JR_HB;
381 unsigned JR_HB_R6 = ABI.
IsN64() ? Mips::JR_HB64_R6 : Mips::JR_HB_R6;
385 JumpOp = HasR6 ? JR_HB_R6 : JR_HB;
387 JumpOp = HasR6 ? JIC : JR;
390 JumpOp = Mips::JIC_MMR6;
392 unsigned ATReg = ABI.
IsN64() ? Mips::R1_64 : Mips::R1;
393 MachineInstrBuilder
Instr =
406void MipsBranchExpansionImpl::expandToLongBranch(MBBInfo &
I) {
412 MachineBasicBlock *LongBrMBB = MFp->CreateMachineBasicBlock(BB);
414 MFp->insert(FallThroughMBB, LongBrMBB);
418 MachineBasicBlock *BalTgtMBB = MFp->CreateMachineBasicBlock(BB);
419 MFp->insert(FallThroughMBB, BalTgtMBB);
426 const unsigned BalOp =
461 Pos = LongBrMBB->
begin();
487 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi), Mips::R1)
491 MachineInstrBuilder BalInstr =
493 MachineInstrBuilder ADDiuInstr =
494 BuildMI(*MFp,
DL,
TII->get(Mips::LONG_BRANCH_ADDiu), Mips::R1)
499 LongBrMBB->
insert(Pos, ADDiuInstr);
500 LongBrMBB->
insert(Pos, BalInstr);
502 LongBrMBB->
insert(Pos, BalInstr);
503 LongBrMBB->
insert(Pos, ADDiuInstr);
504 LongBrMBB->
rbegin()->bundleWithPred();
507 Pos = BalTgtMBB->
begin();
509 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::ADDu), Mips::R1)
517 bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos,
DL);
528 BalTgtMBB->
rbegin()->bundleWithPred();
576 Pos = LongBrMBB->
begin();
585 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu),
590 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::R1_64)
594 MachineInstrBuilder BalInstr =
596 MachineInstrBuilder DADDiuInstr =
597 BuildMI(*MFp,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu), Mips::R1_64)
602 LongBrMBB->
insert(Pos, DADDiuInstr);
603 LongBrMBB->
insert(Pos, BalInstr);
605 LongBrMBB->
insert(Pos, BalInstr);
606 LongBrMBB->
insert(Pos, DADDiuInstr);
607 LongBrMBB->
rbegin()->bundleWithPred();
610 Pos = BalTgtMBB->
begin();
612 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::DADDu), Mips::R1_64)
619 bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos,
DL);
622 BuildMI(*BalTgtMBB, std::prev(Pos),
DL,
TII->get(Mips::DADDiu),
630 BalTgtMBB->
rbegin()->bundleWithPred();
634 Pos = LongBrMBB->
begin();
641 uint64_t TgtMBBOffset = computeOffsetFromTheBeginning(TgtMBB->getNumber());
644 if (JOffset < TgtMBBOffset)
645 TgtMBBOffset += 2 * 4;
647 bool SameSegmentJump = JOffset >> 28 == TgtMBBOffset >> 28;
649 if (STI->
hasMips32r6() &&
TII->isBranchOffsetInRange(Mips::BC,
I.Offset)) {
658 }
else if (SameSegmentJump) {
666 TII->insertNop(*LongBrMBB, Pos,
DL)->bundleWithPred();
674 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi2Op_64),
677 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
681 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::R1_64)
684 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
688 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::R1_64)
691 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
696 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi2Op),
699 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_ADDiu2Op),
704 buildProperJumpMI(LongBrMBB, Pos,
DL);
708 if (
I.Br->isUnconditionalBranch()) {
710 assert(
I.Br->getDesc().getNumOperands() == 1);
711 I.Br->removeOperand(0);
715 replaceBranch(*
MBB,
I.Br,
DL, &*FallThroughMBB);
727 MBB.removeLiveIn(Mips::R2);
730template <
typename Pred,
typename Safe>
731bool MipsBranchExpansionImpl::handleMFLOSlot(
Pred Predicate, Safe SafeInSlot) {
733 bool hasPendingMFLO =
false;
736 for (Iter
I = FI->begin();
I != FI->end(); ++
I) {
743 bool LastInstInFunction =
744 std::next(
I) == FI->end() && std::next(FI) == MFp->end();
750 if (!LastInstInFunction) {
752 LastInstInFunction |= Res.second;
754 if (LastInstInFunction)
756 if (!SafeInSlot(*IInSlot, *
I)) {
758 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
762 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
767 hasPendingMFLO =
false;
768 }
else if (hasPendingMFLO)
769 hasPendingMFLO =
false;
771 hasPendingMFLO =
true;
779template <
typename Pred,
typename Safe>
780bool MipsBranchExpansionImpl::handleSlot(
Pred Predicate, Safe SafeInSlot) {
784 for (Iter
I = FI->begin();
I != FI->end(); ++
I) {
791 bool LastInstInFunction =
792 std::next(
I) == FI->end() && std::next(FI) == MFp->end();
793 if (!LastInstInFunction) {
795 LastInstInFunction |= Res.second;
799 if (LastInstInFunction || !SafeInSlot(*IInSlot, *
I)) {
801 if (std::next(Iit) == FI->end() ||
802 std::next(Iit)->getOpcode() != Mips::NOP) {
804 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
815bool MipsBranchExpansionImpl::handleMFLO() {
821 return handleMFLOSlot(
822 [
this](
auto &
I) ->
bool {
return TII->IsMfloOrMfhi(
I); },
823 [
this](
auto &IInSlot,
auto &
I) ->
bool {
824 return TII->SafeAfterMflo(IInSlot);
828bool MipsBranchExpansionImpl::handleForbiddenSlot() {
834 [
this](
auto &
I) ->
bool {
return TII->HasForbiddenSlot(
I); },
835 [
this](
auto &IInSlot,
auto &
I) ->
bool {
836 return TII->SafeInForbiddenSlot(IInSlot);
840bool MipsBranchExpansionImpl::handleFPUDelaySlot() {
845 return handleSlot([
this](
auto &
I) ->
bool {
return TII->HasFPUDelaySlot(
I); },
846 [
this](
auto &IInSlot,
auto &
I) ->
bool {
847 return TII->SafeInFPUDelaySlot(IInSlot,
I);
851bool MipsBranchExpansionImpl::handleLoadDelaySlot() {
857 [
this](
auto &
I) ->
bool {
return TII->HasLoadDelaySlot(
I); },
858 [
this](
auto &IInSlot,
auto &
I) ->
bool {
859 return TII->SafeInLoadDelaySlot(IInSlot,
I);
863bool MipsBranchExpansionImpl::handlePossibleLongBranch() {
867 if (STI->
getCLOpts().skip_mips_long_branch)
870 bool EverMadeChange =
false, MadeChange =
true;
877 for (
unsigned I = 0,
E = MBBInfos.size();
I <
E; ++
I) {
878 MachineBasicBlock *
MBB = MFp->getBlockNumbered(
I);
883 if ((Br !=
End) && Br->isBranch() && !Br->isIndirectBranch() &&
884 (Br->isConditionalBranch() ||
885 (Br->isUnconditionalBranch() && IsPIC))) {
886 int64_t
Offset = computeOffset(&*Br);
888 if (ForceLongBranchFirstPass ||
889 !
TII->isBranchOffsetInRange(Br->getOpcode(),
Offset)) {
891 MBBInfos[
I].Br = &*Br;
896 ForceLongBranchFirstPass =
false;
900 for (
I = MBBInfos.begin();
I !=
E; ++
I) {
906 expandToLongBranch(*
I);
908 EverMadeChange = MadeChange =
true;
911 MFp->RenumberBlocks();
914 return EverMadeChange;
917bool MipsBranchExpansionImpl::runOnMachineFunction(
MachineFunction &MF) {
918 const TargetMachine &TM = MF.
getTarget();
924 if (IsPIC &&
ABI.IsO32() &&
925 MF.
getInfo<MipsFunctionInfo>()->globalBaseRegSet())
930 ForceLongBranchFirstPass = STI->
getCLOpts().force_mips_long_branch;
932 bool longBranchChanged = handlePossibleLongBranch();
933 bool forbiddenSlotChanged = handleForbiddenSlot();
934 bool fpuDelaySlotChanged = handleFPUDelaySlot();
935 bool loadDelaySlotChanged = handleLoadDelaySlot();
936 bool MfloChanged = handleMFLO();
938 bool Changed = longBranchChanged || forbiddenSlotChanged ||
939 fpuDelaySlotChanged || loadDelaySlotChanged || MfloChanged;
942 while (forbiddenSlotChanged) {
943 longBranchChanged = handlePossibleLongBranch();
944 fpuDelaySlotChanged = handleFPUDelaySlot();
945 loadDelaySlotChanged = handleLoadDelaySlot();
946 MfloChanged = handleMFLO();
947 if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged &&
950 forbiddenSlotChanged = handleForbiddenSlot();
956bool MipsBranchExpansionLegacy::runOnMachineFunction(
MachineFunction &MF) {
957 MipsBranchExpansionImpl Impl;
958 return Impl.runOnMachineFunction(MF);
964 MipsBranchExpansionImpl Impl;
965 return Impl.runOnMachineFunction(MF)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const HexagonInstrInfo * TII
static std::pair< Iter, bool > getNextMachineInstr(Iter Position, MachineBasicBlock *Parent)
static MachineBasicBlock * getTargetMBB(const MachineInstr &Br)
Iterate over list of Br's operands and search for a MachineBasicBlock operand.
static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII)
static ReverseIter getNonDebugInstr(ReverseIter B, const ReverseIter &E)
static Iter getNextMachineInstrInBB(Iter Position)
#define IsMFLOMFHI(instr)
uint64_t IntrinsicInst * II
static bool splitMBB(BlockSplitInfo &BSI)
Splits a MachineBasicBlock to branch before SplitBefore.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
FunctionPass class - This class is used to implement most global optimizations.
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
LLVM_ABI void replaceSuccessor(MachineBasicBlock *Old, MachineBasicBlock *New)
Replace successor OLD with NEW and update probability info.
LLVM_ABI void transferSuccessors(MachineBasicBlock *FromMBB)
Transfers all the successors from MBB to this machine basic block (i.e., copies all the successors Fr...
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
LLVM_ABI void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
Instructions::iterator instr_iterator
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
reverse_iterator rbegin()
LLVM_ABI bool isSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a successor of this block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
const MachineBasicBlock * getParent() const
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
MachineBasicBlock * getMBB() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
static MipsABIInfo Unknown()
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
bool inMicroMipsMode() const
const MipsInstrInfo * getInstrInfo() const override
bool useIndirectJumpsHazard() const
bool inMips16Mode() const
const MipsOptions & getCLOpts() const
const MipsABIInfo & getABI() const
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
typename SuperClass::iterator iterator
bool isPositionIndependent() const
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Pass manager infrastructure for declaring and invalidating analyses.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BasicBlock
Various leaf nodes.
constexpr MCPhysReg RA_64
constexpr MCPhysReg SP_64
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createMipsBranchExpansionLegacyPass()
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ End
Run the machine verifier once, at the end of the pipeline.