Go to the documentation of this file.
53 #define DEBUG_TYPE "mips-delay-slot-filler"
55 STATISTIC(FilledSlots,
"Number of delay slots filled");
56 STATISTIC(UsefulSlots,
"Number of delay slots filled with instructions that"
60 "disable-mips-delay-filler",
62 cl::desc(
"Fill all delay slots with NOPs."),
66 "disable-mips-df-forward-search",
68 cl::desc(
"Disallow MIPS delay filler to search forward."),
72 "disable-mips-df-succbb-search",
74 cl::desc(
"Disallow MIPS delay filler to search successor basic blocks."),
78 "disable-mips-df-backward-search",
80 cl::desc(
"Disallow MIPS delay filler to search backward."),
95 cl::desc(
"MIPS Specific: Compact branch policy."),
97 "Do not use compact branches if possible."),
99 "Use compact branches where appropriate (default)."),
101 "Always use compact branches if possible.")));
126 bool update(
const MachineInstr &
MI,
unsigned Begin,
unsigned End);
133 bool isRegInSet(
const BitVector &RegSet,
unsigned Reg)
const;
140 class InspectMemInstr {
142 InspectMemInstr(
bool ForbidMemInstr_) : ForbidMemInstr(ForbidMemInstr_) {}
143 virtual ~InspectMemInstr() =
default;
150 bool OrigSeenLoad =
false;
151 bool OrigSeenStore =
false;
152 bool SeenLoad =
false;
153 bool SeenStore =
false;
164 class NoMemInstr :
public InspectMemInstr {
166 NoMemInstr() : InspectMemInstr(
true) {}
173 class LoadFromStackOrConst :
public InspectMemInstr {
175 LoadFromStackOrConst() : InspectMemInstr(
false) {}
183 class MemDefsUses :
public InspectMemInstr {
206 bool SeenNoObjLoad =
false;
207 bool SeenNoObjStore =
false;
216 StringRef getPassName()
const override {
return "Mips Delay Slot Filler"; }
220 bool Changed =
false;
222 Changed |= runOnMachineBasicBlock(
MBB);
228 F.getRegInfo().invalidateLiveness();
254 bool delayHasHazard(
const MachineInstr &Candidate, RegDefsUses &RegDU,
255 InspectMemInstr &IM)
const;
259 template<
typename IterTy>
261 RegDefsUses &RegDU, InspectMemInstr &IM, Iter Slot,
262 IterTy &Filler)
const;
283 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
289 RegDefsUses &RegDU,
bool &HasMultipleSuccs,
290 BB2BrMap &
BrMap)
const;
292 bool terminateSearch(
const MachineInstr &Candidate)
const;
302 return MI->hasDelaySlot() && !
MI->isBundledWithSucc();
306 "Fill delay slot for MIPS",
false,
false)
309 static
void insertDelayFiller(Iter Filler,
const BB2BrMap &
BrMap) {
324 for (
unsigned I = 0,
E = Filler->getNumOperands();
I !=
E; ++
I) {
334 "Shouldn't move an instruction with unallocatable registers across "
335 "basic block boundaries.");
348 update(
MI, 0,
MI.getDesc().getNumOperands());
358 update(
MI,
MI.getDesc().getNumOperands(),
MI.getNumOperands());
359 Defs.reset(Mips::AT);
369 if (
MI.definesRegister(
Mips::RA) ||
MI.definesRegister(Mips::RA_64)) {
371 Defs.set(Mips::RA_64);
377 CallerSavedRegs.reset(Mips::ZERO);
378 CallerSavedRegs.reset(Mips::ZERO_64);
383 CallerSavedRegs.reset(*AI);
385 Defs |= CallerSavedRegs;
395 AllocSet.
set(Mips::ZERO);
396 AllocSet.
set(Mips::ZERO_64);
398 Defs |= AllocSet.
flip();
405 for (
const auto &LI :
S->liveins())
406 Uses.set(LI.PhysReg);
409 bool RegDefsUses::update(
const MachineInstr &
MI,
unsigned Begin,
unsigned End) {
411 bool HasHazard =
false;
413 for (
unsigned I = Begin;
I != End; ++
I) {
417 if (checkRegDefsUses(NewDefs, NewUses, MO.
getReg(), MO.
isDef())) {
433 unsigned Reg,
bool IsDef)
const {
437 return (isRegInSet(Defs,
Reg) || isRegInSet(
Uses,
Reg));
442 return isRegInSet(Defs,
Reg);
445 bool RegDefsUses::isRegInSet(
const BitVector &RegSet,
unsigned Reg)
const {
448 if (RegSet.
test(*AI))
454 if (!
MI.mayStore() && !
MI.mayLoad())
460 OrigSeenLoad = SeenLoad;
461 OrigSeenStore = SeenStore;
462 SeenLoad |=
MI.mayLoad();
463 SeenStore |=
MI.mayStore();
467 if (
MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) {
468 ForbidMemInstr =
true;
472 return hasHazard_(
MI);
479 if (!
MI.hasOneMemOperand() || !(*
MI.memoperands_begin())->getPseudoValue())
483 (*
MI.memoperands_begin())->getPseudoValue()) {
484 if (isa<FixedStackPseudoSourceValue>(PSV))
486 return !PSV->isConstant(
nullptr) && !PSV->isStack();
493 : InspectMemInstr(
false), MFI(MFI_) {}
496 bool HasHazard =
false;
502 HasHazard |= updateDefsUses(VT,
MI.mayStore());
507 HasHazard =
MI.mayStore() && (OrigSeenLoad || OrigSeenStore);
508 HasHazard |=
MI.mayLoad() || OrigSeenStore;
510 SeenNoObjLoad |=
MI.mayLoad();
511 SeenNoObjStore |=
MI.mayStore();
518 return !Defs.insert(V).second ||
Uses.count(V) || SeenNoObjStore ||
522 return Defs.count(V) || SeenNoObjStore;
528 if (!
MI.hasOneMemOperand())
531 auto & MMO = **
MI.memoperands_begin();
534 if (!PSV->isAliased(MFI))
536 Objects.push_back(PSV);
540 if (
const Value *V = MMO.getValue()) {
544 for (
const Value *UValue : Objs) {
548 Objects.push_back(UValue);
563 unsigned NewOpcode =
TII->getEquivalentCompactForm(
Branch);
566 auto *ToErase = cast<MachineInstr>(&*std::next(
Branch));
568 if (ToErase->shouldUpdateCallSiteInfo())
569 ToErase->getMF()->moveCallSiteInfo(ToErase, cast<MachineInstr>(&*
Branch));
570 ToErase->eraseFromParent();
582 return Mips::BGEZALS_MM;
584 return Mips::BLTZALS_MM;
587 return Mips::JALS_MM;
589 return Mips::JALRS_MM;
590 case Mips::JALR16_MM:
591 return Mips::JALRS16_MM;
592 case Mips::TAILCALL_MM:
594 case Mips::TAILCALLREG:
595 return Mips::JR16_MM;
604 bool Changed =
false;
620 !
TII->getEquivalentCompactForm(
I)) {
621 if (searchBackward(
MBB, *
I)) {
623 " in backwards search.\n");
625 }
else if (
I->isTerminator()) {
626 if (searchSuccBBs(
MBB,
I)) {
629 " in successor BB search.\n");
631 }
else if (searchForward(
MBB,
I)) {
633 " in forwards search.\n");
642 if (InMicroMipsMode &&
TII->getInstSizeInBytes(*std::next(DSI)) == 2 &&
669 if ((InMicroMipsMode ||
671 TII->getEquivalentCompactForm(
I)) {
672 I = replaceWithCompactBranch(
MBB,
I,
I->getDebugLoc());
680 TII->insertNop(
MBB, std::next(
I),
I->getDebugLoc());
689 template <
typename IterTy>
691 IterTy End, RegDefsUses &RegDU,
692 InspectMemInstr &IM, Iter Slot,
693 IterTy &Filler)
const {
694 for (IterTy
I = Begin;
I != End;) {
699 if (CurrI->isDebugInstr()) {
705 if (CurrI->isBundle()) {
709 RegDU.update(*CurrI, 0, CurrI->getNumOperands());
713 if (terminateSearch(*CurrI)) {
719 assert((!CurrI->isCall() && !CurrI->isReturn() && !CurrI->isBranch()) &&
720 "Cannot put calls, returns or branches in delay slot.");
722 if (CurrI->isKill()) {
723 CurrI->eraseFromParent();
727 if (delayHasHazard(*CurrI, RegDU, IM))
745 unsigned Opcode = (*Slot).getOpcode();
751 if (InMicroMipsMode &&
TII->getInstSizeInBytes(*CurrI) == 2 &&
752 (Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch ||
753 Opcode == Mips::PseudoIndirectBranch_MM ||
754 Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL))
758 if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM ||
759 Opcode == Mips::MOVEP_MM))
778 RegDefsUses RegDU(*Fn->getSubtarget().getRegisterInfo());
779 MemDefsUses MemDU(&Fn->getFrameInfo());
788 "slot using backwards search.\n");
792 MBB.
splice(std::next(SlotI), &
MBB, Filler.getReverse());
808 RegDU.setCallerSaved(*Slot);
810 if (!searchRange(
MBB, std::next(Slot),
MBB.
end(), RegDU, NM, Slot, Filler)) {
812 "slot using forwards search.\n");
833 bool HasMultipleSuccs =
false;
835 std::unique_ptr<InspectMemInstr> IM;
841 if (!examinePred(*Pred, *SuccBB, RegDU, HasMultipleSuccs,
BrMap))
846 RegDU.setUnallocatableRegs(*Fn);
850 if (HasMultipleSuccs) {
851 IM.reset(
new LoadFromStackOrConst());
854 IM.reset(
new MemDefsUses(&MFI));
857 if (!searchRange(
MBB, SuccBB->
begin(), SuccBB->
end(), RegDU, *IM, Slot,
861 insertDelayFiller(Filler,
BrMap);
863 Filler->eraseFromParent();
874 auto &Prob = getAnalysis<MachineBranchProbabilityInfo>();
876 B.succ_begin(),
B.succ_end(),
878 return Prob.getEdgeProbability(&B, Dst0) <
879 Prob.getEdgeProbability(&B, Dst1);
881 return S->isEHPad() ? nullptr :
S;
884 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
896 if ((
R == MipsInstrInfo::BT_None) || (
R == MipsInstrInfo::BT_NoBranch))
897 return std::make_pair(
R,
nullptr);
899 if (
R != MipsInstrInfo::BT_CondUncond) {
901 return std::make_pair(MipsInstrInfo::BT_None,
nullptr);
903 assert(((
R != MipsInstrInfo::BT_Uncond) || (TrueBB == &Dst)));
905 return std::make_pair(
R, BranchInstrs[0]);
908 assert((TrueBB == &Dst) || (FalseBB == &Dst));
912 return std::make_pair(MipsInstrInfo::BT_Cond, BranchInstrs[0]);
916 return std::make_pair(MipsInstrInfo::BT_Uncond, BranchInstrs[1]);
918 return std::make_pair(MipsInstrInfo::BT_None,
nullptr);
924 bool &HasMultipleSuccs,
925 BB2BrMap &
BrMap)
const {
926 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
P =
927 getBranch(Pred, Succ);
931 if (
P.first == MipsInstrInfo::BT_None)
934 if ((
P.first != MipsInstrInfo::BT_Uncond) &&
935 (
P.first != MipsInstrInfo::BT_NoBranch)) {
936 HasMultipleSuccs =
true;
937 RegDU.addLiveOut(Pred, Succ);
944 bool MipsDelaySlotFiller::delayHasHazard(
const MachineInstr &Candidate,
946 InspectMemInstr &IM)
const {
948 "KILL instructions should have been eliminated at this point.");
952 HasHazard |= IM.hasHazard(Candidate);
953 HasHazard |= RegDU.update(Candidate, 0, Candidate.
getNumOperands());
958 bool MipsDelaySlotFiller::terminateSearch(
const MachineInstr &Candidate)
const {
967 return new MipsDelaySlotFiller();
This is an optimization pass for GlobalISel generic memory operations.
bool isImplicitDef() const
bool isLiveIn(MCPhysReg Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
void initializeMipsDelaySlotFillerPass(PassRegistry &)
static cl::opt< CompactBranchPolicy > MipsCompactBranchPolicy("mips-compact-branches", cl::Optional, cl::init(CB_Optimal), cl::desc("MIPS Specific: Compact branch policy."), cl::values(clEnumValN(CB_Never, "never", "Do not use compact branches if possible."), clEnumValN(CB_Optimal, "optimal", "Use compact branches where appropriate (default)."), clEnumValN(CB_Always, "always", "Always use compact branches if possible.")))
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
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....
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
unsigned getNumRegs() const
Return the number of registers this target has (useful for sizing arrays holding per register informa...
Reg
All possible values of the reg field in the ModR/M byte.
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.
iterator_range< const_set_bits_iterator > set_bits() const
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Properties which a MachineFunction may have at a given point in time.
const MipsInstrInfo * getInstrInfo() const override
@ CB_Never
The policy 'never' may in some circumstances or for some ISAs not be absolutely adhered to.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
static int getEquivalentCallShort(int Opcode)
static cl::opt< bool > DisableBackwardSearch("disable-mips-df-backward-search", cl::init(false), cl::desc("Disallow MIPS delay filler to search backward."), cl::Hidden)
unsigned const TargetRegisterInfo * TRI
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
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)
SmallPtrSet< MachineInstr *, 2 > Uses
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
const MipsRegisterInfo * getRegisterInfo() const override
virtual const MCPhysReg * getCalleeSavedRegs(const MachineFunction *MF) const =0
Return a null-terminated list of all of the callee-saved registers on this target.
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
bool isCall(QueryType Type=AnyInBundle) const
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
INITIALIZE_PASS(MipsDelaySlotFiller, DEBUG_TYPE, "Fill delay slot for MIPS", false, false) static void insertDelayFiller(Iter Filler
This function inserts clones of Filler into predecessor blocks.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Represent the analysis usage information of a pass.
const HexagonInstrInfo * TII
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
MachineOperand class - Representation of each machine instruction operand.
MachineFunctionProperties & set(Property P)
STATISTIC(NumFunctions, "Total number of functions")
Special value supplied for machine level alias analysis.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
void getUnderlyingObjects(const Value *V, SmallVectorImpl< const Value * > &Objects, LoopInfo *LI=nullptr, unsigned MaxLookup=6)
This method is similar to getUnderlyingObject except that it can look through phi and select instruct...
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
reverse_iterator getReverse() const
Get a reverse iterator to the same node.
@ CB_Optimal
Optimal is the default and will produce compact branches when delay slots cannot be filled.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Representation of each machine instruction.
MachineInstr * CloneMachineInstr(const MachineInstr *Orig)
Create a new MachineInstr which is a copy of Orig, identical in all ways except the instruction has n...
bool baseRegNeedsLoadStoreMask(unsigned Reg)
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
initializer< Ty > init(const Ty &Val)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Primary interface to the complete machine description for the target machine.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
Register getReg() const
getReg - Returns the register number.
iterator_range< pred_iterator > predecessors()
SI optimize exec mask operations pre RA
MachineInstrBundleIterator< MachineInstr > iterator
static void addLiveInRegs(Iter Filler, MachineBasicBlock &MBB)
This function adds registers Filler defines to MBB's live-in register list.
SmallVector< MachineOperand, 4 > Cond
iterator_range< succ_iterator > successors()
StringRef - Represent a constant reference to a string, i.e.
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 '...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Helper class for constructing bundles of MachineInstrs.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
bool isTerminator(QueryType Type=AnyInBundle) const
Returns true if this instruction part of the terminator for a basic block.
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
bool inMicroMipsMode() const
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
bool test(unsigned Idx) const
bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
Iterator for intrusive lists based on ilist_node.
bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx, bool *IsStore=nullptr)
bool hasUnmodeledSideEffects() const
Return true if this instruction has side effects that are not modeled by mayLoad / mayStore,...
FunctionPass * createMipsDelaySlotFillerPass()
createMipsDelaySlotFillerPass - Returns a pass that fills in delay slots in Mips MachineFunctions
MIBundleBuilder & append(MachineInstr *MI)
Insert MI into MBB by appending it to the instructions in the bundle.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
static bool hasUnoccupiedSlot(const MachineInstr *MI)
@ CB_Always
'always' may in some circumstances may not be absolutely adhered to there may not be a corresponding ...
bool isTargetNaCl() const
unsigned getNumOperands() const
Retuns the total number of operands.
static cl::opt< bool > DisableForwardSearch("disable-mips-df-forward-search", cl::init(true), cl::desc("Disallow MIPS delay filler to search forward."), cl::Hidden)
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
static cl::opt< bool > DisableDelaySlotFiller("disable-mips-delay-filler", cl::init(false), cl::desc("Fill all delay slots with NOPs."), cl::Hidden)
const char LLVMTargetMachineRef TM
FunctionPass class - This class is used to implement most global optimizations.
static void getUnderlyingObjects(const MachineInstr *MI, SmallVectorImpl< const Value * > &Objs)
Return the underlying objects for the memory references of an instruction.
AnalysisUsage & addRequired()
LLVM Value Representation.
MCRegAliasIterator enumerates all registers aliasing Reg.