LLVM 24.0.0git
WindowScheduler.cpp
Go to the documentation of this file.
1//======----------- WindowScheduler.cpp - window scheduler -------------======//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// An implementation of the Window Scheduling software pipelining algorithm.
10//
11// The fundamental concept of the window scheduling algorithm involves folding
12// the original MBB at a specific position, followed by list scheduling on the
13// folded MIs. The optimal scheduling result is then chosen from various folding
14// positions as the final scheduling outcome.
15//
16// The primary challenge in this algorithm lies in generating the folded MIs and
17// establishing their dependencies. We have innovatively employed a new MBB,
18// created by copying the original MBB three times, known as TripleMBB. This
19// TripleMBB enables the convenient implementation of MI folding and dependency
20// establishment. To facilitate the algorithm's implementation, we have also
21// devised data structures such as OriMIs, TriMIs, TriToOri, and OriToCycle.
22//
23// Another challenge in the algorithm is the scheduling of phis. Semantically,
24// it is difficult to place the phis in the window and perform list scheduling.
25// Therefore, we schedule these phis separately after each list scheduling.
26//
27// The provided implementation is designed for use before the Register Allocator
28// (RA). If the target requires implementation after RA, it is recommended to
29// reimplement analyseII(), schedulePhi(), and expand(). Additionally,
30// target-specific logic can be added in initialize(), preProcess(), and
31// postProcess().
32//
33// Lastly, it is worth mentioning that getSearchIndexes() is an important
34// function. We have experimented with more complex heuristics on downstream
35// target and achieved favorable results.
36//
37//===----------------------------------------------------------------------===//
39#include "llvm/ADT/Statistic.h"
50#include "llvm/Support/Debug.h"
53
54using namespace llvm;
55
56#define DEBUG_TYPE "pipeliner"
57
58namespace {
59STATISTIC(NumTryWindowSchedule,
60 "Number of loops that we attempt to use window scheduling");
61STATISTIC(NumTryWindowSearch,
62 "Number of times that we run list schedule in the window scheduling");
63STATISTIC(NumWindowSchedule,
64 "Number of loops that we successfully use window scheduling");
65STATISTIC(NumFailAnalyseII,
66 "Window scheduling abort due to the failure of the II analysis");
67
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."),
73
74cl::opt<unsigned> WindowSearchRatio(
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."),
79 cl::Hidden, cl::init(40));
80
81cl::opt<unsigned> WindowIICoeff(
82 "window-ii-coeff",
84 "The coefficient used when initializing II in the window algorithm."),
86
87cl::opt<unsigned> WindowRegionLimit(
88 "window-region-limit",
90 "The lower limit of the scheduling region in the window algorithm."),
92
93cl::opt<unsigned> WindowDiffLimit(
94 "window-diff-limit",
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."),
99} // namespace
100
101// WindowIILimit serves as an indicator of abnormal scheduling results and could
102// potentially be referenced by the derived target window scheduler.
104 WindowIILimit("window-ii-limit",
105 cl::desc("The upper limit of II in the window algorithm."),
106 cl::Hidden, cl::init(1000));
107
108/// Collect the underlying objects and alias metadata for the single memory
109/// operand of MI. Returns false when MI does not have exactly one memory
110/// operand with a known IR value.
111static bool getMemInfo(const MachineInstr *MI, const Value *&MemOpValue,
112 int64_t &MemOpOffset,
113 SmallVectorImpl<const Value *> &UnderlyingObjs,
114 AAMDNodes &AATags, bool &IsAllIdentified) {
115 if (!MI->hasOneMemOperand())
116 return false;
117 MachineMemOperand *MM = *MI->memoperands_begin();
118 if (!MM->getValue())
119 return false;
120 MemOpValue = MM->getValue();
121 MemOpOffset = MM->getOffset();
122 getUnderlyingObjects(MemOpValue, UnderlyingObjs);
123 AATags = MM->getAAInfo();
124 IsAllIdentified = llvm::all_of(UnderlyingObjs, isIdentifiedObject);
125 return true;
126}
127
128/// Return true if there is a loop-carried order dependency from memory access
129/// SrcMI to DstMI in loop LoopBB.
130static bool hasLoopCarriedMemDep(const MachineInstr *SrcMI,
131 const MachineInstr *DstMI, BatchAAResults &BAA,
132 const MachineBasicBlock *LoopBB,
134 const TargetInstrInfo *TII) {
135 const Value *SrcVal = nullptr, *DstVal = nullptr;
136 int64_t SrcOffset = 0, DstOffset = 0;
137 SmallVector<const Value *, 4> SrcObjs, DstObjs;
138 AAMDNodes SrcAATags, DstAATags;
139 bool SrcAllIdentified = false, DstAllIdentified = false;
140 bool SrcKnown = getMemInfo(SrcMI, SrcVal, SrcOffset, SrcObjs, SrcAATags,
141 SrcAllIdentified);
142 bool DstKnown = getMemInfo(DstMI, DstVal, DstOffset, DstObjs, DstAATags,
143 DstAllIdentified);
144
145 // If all underlying objects are identified and disjoint, the accesses cannot
146 // alias.
147 if (SrcKnown && DstKnown && SrcAllIdentified && DstAllIdentified &&
148 llvm::none_of(SrcObjs, [&](const Value *Obj) {
149 return llvm::is_contained(DstObjs, Obj);
150 }))
151 return false;
152
153 // The overlap helper inspects only the first memory operand. Multi-MMO
154 // instructions could carry an overlap through a later operand, so be
155 // conservative and keep the dependency for them.
156 if (!SrcMI->hasOneMemOperand() || !DstMI->hasOneMemOperand())
157 return true;
158
159 if (!mayOverlapInLaterIter(SrcMI, DstMI, LoopBB, MRI, *TII))
160 return false;
161
162 // The more expensive check that uses alias analysis on the base values.
163 if (!SrcKnown || !DstKnown)
164 return true;
165 if (SrcVal == DstVal && SrcOffset <= DstOffset)
166 return true;
167
168 if (BAA.isNoAlias(MemoryLocation::getBeforeOrAfter(SrcVal, SrcAATags),
169 MemoryLocation::getBeforeOrAfter(DstVal, DstAATags)))
170 return false;
171
172 // AliasAnalysis sometimes gives up on following the underlying object. In
173 // such a case, separate checks for underlying objects may prove that there
174 // are no aliases between two accesses.
175 for (const Value *SrcObj : SrcObjs)
176 for (const Value *DstObj : DstObjs)
177 if (!BAA.isNoAlias(MemoryLocation::getBeforeOrAfter(SrcObj, SrcAATags),
178 MemoryLocation::getBeforeOrAfter(DstObj, DstAATags)))
179 return true;
180
181 return false;
182}
183
184namespace {
185/// A DAG mutation that enforces the loop-carried memory dependences discovered
186/// on the original loop while list scheduling each window of TripleMBB.
187///
188/// For each recorded hazard pair (Pred, Succ) we add an artificial order edge
189/// between the clone of Pred and the clone of Succ belonging to a later copy,
190/// so that the iteration-N Pred is kept before the iteration-(N+1) Succ.
191class WindowMemDepMutation : public ScheduleDAGMutation {
192 const DenseSet<std::pair<MachineInstr *, MachineInstr *>> &LoopCarriedMemDeps;
193 const DenseMap<MachineInstr *, TriCloneInfo> &TriToOri;
194 bool &EdgeFailed;
195
196public:
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) {}
201
202 void apply(ScheduleDAGInstrs *DAG) override {
203 if (LoopCarriedMemDeps.empty())
204 return;
205 for (SUnit &PredSU : DAG->SUnits) {
206 MachineInstr *PredMI = PredSU.getInstr();
207 if (!PredMI || !PredMI->mayLoadOrStore())
208 continue;
209 auto PredIt = TriToOri.find(PredMI);
210 if (PredIt == TriToOri.end())
211 continue;
212 for (SUnit &SuccSU : DAG->SUnits) {
213 MachineInstr *SuccMI = SuccSU.getInstr();
214 if (&PredSU == &SuccSU || !SuccMI || !SuccMI->mayLoadOrStore())
215 continue;
216 auto SuccIt = TriToOri.find(SuccMI);
217 if (SuccIt == TriToOri.end())
218 continue;
219 // Only order a Pred from an earlier copy before a Succ from a later
220 // copy, which models the iteration-N to iteration-(N+1) dependence.
221 if (PredIt->second.Copy >= SuccIt->second.Copy)
222 continue;
223 if (!LoopCarriedMemDeps.contains(
224 {PredIt->second.Ori, SuccIt->second.Ori}))
225 continue;
226 // If the edge would create a cycle, addEdge() returns false and does
227 // not insert it. The required dependence then cannot be enforced in
228 // this window, so mark it to make the caller abandon this window's
229 // schedule.
230 if (!DAG->addEdge(&SuccSU, SDep(&PredSU, SDep::Barrier)))
231 EdgeFailed = true;
232 }
233 }
234 }
235};
236} // end anonymous namespace
237
239 : Context(C), MF(C->MF), MBB(ML.getHeader()), Loop(ML),
240 Subtarget(&MF->getSubtarget()), TII(Subtarget->getInstrInfo()),
241 TRI(Subtarget->getRegisterInfo()), MRI(&MF->getRegInfo()) {
242 TripleDAG = std::unique_ptr<ScheduleDAGInstrs>(
243 createMachineScheduler(/*OnlyBuildGraph=*/true));
244}
245
247 if (!initialize()) {
248 LLVM_DEBUG(dbgs() << "The WindowScheduler failed to initialize!\n");
249 return false;
250 }
251 // The window algorithm is time-consuming, and its compilation time should be
252 // taken into consideration.
253 TimeTraceScope Scope("WindowSearch");
254 ++NumTryWindowSchedule;
255 // Performing the relevant processing before window scheduling.
256 preProcess();
257 // The main window scheduling begins.
258 std::unique_ptr<ScheduleDAGInstrs> SchedDAG(createMachineScheduler());
259 // A target may decline to provide a scheduler, in which case fall back to the
260 // generic live scheduler so that window scheduling still has one to drive.
261 if (!SchedDAG)
262 SchedDAG.reset(createSchedLive(Context));
263 // Attach the mutation that enforces the loop-carried memory dependences.
264 // This requires the scheduler to support DAG mutations, i.e. to be a
265 // ScheduleDAGMI. Every in-tree target's pre-RA machine scheduler is a
266 // ScheduleDAGMI (or ScheduleDAGMILive), and the generic fallback
267 // createSchedLive() above returns one as well, so the cast below is safe.
268 // The assert documents and guards this invariant.
269 assert(SchedDAG && "Expected a scheduler for window scheduling");
270 auto *SchedDAGMI = static_cast<ScheduleDAGMI *>(SchedDAG.get());
271 SchedDAGMI->addMutation(std::make_unique<WindowMemDepMutation>(
273 auto SearchIndexes = getSearchIndexes(WindowSearchNum, WindowSearchRatio);
274 for (unsigned Idx : SearchIndexes) {
275 OriToCycle.clear();
276 ++NumTryWindowSearch;
277 // The scheduling starts with non-phi instruction, so SchedPhiNum needs to
278 // be added to Idx.
279 unsigned Offset = Idx + SchedPhiNum;
281 MemDepEdgeFailed = false;
282 SchedDAG->startBlock(MBB);
283 SchedDAG->enterRegion(MBB, Range.begin(), Range.end(), SchedInstrNum);
284 SchedDAG->schedule();
285 LLVM_DEBUG(SchedDAG->dump());
286 if (MemDepEdgeFailed) {
288 LLVM_DEBUG(dbgs() << "Can't enforce a loop-carried memory dependence. "
289 "Keep searching...\n");
290 continue;
291 }
292 unsigned II = analyseII(*SchedDAG, Offset);
293 if (II == WindowIILimit) {
295 LLVM_DEBUG(dbgs() << "Can't find a valid II. Keep searching...\n");
296 ++NumFailAnalyseII;
297 continue;
298 }
302 LLVM_DEBUG(dbgs() << "Current window Offset is " << Offset << " and II is "
303 << II << ".\n");
304 }
305 // Performing the relevant processing after window scheduling.
306 postProcess();
307 // Check whether the scheduling result is valid.
308 if (!isScheduleValid()) {
309 LLVM_DEBUG(dbgs() << "Window scheduling is not needed!\n");
310 return false;
311 }
312 LLVM_DEBUG(dbgs() << "\nBest window offset is " << BestOffset
313 << " and Best II is " << BestII << ".\n");
314 // Expand the scheduling result to prologue, kernel, and epilogue.
315 expand();
316 ++NumWindowSchedule;
317 return true;
318}
319
322 return OnlyBuildGraph
323 ? new ScheduleDAGMI(
324 Context, std::make_unique<PostGenericScheduler>(Context),
325 true)
326 : Context->TM->createMachineScheduler(Context);
327}
328
330 if (!Subtarget->enableWindowScheduler()) {
331 LLVM_DEBUG(dbgs() << "Target disables the window scheduling!\n");
332 return false;
333 }
334 // Initialized the member variables used by window algorithm.
335 OriMIs.clear();
336 TriMIs.clear();
337 TriToOri.clear();
338 OriToCycle.clear();
339 SchedResult.clear();
340 SchedPhiNum = 0;
341 SchedInstrNum = 0;
342 BestII = UINT_MAX;
343 BestOffset = 0;
344 BaseII = 0;
345 // List scheduling used in the window algorithm depends on LiveIntervals.
346 if (!Context->LIS) {
347 LLVM_DEBUG(dbgs() << "There is no LiveIntervals information!\n");
348 return false;
349 }
350 // Check each MI in MBB.
351 SmallSet<Register, 8> PrevDefs;
352 SmallSet<Register, 8> PrevUses;
353 auto IsLoopCarried = [&](MachineInstr &Phi) {
354 // Two cases are checked here: (1)The virtual register defined by the
355 // preceding phi is used by the succeeding phi;(2)The preceding phi uses the
356 // virtual register defined by the succeeding phi.
357 if (PrevUses.count(Phi.getOperand(0).getReg()))
358 return true;
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()))
362 return true;
363 PrevUses.insert(Phi.getOperand(I).getReg());
364 }
365 return false;
366 };
367 auto PLI = TII->analyzeLoopForPipelining(MBB);
368 for (auto &MI : *MBB) {
369 if (MI.isDebugOrPseudoInstr() || MI.isTerminator())
370 continue;
371 if (MI.isPHI()) {
372 if (IsLoopCarried(MI)) {
373 LLVM_DEBUG(dbgs() << "Loop carried phis are not supported yet!\n");
374 return false;
375 }
376 ++SchedPhiNum;
377 ++BestOffset;
378 } else
380 if (TII->isSchedulingBoundary(MI, MBB, *MF)) {
382 dbgs() << "Boundary MI is not allowed in window scheduling!\n");
383 return false;
384 }
385 if (PLI->shouldIgnoreForPipelining(&MI)) {
386 LLVM_DEBUG(dbgs() << "Special MI defined by target is not allowed in "
387 "window scheduling!\n");
388 return false;
389 }
390 for (auto &Def : MI.all_defs())
391 if (Def.isReg() && Def.getReg().isPhysical()) {
392 LLVM_DEBUG(dbgs() << "Physical registers are not supported in "
393 "window scheduling!\n");
394 return false;
395 }
396 }
397 if (SchedInstrNum <= WindowRegionLimit) {
398 LLVM_DEBUG(dbgs() << "There are too few MIs in the window region!\n");
399 return false;
400 }
401 return true;
402}
403
405 // Prior to window scheduling, it's necessary to backup the original MBB,
406 // generate a new TripleMBB, and build a TripleDAG based on the TripleMBB.
407 // Collect loop-carried memory dependences first, while the original MBB is
408 // still live (see collectLoopCarriedMemDeps() and run()).
410 backupMBB();
412 TripleDAG->startBlock(MBB);
413 TripleDAG->enterRegion(
414 MBB, MBB->begin(), MBB->getFirstTerminator(),
415 std::distance(MBB->begin(), MBB->getFirstTerminator()));
416 TripleDAG->buildSchedGraph(Context->AA);
417}
418
420 LoopCarriedMemDeps.clear();
421 MachineBasicBlock *LoopBB = MBB;
422
423 // Collect the memory instructions of the original loop in program order.
425 for (MachineInstr &MI : *LoopBB)
426 if (MI.mayLoadOrStore() && !MI.isDebugInstr())
427 MemMIs.push_back(&MI);
428
429 // Nothing to do unless there is at least one store to order against.
430 if (llvm::none_of(MemMIs,
431 [](const MachineInstr *MI) { return MI->mayStore(); }))
432 return;
433
434 BatchAAResults BAA(*Context->AA);
436
437 for (MachineInstr *SrcMI : MemMIs) {
438 for (MachineInstr *DstMI : MemMIs) {
439 if (SrcMI == DstMI)
440 continue;
441 // A loop-carried order edge is only required when at least one of the
442 // accesses stores.
443 if (!SrcMI->mayStore() && !DstMI->mayStore())
444 continue;
445 if (hasLoopCarriedMemDep(SrcMI, DstMI, BAA, LoopBB, *MRI, TII))
446 LoopCarriedMemDeps.insert({SrcMI, DstMI});
447 }
448 }
449}
450
452 // After window scheduling, it's necessary to clear the TripleDAG and restore
453 // to the original MBB.
454 TripleDAG->exitRegion();
455 TripleDAG->finishBlock();
456 restoreMBB();
457}
458
460 for (auto &MI : MBB->instrs())
461 OriMIs.push_back(&MI);
462 // Remove MIs and the corresponding live intervals.
463 for (auto &MI : make_early_inc_range(*MBB)) {
464 Context->LIS->getSlotIndexes()->removeMachineInstrFromMaps(MI, true);
465 MBB->remove(&MI);
466 }
467}
468
470 // Erase MIs and the corresponding live intervals.
471 for (auto &MI : make_early_inc_range(*MBB)) {
472 Context->LIS->getSlotIndexes()->removeMachineInstrFromMaps(MI, true);
473 MI.eraseFromParent();
474 }
475 // Restore MBB to the state before window scheduling.
478}
479
481 const unsigned DuplicateNum = 3;
482 TriMIs.clear();
483 TriToOri.clear();
484 assert(OriMIs.size() > 0 && "The Original MIs were not backed up!");
485 // Step 1: Performing the first copy of MBB instructions, excluding
486 // terminators. At the same time, we back up the anti-register of phis.
487 // DefPairs hold the old and new define register pairs.
489 for (auto *MI : OriMIs) {
490 if (MI->isDebugOrPseudoInstr() || MI->isTerminator())
491 continue;
492 if (MI->isPHI())
493 if (Register AntiReg = getAntiRegister(MI))
494 DefPairs[MI->getOperand(0).getReg()] = AntiReg;
495 auto *NewMI = MF->CloneMachineInstr(MI);
496 MBB->push_back(NewMI);
497 TriMIs.push_back(NewMI);
498 TriToOri[NewMI] = {MI, 0};
499 }
500 // Step 2: Performing the remaining two copies of MBB instructions excluding
501 // phis, and the last one contains terminators. At the same time, registers
502 // are updated accordingly.
503 for (size_t Cnt = 1; Cnt < DuplicateNum; ++Cnt) {
504 for (auto *MI : OriMIs) {
505 if (MI->isPHI() || MI->isDebugOrPseudoInstr() ||
506 (MI->isTerminator() && Cnt < DuplicateNum - 1))
507 continue;
508 auto *NewMI = MF->CloneMachineInstr(MI);
510 // New defines are updated.
511 for (auto MO : NewMI->all_defs())
512 if (MO.isReg() && MO.getReg().isVirtual()) {
513 Register NewDef =
514 MRI->createVirtualRegister(MRI->getRegClass(MO.getReg()));
515 NewMI->substituteRegister(MO.getReg(), NewDef, 0, *TRI);
516 NewDefs[MO.getReg()] = NewDef;
517 }
518 // New uses are updated.
519 for (auto DefRegPair : DefPairs)
520 if (NewMI->readsRegister(DefRegPair.first, TRI)) {
521 Register NewUse = DefRegPair.second;
522 // Note the update process for '%1 -> %9' in '%10 = sub i32 %9, %3':
523 //
524 // BB.3: DefPairs
525 // ==================================
526 // %1 = phi i32 [%2, %BB.1], [%7, %BB.3] (%1,%7)
527 // ...
528 // ==================================
529 // ...
530 // %4 = sub i32 %1, %3
531 // ...
532 // %7 = add i32 %5, %6
533 // ...
534 // ----------------------------------
535 // ...
536 // %8 = sub i32 %7, %3 (%1,%7),(%4,%8)
537 // ...
538 // %9 = add i32 %5, %6 (%1,%7),(%4,%8),(%7,%9)
539 // ...
540 // ----------------------------------
541 // ...
542 // %10 = sub i32 %9, %3 (%1,%7),(%4,%10),(%7,%9)
543 // ... ^
544 // %11 = add i32 %5, %6 (%1,%7),(%4,%10),(%7,%11)
545 // ...
546 // ==================================
547 // < Terminators >
548 // ==================================
549 if (auto It = DefPairs.find(NewUse); It != DefPairs.end())
550 NewUse = It->second;
551 NewMI->substituteRegister(DefRegPair.first, NewUse, 0, *TRI);
552 }
553 // DefPairs is updated at last.
554 for (auto &NewDef : NewDefs)
555 DefPairs[NewDef.first] = NewDef.second;
556 MBB->push_back(NewMI);
557 TriMIs.push_back(NewMI);
558 TriToOri[NewMI] = {MI, static_cast<unsigned>(Cnt)};
559 }
560 }
561 // Step 3: The registers used by phis are updated, and they are generated in
562 // the third copy of MBB.
563 // In the privious example, the old phi is:
564 // %1 = phi i32 [%2, %BB.1], [%7, %BB.3]
565 // The new phi is:
566 // %1 = phi i32 [%2, %BB.1], [%11, %BB.3]
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);
571 }
573}
574
576 // After list scheduling, the MBB is restored in one traversal.
577 for (size_t I = 0; I < TriMIs.size(); ++I) {
578 auto *MI = TriMIs[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);
584 Context->LIS->handleMove(*MI, /*UpdateFlags=*/false);
585 }
586 }
587}
588
590 unsigned SearchRatio) {
591 // We use SearchRatio to get the index range, and then evenly get the indexes
592 // according to the SearchNum. This is a simple huristic. Depending on the
593 // characteristics of the target, more complex algorithms can be used for both
594 // performance and compilation time.
595 assert(SearchRatio <= 100 && "SearchRatio should be equal or less than 100!");
596 unsigned MaxIdx = SchedInstrNum * SearchRatio / 100;
597 unsigned Step = SearchNum > 0 && SearchNum <= MaxIdx ? MaxIdx / SearchNum : 1;
598 SmallVector<unsigned> SearchIndexes;
599 for (unsigned Idx = 0; Idx < MaxIdx; Idx += Step)
600 SearchIndexes.push_back(Idx);
601 return SearchIndexes;
602}
603
605 // Sometimes MaxDepth is 0, so it should be limited to the minimum of 1.
606 unsigned MaxDepth = 1;
607 for (auto &SU : DAG.SUnits)
608 MaxDepth = std::max(SU.getDepth() + SU.Latency, MaxDepth);
609 return MaxDepth * WindowIICoeff;
610}
611
613 unsigned Offset) {
614 int InitII = getEstimatedII(DAG);
615 ResourceManager RM(Subtarget, &DAG);
616 RM.init(InitII);
617 // ResourceManager and DAG are used to calculate the maximum cycle for the
618 // scheduled MIs. Since MIs in the Region have already been scheduled, the
619 // emit cycles can be estimated in order here.
620 int CurCycle = 0;
622 for (auto &MI : Range) {
623 auto *SU = DAG.getSUnit(&MI);
624 int ExpectCycle = CurCycle;
625 // The predecessors of current MI determine its earliest issue cycle.
626 for (auto &Pred : SU->Preds) {
627 if (Pred.isWeak())
628 continue;
629 auto *PredMI = Pred.getSUnit()->getInstr();
630 int PredCycle = getOriCycle(PredMI);
631 ExpectCycle = std::max(ExpectCycle, PredCycle + (int)Pred.getLatency());
632 }
633 // Zero cost instructions do not need to check resource.
634 if (!TII->isZeroCost(MI.getOpcode())) {
635 // ResourceManager can be used to detect resource conflicts between the
636 // current MI and the previously inserted MIs.
637 while (!RM.canReserveResources(*SU, CurCycle) || CurCycle < ExpectCycle) {
638 ++CurCycle;
639 if (CurCycle == (int)WindowIILimit)
640 return CurCycle;
641 }
642 RM.reserveResources(*SU, CurCycle);
643 }
644 OriToCycle[getOriMI(&MI)] = CurCycle;
645 LLVM_DEBUG(dbgs() << "\tCycle " << CurCycle << " [S."
646 << getOriStage(getOriMI(&MI), Offset) << "]: " << MI);
647 }
648 LLVM_DEBUG(dbgs() << "MaxCycle is " << CurCycle << ".\n");
649 return CurCycle;
650}
651
652// By utilizing TripleDAG, we can easily establish dependencies between A and B.
653// Based on the MaxCycle and the issue cycle of A and B, we can determine
654// whether it is necessary to add a stall cycle. This is because, without
655// inserting the stall cycle, the latency constraint between A and B cannot be
656// satisfied. The details are as follows:
657//
658// New MBB:
659// ========================================
660// < Phis >
661// ======================================== (sliding direction)
662// MBB copy 1 |
663// V
664//
665// ~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~~ ----schedule window-----
666// | |
667// ===================V==================== |
668// MBB copy 2 < MI B > |
669// |
670// < MI A > V
671// ~~~~~~~~~~~~~~~~~~~:~~~~~~~~~~~~~~~~~~~~ ------------------------
672// :
673// ===================V====================
674// MBB copy 3 < MI B'>
675//
676//
677//
678//
679// ========================================
680// < Terminators >
681// ========================================
682int WindowScheduler::calculateStallCycle(unsigned Offset, int MaxCycle) {
683 int MaxStallCycle = 0;
684 int CurrentII = MaxCycle + 1;
686 for (auto &MI : Range) {
687 auto *SU = TripleDAG->getSUnit(&MI);
688 int DefCycle = getOriCycle(&MI);
689 for (auto &Succ : SU->Succs) {
690 if (Succ.isWeak() || Succ.getSUnit() == &TripleDAG->ExitSU)
691 continue;
692 // If the expected cycle does not exceed CurrentII, no check is needed.
693 if (DefCycle + (int)Succ.getLatency() <= CurrentII)
694 continue;
695 // If the cycle of the scheduled MI A is less than that of the scheduled
696 // MI B, the scheduling will fail because the lifetime of the
697 // corresponding register exceeds II.
698 auto *SuccMI = Succ.getSUnit()->getInstr();
699 int UseCycle = getOriCycle(SuccMI);
700 if (DefCycle < UseCycle)
701 return WindowIILimit;
702 // Get the stall cycle introduced by the register between two trips.
703 int StallCycle = DefCycle + (int)Succ.getLatency() - CurrentII - UseCycle;
704 MaxStallCycle = std::max(MaxStallCycle, StallCycle);
705 }
706 }
707 LLVM_DEBUG(dbgs() << "MaxStallCycle is " << MaxStallCycle << ".\n");
708 return MaxStallCycle;
709}
710
712 LLVM_DEBUG(dbgs() << "Start analyzing II:\n");
713 int MaxCycle = calculateMaxCycle(DAG, Offset);
714 if (MaxCycle == (int)WindowIILimit)
715 return MaxCycle;
716 int StallCycle = calculateStallCycle(Offset, MaxCycle);
717 if (StallCycle == (int)WindowIILimit)
718 return StallCycle;
719 // The value of II is equal to the maximum execution cycle plus 1.
720 return MaxCycle + StallCycle + 1;
721}
722
724 LLVM_DEBUG(dbgs() << "Start scheduling Phis:\n");
725 for (auto &Phi : MBB->phis()) {
726 int LateCycle = INT_MAX;
727 auto *SU = TripleDAG->getSUnit(&Phi);
728 for (auto &Succ : SU->Succs) {
729 // Phi doesn't have any Anti successors.
730 if (Succ.getKind() != SDep::Data)
731 continue;
732 // Phi is scheduled before the successor of stage 0. The issue cycle of
733 // phi is the latest cycle in this interval.
734 auto *SuccMI = Succ.getSUnit()->getInstr();
735 int Cycle = getOriCycle(SuccMI);
736 if (getOriStage(getOriMI(SuccMI), Offset) == 0)
737 LateCycle = std::min(LateCycle, Cycle);
738 }
739 // The anti-dependency of phi need to be handled separately in the same way.
740 if (Register AntiReg = getAntiRegister(&Phi)) {
741 auto *AntiMI = MRI->getVRegDef(AntiReg);
742 // AntiReg may be defined outside the kernel MBB.
743 if (AntiMI->getParent() == MBB) {
744 auto AntiCycle = getOriCycle(AntiMI);
745 if (getOriStage(getOriMI(AntiMI), Offset) == 0)
746 LateCycle = std::min(LateCycle, AntiCycle);
747 }
748 }
749 // If there is no limit to the late cycle, a default value is given.
750 if (LateCycle == INT_MAX)
751 LateCycle = (int)(II - 1);
752 LLVM_DEBUG(dbgs() << "\tCycle range [0, " << LateCycle << "] " << Phi);
753 // The issue cycle of phi is set to the latest cycle in the interval.
754 auto *OriPhi = getOriMI(&Phi);
755 OriToCycle[OriPhi] = LateCycle;
756 }
757}
758
760 unsigned II) {
761 // At each issue cycle, phi is placed before MIs in stage 0. So the simplest
762 // way is to put phi at the beginning of the current cycle.
765 for (auto &Phi : MBB->phis())
766 CycleToMIs[getOriCycle(&Phi)].push_back(getOriMI(&Phi));
767 for (auto &MI : Range)
768 CycleToMIs[getOriCycle(&MI)].push_back(getOriMI(&MI));
769 // Each MI is assigned a separate ordered Id, which is used as a sort marker
770 // in the following expand process.
772 int Id = 0;
773 for (int Cycle = 0; Cycle < (int)II; ++Cycle) {
774 auto It = CycleToMIs.find(Cycle);
775 if (It == CycleToMIs.end())
776 continue;
777 for (auto *MI : It->second)
778 IssueOrder[MI] = Id++;
779 }
780 return IssueOrder;
781}
782
784 // At the first update, Offset is equal to SchedPhiNum. At this time, only
785 // BestII, BestOffset, and BaseII need to be updated.
786 if (Offset == SchedPhiNum) {
787 BestII = II;
789 BaseII = II;
790 return;
791 }
792 // The update will only continue if the II is smaller than BestII and the II
793 // is sufficiently small.
794 if ((II >= BestII) || (II + WindowDiffLimit > BaseII))
795 return;
796 BestII = II;
798 // Record the result of the current list scheduling, noting that each MI is
799 // stored unordered in SchedResult.
800 SchedResult.clear();
801 auto IssueOrder = getIssueOrder(Offset, II);
802 for (auto &Pair : OriToCycle) {
803 assert(IssueOrder.count(Pair.first) && "Cannot find original MI!");
804 SchedResult.push_back(std::make_tuple(Pair.first, Pair.second,
805 getOriStage(Pair.first, Offset),
806 IssueOrder[Pair.first]));
807 }
808}
809
811 // The MIs in the SchedResult are sorted by the issue order ID.
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);
816 });
817 // Use the scheduling infrastructure for expansion, noting that InstrChanges
818 // is not supported here.
819 DenseMap<MachineInstr *, int> Cycles, Stages;
820 std::vector<MachineInstr *> OrderedInsts;
821 for (auto &Info : SchedResult) {
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);
826 LLVM_DEBUG(dbgs() << "\tCycle " << Cycles[MI] << " [S." << Stages[MI]
827 << "]: " << *MI);
828 }
829 ModuloSchedule MS(*MF, &Loop, std::move(OrderedInsts), std::move(Cycles),
830 std::move(Stages));
831 ModuloScheduleExpander MSE(*MF, MS, *Context->LIS,
833 MSE.expand();
834 MSE.cleanup();
835}
836
839 for (MachineInstr &MI : *MBB)
840 for (const MachineOperand &MO : MI.operands()) {
841 if (!MO.isReg() || MO.getReg() == 0)
842 continue;
843 Register Reg = MO.getReg();
844 if (!is_contained(UsedRegs, Reg))
845 UsedRegs.push_back(Reg);
846 }
847 Context->LIS->repairIntervalsInRange(MBB, MBB->begin(), MBB->end(), UsedRegs);
848}
849
852 auto RegionBegin = MBB->begin();
853 std::advance(RegionBegin, Offset);
854 auto RegionEnd = RegionBegin;
855 std::advance(RegionEnd, Num);
856 return make_range(RegionBegin, RegionEnd);
857}
858
860 assert(TriToOri.count(NewMI) && "Cannot find original MI!");
861 auto *OriMI = TriToOri[NewMI].Ori;
862 assert(OriToCycle.count(OriMI) && "Cannot find schedule cycle!");
863 return OriToCycle[OriMI];
864}
865
867 assert(TriToOri.count(NewMI) && "Cannot find original MI!");
868 return TriToOri[NewMI].Ori;
869}
870
872 assert(llvm::is_contained(OriMIs, OriMI) && "Cannot find OriMI in OriMIs!");
873 // If there is no instruction fold, all MI stages are 0.
874 if (Offset == SchedPhiNum)
875 return 0;
876 // For those MIs with an ID less than the Offset, their stages are set to 0,
877 // while the rest are set to 1.
878 unsigned Id = 0;
879 for (auto *MI : OriMIs) {
880 if (MI->isDebugOrPseudoInstr())
881 continue;
882 if (MI == OriMI)
883 break;
884 ++Id;
885 }
886 return Id >= (size_t)Offset ? 1 : 0;
887}
888
890 assert(Phi->isPHI() && "Expecting PHI!");
891 Register AntiReg;
892 for (auto MO : Phi->uses()) {
893 if (MO.isReg())
894 AntiReg = MO.getReg();
895 else if (MO.isMBB() && MO.getMBB() == MBB)
896 return AntiReg;
897 }
898 return 0;
899}
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
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
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)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
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)
Definition DenseMap.h:766
iterator end()
Definition DenseMap.h:686
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.
Definition Register.h:20
@ Data
Regular data dependence (aka true-dependence).
Definition ScheduleDAG.h:58
@ Barrier
An unknown scheduling barrier.
Definition ScheduleDAG.h:74
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...
Definition SmallSet.h:134
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
Definition SmallSet.h:176
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
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.
Definition Value.h:75
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
MachineBasicBlock * MBB
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.
MachineFunction * MF
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.
@ Offset
Definition DWP.cpp:577
void stable_sort(R &&Range)
Definition STLExtras.h:2132
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
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.
Definition STLExtras.h:2224
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...
Definition STLExtras.h:649
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1769
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.
Definition STLExtras.h:1963
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...
Definition Metadata.h:774
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...