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"
57 "disable-mips-delay-filler",
59 cl::desc(
"Fill all delay slots with NOPs."),
63 "disable-mips-df-forward-search",
65 cl::desc(
"Disallow MIPS delay filler to search forward."),
69 "disable-mips-df-succbb-search",
71 cl::desc(
"Disallow MIPS delay filler to search successor basic blocks."),
75 "disable-mips-df-backward-search",
77 cl::desc(
"Disallow MIPS delay filler to search backward."),
105 bool update(
const MachineInstr &
MI,
unsigned Begin,
unsigned End);
112 bool isRegInSet(
const BitVector &RegSet,
unsigned Reg)
const;
119 class InspectMemInstr {
121 InspectMemInstr(
bool ForbidMemInstr_) : ForbidMemInstr(ForbidMemInstr_) {}
122 virtual ~InspectMemInstr() =
default;
129 bool OrigSeenLoad =
false;
130 bool OrigSeenStore =
false;
131 bool SeenLoad =
false;
132 bool SeenStore =
false;
139 virtual bool hasHazard_(
const MachineInstr &
MI) = 0;
143 class NoMemInstr :
public InspectMemInstr {
145 NoMemInstr() : InspectMemInstr(
true) {}
148 bool hasHazard_(
const MachineInstr &
MI)
override {
return true; }
152 class LoadFromStackOrConst :
public InspectMemInstr {
154 LoadFromStackOrConst() : InspectMemInstr(
false) {}
157 bool hasHazard_(
const MachineInstr &
MI)
override;
162 class MemDefsUses :
public InspectMemInstr {
164 explicit MemDefsUses(
const MachineFrameInfo *MFI);
167 using ValueType = PointerUnion<const Value *, const PseudoSourceValue *>;
169 bool hasHazard_(
const MachineInstr &
MI)
override;
174 bool updateDefsUses(ValueType V,
bool MayStore);
178 SmallVectorImpl<ValueType> &Objects)
const;
180 const MachineFrameInfo *MFI;
181 SmallPtrSet<ValueType, 4> Uses, Defs;
185 bool SeenNoObjLoad =
false;
186 bool SeenNoObjStore =
false;
191 MipsDelaySlotFiller() : MachineFunctionPass(ID) {}
193 StringRef getPassName()
const override {
return "Mips Delay Slot Filler"; }
195 bool runOnMachineFunction(MachineFunction &
F)
override {
198 for (MachineBasicBlock &
MBB :
F)
205 F.getRegInfo().invalidateLiveness();
210 MachineFunctionProperties getRequiredProperties()
const override {
211 return MachineFunctionProperties().setNoVRegs();
214 void getAnalysisUsage(AnalysisUsage &AU)
const override {
215 AU.
addRequired<MachineBranchProbabilityInfoWrapperPass>();
222 bool runOnMachineBasicBlock(MachineBasicBlock &
MBB);
224 Iter replaceWithCompactBranch(MachineBasicBlock &
MBB, Iter Branch,
230 bool delayHasHazard(
const MachineInstr &Candidate, RegDefsUses &RegDU,
231 InspectMemInstr &IM)
const;
235 template<
typename IterTy>
236 bool searchRange(MachineBasicBlock &
MBB, IterTy Begin, IterTy End,
237 RegDefsUses &RegDU, InspectMemInstr &IM, Iter Slot,
238 IterTy &Filler)
const;
242 bool searchBackward(MachineBasicBlock &
MBB, MachineInstr &Slot)
const;
246 bool searchForward(MachineBasicBlock &
MBB, Iter Slot)
const;
251 bool searchSuccBBs(MachineBasicBlock &
MBB, Iter Slot)
const;
255 MachineBasicBlock *selectSuccBB(MachineBasicBlock &
B)
const;
259 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
260 getBranch(MachineBasicBlock &
MBB,
const MachineBasicBlock &Dst)
const;
264 bool examinePred(MachineBasicBlock &Pred,
const MachineBasicBlock &Succ,
265 RegDefsUses &RegDU,
bool &HasMultipleSuccs,
266 BB2BrMap &
BrMap)
const;
268 bool terminateSearch(
const MachineInstr &Candidate)
const;
270 const TargetMachine *TM =
nullptr;
275char MipsDelaySlotFiller::ID = 0;
278 return MI->hasDelaySlot() && !
MI->isBundledWithSucc();
282 "Fill delay slot for MIPS",
false,
false)
285static
void insertDelayFiller(Iter Filler,
const BB2BrMap &
BrMap) {
293 I.first->push_back(MF->CloneMachineInstr(&*Filler));
303 if (!MO.isReg() || !MO.isDef() || !(R = MO.getReg()))
309 "Shouldn't move an instruction with unallocatable registers across "
310 "basic block boundaries.");
313 if (!
MBB.isLiveIn(R))
323 update(
MI, 0,
MI.getDesc().getNumOperands());
333 update(
MI,
MI.getDesc().getNumOperands(),
MI.getNumOperands());
334 Defs.
reset(Mips::AT);
338void RegDefsUses::setCallerSaved(
const MachineInstr &
MI) {
344 if (
MI.definesRegister(Mips::RA,
nullptr) ||
345 MI.definesRegister(Mips::RA_64,
nullptr)) {
347 Defs.
set(Mips::RA_64);
351 BitVector CallerSavedRegs(
TRI.getNumRegs(),
true);
353 CallerSavedRegs.reset(Mips::ZERO);
354 CallerSavedRegs.reset(Mips::ZERO_64);
356 for (
const MCPhysReg *R =
TRI.getCalleeSavedRegs(
MI.getParent()->getParent());
358 for (MCRegAliasIterator AI(*R, &
TRI,
true); AI.isValid(); ++AI)
359 CallerSavedRegs.reset(*AI);
361 Defs |= CallerSavedRegs;
364void RegDefsUses::setUnallocatableRegs(
const MachineFunction &MF) {
365 BitVector AllocSet =
TRI.getAllocatableSet(MF);
367 for (
unsigned R : AllocSet.
set_bits())
368 for (MCRegAliasIterator AI(R, &
TRI,
false); AI.isValid(); ++AI)
371 AllocSet.
set(Mips::ZERO);
372 AllocSet.
set(Mips::ZERO_64);
374 Defs |= AllocSet.
flip();
377void RegDefsUses::addLiveOut(
const MachineBasicBlock &
MBB,
378 const MachineBasicBlock &SuccBB) {
381 for (
const auto &LI : S->liveins())
385bool RegDefsUses::update(
const MachineInstr &
MI,
unsigned Begin,
unsigned End) {
386 BitVector NewDefs(
TRI.getNumRegs()), NewUses(
TRI.getNumRegs());
387 bool HasHazard =
false;
389 for (
unsigned I = Begin;
I != End; ++
I) {
390 const MachineOperand &MO =
MI.getOperand(
I);
393 if (checkRegDefsUses(NewDefs, NewUses, MO.
getReg(), MO.
isDef())) {
408bool RegDefsUses::checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses,
409 unsigned Reg,
bool IsDef)
const {
413 return (isRegInSet(Defs,
Reg) || isRegInSet(
Uses,
Reg));
418 return isRegInSet(Defs,
Reg);
421bool RegDefsUses::isRegInSet(
const BitVector &RegSet,
unsigned Reg)
const {
423 for (MCRegAliasIterator AI(
Reg, &
TRI,
true); AI.isValid(); ++AI)
424 if (RegSet.
test(*AI))
429bool InspectMemInstr::hasHazard(
const MachineInstr &
MI) {
430 if (!
MI.mayStore() && !
MI.mayLoad())
436 OrigSeenLoad = SeenLoad;
437 OrigSeenStore = SeenStore;
438 SeenLoad |=
MI.mayLoad();
439 SeenStore |=
MI.mayStore();
443 if (
MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) {
444 ForbidMemInstr =
true;
448 return hasHazard_(
MI);
451bool LoadFromStackOrConst::hasHazard_(
const MachineInstr &
MI) {
455 if (!
MI.hasOneMemOperand() || !(*
MI.memoperands_begin())->getPseudoValue())
458 if (
const PseudoSourceValue *PSV =
459 (*
MI.memoperands_begin())->getPseudoValue()) {
462 return !PSV->isConstant(
nullptr) && !PSV->isStack();
468MemDefsUses::MemDefsUses(
const MachineFrameInfo *MFI_)
469 : InspectMemInstr(
false), MFI(MFI_) {}
472 bool HasHazard =
false;
478 HasHazard |= updateDefsUses(VT,
MI.mayStore());
483 HasHazard =
MI.mayStore() && (OrigSeenLoad || OrigSeenStore);
484 HasHazard |=
MI.mayLoad() || OrigSeenStore;
486 SeenNoObjLoad |=
MI.mayLoad();
487 SeenNoObjStore |=
MI.mayStore();
492bool MemDefsUses::updateDefsUses(
ValueType V,
bool MayStore) {
494 return !Defs.insert(V).second ||
Uses.count(V) || SeenNoObjStore ||
498 return Defs.count(V) || SeenNoObjStore;
502getUnderlyingObjects(
const MachineInstr &
MI,
503 SmallVectorImpl<ValueType> &Objects)
const {
504 if (!
MI.hasOneMemOperand())
507 auto & MMO = **
MI.memoperands_begin();
509 if (
const PseudoSourceValue *PSV = MMO.getPseudoValue()) {
510 if (!PSV->isAliased(MFI))
516 if (
const Value *V = MMO.getValue()) {
520 for (
const Value *UValue : Objs) {
533Iter MipsDelaySlotFiller::replaceWithCompactBranch(MachineBasicBlock &
MBB,
539 unsigned NewOpcode =
TII->getEquivalentCompactForm(Branch);
540 Branch =
TII->genInstrWithNewOpc(NewOpcode, Branch);
544 if (ToErase->shouldUpdateAdditionalCallInfo())
545 ToErase->getMF()->moveAdditionalCallInfo(ToErase,
547 ToErase->eraseFromParent();
559 return Mips::BGEZALS_MM;
561 return Mips::BLTZALS_MM;
564 return Mips::JALS_MM;
566 return Mips::JALRS_MM;
567 case Mips::JALR16_MM:
568 return Mips::JALRS16_MM;
569 case Mips::TAILCALL_MM:
571 case Mips::TAILCALLREG:
572 return Mips::JR16_MM;
580bool MipsDelaySlotFiller::runOnMachineBasicBlock(MachineBasicBlock &
MBB) {
598 !
TII->getEquivalentCompactForm(
I)) {
599 if (searchBackward(
MBB, *
I)) {
601 " in backwards search.\n");
603 }
else if (
I->isTerminator()) {
604 if (searchSuccBBs(
MBB,
I)) {
607 " in successor BB search.\n");
609 }
else if (searchForward(
MBB,
I)) {
611 " in forwards search.\n");
620 if (InMicroMipsMode &&
TII->getInstSizeInBytes(*std::next(DSI)) == 2 &&
647 if ((InMicroMipsMode ||
649 TII->getEquivalentCompactForm(
I)) {
650 I = replaceWithCompactBranch(
MBB,
I,
I->getDebugLoc());
658 TII->insertNop(
MBB, std::next(
I),
I->getDebugLoc());
659 MIBundleBuilder(
MBB,
I, std::next(
I, 2));
667template <
typename IterTy>
668bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &
MBB, IterTy Begin,
669 IterTy End, RegDefsUses &RegDU,
670 InspectMemInstr &IM, Iter Slot,
671 IterTy &Filler)
const {
672 for (IterTy
I = Begin;
I != End;) {
679 if (CurrI->isDebugInstr() || CurrI->isJumpTableDebugInfo()) {
685 if (CurrI->isBundle()) {
689 RegDU.update(*CurrI, 0, CurrI->getNumOperands());
693 if (terminateSearch(*CurrI)) {
699 assert((!CurrI->isCall() && !CurrI->isReturn() && !CurrI->isBranch()) &&
700 "Cannot put calls, returns or branches in delay slot.");
702 if (CurrI->isKill()) {
703 CurrI->eraseFromParent();
707 if (delayHasHazard(*CurrI, RegDU, IM))
713 unsigned Opcode = (*Slot).getOpcode();
725 if (InMicroMipsMode &&
TII->getInstSizeInBytes(*CurrI) == 2 &&
726 (Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch ||
727 Opcode == Mips::PseudoIndirectBranch_MM ||
728 Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL))
732 if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM ||
733 Opcode == Mips::MOVEP_MM))
746bool MipsDelaySlotFiller::searchBackward(MachineBasicBlock &
MBB,
747 MachineInstr &Slot)
const {
752 RegDefsUses RegDU(*Fn->getSubtarget().getRegisterInfo());
753 MemDefsUses MemDU(&Fn->getFrameInfo());
762 "slot using backwards search.\n");
766 MBB.
splice(std::next(SlotI), &
MBB, Filler.getReverse());
767 MIBundleBuilder(
MBB, SlotI, std::next(SlotI, 2));
772bool MipsDelaySlotFiller::searchForward(MachineBasicBlock &
MBB,
782 RegDU.setCallerSaved(*Slot);
784 if (!searchRange(
MBB, std::next(Slot),
MBB.
end(), RegDU, NM, Slot, Filler)) {
786 "slot using forwards search.\n");
791 MIBundleBuilder(
MBB, Slot, std::next(Slot, 2));
796bool MipsDelaySlotFiller::searchSuccBBs(MachineBasicBlock &
MBB,
801 MachineBasicBlock *SuccBB = selectSuccBB(
MBB);
807 bool HasMultipleSuccs =
false;
809 std::unique_ptr<InspectMemInstr> IM;
815 if (!examinePred(*Pred, *SuccBB, RegDU, HasMultipleSuccs,
BrMap))
820 RegDU.setUnallocatableRegs(*Fn);
824 if (HasMultipleSuccs) {
825 IM.reset(
new LoadFromStackOrConst());
827 const MachineFrameInfo &MFI = Fn->getFrameInfo();
828 IM.reset(
new MemDefsUses(&MFI));
831 if (!searchRange(
MBB, SuccBB->
begin(), SuccBB->
end(), RegDU, *IM, Slot,
835 insertDelayFiller(Filler,
BrMap);
837 Filler->eraseFromParent();
843MipsDelaySlotFiller::selectSuccBB(MachineBasicBlock &
B)
const {
848 auto &Prob = getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
849 MachineBasicBlock *S =
851 const MachineBasicBlock *Dst1) {
852 return Prob.getEdgeProbability(&B, Dst0) <
853 Prob.getEdgeProbability(&B, Dst1);
855 return S->
isEHPad() ? nullptr : S;
858std::pair<MipsInstrInfo::BranchType, MachineInstr *>
859MipsDelaySlotFiller::getBranch(MachineBasicBlock &
MBB,
860 const MachineBasicBlock &Dst)
const {
861 const MipsInstrInfo *
TII =
863 MachineBasicBlock *TrueBB =
nullptr, *FalseBB =
nullptr;
864 SmallVector<MachineInstr*, 2> BranchInstrs;
871 return std::make_pair(R,
nullptr);
879 return std::make_pair(R, BranchInstrs[0]);
882 assert((TrueBB == &Dst) || (FalseBB == &Dst));
895bool MipsDelaySlotFiller::examinePred(MachineBasicBlock &Pred,
896 const MachineBasicBlock &Succ,
898 bool &HasMultipleSuccs,
899 BB2BrMap &
BrMap)
const {
900 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
P =
901 getBranch(Pred, Succ);
910 HasMultipleSuccs =
true;
911 RegDU.addLiveOut(Pred, Succ);
918bool MipsDelaySlotFiller::delayHasHazard(
const MachineInstr &Candidate,
920 InspectMemInstr &IM)
const {
922 "KILL instructions should have been eliminated at this point.");
926 HasHazard |= IM.hasHazard(Candidate);
927 HasHazard |= RegDU.update(Candidate, 0, Candidate.
getNumOperands());
932bool MipsDelaySlotFiller::terminateSearch(
const MachineInstr &Candidate)
const {
941 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")
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 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.