56#define DEBUG_TYPE "pipeliner"
60 "Number of loops that we attempt to use window scheduling");
62 "Number of times that we run list schedule in the window scheduling");
64 "Number of loops that we successfully use window scheduling");
66 "Window scheduling abort due to the failure of the II analysis");
69 WindowSearchNum(
"window-search-num",
70 cl::desc(
"The number of searches per loop in the window "
71 "algorithm. 0 means no search number limit."),
75 "window-search-ratio",
76 cl::desc(
"The ratio of searches per loop in the window algorithm. 100 "
77 "means search all positions in the loop, while 0 means not "
78 "performing any search."),
84 "The coefficient used when initializing II in the window algorithm."),
88 "window-region-limit",
90 "The lower limit of the scheduling region in the window algorithm."),
95 cl::desc(
"The lower limit of the difference between best II and base II in "
96 "the window algorithm. If the difference is smaller than "
97 "this lower limit, window scheduling will not be performed."),
105 cl::desc(
"The upper limit of II in the window algorithm."),
112 int64_t &MemOpOffset,
114 AAMDNodes &AATags,
bool &IsAllIdentified) {
115 if (!
MI->hasOneMemOperand())
135 const Value *SrcVal =
nullptr, *DstVal =
nullptr;
136 int64_t SrcOffset = 0, DstOffset = 0;
139 bool SrcAllIdentified =
false, DstAllIdentified =
false;
140 bool SrcKnown =
getMemInfo(SrcMI, SrcVal, SrcOffset, SrcObjs, SrcAATags,
142 bool DstKnown =
getMemInfo(DstMI, DstVal, DstOffset, DstObjs, DstAATags,
147 if (SrcKnown && DstKnown && SrcAllIdentified && DstAllIdentified &&
163 if (!SrcKnown || !DstKnown)
165 if (SrcVal == DstVal && SrcOffset <= DstOffset)
175 for (
const Value *SrcObj : SrcObjs)
176 for (
const Value *DstObj : DstObjs)
192 const DenseSet<std::pair<MachineInstr *, MachineInstr *>> &LoopCarriedMemDeps;
193 const DenseMap<MachineInstr *, TriCloneInfo> &TriToOri;
197 WindowMemDepMutation(
198 const DenseSet<std::pair<MachineInstr *, MachineInstr *>> &Deps,
199 const DenseMap<MachineInstr *, TriCloneInfo> &TriToOri,
bool &EdgeFailed)
200 : LoopCarriedMemDeps(Deps), TriToOri(TriToOri), EdgeFailed(EdgeFailed) {}
202 void apply(ScheduleDAGInstrs *DAG)
override {
203 if (LoopCarriedMemDeps.empty())
205 for (SUnit &PredSU : DAG->
SUnits) {
206 MachineInstr *PredMI = PredSU.
getInstr();
209 auto PredIt = TriToOri.find(PredMI);
210 if (PredIt == TriToOri.end())
212 for (SUnit &SuccSU : DAG->
SUnits) {
213 MachineInstr *SuccMI = SuccSU.
getInstr();
216 auto SuccIt = TriToOri.find(SuccMI);
217 if (SuccIt == TriToOri.end())
221 if (PredIt->second.Copy >= SuccIt->second.Copy)
223 if (!LoopCarriedMemDeps.contains(
224 {PredIt->second.Ori, SuccIt->second.Ori}))
242 TripleDAG = std::unique_ptr<ScheduleDAGInstrs>(
248 LLVM_DEBUG(
dbgs() <<
"The WindowScheduler failed to initialize!\n");
254 ++NumTryWindowSchedule;
269 assert(SchedDAG &&
"Expected a scheduler for window scheduling");
270 auto *SchedDAGMI =
static_cast<ScheduleDAGMI *
>(SchedDAG.get());
271 SchedDAGMI->
addMutation(std::make_unique<WindowMemDepMutation>(
274 for (
unsigned Idx : SearchIndexes) {
276 ++NumTryWindowSearch;
282 SchedDAG->startBlock(
MBB);
284 SchedDAG->schedule();
288 LLVM_DEBUG(
dbgs() <<
"Can't enforce a loop-carried memory dependence. "
289 "Keep searching...\n");
295 LLVM_DEBUG(
dbgs() <<
"Can't find a valid II. Keep searching...\n");
313 <<
" and Best II is " <<
BestII <<
".\n");
322 return OnlyBuildGraph
330 if (!
Subtarget->enableWindowScheduler()) {
357 if (PrevUses.
count(Phi.getOperand(0).getReg()))
359 PrevDefs.
insert(Phi.getOperand(0).getReg());
360 for (
unsigned I = 1, E = Phi.getNumOperands();
I != E;
I += 2) {
361 if (PrevDefs.
count(Phi.getOperand(
I).getReg()))
363 PrevUses.
insert(Phi.getOperand(
I).getReg());
367 auto PLI =
TII->analyzeLoopForPipelining(
MBB);
368 for (
auto &
MI : *
MBB) {
369 if (
MI.isDebugOrPseudoInstr() ||
MI.isTerminator())
372 if (IsLoopCarried(
MI)) {
373 LLVM_DEBUG(
dbgs() <<
"Loop carried phis are not supported yet!\n");
380 if (
TII->isSchedulingBoundary(
MI,
MBB, *
MF)) {
382 dbgs() <<
"Boundary MI is not allowed in window scheduling!\n");
385 if (PLI->shouldIgnoreForPipelining(&
MI)) {
386 LLVM_DEBUG(
dbgs() <<
"Special MI defined by target is not allowed in "
387 "window scheduling!\n");
390 for (
auto &Def :
MI.all_defs())
391 if (Def.isReg() && Def.getReg().isPhysical()) {
393 "window scheduling!\n");
398 LLVM_DEBUG(
dbgs() <<
"There are too few MIs in the window region!\n");
414 MBB,
MBB->begin(),
MBB->getFirstTerminator(),
415 std::distance(
MBB->begin(),
MBB->getFirstTerminator()));
426 if (
MI.mayLoadOrStore() && !
MI.isDebugInstr())
443 if (!SrcMI->mayStore() && !DstMI->mayStore())
460 for (
auto &
MI :
MBB->instrs())
464 Context->LIS->getSlotIndexes()->removeMachineInstrFromMaps(
MI,
true);
472 Context->LIS->getSlotIndexes()->removeMachineInstrFromMaps(
MI,
true);
473 MI.eraseFromParent();
481 const unsigned DuplicateNum = 3;
484 assert(
OriMIs.size() > 0 &&
"The Original MIs were not backed up!");
490 if (
MI->isDebugOrPseudoInstr() ||
MI->isTerminator())
494 DefPairs[
MI->getOperand(0).getReg()] = AntiReg;
495 auto *NewMI =
MF->CloneMachineInstr(
MI);
496 MBB->push_back(NewMI);
503 for (
size_t Cnt = 1; Cnt < DuplicateNum; ++Cnt) {
505 if (
MI->isPHI() ||
MI->isDebugOrPseudoInstr() ||
506 (
MI->isTerminator() && Cnt < DuplicateNum - 1))
508 auto *NewMI =
MF->CloneMachineInstr(
MI);
511 for (
auto MO : NewMI->all_defs())
512 if (MO.isReg() && MO.getReg().isVirtual()) {
514 MRI->createVirtualRegister(
MRI->getRegClass(MO.getReg()));
515 NewMI->substituteRegister(MO.getReg(), NewDef, 0, *
TRI);
516 NewDefs[MO.getReg()] = NewDef;
519 for (
auto DefRegPair : DefPairs)
520 if (NewMI->readsRegister(DefRegPair.first,
TRI)) {
521 Register NewUse = DefRegPair.second;
549 if (
auto It = DefPairs.find(NewUse); It != DefPairs.end())
551 NewMI->substituteRegister(DefRegPair.first, NewUse, 0, *
TRI);
554 for (
auto &NewDef : NewDefs)
555 DefPairs[NewDef.first] = NewDef.second;
556 MBB->push_back(NewMI);
558 TriToOri[NewMI] = {
MI,
static_cast<unsigned>(Cnt)};
567 for (
auto &Phi :
MBB->phis()) {
568 for (
auto DefRegPair : DefPairs)
569 if (Phi.readsRegister(DefRegPair.first,
TRI))
570 Phi.substituteRegister(DefRegPair.first, DefRegPair.second, 0, *
TRI);
577 for (
size_t I = 0;
I <
TriMIs.size(); ++
I) {
579 auto OldPos =
MBB->begin();
580 std::advance(OldPos,
I);
581 auto CurPos =
MI->getIterator();
582 if (CurPos != OldPos) {
583 MBB->splice(OldPos,
MBB, CurPos);
590 unsigned SearchRatio) {
595 assert(SearchRatio <= 100 &&
"SearchRatio should be equal or less than 100!");
597 unsigned Step = SearchNum > 0 && SearchNum <= MaxIdx ? MaxIdx / SearchNum : 1;
599 for (
unsigned Idx = 0; Idx < MaxIdx; Idx += Step)
601 return SearchIndexes;
606 unsigned MaxDepth = 1;
607 for (
auto &SU : DAG.
SUnits)
608 MaxDepth = std::max(SU.getDepth() + SU.Latency, MaxDepth);
609 return MaxDepth * WindowIICoeff;
624 int ExpectCycle = CurCycle;
626 for (
auto &Pred : SU->Preds) {
629 auto *PredMI = Pred.getSUnit()->getInstr();
631 ExpectCycle = std::max(ExpectCycle, PredCycle + (
int)Pred.getLatency());
634 if (!
TII->isZeroCost(
MI.getOpcode())) {
637 while (!RM.canReserveResources(*SU, CurCycle) || CurCycle < ExpectCycle) {
642 RM.reserveResources(*SU, CurCycle);
683 int MaxStallCycle = 0;
684 int CurrentII = MaxCycle + 1;
689 for (
auto &Succ : SU->Succs) {
690 if (Succ.isWeak() || Succ.getSUnit() == &
TripleDAG->ExitSU)
693 if (DefCycle + (
int)Succ.getLatency() <= CurrentII)
698 auto *SuccMI = Succ.getSUnit()->getInstr();
700 if (DefCycle < UseCycle)
703 int StallCycle = DefCycle + (int)Succ.getLatency() - CurrentII - UseCycle;
704 MaxStallCycle = std::max(MaxStallCycle, StallCycle);
707 LLVM_DEBUG(
dbgs() <<
"MaxStallCycle is " << MaxStallCycle <<
".\n");
708 return MaxStallCycle;
720 return MaxCycle + StallCycle + 1;
725 for (
auto &Phi :
MBB->phis()) {
726 int LateCycle = INT_MAX;
728 for (
auto &Succ : SU->Succs) {
734 auto *SuccMI = Succ.getSUnit()->getInstr();
737 LateCycle = std::min(LateCycle, Cycle);
741 auto *AntiMI =
MRI->getVRegDef(AntiReg);
743 if (AntiMI->getParent() ==
MBB) {
746 LateCycle = std::min(LateCycle, AntiCycle);
750 if (LateCycle == INT_MAX)
751 LateCycle = (int)(
II - 1);
752 LLVM_DEBUG(
dbgs() <<
"\tCycle range [0, " << LateCycle <<
"] " << Phi);
765 for (
auto &Phi :
MBB->phis())
773 for (
int Cycle = 0; Cycle < (int)
II; ++Cycle) {
774 auto It = CycleToMIs.
find(Cycle);
775 if (It == CycleToMIs.
end())
777 for (
auto *
MI : It->second)
778 IssueOrder[
MI] = Id++;
803 assert(IssueOrder.count(Pair.first) &&
"Cannot find original MI!");
804 SchedResult.push_back(std::make_tuple(Pair.first, Pair.second,
806 IssueOrder[Pair.first]));
813 [](
const std::tuple<MachineInstr *, int, int, int> &
A,
814 const std::tuple<MachineInstr *, int, int, int> &
B) {
815 return std::get<3>(
A) < std::get<3>(
B);
820 std::vector<MachineInstr *> OrderedInsts;
822 auto *
MI = std::get<0>(Info);
823 OrderedInsts.push_back(
MI);
824 Cycles[
MI] = std::get<1>(Info);
825 Stages[
MI] = std::get<2>(Info);
841 if (!MO.isReg() || MO.getReg() == 0)
847 Context->LIS->repairIntervalsInRange(
MBB,
MBB->begin(),
MBB->end(), UsedRegs);
852 auto RegionBegin =
MBB->begin();
853 std::advance(RegionBegin,
Offset);
854 auto RegionEnd = RegionBegin;
855 std::advance(RegionEnd, Num);
880 if (
MI->isDebugOrPseudoInstr())
886 return Id >= (size_t)
Offset ? 1 : 0;
890 assert(Phi->isPHI() &&
"Expecting PHI!");
892 for (
auto MO : Phi->uses()) {
894 AntiReg = MO.getReg();
895 else if (MO.isMBB() && MO.getMBB() ==
MBB)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const HexagonInstrInfo * TII
static bool hasLoopCarriedMemDep(const SUnitWithMemInfo &Src, const SUnitWithMemInfo &Dst, BatchAAResults &BAA, const TargetInstrInfo *TII)
Returns true if there is a loop-carried order dependency from Src to Dst.
This file provides utility analysis objects describing memory locations.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
MachineRegisterInfo & MRI
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Target-Independent Code Generator Pass Configuration Options pass.
static bool getMemInfo(const MachineInstr *MI, const Value *&MemOpValue, int64_t &MemOpOffset, SmallVectorImpl< const Value * > &UnderlyingObjs, AAMDNodes &AATags, bool &IsAllIdentified)
Collect the underlying objects and alias metadata for the single memory operand of MI.
static bool hasLoopCarriedMemDep(const MachineInstr *SrcMI, const MachineInstr *DstMI, BatchAAResults &BAA, const MachineBasicBlock *LoopBB, const MachineRegisterInfo &MRI, const TargetInstrInfo *TII)
Return true if there is a loop-carried order dependency from memory access SrcMI to DstMI in loop Loo...
static cl::opt< unsigned > WindowIILimit("window-ii-limit", cl::desc("The upper limit of II in the window algorithm."), cl::Hidden, cl::init(1000))
This class is a wrapper over an AAResults, and it is intended to be used only when there are no IR ch...
void enableCrossIterationMode()
Assume that values may come from different cycle iterations.
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
iterator find(const_arg_type_t< KeyT > Val)
Representation of each machine instruction.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
bool hasOneMemOperand() const
Return true if this instruction has exactly one MachineMemOperand.
A description of a memory reference used in the backend.
AAMDNodes getAAInfo() const
Return the AA tags for the memory reference.
const Value * getValue() const
Return the base address of the memory access.
int64_t getOffset() const
For normal values, this is a byte offset added to the base address.
MachineOperand class - Representation of each machine instruction operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
static MemoryLocation getBeforeOrAfter(const Value *Ptr, const AAMDNodes &AATags=AAMDNodes())
Return a location that may access any location before or after Ptr, while remaining within the underl...
The ModuloScheduleExpander takes a ModuloSchedule and expands it in-place, rewriting the old loop and...
LLVM_ABI void cleanup()
Performs final cleanup after expansion.
LLVM_ABI void expand()
Performs the actual expansion.
DenseMap< MachineInstr *, std::pair< Register, int64_t > > InstrChangesTy
Represents a schedule for a single-block loop.
Wrapper class representing virtual and physical registers.
@ Data
Regular data dependence (aka true-dependence).
@ Barrier
An unknown scheduling barrier.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
A ScheduleDAG for scheduling lists of MachineInstr.
bool addEdge(SUnit *SuccSU, const SDep &PredDep)
Add a DAG edge to the given SU with the given predecessor dependence data.
SUnit * getSUnit(MachineInstr *MI) const
Returns an existing SUnit for this MI, or nullptr.
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
void addMutation(std::unique_ptr< ScheduleDAGMutation > Mutation)
Add a postprocessing step to the DAG builder.
Mutate the DAG as a postpass after normal DAG building.
std::vector< SUnit > SUnits
The scheduling units.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetInstrInfo - Interface to description of machine instruction set.
The TimeTraceScope is a helper class to call the begin and end functions of the time trace profiler.
LLVM Value Representation.
MachineInstr * getOriMI(MachineInstr *NewMI)
Get the original MI from which the new MI is cloned.
virtual ScheduleDAGInstrs * createMachineScheduler(bool OnlyBuildGraph=false)
Two types of ScheduleDAGs are needed, one for creating dependency graphs only, and the other for list...
unsigned SchedPhiNum
SchedPhiNum records the number of phi in the original MBB, and the scheduling starts with MI after ph...
virtual void preProcess()
Add some related processing before running window scheduling.
void collectLoopCarriedMemDeps()
Detect loop-carried memory dependences in the original MBB that must be preserved across loop iterati...
MachineSchedContext * Context
virtual void restoreTripleMBB()
Restore the order of MIs in TripleMBB after each list scheduling.
virtual void postProcess()
Add some related processing after running window scheduling.
DenseMap< MachineInstr *, int > OriToCycle
OriToCycle keeps the mappings between the original MI and its issue cycle.
virtual int calculateMaxCycle(ScheduleDAGInstrs &DAG, unsigned Offset)
Calculate MIs execution cycle after list scheduling.
MachineRegisterInfo * MRI
unsigned BestII
BestII and BestOffset record the characteristics of the best scheduling result and are used together ...
void backupMBB()
Back up the MIs in the original MBB and remove them from MBB.
int getEstimatedII(ScheduleDAGInstrs &DAG)
Estimate a II value at which all MIs will be scheduled successfully.
virtual void expand()
Using the scheduling infrastructure to expand the results of window scheduling.
DenseMap< MachineInstr *, int > getIssueOrder(unsigned Offset, unsigned II)
Get the final issue order of all scheduled MIs including phis.
Register getAntiRegister(MachineInstr *Phi)
Gets the register in phi which is generated from the current MBB.
unsigned getOriStage(MachineInstr *OriMI, unsigned Offset)
Get the scheduling stage, where the stage of the new MI is identical to the original MI.
const TargetRegisterInfo * TRI
virtual void updateLiveIntervals()
Update the live intervals for all registers used within MBB.
const TargetSubtargetInfo * Subtarget
bool MemDepEdgeFailed
MemDepEdgeFailed is set when enforcing a loop-carried memory dependence as an artificial DAG edge wou...
std::unique_ptr< ScheduleDAGInstrs > TripleDAG
To innovatively identify the dependencies between MIs across two trips, we construct a DAG for a new ...
unsigned BaseII
BaseII is the II obtained when the window offset is SchedPhiNum.
DenseSet< std::pair< MachineInstr *, MachineInstr * > > LoopCarriedMemDeps
LoopCarriedMemDeps keeps ordered pairs (Pred, Succ) of original memory MIs such that the iteration-N ...
virtual void schedulePhi(int Offset, unsigned &II)
Phis are scheduled separately after each list scheduling.
DenseMap< MachineInstr *, TriCloneInfo > TriToOri
TriToOri keeps the mappings between the MI clones in TripleMBB and the information about their origin...
virtual unsigned analyseII(ScheduleDAGInstrs &DAG, unsigned Offset)
Analyzes the II value after each list scheduling.
int getOriCycle(MachineInstr *NewMI)
Get the issue cycle of the new MI based on the cycle of the original MI.
unsigned SchedInstrNum
SchedInstrNum records the MIs involved in scheduling in the original MBB, excluding debug instruction...
const TargetInstrInfo * TII
virtual void generateTripleMBB()
Make three copies of the original MBB to generate a new TripleMBB.
iterator_range< MachineBasicBlock::iterator > getScheduleRange(unsigned Offset, unsigned Num)
Gets the iterator range of MIs in the scheduling window.
virtual bool isScheduleValid()
Check whether the final result of window scheduling is valid.
virtual int calculateStallCycle(unsigned Offset, int MaxCycle)
Calculate the stall cycle between two trips after list scheduling.
virtual void updateScheduleResult(unsigned Offset, unsigned II)
Update the scheduling result after each list scheduling.
SmallVector< MachineInstr * > OriMIs
OriMIs keeps the MIs removed from the original MBB.
virtual bool initialize()
Initializes the algorithm and determines if it can be executed.
SmallVector< std::tuple< MachineInstr *, int, int, int >, 256 > SchedResult
SchedResult keeps the result of each list scheduling, and the format of the tuple is <MI pointer,...
virtual SmallVector< unsigned > getSearchIndexes(unsigned SearchNum, unsigned SearchRatio)
Give the folding position in the window algorithm, where different heuristics can be used.
void restoreMBB()
Erase the MIs in current MBB and restore the original MIs.
WindowScheduler(MachineSchedContext *C, MachineLoop &ML)
SmallVector< MachineInstr * > TriMIs
TriMIs keeps the MIs of TripleMBB, which is used to restore TripleMBB.
A range adaptor for a pair of iterators.
void apply(Opt *O, const Mod &M, const Mods &... Ms)
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
ScheduleDAGMILive * createSchedLive(MachineSchedContext *C)
Create the standard converging machine scheduler.
void stable_sort(R &&Range)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool mayOverlapInLaterIter(const MachineInstr *BaseMI, const MachineInstr *OtherMI, const MachineBasicBlock *LoopBB, const MachineRegisterInfo &MRI, const TargetInstrInfo &TII)
Return true if BaseMI and OtherMI may access overlapping memory in a later iteration of the loop Loop...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
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.
A collection of metadata nodes that might be associated with a memory access used by the alias-analys...
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...