104#define DEBUG_TYPE "mips-branch-expansion"
116 bool HasLongBranch =
false;
126 MipsBranchExpansion()
127 : MachineFunctionPass(ID), ABI(MipsABIInfo::
Unknown()) {}
129 StringRef getPassName()
const override {
130 return "Mips Branch Expansion Pass";
135 MachineFunctionProperties getRequiredProperties()
const override {
136 return MachineFunctionProperties().setNoVRegs();
142 int64_t computeOffset(
const MachineInstr *Br);
144 void replaceBranch(MachineBasicBlock &
MBB, Iter Br,
const DebugLoc &
DL,
145 MachineBasicBlock *MBBOpnd);
146 bool buildProperJumpMI(MachineBasicBlock *
MBB,
148 void expandToLongBranch(MBBInfo &Info);
149 template <
typename Pred,
typename Safe>
150 bool handleSlot(Pred Predicate, Safe SafeInSlot);
151 bool handleForbiddenSlot();
152 bool handleFPUDelaySlot();
153 bool handleLoadDelaySlot();
154 bool handlePossibleLongBranch();
156 template <
typename Pred,
typename Safe>
157 bool handleMFLOSlot(Pred Predicate, Safe SafeInSlot);
159 const MipsSubtarget *STI;
160 const MipsInstrInfo *TII;
166 bool ForceLongBranchFirstPass =
false;
171char MipsBranchExpansion::ID = 0;
174 "Expand out of range branch instructions and fix forbidden"
180 return new MipsBranchExpansion();
186 Iter
I = Position,
E = Position->getParent()->end();
187 I = std::find_if_not(
I,
E,
188 [](
const Iter &Insn) {
return Insn->isTransient(); });
197 if (Position == Parent->
end()) {
200 if (Succ !=
nullptr && Parent->
isSuccessor(Succ)) {
201 Position = Succ->
begin();
204 return std::make_pair(Position,
true);
206 }
while (Parent->
empty());
210 if (Instr == Parent->
end()) {
213 return std::make_pair(Instr,
false);
233 if (!
B->isDebugInstr())
245 if ((LastBr ==
End) ||
246 (!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch()))
253 if ((FirstBr ==
End) ||
254 (!FirstBr->isConditionalBranch() && !FirstBr->isUnconditionalBranch()))
257 assert(!FirstBr->isIndirectBranch() &&
"Unexpected indirect branch found.");
260 MachineBasicBlock *NewMBB =
276void MipsBranchExpansion::initMBBInfo() {
279 for (
auto &
MBB : *MFp)
282 MFp->RenumberBlocks();
284 MBBInfos.resize(MFp->size());
286 for (
unsigned I = 0,
E = MBBInfos.size();
I <
E; ++
I) {
287 MachineBasicBlock *
MBB = MFp->getBlockNumbered(
I);
290 for (MachineInstr &
MI : *
MBB)
291 MBBInfos[
I].Size +=
TII->getInstSizeInBytes(
MI);
296int64_t MipsBranchExpansion::computeOffset(
const MachineInstr *Br) {
302 if (ThisMBB < TargetMBB) {
303 for (
int N = ThisMBB + 1;
N < TargetMBB; ++
N)
310 for (
int N = ThisMBB;
N >= TargetMBB; --
N)
317uint64_t MipsBranchExpansion::computeOffsetFromTheBeginning(
int MBB) {
319 for (
int N = 0;
N <
MBB; ++
N)
326void MipsBranchExpansion::replaceBranch(MachineBasicBlock &
MBB, Iter Br,
328 MachineBasicBlock *MBBOpnd) {
329 unsigned NewOpc =
TII->getOppositeBranchOpc(Br->getOpcode());
330 const MCInstrDesc &NewDesc =
TII->get(NewOpc);
332 MachineInstrBuilder MIB =
BuildMI(
MBB, Br,
DL, NewDesc);
334 for (
unsigned I = 0,
E = Br->getDesc().getNumOperands();
I <
E; ++
I) {
335 MachineOperand &MO = Br->getOperand(
I);
344 if (!
TII->isBranchWithImm(Br->getOpcode()))
356 if (Br->hasDelaySlot()) {
359 assert(Br->isBundledWithSucc());
361 MIBundleBuilder(&*MIB).append((++
II)->removeFromBundle());
363 Br->eraseFromParent();
366bool MipsBranchExpansion::buildProperJumpMI(MachineBasicBlock *
MBB,
372 unsigned JR = ABI.
IsN64() ? Mips::JR64 : Mips::JR;
373 unsigned JIC = ABI.
IsN64() ? Mips::JIC64 : Mips::JIC;
374 unsigned JR_HB = ABI.
IsN64() ? Mips::JR_HB64 : Mips::JR_HB;
375 unsigned JR_HB_R6 = ABI.
IsN64() ? Mips::JR_HB64_R6 : Mips::JR_HB_R6;
379 JumpOp = HasR6 ? JR_HB_R6 : JR_HB;
381 JumpOp = HasR6 ? JIC : JR;
384 JumpOp = Mips::JIC_MMR6;
386 unsigned ATReg = ABI.
IsN64() ? Mips::AT_64 : Mips::AT;
387 MachineInstrBuilder
Instr =
400void MipsBranchExpansion::expandToLongBranch(MBBInfo &
I) {
406 MachineBasicBlock *LongBrMBB = MFp->CreateMachineBasicBlock(BB);
408 MFp->insert(FallThroughMBB, LongBrMBB);
412 MachineBasicBlock *BalTgtMBB = MFp->CreateMachineBasicBlock(BB);
413 MFp->insert(FallThroughMBB, BalTgtMBB);
420 const unsigned BalOp =
455 Pos = LongBrMBB->
begin();
457 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::ADDiu), Mips::SP)
481 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi), Mips::AT)
485 MachineInstrBuilder BalInstr =
487 MachineInstrBuilder ADDiuInstr =
488 BuildMI(*MFp,
DL,
TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT)
493 LongBrMBB->
insert(Pos, ADDiuInstr);
494 LongBrMBB->
insert(Pos, BalInstr);
496 LongBrMBB->
insert(Pos, BalInstr);
497 LongBrMBB->
insert(Pos, ADDiuInstr);
498 LongBrMBB->
rbegin()->bundleWithPred();
501 Pos = BalTgtMBB->
begin();
503 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::ADDu), Mips::AT)
506 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::LW), Mips::RA)
511 bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos,
DL);
514 BuildMI(*BalTgtMBB, std::prev(Pos),
DL,
TII->get(Mips::ADDiu), Mips::SP)
519 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::ADDiu), Mips::SP)
522 BalTgtMBB->
rbegin()->bundleWithPred();
570 Pos = LongBrMBB->
begin();
572 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DADDiu), Mips::SP_64)
579 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu),
584 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::AT_64)
588 MachineInstrBuilder BalInstr =
590 MachineInstrBuilder DADDiuInstr =
591 BuildMI(*MFp,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu), Mips::AT_64)
596 LongBrMBB->
insert(Pos, DADDiuInstr);
597 LongBrMBB->
insert(Pos, BalInstr);
599 LongBrMBB->
insert(Pos, BalInstr);
600 LongBrMBB->
insert(Pos, DADDiuInstr);
601 LongBrMBB->
rbegin()->bundleWithPred();
604 Pos = BalTgtMBB->
begin();
606 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::DADDu), Mips::AT_64)
609 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::LD), Mips::RA_64)
613 bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos,
DL);
616 BuildMI(*BalTgtMBB, std::prev(Pos),
DL,
TII->get(Mips::DADDiu),
621 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::DADDiu), Mips::SP_64)
624 BalTgtMBB->
rbegin()->bundleWithPred();
628 Pos = LongBrMBB->
begin();
635 uint64_t TgtMBBOffset = computeOffsetFromTheBeginning(TgtMBB->getNumber());
638 if (JOffset < TgtMBBOffset)
639 TgtMBBOffset += 2 * 4;
641 bool SameSegmentJump = JOffset >> 28 == TgtMBBOffset >> 28;
643 if (STI->
hasMips32r6() &&
TII->isBranchOffsetInRange(Mips::BC,
I.Offset)) {
652 }
else if (SameSegmentJump) {
660 TII->insertNop(*LongBrMBB, Pos,
DL)->bundleWithPred();
668 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi2Op_64),
671 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
675 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::AT_64)
678 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
682 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::AT_64)
685 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
690 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi2Op),
693 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_ADDiu2Op),
698 buildProperJumpMI(LongBrMBB, Pos,
DL);
702 if (
I.Br->isUnconditionalBranch()) {
704 assert(
I.Br->getDesc().getNumOperands() == 1);
705 I.Br->removeOperand(0);
709 replaceBranch(*
MBB,
I.Br,
DL, &*FallThroughMBB);
721 MBB.removeLiveIn(Mips::V0);
724template <
typename Pred,
typename Safe>
725bool MipsBranchExpansion::handleMFLOSlot(Pred Predicate, Safe SafeInSlot) {
727 bool hasPendingMFLO =
false;
730 for (Iter
I = FI->begin();
I != FI->end(); ++
I) {
737 bool LastInstInFunction =
738 std::next(
I) == FI->end() && std::next(FI) == MFp->end();
744 if (!LastInstInFunction) {
746 LastInstInFunction |= Res.second;
748 if (LastInstInFunction)
750 if (!SafeInSlot(*IInSlot, *
I)) {
752 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
756 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
761 hasPendingMFLO =
false;
762 }
else if (hasPendingMFLO)
763 hasPendingMFLO =
false;
765 hasPendingMFLO =
true;
773template <
typename Pred,
typename Safe>
774bool MipsBranchExpansion::handleSlot(Pred Predicate, Safe SafeInSlot) {
778 for (Iter
I = FI->begin();
I != FI->end(); ++
I) {
785 bool LastInstInFunction =
786 std::next(
I) == FI->end() && std::next(FI) == MFp->end();
787 if (!LastInstInFunction) {
789 LastInstInFunction |= Res.second;
793 if (LastInstInFunction || !SafeInSlot(*IInSlot, *
I)) {
795 if (std::next(Iit) == FI->end() ||
796 std::next(Iit)->getOpcode() != Mips::NOP) {
798 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
809bool MipsBranchExpansion::handleMFLO() {
815 return handleMFLOSlot(
816 [
this](
auto &
I) ->
bool {
return TII->IsMfloOrMfhi(
I); },
817 [
this](
auto &IInSlot,
auto &
I) ->
bool {
818 return TII->SafeAfterMflo(IInSlot);
822bool MipsBranchExpansion::handleForbiddenSlot() {
828 [
this](
auto &
I) ->
bool {
return TII->HasForbiddenSlot(
I); },
829 [
this](
auto &IInSlot,
auto &
I) ->
bool {
830 return TII->SafeInForbiddenSlot(IInSlot);
834bool MipsBranchExpansion::handleFPUDelaySlot() {
839 return handleSlot([
this](
auto &
I) ->
bool {
return TII->HasFPUDelaySlot(
I); },
840 [
this](
auto &IInSlot,
auto &
I) ->
bool {
841 return TII->SafeInFPUDelaySlot(IInSlot,
I);
845bool MipsBranchExpansion::handleLoadDelaySlot() {
851 [
this](
auto &
I) ->
bool {
return TII->HasLoadDelaySlot(
I); },
852 [
this](
auto &IInSlot,
auto &
I) ->
bool {
853 return TII->SafeInLoadDelaySlot(IInSlot,
I);
857bool MipsBranchExpansion::handlePossibleLongBranch() {
861 if (STI->
getCLOpts().skip_mips_long_branch)
864 bool EverMadeChange =
false, MadeChange =
true;
871 for (
unsigned I = 0,
E = MBBInfos.size();
I <
E; ++
I) {
872 MachineBasicBlock *
MBB = MFp->getBlockNumbered(
I);
877 if ((Br !=
End) && Br->isBranch() && !Br->isIndirectBranch() &&
878 (Br->isConditionalBranch() ||
879 (Br->isUnconditionalBranch() && IsPIC))) {
880 int64_t
Offset = computeOffset(&*Br);
882 if (ForceLongBranchFirstPass ||
883 !
TII->isBranchOffsetInRange(Br->getOpcode(),
Offset)) {
885 MBBInfos[
I].Br = &*Br;
890 ForceLongBranchFirstPass =
false;
894 for (
I = MBBInfos.begin();
I !=
E; ++
I) {
900 expandToLongBranch(*
I);
902 EverMadeChange = MadeChange =
true;
905 MFp->RenumberBlocks();
908 return EverMadeChange;
912 const TargetMachine &TM = MF.
getTarget();
918 if (IsPIC &&
ABI.IsO32() &&
919 MF.
getInfo<MipsFunctionInfo>()->globalBaseRegSet())
924 ForceLongBranchFirstPass = STI->
getCLOpts().force_mips_long_branch;
926 bool longBranchChanged = handlePossibleLongBranch();
927 bool forbiddenSlotChanged = handleForbiddenSlot();
928 bool fpuDelaySlotChanged = handleFPUDelaySlot();
929 bool loadDelaySlotChanged = handleLoadDelaySlot();
930 bool MfloChanged = handleMFLO();
932 bool Changed = longBranchChanged || forbiddenSlotChanged ||
933 fpuDelaySlotChanged || loadDelaySlotChanged || MfloChanged;
936 while (forbiddenSlotChanged) {
937 longBranchChanged = handlePossibleLongBranch();
938 fpuDelaySlotChanged = handleFPUDelaySlot();
939 loadDelaySlotChanged = handleLoadDelaySlot();
940 MfloChanged = handleMFLO();
941 if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged &&
944 forbiddenSlotChanged = handleForbiddenSlot();
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.
bool inMicroMipsMode() const
const MipsInstrInfo * getInstrInfo() const override
bool useIndirectJumpsHazard() const
bool inMips16Mode() const
const MipsOptions & getCLOpts() const
const MipsABIInfo & getABI() const
typename SuperClass::iterator iterator
bool isPositionIndependent() const
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BasicBlock
Various leaf nodes.
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Unknown
Not known to have no common set bits.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FunctionPass * createMipsBranchExpansion()
@ End
Run the machine verifier once, at the end of the pipeline.