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}))
243 TripleDAG = std::unique_ptr<ScheduleDAGInstrs>(
249 LLVM_DEBUG(
dbgs() <<
"The WindowScheduler failed to initialize!\n");
255 ++NumTryWindowSchedule;
270 assert(SchedDAG &&
"Expected a scheduler for window scheduling");
271 auto *SchedDAGMI =
static_cast<ScheduleDAGMI *
>(SchedDAG.get());
272 SchedDAGMI->
addMutation(std::make_unique<WindowMemDepMutation>(
275 for (
unsigned Idx : SearchIndexes) {
277 ++NumTryWindowSearch;
283 SchedDAG->startBlock(
MBB);
285 SchedDAG->schedule();
289 LLVM_DEBUG(
dbgs() <<
"Can't enforce a loop-carried memory dependence. "
290 "Keep searching...\n");
296 LLVM_DEBUG(
dbgs() <<
"Can't find a valid II. Keep searching...\n");
314 <<
" and Best II is " <<
BestII <<
".\n");
323 return OnlyBuildGraph
331 if (!
Subtarget->enableWindowScheduler()) {
358 if (PrevUses.
count(Phi.getOperand(0).getReg()))
360 PrevDefs.
insert(Phi.getOperand(0).getReg());
361 for (
unsigned I = 1, E = Phi.getNumOperands();
I != E;
I += 2) {
362 if (PrevDefs.
count(Phi.getOperand(
I).getReg()))
364 PrevUses.
insert(Phi.getOperand(
I).getReg());
368 auto PLI =
TII->analyzeLoopForPipelining(
MBB);
369 for (
auto &
MI : *
MBB) {
370 if (
MI.isDebugOrPseudoInstr() ||
MI.isTerminator())
373 if (IsLoopCarried(
MI)) {
374 LLVM_DEBUG(
dbgs() <<
"Loop carried phis are not supported yet!\n");
381 if (
TII->isSchedulingBoundary(
MI,
MBB, *
MF)) {
383 dbgs() <<
"Boundary MI is not allowed in window scheduling!\n");
386 if (PLI->shouldIgnoreForPipelining(&
MI)) {
387 LLVM_DEBUG(
dbgs() <<
"Special MI defined by target is not allowed in "
388 "window scheduling!\n");
391 for (
auto &Def :
MI.all_defs())
392 if (Def.isReg() && Def.getReg().isPhysical()) {
394 "window scheduling!\n");
399 LLVM_DEBUG(
dbgs() <<
"There are too few MIs in the window region!\n");
415 MBB,
MBB->begin(),
MBB->getFirstTerminator(),
416 std::distance(
MBB->begin(),
MBB->getFirstTerminator()));
427 if (
MI.mayLoadOrStore() && !
MI.isDebugInstr())
444 if (!SrcMI->mayStore() && !DstMI->mayStore())
461 for (
auto &
MI :
MBB->instrs())
465 Context->LIS->getSlotIndexes()->removeMachineInstrFromMaps(
MI,
true);
473 Context->LIS->getSlotIndexes()->removeMachineInstrFromMaps(
MI,
true);
474 MI.eraseFromParent();
482 const unsigned DuplicateNum = 3;
485 assert(
OriMIs.size() > 0 &&
"The Original MIs were not backed up!");
491 if (
MI->isDebugOrPseudoInstr() ||
MI->isTerminator())
495 DefPairs[
MI->getOperand(0).getReg()] = AntiReg;
496 auto *NewMI =
MF->CloneMachineInstr(
MI);
497 MBB->push_back(NewMI);
504 for (
size_t Cnt = 1; Cnt < DuplicateNum; ++Cnt) {
506 if (
MI->isPHI() ||
MI->isDebugOrPseudoInstr() ||
507 (
MI->isTerminator() && Cnt < DuplicateNum - 1))
509 auto *NewMI =
MF->CloneMachineInstr(
MI);
512 for (
auto MO : NewMI->all_defs())
513 if (MO.isReg() && MO.getReg().isVirtual()) {
515 MRI->createVirtualRegister(
MRI->getRegClass(MO.getReg()));
516 NewMI->substituteRegister(MO.getReg(), NewDef, 0, *
TRI);
517 NewDefs[MO.getReg()] = NewDef;
520 for (
auto DefRegPair : DefPairs)
521 if (NewMI->readsRegister(DefRegPair.first,
TRI)) {
522 Register NewUse = DefRegPair.second;
550 if (
auto It = DefPairs.find(NewUse); It != DefPairs.end())
552 NewMI->substituteRegister(DefRegPair.first, NewUse, 0, *
TRI);
555 for (
auto &NewDef : NewDefs)
556 DefPairs[NewDef.first] = NewDef.second;
557 MBB->push_back(NewMI);
559 TriToOri[NewMI] = {
MI,
static_cast<unsigned>(Cnt)};
568 for (
auto &Phi :
MBB->phis()) {
569 for (
auto DefRegPair : DefPairs)
570 if (Phi.readsRegister(DefRegPair.first,
TRI))
571 Phi.substituteRegister(DefRegPair.first, DefRegPair.second, 0, *
TRI);
578 for (
size_t I = 0;
I <
TriMIs.size(); ++
I) {
580 auto OldPos =
MBB->begin();
581 std::advance(OldPos,
I);
582 auto CurPos =
MI->getIterator();
583 if (CurPos != OldPos) {
584 MBB->splice(OldPos,
MBB, CurPos);
591 unsigned SearchRatio) {
596 assert(SearchRatio <= 100 &&
"SearchRatio should be equal or less than 100!");
598 unsigned Step = SearchNum > 0 && SearchNum <= MaxIdx ? MaxIdx / SearchNum : 1;
600 for (
unsigned Idx = 0; Idx < MaxIdx; Idx += Step)
602 return SearchIndexes;
607 unsigned MaxDepth = 1;
608 for (
auto &SU : DAG.
SUnits)
609 MaxDepth = std::max(SU.getDepth() + SU.Latency, MaxDepth);
610 return MaxDepth * WindowIICoeff;
625 int ExpectCycle = CurCycle;
627 for (
auto &Pred : SU->Preds) {
630 auto *PredMI = Pred.getSUnit()->getInstr();
632 ExpectCycle = std::max(ExpectCycle, PredCycle + (
int)Pred.getLatency());
635 if (!
TII->isZeroCost(
MI.getOpcode())) {
638 while (!RM.canReserveResources(*SU, CurCycle) || CurCycle < ExpectCycle) {
643 RM.reserveResources(*SU, CurCycle);
684 int MaxStallCycle = 0;
685 int CurrentII = MaxCycle + 1;
690 for (
auto &Succ : SU->Succs) {
691 if (Succ.isWeak() || Succ.getSUnit() == &
TripleDAG->ExitSU)
694 if (DefCycle + (
int)Succ.getLatency() <= CurrentII)
699 auto *SuccMI = Succ.getSUnit()->getInstr();
701 if (DefCycle < UseCycle)
704 int StallCycle = DefCycle + (int)Succ.getLatency() - CurrentII - UseCycle;
705 MaxStallCycle = std::max(MaxStallCycle, StallCycle);
708 LLVM_DEBUG(
dbgs() <<
"MaxStallCycle is " << MaxStallCycle <<
".\n");
709 return MaxStallCycle;
721 return MaxCycle + StallCycle + 1;
726 for (
auto &Phi :
MBB->phis()) {
727 int LateCycle = INT_MAX;
729 for (
auto &Succ : SU->Succs) {
735 auto *SuccMI = Succ.getSUnit()->getInstr();
738 LateCycle = std::min(LateCycle, Cycle);
742 auto *AntiMI =
MRI->getVRegDef(AntiReg);
744 if (AntiMI->getParent() ==
MBB) {
747 LateCycle = std::min(LateCycle, AntiCycle);
751 if (LateCycle == INT_MAX)
752 LateCycle = (int)(
II - 1);
753 LLVM_DEBUG(
dbgs() <<
"\tCycle range [0, " << LateCycle <<
"] " << Phi);
766 for (
auto &Phi :
MBB->phis())
774 for (
int Cycle = 0; Cycle < (int)
II; ++Cycle) {
775 auto It = CycleToMIs.
find(Cycle);
776 if (It == CycleToMIs.
end())
778 for (
auto *
MI : It->second)
779 IssueOrder[
MI] = Id++;
804 assert(IssueOrder.count(Pair.first) &&
"Cannot find original MI!");
805 SchedResult.push_back(std::make_tuple(Pair.first, Pair.second,
807 IssueOrder[Pair.first]));
814 [](
const std::tuple<MachineInstr *, int, int, int> &
A,
815 const std::tuple<MachineInstr *, int, int, int> &
B) {
816 return std::get<3>(
A) < std::get<3>(
B);
821 std::vector<MachineInstr *> OrderedInsts;
823 auto *
MI = std::get<0>(Info);
824 OrderedInsts.push_back(
MI);
825 Cycles[
MI] = std::get<1>(Info);
826 Stages[
MI] = std::get<2>(Info);
842 if (!MO.isReg() || MO.getReg() == 0)
848 Context->LIS->repairIntervalsInRange(
MBB,
MBB->begin(),
MBB->end(), UsedRegs);
853 auto RegionBegin =
MBB->begin();
854 std::advance(RegionBegin,
Offset);
855 auto RegionEnd = RegionBegin;
856 std::advance(RegionEnd, Num);
881 if (
MI->isDebugOrPseudoInstr())
887 return Id >= (size_t)
Offset ? 1 : 0;
891 assert(Phi->isPHI() &&
"Expecting PHI!");
893 for (
auto MO : Phi->uses()) {
895 AntiReg = MO.getReg();
896 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)
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
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.
WindowScheduler(MachineSchedContext *C, MachineLoop &ML, MachineDominatorTree *MDT=nullptr)
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
MachineDominatorTree * MDT
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.
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...