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."),
92 cl::desc(
"MIPS Specific: Compact branch policy."),
94 "Do not use compact branches if possible."),
96 "Use compact branches where appropriate (default)."),
98 "Always use compact branches if possible.")));
123 bool update(
const MachineInstr &
MI,
unsigned Begin,
unsigned End);
130 bool isRegInSet(
const BitVector &RegSet,
unsigned Reg)
const;
137 class InspectMemInstr {
139 InspectMemInstr(
bool ForbidMemInstr_) : ForbidMemInstr(ForbidMemInstr_) {}
140 virtual ~InspectMemInstr() =
default;
147 bool OrigSeenLoad =
false;
148 bool OrigSeenStore =
false;
149 bool SeenLoad =
false;
150 bool SeenStore =
false;
157 virtual bool hasHazard_(
const MachineInstr &
MI) = 0;
161 class NoMemInstr :
public InspectMemInstr {
163 NoMemInstr() : InspectMemInstr(
true) {}
166 bool hasHazard_(
const MachineInstr &
MI)
override {
return true; }
170 class LoadFromStackOrConst :
public InspectMemInstr {
172 LoadFromStackOrConst() : InspectMemInstr(
false) {}
175 bool hasHazard_(
const MachineInstr &
MI)
override;
180 class MemDefsUses :
public InspectMemInstr {
182 explicit MemDefsUses(
const MachineFrameInfo *MFI);
185 using ValueType = PointerUnion<const Value *, const PseudoSourceValue *>;
187 bool hasHazard_(
const MachineInstr &
MI)
override;
192 bool updateDefsUses(ValueType V,
bool MayStore);
196 SmallVectorImpl<ValueType> &Objects)
const;
198 const MachineFrameInfo *MFI;
199 SmallPtrSet<ValueType, 4> Uses, Defs;
203 bool SeenNoObjLoad =
false;
204 bool SeenNoObjStore =
false;
209 MipsDelaySlotFiller() : MachineFunctionPass(ID) {}
211 StringRef getPassName()
const override {
return "Mips Delay Slot Filler"; }
213 bool runOnMachineFunction(MachineFunction &
F)
override {
216 for (MachineBasicBlock &
MBB :
F)
223 F.getRegInfo().invalidateLiveness();
228 MachineFunctionProperties getRequiredProperties()
const override {
229 return MachineFunctionProperties().setNoVRegs();
232 void getAnalysisUsage(AnalysisUsage &AU)
const override {
233 AU.
addRequired<MachineBranchProbabilityInfoWrapperPass>();
240 bool runOnMachineBasicBlock(MachineBasicBlock &
MBB);
242 Iter replaceWithCompactBranch(MachineBasicBlock &
MBB, Iter Branch,
248 bool delayHasHazard(
const MachineInstr &Candidate, RegDefsUses &RegDU,
249 InspectMemInstr &IM)
const;
253 template<
typename IterTy>
254 bool searchRange(MachineBasicBlock &
MBB, IterTy Begin, IterTy End,
255 RegDefsUses &RegDU, InspectMemInstr &IM, Iter Slot,
256 IterTy &Filler)
const;
260 bool searchBackward(MachineBasicBlock &
MBB, MachineInstr &Slot)
const;
264 bool searchForward(MachineBasicBlock &
MBB, Iter Slot)
const;
269 bool searchSuccBBs(MachineBasicBlock &
MBB, Iter Slot)
const;
273 MachineBasicBlock *selectSuccBB(MachineBasicBlock &
B)
const;
277 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
278 getBranch(MachineBasicBlock &
MBB,
const MachineBasicBlock &Dst)
const;
282 bool examinePred(MachineBasicBlock &Pred,
const MachineBasicBlock &Succ,
283 RegDefsUses &RegDU,
bool &HasMultipleSuccs,
284 BB2BrMap &
BrMap)
const;
286 bool terminateSearch(
const MachineInstr &Candidate)
const;
288 const TargetMachine *TM =
nullptr;
293char MipsDelaySlotFiller::ID = 0;
296 return MI->hasDelaySlot() && !
MI->isBundledWithSucc();
300 "Fill delay slot for MIPS",
false,
false)
303static
void insertDelayFiller(Iter Filler,
const BB2BrMap &
BrMap) {
311 I.first->push_back(MF->CloneMachineInstr(&*Filler));
321 if (!MO.isReg() || !MO.isDef() || !(R = MO.getReg()))
327 "Shouldn't move an instruction with unallocatable registers across "
328 "basic block boundaries.");
331 if (!
MBB.isLiveIn(R))
341 update(
MI, 0,
MI.getDesc().getNumOperands());
351 update(
MI,
MI.getDesc().getNumOperands(),
MI.getNumOperands());
352 Defs.
reset(Mips::AT);
356void RegDefsUses::setCallerSaved(
const MachineInstr &
MI) {
362 if (
MI.definesRegister(Mips::RA,
nullptr) ||
363 MI.definesRegister(Mips::RA_64,
nullptr)) {
365 Defs.
set(Mips::RA_64);
369 BitVector CallerSavedRegs(
TRI.getNumRegs(),
true);
371 CallerSavedRegs.reset(Mips::ZERO);
372 CallerSavedRegs.reset(Mips::ZERO_64);
374 for (
const MCPhysReg *R =
TRI.getCalleeSavedRegs(
MI.getParent()->getParent());
376 for (MCRegAliasIterator AI(*R, &
TRI,
true); AI.isValid(); ++AI)
377 CallerSavedRegs.reset(*AI);
379 Defs |= CallerSavedRegs;
382void RegDefsUses::setUnallocatableRegs(
const MachineFunction &MF) {
383 BitVector AllocSet =
TRI.getAllocatableSet(MF);
385 for (
unsigned R : AllocSet.
set_bits())
386 for (MCRegAliasIterator AI(R, &
TRI,
false); AI.isValid(); ++AI)
389 AllocSet.
set(Mips::ZERO);
390 AllocSet.
set(Mips::ZERO_64);
392 Defs |= AllocSet.
flip();
395void RegDefsUses::addLiveOut(
const MachineBasicBlock &
MBB,
396 const MachineBasicBlock &SuccBB) {
399 for (
const auto &LI : S->liveins())
403bool RegDefsUses::update(
const MachineInstr &
MI,
unsigned Begin,
unsigned End) {
404 BitVector NewDefs(
TRI.getNumRegs()), NewUses(
TRI.getNumRegs());
405 bool HasHazard =
false;
407 for (
unsigned I = Begin;
I != End; ++
I) {
408 const MachineOperand &MO =
MI.getOperand(
I);
411 if (checkRegDefsUses(NewDefs, NewUses, MO.
getReg(), MO.
isDef())) {
426bool RegDefsUses::checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses,
427 unsigned Reg,
bool IsDef)
const {
431 return (isRegInSet(Defs,
Reg) || isRegInSet(
Uses,
Reg));
436 return isRegInSet(Defs,
Reg);
439bool RegDefsUses::isRegInSet(
const BitVector &RegSet,
unsigned Reg)
const {
441 for (MCRegAliasIterator AI(
Reg, &
TRI,
true); AI.isValid(); ++AI)
442 if (RegSet.
test(*AI))
447bool InspectMemInstr::hasHazard(
const MachineInstr &
MI) {
448 if (!
MI.mayStore() && !
MI.mayLoad())
454 OrigSeenLoad = SeenLoad;
455 OrigSeenStore = SeenStore;
456 SeenLoad |=
MI.mayLoad();
457 SeenStore |=
MI.mayStore();
461 if (
MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) {
462 ForbidMemInstr =
true;
466 return hasHazard_(
MI);
469bool LoadFromStackOrConst::hasHazard_(
const MachineInstr &
MI) {
473 if (!
MI.hasOneMemOperand() || !(*
MI.memoperands_begin())->getPseudoValue())
476 if (
const PseudoSourceValue *PSV =
477 (*
MI.memoperands_begin())->getPseudoValue()) {
480 return !PSV->isConstant(
nullptr) && !PSV->isStack();
486MemDefsUses::MemDefsUses(
const MachineFrameInfo *MFI_)
487 : InspectMemInstr(
false), MFI(MFI_) {}
490 bool HasHazard =
false;
496 HasHazard |= updateDefsUses(VT,
MI.mayStore());
501 HasHazard =
MI.mayStore() && (OrigSeenLoad || OrigSeenStore);
502 HasHazard |=
MI.mayLoad() || OrigSeenStore;
504 SeenNoObjLoad |=
MI.mayLoad();
505 SeenNoObjStore |=
MI.mayStore();
510bool MemDefsUses::updateDefsUses(
ValueType V,
bool MayStore) {
512 return !Defs.insert(V).second ||
Uses.count(V) || SeenNoObjStore ||
516 return Defs.count(V) || SeenNoObjStore;
520getUnderlyingObjects(
const MachineInstr &
MI,
521 SmallVectorImpl<ValueType> &Objects)
const {
522 if (!
MI.hasOneMemOperand())
525 auto & MMO = **
MI.memoperands_begin();
527 if (
const PseudoSourceValue *PSV = MMO.getPseudoValue()) {
528 if (!PSV->isAliased(MFI))
534 if (
const Value *V = MMO.getValue()) {
538 for (
const Value *UValue : Objs) {
551Iter MipsDelaySlotFiller::replaceWithCompactBranch(MachineBasicBlock &
MBB,
557 unsigned NewOpcode =
TII->getEquivalentCompactForm(Branch);
558 Branch =
TII->genInstrWithNewOpc(NewOpcode, Branch);
562 if (ToErase->shouldUpdateAdditionalCallInfo())
563 ToErase->getMF()->moveAdditionalCallInfo(ToErase,
565 ToErase->eraseFromParent();
577 return Mips::BGEZALS_MM;
579 return Mips::BLTZALS_MM;
582 return Mips::JALS_MM;
584 return Mips::JALRS_MM;
585 case Mips::JALR16_MM:
586 return Mips::JALRS16_MM;
587 case Mips::TAILCALL_MM:
589 case Mips::TAILCALLREG:
590 return Mips::JR16_MM;
598bool MipsDelaySlotFiller::runOnMachineBasicBlock(MachineBasicBlock &
MBB) {
616 !
TII->getEquivalentCompactForm(
I)) {
617 if (searchBackward(
MBB, *
I)) {
619 " in backwards search.\n");
621 }
else if (
I->isTerminator()) {
622 if (searchSuccBBs(
MBB,
I)) {
625 " in successor BB search.\n");
627 }
else if (searchForward(
MBB,
I)) {
629 " in forwards search.\n");
638 if (InMicroMipsMode &&
TII->getInstSizeInBytes(*std::next(DSI)) == 2 &&
665 if ((InMicroMipsMode ||
667 TII->getEquivalentCompactForm(
I)) {
668 I = replaceWithCompactBranch(
MBB,
I,
I->getDebugLoc());
676 TII->insertNop(
MBB, std::next(
I),
I->getDebugLoc());
677 MIBundleBuilder(
MBB,
I, std::next(
I, 2));
685template <
typename IterTy>
686bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &
MBB, IterTy Begin,
687 IterTy End, RegDefsUses &RegDU,
688 InspectMemInstr &IM, Iter Slot,
689 IterTy &Filler)
const {
690 for (IterTy
I = Begin;
I != End;) {
697 if (CurrI->isDebugInstr() || CurrI->isJumpTableDebugInfo()) {
703 if (CurrI->isBundle()) {
707 RegDU.update(*CurrI, 0, CurrI->getNumOperands());
711 if (terminateSearch(*CurrI)) {
717 assert((!CurrI->isCall() && !CurrI->isReturn() && !CurrI->isBranch()) &&
718 "Cannot put calls, returns or branches in delay slot.");
720 if (CurrI->isKill()) {
721 CurrI->eraseFromParent();
725 if (delayHasHazard(*CurrI, RegDU, IM))
731 unsigned Opcode = (*Slot).getOpcode();
743 if (InMicroMipsMode &&
TII->getInstSizeInBytes(*CurrI) == 2 &&
744 (Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch ||
745 Opcode == Mips::PseudoIndirectBranch_MM ||
746 Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL))
750 if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM ||
751 Opcode == Mips::MOVEP_MM))
764bool MipsDelaySlotFiller::searchBackward(MachineBasicBlock &
MBB,
765 MachineInstr &Slot)
const {
770 RegDefsUses RegDU(*Fn->getSubtarget().getRegisterInfo());
771 MemDefsUses MemDU(&Fn->getFrameInfo());
780 "slot using backwards search.\n");
784 MBB.
splice(std::next(SlotI), &
MBB, Filler.getReverse());
785 MIBundleBuilder(
MBB, SlotI, std::next(SlotI, 2));
790bool MipsDelaySlotFiller::searchForward(MachineBasicBlock &
MBB,
800 RegDU.setCallerSaved(*Slot);
802 if (!searchRange(
MBB, std::next(Slot),
MBB.
end(), RegDU, NM, Slot, Filler)) {
804 "slot using forwards search.\n");
809 MIBundleBuilder(
MBB, Slot, std::next(Slot, 2));
814bool MipsDelaySlotFiller::searchSuccBBs(MachineBasicBlock &
MBB,
819 MachineBasicBlock *SuccBB = selectSuccBB(
MBB);
825 bool HasMultipleSuccs =
false;
827 std::unique_ptr<InspectMemInstr> IM;
833 if (!examinePred(*Pred, *SuccBB, RegDU, HasMultipleSuccs,
BrMap))
838 RegDU.setUnallocatableRegs(*Fn);
842 if (HasMultipleSuccs) {
843 IM.reset(
new LoadFromStackOrConst());
845 const MachineFrameInfo &MFI = Fn->getFrameInfo();
846 IM.reset(
new MemDefsUses(&MFI));
849 if (!searchRange(
MBB, SuccBB->
begin(), SuccBB->
end(), RegDU, *IM, Slot,
853 insertDelayFiller(Filler,
BrMap);
855 Filler->eraseFromParent();
861MipsDelaySlotFiller::selectSuccBB(MachineBasicBlock &
B)
const {
866 auto &Prob = getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
867 MachineBasicBlock *S =
869 const MachineBasicBlock *Dst1) {
870 return Prob.getEdgeProbability(&B, Dst0) <
871 Prob.getEdgeProbability(&B, Dst1);
873 return S->
isEHPad() ? nullptr : S;
876std::pair<MipsInstrInfo::BranchType, MachineInstr *>
877MipsDelaySlotFiller::getBranch(MachineBasicBlock &
MBB,
878 const MachineBasicBlock &Dst)
const {
879 const MipsInstrInfo *
TII =
881 MachineBasicBlock *TrueBB =
nullptr, *FalseBB =
nullptr;
882 SmallVector<MachineInstr*, 2> BranchInstrs;
889 return std::make_pair(R,
nullptr);
897 return std::make_pair(R, BranchInstrs[0]);
900 assert((TrueBB == &Dst) || (FalseBB == &Dst));
913bool MipsDelaySlotFiller::examinePred(MachineBasicBlock &Pred,
914 const MachineBasicBlock &Succ,
916 bool &HasMultipleSuccs,
917 BB2BrMap &
BrMap)
const {
918 std::pair<MipsInstrInfo::BranchType, MachineInstr *>
P =
919 getBranch(Pred, Succ);
928 HasMultipleSuccs =
true;
929 RegDU.addLiveOut(Pred, Succ);
936bool MipsDelaySlotFiller::delayHasHazard(
const MachineInstr &Candidate,
938 InspectMemInstr &IM)
const {
940 "KILL instructions should have been eliminated at this point.");
944 HasHazard |= IM.hasHazard(Candidate);
945 HasHazard |= RegDU.update(Candidate, 0, Candidate.
getNumOperands());
950bool MipsDelaySlotFiller::terminateSearch(
const MachineInstr &Candidate)
const {
959 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")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This file defines the DenseMap class.
static bool hasHazard(StateT State, function_ref< HazardFnResult(StateT &, const MachineInstr &)> IsHazard, function_ref< void(StateT &, const MachineInstr &)> UpdateState, const MachineBasicBlock *MBB, MachineBasicBlock::const_reverse_instr_iterator I, DenseSet< const MachineBasicBlock * > &Visited)
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)
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.")))
@ CB_Never
The policy 'never' may in some circumstances or for some ISAs not be absolutely adhered to.
@ CB_Optimal
Optimal is the default and will produce compact branches when delay slots cannot be filled.
@ CB_Always
'always' may in some circumstances may not be absolutely adhered to there may not be a corresponding ...
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.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
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...
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.