50#define DEBUG_TYPE "mips-delay-slot-filler"
52STATISTIC(FilledSlots,
"Number of delay slots filled");
53STATISTIC(UsefulSlots,
"Number of delay slots filled with instructions that"
55STATISTIC(R5900ShortLoopNops,
"Number of delay slots left as NOP for R5900 "
59 "disable-mips-delay-filler",
61 cl::desc(
"Fill all delay slots with NOPs."),
65 "disable-mips-df-forward-search",
67 cl::desc(
"Disallow MIPS delay filler to search forward."),
71 "disable-mips-df-succbb-search",
73 cl::desc(
"Disallow MIPS delay filler to search successor basic blocks."),
77 "disable-mips-df-backward-search",
79 cl::desc(
"Disallow MIPS delay filler to search backward."),
107 bool update(
const MachineInstr &
MI,
unsigned Begin,
unsigned End);
114 bool isRegInSet(
const BitVector &RegSet,
unsigned Reg)
const;
121 class InspectMemInstr {
123 InspectMemInstr(
bool ForbidMemInstr_) : ForbidMemInstr(ForbidMemInstr_) {}
124 virtual ~InspectMemInstr() =
default;
131 bool OrigSeenLoad =
false;
132 bool OrigSeenStore =
false;
133 bool SeenLoad =
false;
134 bool SeenStore =
false;
141 virtual bool hasHazard_(
const MachineInstr &
MI) = 0;
145 class NoMemInstr :
public InspectMemInstr {
147 NoMemInstr() : InspectMemInstr(
true) {}
150 bool hasHazard_(
const MachineInstr &
MI)
override {
return true; }
154 class LoadFromStackOrConst :
public InspectMemInstr {
156 LoadFromStackOrConst() : InspectMemInstr(
false) {}
159 bool hasHazard_(
const MachineInstr &
MI)
override;
164 class MemDefsUses :
public InspectMemInstr {
166 explicit MemDefsUses(
const MachineFrameInfo *MFI);
169 using ValueType = PointerUnion<const Value *, const PseudoSourceValue *>;
171 bool hasHazard_(
const MachineInstr &
MI)
override;
176 bool updateDefsUses(ValueType V,
bool MayStore);
180 SmallVectorImpl<ValueType> &Objects)
const;
182 const MachineFrameInfo *MFI;
183 SmallPtrSet<ValueType, 4> Uses, Defs;
187 bool SeenNoObjLoad =
false;
188 bool SeenNoObjStore =
false;
193 MipsDelaySlotFiller() : MachineFunctionPass(ID) {}
195 StringRef getPassName()
const override {
return "Mips Delay Slot Filler"; }
197 bool runOnMachineFunction(MachineFunction &
F)
override {
200 for (MachineBasicBlock &
MBB :
F)
207 F.getRegInfo().invalidateLiveness();
212 MachineFunctionProperties getRequiredProperties()
const override {
213 return MachineFunctionProperties().setNoVRegs();
216 void getAnalysisUsage(AnalysisUsage &AU)
const override {
217 AU.
addRequired<MachineBranchProbabilityInfoWrapperPass>();
224 bool runOnMachineBasicBlock(MachineBasicBlock &
MBB);
226 Iter replaceWithCompactBranch(MachineBasicBlock &
MBB, Iter Branch,
232 bool delayHasHazard(
const MachineInstr &Candidate, RegDefsUses &RegDU,
233 InspectMemInstr &IM)
const;
237 template<
typename IterTy>
238 bool searchRange(MachineBasicBlock &
MBB, IterTy Begin, IterTy End,
239 RegDefsUses &RegDU, InspectMemInstr &IM, Iter Slot,
240 IterTy &Filler)
const;
244 bool searchBackward(MachineBasicBlock &
MBB, MachineInstr &Slot)
const;
248 bool searchForward(MachineBasicBlock &
MBB, Iter Slot)
const;
253 bool searchSuccBBs(MachineBasicBlock &
MBB, Iter Slot)
const;
257 MachineBasicBlock *selectSuccBB(MachineBasicBlock &
B)
const;
261 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
262 getBranch(MachineBasicBlock &
MBB,
const MachineBasicBlock &Dst)
const;
266 bool examinePred(MachineBasicBlock &Pred,
const MachineBasicBlock &Succ,
267 RegDefsUses &RegDU,
bool &HasMultipleSuccs,
268 BB2BrMap &
BrMap)
const;
270 bool terminateSearch(
const MachineInstr &Candidate)
const;
272 const TargetMachine *TM =
nullptr;
277char MipsDelaySlotFiller::ID = 0;
280 return MI->hasDelaySlot() && !
MI->isBundledWithSucc();
304 if (!
MI->isBranch() ||
MI->isIndirectBranch())
311 TargetMBB = MO.getMBB();
317 if (!TargetMBB || TargetMBB != &
MBB)
324 bool HasOtherBranch =
false;
331 if (Instr.isDebugInstr() || Instr.isTransient())
337 if (Instr.isBranch() || Instr.isCall()) {
338 HasOtherBranch =
true;
355 "Fill delay slot for MIPS",
false,
false)
358static
void insertDelayFiller(Iter Filler,
const BB2BrMap &
BrMap) {
366 I.first->push_back(MF->CloneMachineInstr(&*Filler));
376 if (!MO.isReg() || !MO.isDef() || !(R = MO.getReg()))
382 "Shouldn't move an instruction with unallocatable registers across "
383 "basic block boundaries.");
386 if (!
MBB.isLiveIn(R))
396 update(
MI, 0,
MI.getDesc().getNumOperands());
406 update(
MI,
MI.getDesc().getNumOperands(),
MI.getNumOperands());
407 Defs.
reset(Mips::AT);
411void RegDefsUses::setCallerSaved(
const MachineInstr &
MI) {
417 if (
MI.definesRegister(Mips::RA,
nullptr) ||
418 MI.definesRegister(Mips::RA_64,
nullptr)) {
420 Defs.
set(Mips::RA_64);
424 BitVector CallerSavedRegs(
TRI.getNumRegs(),
true);
426 CallerSavedRegs.reset(Mips::ZERO);
427 CallerSavedRegs.reset(Mips::ZERO_64);
429 for (
const MCPhysReg *R =
TRI.getCalleeSavedRegs(
MI.getParent()->getParent());
431 for (MCRegAliasIterator AI(*R, &
TRI,
true); AI.isValid(); ++AI)
432 CallerSavedRegs.reset(*AI);
434 Defs |= CallerSavedRegs;
437void RegDefsUses::setUnallocatableRegs(
const MachineFunction &MF) {
438 BitVector AllocSet =
TRI.getAllocatableSet(MF);
440 for (
unsigned R : AllocSet.
set_bits())
441 for (MCRegAliasIterator AI(R, &
TRI,
false); AI.isValid(); ++AI)
444 AllocSet.
set(Mips::ZERO);
445 AllocSet.
set(Mips::ZERO_64);
447 Defs |= AllocSet.
flip();
450void RegDefsUses::addLiveOut(
const MachineBasicBlock &
MBB,
451 const MachineBasicBlock &SuccBB) {
454 for (
const auto &LI : S->liveins())
458bool RegDefsUses::update(
const MachineInstr &
MI,
unsigned Begin,
unsigned End) {
459 BitVector NewDefs(
TRI.getNumRegs()), NewUses(
TRI.getNumRegs());
460 bool HasHazard =
false;
462 for (
unsigned I = Begin;
I != End; ++
I) {
463 const MachineOperand &MO =
MI.getOperand(
I);
466 if (checkRegDefsUses(NewDefs, NewUses, MO.
getReg(), MO.
isDef())) {
481bool RegDefsUses::checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses,
482 unsigned Reg,
bool IsDef)
const {
486 return (isRegInSet(Defs,
Reg) || isRegInSet(
Uses,
Reg));
491 return isRegInSet(Defs,
Reg);
494bool RegDefsUses::isRegInSet(
const BitVector &RegSet,
unsigned Reg)
const {
496 for (MCRegAliasIterator AI(
Reg, &
TRI,
true); AI.isValid(); ++AI)
497 if (RegSet.
test(*AI))
502bool InspectMemInstr::hasHazard(
const MachineInstr &
MI) {
503 if (!
MI.mayStore() && !
MI.mayLoad())
509 OrigSeenLoad = SeenLoad;
510 OrigSeenStore = SeenStore;
511 SeenLoad |=
MI.mayLoad();
512 SeenStore |=
MI.mayStore();
516 if (
MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) {
517 ForbidMemInstr =
true;
521 return hasHazard_(
MI);
524bool LoadFromStackOrConst::hasHazard_(
const MachineInstr &
MI) {
528 if (!
MI.hasOneMemOperand() || !(*
MI.memoperands_begin())->getPseudoValue())
531 if (
const PseudoSourceValue *PSV =
532 (*
MI.memoperands_begin())->getPseudoValue()) {
535 return !PSV->isConstant(
nullptr) && !PSV->isStack();
541MemDefsUses::MemDefsUses(
const MachineFrameInfo *MFI_)
542 : InspectMemInstr(
false), MFI(MFI_) {}
545 bool HasHazard =
false;
551 HasHazard |= updateDefsUses(VT,
MI.mayStore());
556 HasHazard =
MI.mayStore() && (OrigSeenLoad || OrigSeenStore);
557 HasHazard |=
MI.mayLoad() || OrigSeenStore;
559 SeenNoObjLoad |=
MI.mayLoad();
560 SeenNoObjStore |=
MI.mayStore();
565bool MemDefsUses::updateDefsUses(
ValueType V,
bool MayStore) {
567 return !Defs.insert(V).second ||
Uses.count(V) || SeenNoObjStore ||
571 return Defs.count(V) || SeenNoObjStore;
575getUnderlyingObjects(
const MachineInstr &
MI,
576 SmallVectorImpl<ValueType> &Objects)
const {
577 if (!
MI.hasOneMemOperand())
580 auto & MMO = **
MI.memoperands_begin();
582 if (
const PseudoSourceValue *PSV = MMO.getPseudoValue()) {
583 if (!PSV->isAliased(MFI))
589 if (
const Value *V = MMO.getValue()) {
593 for (
const Value *UValue : Objs) {
606Iter MipsDelaySlotFiller::replaceWithCompactBranch(MachineBasicBlock &
MBB,
612 unsigned NewOpcode =
TII->getEquivalentCompactForm(Branch);
613 Branch =
TII->genInstrWithNewOpc(NewOpcode, Branch);
617 if (ToErase->shouldUpdateAdditionalCallInfo())
618 ToErase->getMF()->moveAdditionalCallInfo(ToErase,
620 ToErase->eraseFromParent();
632 return Mips::BGEZALS_MM;
634 return Mips::BLTZALS_MM;
637 return Mips::JALS_MM;
639 return Mips::JALRS_MM;
640 case Mips::JALR16_MM:
641 return Mips::JALRS16_MM;
642 case Mips::TAILCALL_MM:
644 case Mips::TAILCALLREG:
645 return Mips::JR16_MM;
653bool MipsDelaySlotFiller::runOnMachineBasicBlock(MachineBasicBlock &
MBB) {
666 bool SkipForFixR5900 =
false;
669 "short loop branch.\n");
670 ++R5900ShortLoopNops;
671 SkipForFixR5900 =
true;
678 !(InMicroMipsMode && STI.
hasMips32r6()) && !SkipForFixR5900) {
683 !
TII->getEquivalentCompactForm(
I)) {
684 if (searchBackward(
MBB, *
I)) {
686 " in backwards search.\n");
688 }
else if (
I->isTerminator()) {
689 if (searchSuccBBs(
MBB,
I)) {
692 " in successor BB search.\n");
694 }
else if (searchForward(
MBB,
I)) {
696 " in forwards search.\n");
705 if (InMicroMipsMode &&
TII->getInstSizeInBytes(*std::next(DSI)) == 2 &&
732 if ((InMicroMipsMode ||
734 TII->getEquivalentCompactForm(
I)) {
735 I = replaceWithCompactBranch(
MBB,
I,
I->getDebugLoc());
743 TII->insertNop(
MBB, std::next(
I),
I->getDebugLoc());
744 MIBundleBuilder(
MBB,
I, std::next(
I, 2));
752template <
typename IterTy>
753bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &
MBB, IterTy Begin,
754 IterTy End, RegDefsUses &RegDU,
755 InspectMemInstr &IM, Iter Slot,
756 IterTy &Filler)
const {
757 for (IterTy
I = Begin;
I != End;) {
764 if (CurrI->isDebugInstr() || CurrI->isJumpTableDebugInfo()) {
770 if (CurrI->isBundle()) {
774 RegDU.update(*CurrI, 0, CurrI->getNumOperands());
778 if (terminateSearch(*CurrI)) {
784 assert((!CurrI->isCall() && !CurrI->isReturn() && !CurrI->isBranch()) &&
785 "Cannot put calls, returns or branches in delay slot.");
787 if (CurrI->isKill()) {
788 CurrI->eraseFromParent();
792 if (delayHasHazard(*CurrI, RegDU, IM))
798 unsigned Opcode = (*Slot).getOpcode();
810 if (InMicroMipsMode &&
TII->getInstSizeInBytes(*CurrI) == 2 &&
811 (Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch ||
812 Opcode == Mips::PseudoIndirectBranch_MM ||
813 Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL))
817 if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM ||
818 Opcode == Mips::MOVEP_MM))
831bool MipsDelaySlotFiller::searchBackward(MachineBasicBlock &
MBB,
832 MachineInstr &Slot)
const {
837 RegDefsUses RegDU(*Fn->getSubtarget().getRegisterInfo());
838 MemDefsUses MemDU(&Fn->getFrameInfo());
847 "slot using backwards search.\n");
851 MBB.
splice(std::next(SlotI), &
MBB, Filler.getReverse());
852 MIBundleBuilder(
MBB, SlotI, std::next(SlotI, 2));
857bool MipsDelaySlotFiller::searchForward(MachineBasicBlock &
MBB,
867 RegDU.setCallerSaved(*Slot);
869 if (!searchRange(
MBB, std::next(Slot),
MBB.
end(), RegDU, NM, Slot, Filler)) {
871 "slot using forwards search.\n");
876 MIBundleBuilder(
MBB, Slot, std::next(Slot, 2));
881bool MipsDelaySlotFiller::searchSuccBBs(MachineBasicBlock &
MBB,
886 MachineBasicBlock *SuccBB = selectSuccBB(
MBB);
892 bool HasMultipleSuccs =
false;
894 std::unique_ptr<InspectMemInstr> IM;
900 if (!examinePred(*Pred, *SuccBB, RegDU, HasMultipleSuccs,
BrMap))
905 RegDU.setUnallocatableRegs(*Fn);
909 if (HasMultipleSuccs) {
910 IM.reset(
new LoadFromStackOrConst());
912 const MachineFrameInfo &MFI = Fn->getFrameInfo();
913 IM.reset(
new MemDefsUses(&MFI));
916 if (!searchRange(
MBB, SuccBB->
begin(), SuccBB->
end(), RegDU, *IM, Slot,
920 insertDelayFiller(Filler,
BrMap);
922 Filler->eraseFromParent();
928MipsDelaySlotFiller::selectSuccBB(MachineBasicBlock &
B)
const {
933 auto &Prob = getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
934 MachineBasicBlock *S =
936 const MachineBasicBlock *Dst1) {
937 return Prob.getEdgeProbability(&B, Dst0) <
938 Prob.getEdgeProbability(&B, Dst1);
940 return S->
isEHPad() ? nullptr : S;
943std::pair<MipsInstrInfo::BranchType, MachineInstr *>
944MipsDelaySlotFiller::getBranch(MachineBasicBlock &
MBB,
945 const MachineBasicBlock &Dst)
const {
946 const MipsInstrInfo *
TII =
948 MachineBasicBlock *TrueBB =
nullptr, *FalseBB =
nullptr;
949 SmallVector<MachineInstr*, 2> BranchInstrs;
956 return std::make_pair(R,
nullptr);
964 return std::make_pair(R, BranchInstrs[0]);
967 assert((TrueBB == &Dst) || (FalseBB == &Dst));
980bool MipsDelaySlotFiller::examinePred(MachineBasicBlock &Pred,
981 const MachineBasicBlock &Succ,
983 bool &HasMultipleSuccs,
984 BB2BrMap &
BrMap)
const {
985 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
P =
986 getBranch(Pred, Succ);
995 HasMultipleSuccs =
true;
996 RegDU.addLiveOut(Pred, Succ);
1003bool MipsDelaySlotFiller::delayHasHazard(
const MachineInstr &Candidate,
1005 InspectMemInstr &IM)
const {
1007 "KILL instructions should have been eliminated at this point.");
1011 HasHazard |= IM.hasHazard(Candidate);
1012 HasHazard |= RegDU.update(Candidate, 0, Candidate.
getNumOperands());
1017bool MipsDelaySlotFiller::terminateSearch(
const MachineInstr &Candidate)
const {
1026 return new MipsDelaySlotFiller();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis false
static const Function * getParent(const Value *V)
This file implements the BitVector class.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static unsigned InstrCount
This file defines the DenseMap class.
static bool hasHazard(StateT InitialState, function_ref< HazardFnResult(StateT &, const MachineInstr &)> IsHazard, function_ref< void(StateT &, const MachineInstr &)> UpdateState, const MachineBasicBlock *InitialMBB, MachineBasicBlock::const_reverse_instr_iterator InitialI)
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
static bool hasUnoccupiedSlot(const MachineInstr *MI)
static cl::opt< bool > DisableDelaySlotFiller("disable-mips-delay-filler", cl::init(false), cl::desc("Fill all delay slots with NOPs."), cl::Hidden)
static cl::opt< bool > DisableBackwardSearch("disable-mips-df-backward-search", cl::init(false), cl::desc("Disallow MIPS delay filler to search backward."), cl::Hidden)
static void addLiveInRegs(Iter Filler, MachineBasicBlock &MBB)
This function adds registers Filler defines to MBB's live-in register list.
static bool isR5900ShortLoopBranch(const MachineInstr *MI, const MachineBasicBlock &MBB)
Check if a branch is a short backward loop that triggers the R5900 erratum.
static cl::opt< bool > DisableSuccBBSearch("disable-mips-df-succbb-search", cl::init(true), cl::desc("Disallow MIPS delay filler to search successor basic blocks."), cl::Hidden)
static cl::opt< bool > DisableForwardSearch("disable-mips-df-forward-search", cl::init(true), cl::desc("Disallow MIPS delay filler to search forward."), cl::Hidden)
cl::opt< CompactBranchPolicy > MipsCompactBranchPolicy
static int getEquivalentCallShort(int Opcode)
#define IsMFLOMFHI(instr)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file defines the PointerUnion class, which is a discriminated union of pointer types.
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
This file defines the SmallPtrSet class.
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)
AnalysisUsage & addRequired()
bool test(unsigned Idx) const
iterator_range< const_set_bits_iterator > set_bits() const
FunctionPass class - This class is used to implement most global optimizations.
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify) const override
Analyze the branching code at the end of MBB, returning true if it cannot be understood (e....
Helper class for constructing bundles of MachineInstrs.
MIBundleBuilder & append(MachineInstr *MI)
Insert MI into MBB by appending it to the instructions in the bundle.
bool isEHPad() const
Returns true if the block is a landing pad.
Instructions::iterator instr_iterator
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
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...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
reverse_iterator getReverse() const
Get a reverse iterator to the same node.
Representation of each machine instruction.
bool isTerminator(QueryType Type=AnyInBundle) const
Returns true if this instruction part of the terminator for a basic block.
bool isImplicitDef() const
bool isCall(QueryType Type=AnyInBundle) const
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI bool hasUnmodeledSideEffects() const
Return true if this instruction has side effects that are not modeled by mayLoad / mayStore,...
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void dump() const
Register getReg() const
getReg - Returns the register number.
bool inMicroMipsMode() const
const MipsInstrInfo * getInstrInfo() const override
void push_back(const T &Elt)
CodeGenOptLevel getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
BitVector getAllocatableSet(const MachineFunction &MF, const TargetRegisterClass *RC=nullptr) const
Returns a bitset indexed by register number indicating if a register is allocatable or not.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
@ CB_Never
The policy 'never' may in some circumstances or for some ISAs not be absolutely adhered to.
@ CB_Always
'always' may in some circumstances may not be absolutely adhered to, there may not be a corresponding...
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
FunctionPass * createMipsDelaySlotFillerPass()
createMipsDelaySlotFillerPass - Returns a pass that fills in delay slots in Mips MachineFunctions
LLVM_ABI void getUnderlyingObjects(const Value *V, SmallVectorImpl< const Value * > &Objects, const LoopInfo *LI=nullptr, unsigned MaxLookup=MaxLookupSearchDepth)
This method is similar to getUnderlyingObject except that it can look through phi and select instruct...
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.