106#define DEBUG_TYPE "mips-branch-expansion"
117 cl::desc(
"MIPS: Expand all branches to long format."),
127 bool HasLongBranch =
false;
137 MipsBranchExpansion()
138 : MachineFunctionPass(ID), ABI(MipsABIInfo::
Unknown()) {}
140 StringRef getPassName()
const override {
141 return "Mips Branch Expansion Pass";
144 bool runOnMachineFunction(MachineFunction &
F)
override;
146 MachineFunctionProperties getRequiredProperties()
const override {
147 return MachineFunctionProperties().setNoVRegs();
153 int64_t computeOffset(
const MachineInstr *Br);
154 uint64_t computeOffsetFromTheBeginning(
int MBB);
155 void replaceBranch(MachineBasicBlock &
MBB, Iter Br,
const DebugLoc &
DL,
156 MachineBasicBlock *MBBOpnd);
157 bool buildProperJumpMI(MachineBasicBlock *
MBB,
159 void expandToLongBranch(MBBInfo &
Info);
160 template <
typename Pred,
typename Safe>
161 bool handleSlot(Pred Predicate, Safe SafeInSlot);
162 bool handleForbiddenSlot();
163 bool handleFPUDelaySlot();
164 bool handleLoadDelaySlot();
165 bool handlePossibleLongBranch();
167 template <
typename Pred,
typename Safe>
168 bool handleMFLOSlot(Pred Predicate, Safe SafeInSlot);
170 const MipsSubtarget *STI;
171 const MipsInstrInfo *TII;
173 MachineFunction *MFp;
177 bool ForceLongBranchFirstPass =
false;
182char MipsBranchExpansion::ID = 0;
185 "Expand out of range branch instructions and fix forbidden"
191 return new MipsBranchExpansion();
197 Iter
I = Position,
E = Position->getParent()->end();
198 I = std::find_if_not(
I,
E,
199 [](
const Iter &Insn) {
return Insn->isTransient(); });
208 if (Position == Parent->
end()) {
211 if (Succ !=
nullptr && Parent->
isSuccessor(Succ)) {
212 Position = Succ->
begin();
215 return std::make_pair(Position,
true);
217 }
while (Parent->
empty());
221 if (Instr == Parent->
end()) {
224 return std::make_pair(Instr,
false);
244 if (!
B->isDebugInstr())
256 if ((LastBr == End) ||
257 (!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch()))
264 if ((FirstBr == End) ||
265 (!FirstBr->isConditionalBranch() && !FirstBr->isUnconditionalBranch()))
268 assert(!FirstBr->isIndirectBranch() &&
"Unexpected indirect branch found.");
271 MachineBasicBlock *NewMBB =
287void MipsBranchExpansion::initMBBInfo() {
290 for (
auto &
MBB : *MFp)
293 MFp->RenumberBlocks();
295 MBBInfos.resize(MFp->size());
297 for (
unsigned I = 0,
E = MBBInfos.size();
I <
E; ++
I) {
298 MachineBasicBlock *
MBB = MFp->getBlockNumbered(
I);
302 MBBInfos[
I].Size +=
TII->getInstSizeInBytes(
MI);
307int64_t MipsBranchExpansion::computeOffset(
const MachineInstr *Br) {
313 if (ThisMBB < TargetMBB) {
314 for (
int N = ThisMBB + 1;
N < TargetMBB; ++
N)
321 for (
int N = ThisMBB;
N >= TargetMBB; --
N)
328uint64_t MipsBranchExpansion::computeOffsetFromTheBeginning(
int MBB) {
330 for (
int N = 0;
N <
MBB; ++
N)
337void MipsBranchExpansion::replaceBranch(MachineBasicBlock &
MBB, Iter Br,
339 MachineBasicBlock *MBBOpnd) {
340 unsigned NewOpc =
TII->getOppositeBranchOpc(Br->getOpcode());
341 const MCInstrDesc &NewDesc =
TII->get(NewOpc);
343 MachineInstrBuilder MIB =
BuildMI(
MBB, Br,
DL, NewDesc);
345 for (
unsigned I = 0,
E = Br->getDesc().getNumOperands();
I <
E; ++
I) {
346 MachineOperand &MO = Br->getOperand(
I);
355 if (!
TII->isBranchWithImm(Br->getOpcode()))
367 if (Br->hasDelaySlot()) {
370 assert(Br->isBundledWithSucc());
372 MIBundleBuilder(&*MIB).append((++
II)->removeFromBundle());
374 Br->eraseFromParent();
377bool MipsBranchExpansion::buildProperJumpMI(MachineBasicBlock *
MBB,
383 unsigned JR = ABI.
IsN64() ? Mips::JR64 : Mips::JR;
384 unsigned JIC = ABI.
IsN64() ? Mips::JIC64 : Mips::JIC;
385 unsigned JR_HB = ABI.
IsN64() ? Mips::JR_HB64 : Mips::JR_HB;
386 unsigned JR_HB_R6 = ABI.
IsN64() ? Mips::JR_HB64_R6 : Mips::JR_HB_R6;
390 JumpOp = HasR6 ? JR_HB_R6 : JR_HB;
392 JumpOp = HasR6 ? JIC : JR;
395 JumpOp = Mips::JIC_MMR6;
397 unsigned ATReg = ABI.
IsN64() ? Mips::AT_64 : Mips::AT;
398 MachineInstrBuilder
Instr =
411void MipsBranchExpansion::expandToLongBranch(MBBInfo &
I) {
417 MachineBasicBlock *LongBrMBB = MFp->CreateMachineBasicBlock(BB);
419 MFp->insert(FallThroughMBB, LongBrMBB);
423 MachineBasicBlock *BalTgtMBB = MFp->CreateMachineBasicBlock(BB);
424 MFp->insert(FallThroughMBB, BalTgtMBB);
431 const unsigned BalOp =
466 Pos = LongBrMBB->
begin();
468 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::ADDiu), Mips::SP)
492 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi), Mips::AT)
496 MachineInstrBuilder BalInstr =
498 MachineInstrBuilder ADDiuInstr =
499 BuildMI(*MFp,
DL,
TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT)
504 LongBrMBB->
insert(Pos, ADDiuInstr);
505 LongBrMBB->
insert(Pos, BalInstr);
507 LongBrMBB->
insert(Pos, BalInstr);
508 LongBrMBB->
insert(Pos, ADDiuInstr);
509 LongBrMBB->
rbegin()->bundleWithPred();
512 Pos = BalTgtMBB->
begin();
514 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::ADDu), Mips::AT)
517 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::LW), Mips::RA)
522 bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos,
DL);
525 BuildMI(*BalTgtMBB, std::prev(Pos),
DL,
TII->get(Mips::ADDiu), Mips::SP)
530 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::ADDiu), Mips::SP)
533 BalTgtMBB->
rbegin()->bundleWithPred();
581 Pos = LongBrMBB->
begin();
583 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DADDiu), Mips::SP_64)
590 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu),
595 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::AT_64)
599 MachineInstrBuilder BalInstr =
601 MachineInstrBuilder DADDiuInstr =
602 BuildMI(*MFp,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu), Mips::AT_64)
607 LongBrMBB->
insert(Pos, DADDiuInstr);
608 LongBrMBB->
insert(Pos, BalInstr);
610 LongBrMBB->
insert(Pos, BalInstr);
611 LongBrMBB->
insert(Pos, DADDiuInstr);
612 LongBrMBB->
rbegin()->bundleWithPred();
615 Pos = BalTgtMBB->
begin();
617 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::DADDu), Mips::AT_64)
620 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::LD), Mips::RA_64)
624 bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos,
DL);
627 BuildMI(*BalTgtMBB, std::prev(Pos),
DL,
TII->get(Mips::DADDiu),
632 BuildMI(*BalTgtMBB, Pos,
DL,
TII->get(Mips::DADDiu), Mips::SP_64)
635 BalTgtMBB->
rbegin()->bundleWithPred();
639 Pos = LongBrMBB->
begin();
644 uint64_t JOffset = computeOffsetFromTheBeginning(
MBB->
getNumber()) +
646 uint64_t TgtMBBOffset = computeOffsetFromTheBeginning(TgtMBB->getNumber());
649 if (JOffset < TgtMBBOffset)
650 TgtMBBOffset += 2 * 4;
652 bool SameSegmentJump = JOffset >> 28 == TgtMBBOffset >> 28;
654 if (STI->
hasMips32r6() &&
TII->isBranchOffsetInRange(Mips::BC,
I.Offset)) {
663 }
else if (SameSegmentJump) {
671 TII->insertNop(*LongBrMBB, Pos,
DL)->bundleWithPred();
679 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi2Op_64),
682 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
686 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::AT_64)
689 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
693 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::DSLL), Mips::AT_64)
696 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_DADDiu2Op),
701 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_LUi2Op),
704 BuildMI(*LongBrMBB, Pos,
DL,
TII->get(Mips::LONG_BRANCH_ADDiu2Op),
709 buildProperJumpMI(LongBrMBB, Pos,
DL);
713 if (
I.Br->isUnconditionalBranch()) {
715 assert(
I.Br->getDesc().getNumOperands() == 1);
716 I.Br->removeOperand(0);
720 replaceBranch(*
MBB,
I.Br,
DL, &*FallThroughMBB);
732 MBB.removeLiveIn(Mips::V0);
735template <
typename Pred,
typename Safe>
736bool MipsBranchExpansion::handleMFLOSlot(Pred Predicate, Safe SafeInSlot) {
738 bool hasPendingMFLO =
false;
741 for (Iter
I = FI->begin();
I != FI->end(); ++
I) {
748 bool LastInstInFunction =
749 std::next(
I) == FI->end() && std::next(FI) == MFp->end();
755 if (!LastInstInFunction) {
757 LastInstInFunction |= Res.second;
759 if (LastInstInFunction)
761 if (!SafeInSlot(*IInSlot, *
I)) {
763 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
767 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
772 hasPendingMFLO =
false;
773 }
else if (hasPendingMFLO)
774 hasPendingMFLO =
false;
776 hasPendingMFLO =
true;
784template <
typename Pred,
typename Safe>
785bool MipsBranchExpansion::handleSlot(Pred Predicate, Safe SafeInSlot) {
789 for (Iter
I = FI->begin();
I != FI->end(); ++
I) {
796 bool LastInstInFunction =
797 std::next(
I) == FI->end() && std::next(FI) == MFp->end();
798 if (!LastInstInFunction) {
800 LastInstInFunction |= Res.second;
804 if (LastInstInFunction || !SafeInSlot(*IInSlot, *
I)) {
806 if (std::next(Iit) == FI->end() ||
807 std::next(Iit)->getOpcode() != Mips::NOP) {
809 TII->insertNop(*(
I->getParent()), std::next(
I),
I->getDebugLoc())
820bool MipsBranchExpansion::handleMFLO() {
826 return handleMFLOSlot(
827 [
this](
auto &
I) ->
bool {
return TII->IsMfloOrMfhi(
I); },
828 [
this](
auto &IInSlot,
auto &
I) ->
bool {
829 return TII->SafeAfterMflo(IInSlot);
833bool MipsBranchExpansion::handleForbiddenSlot() {
839 [
this](
auto &
I) ->
bool {
return TII->HasForbiddenSlot(
I); },
840 [
this](
auto &IInSlot,
auto &
I) ->
bool {
841 return TII->SafeInForbiddenSlot(IInSlot);
845bool MipsBranchExpansion::handleFPUDelaySlot() {
850 return handleSlot([
this](
auto &
I) ->
bool {
return TII->HasFPUDelaySlot(
I); },
851 [
this](
auto &IInSlot,
auto &
I) ->
bool {
852 return TII->SafeInFPUDelaySlot(IInSlot,
I);
856bool MipsBranchExpansion::handleLoadDelaySlot() {
862 [
this](
auto &
I) ->
bool {
return TII->HasLoadDelaySlot(
I); },
863 [
this](
auto &IInSlot,
auto &
I) ->
bool {
864 return TII->SafeInLoadDelaySlot(IInSlot,
I);
868bool MipsBranchExpansion::handlePossibleLongBranch() {
875 bool EverMadeChange =
false, MadeChange =
true;
882 for (
unsigned I = 0,
E = MBBInfos.size();
I <
E; ++
I) {
883 MachineBasicBlock *
MBB = MFp->getBlockNumbered(
I);
888 if ((Br != End) && Br->isBranch() && !Br->isIndirectBranch() &&
889 (Br->isConditionalBranch() ||
890 (Br->isUnconditionalBranch() && IsPIC))) {
891 int64_t
Offset = computeOffset(&*Br);
893 if (ForceLongBranchFirstPass ||
894 !
TII->isBranchOffsetInRange(Br->getOpcode(),
Offset)) {
896 MBBInfos[
I].Br = &*Br;
901 ForceLongBranchFirstPass =
false;
905 for (
I = MBBInfos.begin();
I !=
E; ++
I) {
911 expandToLongBranch(*
I);
913 EverMadeChange = MadeChange =
true;
916 MFp->RenumberBlocks();
919 return EverMadeChange;
922bool MipsBranchExpansion::runOnMachineFunction(MachineFunction &MF) {
924 IsPIC =
TM.isPositionIndependent();
925 ABI =
static_cast<const MipsTargetMachine &
>(
TM).getABI();
929 if (IsPIC && ABI.
IsO32() &&
930 MF.
getInfo<MipsFunctionInfo>()->globalBaseRegSet())
937 bool longBranchChanged = handlePossibleLongBranch();
938 bool forbiddenSlotChanged = handleForbiddenSlot();
939 bool fpuDelaySlotChanged = handleFPUDelaySlot();
940 bool loadDelaySlotChanged = handleLoadDelaySlot();
941 bool MfloChanged = handleMFLO();
943 bool Changed = longBranchChanged || forbiddenSlotChanged ||
944 fpuDelaySlotChanged || loadDelaySlotChanged || MfloChanged;
947 while (forbiddenSlotChanged) {
948 longBranchChanged = handlePossibleLongBranch();
949 fpuDelaySlotChanged = handleFPUDelaySlot();
950 loadDelaySlotChanged = handleLoadDelaySlot();
951 MfloChanged = handleMFLO();
952 if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged &&
955 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")
Analysis containing CSE Info
const HexagonInstrInfo * TII
static std::pair< Iter, bool > getNextMachineInstr(Iter Position, MachineBasicBlock *Parent)
static cl::opt< bool > ForceLongBranch("force-mips-long-branch", cl::init(false), cl::desc("MIPS: Expand all branches to long format."), cl::Hidden)
static cl::opt< bool > SkipLongBranch("skip-mips-long-branch", cl::init(false), cl::desc("MIPS: Skip branch expansion pass."), cl::Hidden)
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 & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register 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
bool enableLongBranchPass() const
typename SuperClass::iterator iterator
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.
initializer< Ty > init(const Ty &Val)
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FunctionPass * createMipsBranchExpansion()