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
240 : Context(C), MF(C->MF), MBB(ML.getHeader()), Loop(ML),
241 Subtarget(&MF->getSubtarget()), TII(Subtarget->getInstrInfo()),
242 TRI(Subtarget->getRegisterInfo()), MRI(&MF->getRegInfo()), MDT(MDT) {
243 TripleDAG = std::unique_ptr<ScheduleDAGInstrs>(
244 createMachineScheduler(/*OnlyBuildGraph=*/true));
245}
246
248 if (!initialize()) {
249 LLVM_DEBUG(dbgs() << "The WindowScheduler failed to initialize!\n");
250 return false;
251 }
252 // The window algorithm is time-consuming, and its compilation time should be
253 // taken into consideration.
254 TimeTraceScope Scope("WindowSearch");
255 ++NumTryWindowSchedule;
256 // Performing the relevant processing before window scheduling.
257 preProcess();
258 // The main window scheduling begins.
259 std::unique_ptr<ScheduleDAGInstrs> SchedDAG(createMachineScheduler());
260 // A target may decline to provide a scheduler, in which case fall back to the
261 // generic live scheduler so that window scheduling still has one to drive.
262 if (!SchedDAG)
263 SchedDAG.reset(createSchedLive(Context));
264 // Attach the mutation that enforces the loop-carried memory dependences.
265 // This requires the scheduler to support DAG mutations, i.e. to be a
266 // ScheduleDAGMI. Every in-tree target's pre-RA machine scheduler is a
267 // ScheduleDAGMI (or ScheduleDAGMILive), and the generic fallback
268 // createSchedLive() above returns one as well, so the cast below is safe.
269 // The assert documents and guards this invariant.
270 assert(SchedDAG && "Expected a scheduler for window scheduling");
271 auto *SchedDAGMI = static_cast<ScheduleDAGMI *>(SchedDAG.get());
272 SchedDAGMI->addMutation(std::make_unique<WindowMemDepMutation>(
274 auto SearchIndexes = getSearchIndexes(WindowSearchNum, WindowSearchRatio);
275 for (unsigned Idx : SearchIndexes) {
276 OriToCycle.clear();
277 ++NumTryWindowSearch;
278 // The scheduling starts with non-phi instruction, so SchedPhiNum needs to
279 // be added to Idx.
280 unsigned Offset = Idx + SchedPhiNum;
282 MemDepEdgeFailed = false;
283 SchedDAG->startBlock(MBB);
284 SchedDAG->enterRegion(MBB, Range.begin(), Range.end(), SchedInstrNum);
285 SchedDAG->schedule();
286 LLVM_DEBUG(SchedDAG->dump());
287 if (MemDepEdgeFailed) {
289 LLVM_DEBUG(dbgs() << "Can't enforce a loop-carried memory dependence. "
290 "Keep searching...\n");
291 continue;
292 }
293 unsigned II = analyseII(*SchedDAG, Offset);
294 if (II == WindowIILimit) {
296 LLVM_DEBUG(dbgs() << "Can't find a valid II. Keep searching...\n");
297 ++NumFailAnalyseII;
298 continue;
299 }
303 LLVM_DEBUG(dbgs() << "Current window Offset is " << Offset << " and II is "
304 << II << ".\n");
305 }
306 // Performing the relevant processing after window scheduling.
307 postProcess();
308 // Check whether the scheduling result is valid.
309 if (!isScheduleValid()) {
310 LLVM_DEBUG(dbgs() << "Window scheduling is not needed!\n");
311 return false;
312 }
313 LLVM_DEBUG(dbgs() << "\nBest window offset is " << BestOffset
314 << " and Best II is " << BestII << ".\n");
315 // Expand the scheduling result to prologue, kernel, and epilogue.
316 expand();
317 ++NumWindowSchedule;
318 return true;
319}
320
323 return OnlyBuildGraph
324 ? new ScheduleDAGMI(
325 Context, std::make_unique<PostGenericScheduler>(Context),
326 true)
327 : Context->TM->createMachineScheduler(Context);
328}
329
331 if (!Subtarget->enableWindowScheduler()) {
332 LLVM_DEBUG(dbgs() << "Target disables the window scheduling!\n");
333 return false;
334 }
335 // Initialized the member variables used by window algorithm.
336 OriMIs.clear();
337 TriMIs.clear();
338 TriToOri.clear();
339 OriToCycle.clear();
340 SchedResult.clear();
341 SchedPhiNum = 0;
342 SchedInstrNum = 0;
343 BestII = UINT_MAX;
344 BestOffset = 0;
345 BaseII = 0;
346 // List scheduling used in the window algorithm depends on LiveIntervals.
347 if (!Context->LIS) {
348 LLVM_DEBUG(dbgs() << "There is no LiveIntervals information!\n");
349 return false;
350 }
351 // Check each MI in MBB.
352 SmallSet<Register, 8> PrevDefs;
353 SmallSet<Register, 8> PrevUses;
354 auto IsLoopCarried = [&](MachineInstr &Phi) {
355 // Two cases are checked here: (1)The virtual register defined by the
356 // preceding phi is used by the succeeding phi;(2)The preceding phi uses the
357 // virtual register defined by the succeeding phi.
358 if (PrevUses.count(Phi.getOperand(0).getReg()))
359 return true;
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()))
363 return true;
364 PrevUses.insert(Phi.getOperand(I).getReg());
365 }
366 return false;
367 };
368 auto PLI = TII->analyzeLoopForPipelining(MBB);
369 for (auto &MI : *MBB) {
370 if (MI.isDebugOrPseudoInstr() || MI.isTerminator())
371 continue;
372 if (MI.isPHI()) {
373 if (IsLoopCarried(MI)) {
374 LLVM_DEBUG(dbgs() << "Loop carried phis are not supported yet!\n");
375 return false;
376 }
377 ++SchedPhiNum;
378 ++BestOffset;
379 } else
381 if (TII->isSchedulingBoundary(MI, MBB, *MF)) {
383 dbgs() << "Boundary MI is not allowed in window scheduling!\n");
384 return false;
385 }
386 if (PLI->shouldIgnoreForPipelining(&MI)) {
387 LLVM_DEBUG(dbgs() << "Special MI defined by target is not allowed in "
388 "window scheduling!\n");
389 return false;
390 }
391 for (auto &Def : MI.all_defs())
392 if (Def.isReg() && Def.getReg().isPhysical()) {
393 LLVM_DEBUG(dbgs() << "Physical registers are not supported in "
394 "window scheduling!\n");
395 return false;
396 }
397 }
398 if (SchedInstrNum <= WindowRegionLimit) {
399 LLVM_DEBUG(dbgs() << "There are too few MIs in the window region!\n");
400 return false;
401 }
402 return true;
403}
404
406 // Prior to window scheduling, it's necessary to backup the original MBB,
407 // generate a new TripleMBB, and build a TripleDAG based on the TripleMBB.
408 // Collect loop-carried memory dependences first, while the original MBB is
409 // still live (see collectLoopCarriedMemDeps() and run()).
411 backupMBB();
413 TripleDAG->startBlock(MBB);
414 TripleDAG->enterRegion(
415 MBB, MBB->begin(), MBB->getFirstTerminator(),
416 std::distance(MBB->begin(), MBB->getFirstTerminator()));
417 TripleDAG->buildSchedGraph(Context->AA);
418}
419
421 LoopCarriedMemDeps.clear();
422 MachineBasicBlock *LoopBB = MBB;
423
424 // Collect the memory instructions of the original loop in program order.
426 for (MachineInstr &MI : *LoopBB)
427 if (MI.mayLoadOrStore() && !MI.isDebugInstr())
428 MemMIs.push_back(&MI);
429
430 // Nothing to do unless there is at least one store to order against.
431 if (llvm::none_of(MemMIs,
432 [](const MachineInstr *MI) { return MI->mayStore(); }))
433 return;
434
435 BatchAAResults BAA(*Context->AA);
437
438 for (MachineInstr *SrcMI : MemMIs) {
439 for (MachineInstr *DstMI : MemMIs) {
440 if (SrcMI == DstMI)
441 continue;
442 // A loop-carried order edge is only required when at least one of the
443 // accesses stores.
444 if (!SrcMI->mayStore() && !DstMI->mayStore())
445 continue;
446 if (hasLoopCarriedMemDep(SrcMI, DstMI, BAA, LoopBB, *MRI, TII))
447 LoopCarriedMemDeps.insert({SrcMI, DstMI});
448 }
449 }
450}
451
453 // After window scheduling, it's necessary to clear the TripleDAG and restore
454 // to the original MBB.
455 TripleDAG->exitRegion();
456 TripleDAG->finishBlock();
457 restoreMBB();
458}
459
461 for (auto &MI : MBB->instrs())
462 OriMIs.push_back(&MI);
463 // Remove MIs and the corresponding live intervals.
464 for (auto &MI : make_early_inc_range(*MBB)) {
465 Context->LIS->getSlotIndexes()->removeMachineInstrFromMaps(MI, true);
466 MBB->remove(&MI);
467 }
468}
469
471 // Erase MIs and the corresponding live intervals.
472 for (auto &MI : make_early_inc_range(*MBB)) {
473 Context->LIS->getSlotIndexes()->removeMachineInstrFromMaps(MI, true);
474 MI.eraseFromParent();
475 }
476 // Restore MBB to the state before window scheduling.
479}
480
482 const unsigned DuplicateNum = 3;
483 TriMIs.clear();
484 TriToOri.clear();
485 assert(OriMIs.size() > 0 && "The Original MIs were not backed up!");
486 // Step 1: Performing the first copy of MBB instructions, excluding
487 // terminators. At the same time, we back up the anti-register of phis.
488 // DefPairs hold the old and new define register pairs.
490 for (auto *MI : OriMIs) {
491 if (MI->isDebugOrPseudoInstr() || MI->isTerminator())
492 continue;
493 if (MI->isPHI())
494 if (Register AntiReg = getAntiRegister(MI))
495 DefPairs[MI->getOperand(0).getReg()] = AntiReg;
496 auto *NewMI = MF->CloneMachineInstr(MI);
497 MBB->push_back(NewMI);
498 TriMIs.push_back(NewMI);
499 TriToOri[NewMI] = {MI, 0};
500 }
501 // Step 2: Performing the remaining two copies of MBB instructions excluding
502 // phis, and the last one contains terminators. At the same time, registers
503 // are updated accordingly.
504 for (size_t Cnt = 1; Cnt < DuplicateNum; ++Cnt) {
505 for (auto *MI : OriMIs) {
506 if (MI->isPHI() || MI->isDebugOrPseudoInstr() ||
507 (MI->isTerminator() && Cnt < DuplicateNum - 1))
508 continue;
509 auto *NewMI = MF->CloneMachineInstr(MI);
511 // New defines are updated.
512 for (auto MO : NewMI->all_defs())
513 if (MO.isReg() && MO.getReg().isVirtual()) {
514 Register NewDef =
515 MRI->createVirtualRegister(MRI->getRegClass(MO.getReg()));
516 NewMI->substituteRegister(MO.getReg(), NewDef, 0, *TRI);
517 NewDefs[MO.getReg()] = NewDef;
518 }
519 // New uses are updated.
520 for (auto DefRegPair : DefPairs)
521 if (NewMI->readsRegister(DefRegPair.first, TRI)) {
522 Register NewUse = DefRegPair.second;
523 // Note the update process for '%1 -> %9' in '%10 = sub i32 %9, %3':
524 //
525 // BB.3: DefPairs
526 // ==================================
527 // %1 = phi i32 [%2, %BB.1], [%7, %BB.3] (%1,%7)
528 // ...
529 // ==================================
530 // ...
531 // %4 = sub i32 %1, %3
532 // ...
533 // %7 = add i32 %5, %6
534 // ...
535 // ----------------------------------
536 // ...
537 // %8 = sub i32 %7, %3 (%1,%7),(%4,%8)
538 // ...
539 // %9 = add i32 %5, %6 (%1,%7),(%4,%8),(%7,%9)
540 // ...
541 // ----------------------------------
542 // ...
543 // %10 = sub i32 %9, %3 (%1,%7),(%4,%10),(%7,%9)
544 // ... ^
545 // %11 = add i32 %5, %6 (%1,%7),(%4,%10),(%7,%11)
546 // ...
547 // ==================================
548 // < Terminators >
549 // ==================================
550 if (auto It = DefPairs.find(NewUse); It != DefPairs.end())
551 NewUse = It->second;
552 NewMI->substituteRegister(DefRegPair.first, NewUse, 0, *TRI);
553 }
554 // DefPairs is updated at last.
555 for (auto &NewDef : NewDefs)
556 DefPairs[NewDef.first] = NewDef.second;
557 MBB->push_back(NewMI);
558 TriMIs.push_back(NewMI);
559 TriToOri[NewMI] = {MI, static_cast<unsigned>(Cnt)};
560 }
561 }
562 // Step 3: The registers used by phis are updated, and they are generated in
563 // the third copy of MBB.
564 // In the privious example, the old phi is:
565 // %1 = phi i32 [%2, %BB.1], [%7, %BB.3]
566 // The new phi is:
567 // %1 = phi i32 [%2, %BB.1], [%11, %BB.3]
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);
572 }
574}
575
577 // After list scheduling, the MBB is restored in one traversal.
578 for (size_t I = 0; I < TriMIs.size(); ++I) {
579 auto *MI = TriMIs[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);
585 Context->LIS->handleMove(*MI, /*UpdateFlags=*/false);
586 }
587 }
588}
589
591 unsigned SearchRatio) {
592 // We use SearchRatio to get the index range, and then evenly get the indexes
593 // according to the SearchNum. This is a simple huristic. Depending on the
594 // characteristics of the target, more complex algorithms can be used for both
595 // performance and compilation time.
596 assert(SearchRatio <= 100 && "SearchRatio should be equal or less than 100!");
597 unsigned MaxIdx = SchedInstrNum * SearchRatio / 100;
598 unsigned Step = SearchNum > 0 && SearchNum <= MaxIdx ? MaxIdx / SearchNum : 1;
599 SmallVector<unsigned> SearchIndexes;
600 for (unsigned Idx = 0; Idx < MaxIdx; Idx += Step)
601 SearchIndexes.push_back(Idx);
602 return SearchIndexes;
603}
604
606 // Sometimes MaxDepth is 0, so it should be limited to the minimum of 1.
607 unsigned MaxDepth = 1;
608 for (auto &SU : DAG.SUnits)
609 MaxDepth = std::max(SU.getDepth() + SU.Latency, MaxDepth);
610 return MaxDepth * WindowIICoeff;
611}
612
614 unsigned Offset) {
615 int InitII = getEstimatedII(DAG);
616 ResourceManager RM(Subtarget, &DAG);
617 RM.init(InitII);
618 // ResourceManager and DAG are used to calculate the maximum cycle for the
619 // scheduled MIs. Since MIs in the Region have already been scheduled, the
620 // emit cycles can be estimated in order here.
621 int CurCycle = 0;
623 for (auto &MI : Range) {
624 auto *SU = DAG.getSUnit(&MI);
625 int ExpectCycle = CurCycle;
626 // The predecessors of current MI determine its earliest issue cycle.
627 for (auto &Pred : SU->Preds) {
628 if (Pred.isWeak())
629 continue;
630 auto *PredMI = Pred.getSUnit()->getInstr();
631 int PredCycle = getOriCycle(PredMI);
632 ExpectCycle = std::max(ExpectCycle, PredCycle + (int)Pred.getLatency());
633 }
634 // Zero cost instructions do not need to check resource.
635 if (!TII->isZeroCost(MI.getOpcode())) {
636 // ResourceManager can be used to detect resource conflicts between the
637 // current MI and the previously inserted MIs.
638 while (!RM.canReserveResources(*SU, CurCycle) || CurCycle < ExpectCycle) {
639 ++CurCycle;
640 if (CurCycle == (int)WindowIILimit)
641 return CurCycle;
642 }
643 RM.reserveResources(*SU, CurCycle);
644 }
645 OriToCycle[getOriMI(&MI)] = CurCycle;
646 LLVM_DEBUG(dbgs() << "\tCycle " << CurCycle << " [S."
647 << getOriStage(getOriMI(&MI), Offset) << "]: " << MI);
648 }
649 LLVM_DEBUG(dbgs() << "MaxCycle is " << CurCycle << ".\n");
650 return CurCycle;
651}
652
653// By utilizing TripleDAG, we can easily establish dependencies between A and B.
654// Based on the MaxCycle and the issue cycle of A and B, we can determine
655// whether it is necessary to add a stall cycle. This is because, without
656// inserting the stall cycle, the latency constraint between A and B cannot be
657// satisfied. The details are as follows:
658//
659// New MBB:
660// ========================================
661// < Phis >
662// ======================================== (sliding direction)
663// MBB copy 1 |
664// V
665//
666// ~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~~ ----schedule window-----
667// | |
668// ===================V==================== |
669// MBB copy 2 < MI B > |
670// |
671// < MI A > V
672// ~~~~~~~~~~~~~~~~~~~:~~~~~~~~~~~~~~~~~~~~ ------------------------
673// :
674// ===================V====================
675// MBB copy 3 < MI B'>
676//
677//
678//
679//
680// ========================================
681// < Terminators >
682// ========================================
683int WindowScheduler::calculateStallCycle(unsigned Offset, int MaxCycle) {
684 int MaxStallCycle = 0;
685 int CurrentII = MaxCycle + 1;
687 for (auto &MI : Range) {
688 auto *SU = TripleDAG->getSUnit(&MI);
689 int DefCycle = getOriCycle(&MI);
690 for (auto &Succ : SU->Succs) {
691 if (Succ.isWeak() || Succ.getSUnit() == &TripleDAG->ExitSU)
692 continue;
693 // If the expected cycle does not exceed CurrentII, no check is needed.
694 if (DefCycle + (int)Succ.getLatency() <= CurrentII)
695 continue;
696 // If the cycle of the scheduled MI A is less than that of the scheduled
697 // MI B, the scheduling will fail because the lifetime of the
698 // corresponding register exceeds II.
699 auto *SuccMI = Succ.getSUnit()->getInstr();
700 int UseCycle = getOriCycle(SuccMI);
701 if (DefCycle < UseCycle)
702 return WindowIILimit;
703 // Get the stall cycle introduced by the register between two trips.
704 int StallCycle = DefCycle + (int)Succ.getLatency() - CurrentII - UseCycle;
705 MaxStallCycle = std::max(MaxStallCycle, StallCycle);
706 }
707 }
708 LLVM_DEBUG(dbgs() << "MaxStallCycle is " << MaxStallCycle << ".\n");
709 return MaxStallCycle;
710}
711
713 LLVM_DEBUG(dbgs() << "Start analyzing II:\n");
714 int MaxCycle = calculateMaxCycle(DAG, Offset);
715 if (MaxCycle == (int)WindowIILimit)
716 return MaxCycle;
717 int StallCycle = calculateStallCycle(Offset, MaxCycle);
718 if (StallCycle == (int)WindowIILimit)
719 return StallCycle;
720 // The value of II is equal to the maximum execution cycle plus 1.
721 return MaxCycle + StallCycle + 1;
722}
723
725 LLVM_DEBUG(dbgs() << "Start scheduling Phis:\n");
726 for (auto &Phi : MBB->phis()) {
727 int LateCycle = INT_MAX;
728 auto *SU = TripleDAG->getSUnit(&Phi);
729 for (auto &Succ : SU->Succs) {
730 // Phi doesn't have any Anti successors.
731 if (Succ.getKind() != SDep::Data)
732 continue;
733 // Phi is scheduled before the successor of stage 0. The issue cycle of
734 // phi is the latest cycle in this interval.
735 auto *SuccMI = Succ.getSUnit()->getInstr();
736 int Cycle = getOriCycle(SuccMI);
737 if (getOriStage(getOriMI(SuccMI), Offset) == 0)
738 LateCycle = std::min(LateCycle, Cycle);
739 }
740 // The anti-dependency of phi need to be handled separately in the same way.
741 if (Register AntiReg = getAntiRegister(&Phi)) {
742 auto *AntiMI = MRI->getVRegDef(AntiReg);
743 // AntiReg may be defined outside the kernel MBB.
744 if (AntiMI->getParent() == MBB) {
745 auto AntiCycle = getOriCycle(AntiMI);
746 if (getOriStage(getOriMI(AntiMI), Offset) == 0)
747 LateCycle = std::min(LateCycle, AntiCycle);
748 }
749 }
750 // If there is no limit to the late cycle, a default value is given.
751 if (LateCycle == INT_MAX)
752 LateCycle = (int)(II - 1);
753 LLVM_DEBUG(dbgs() << "\tCycle range [0, " << LateCycle << "] " << Phi);
754 // The issue cycle of phi is set to the latest cycle in the interval.
755 auto *OriPhi = getOriMI(&Phi);
756 OriToCycle[OriPhi] = LateCycle;
757 }
758}
759
761 unsigned II) {
762 // At each issue cycle, phi is placed before MIs in stage 0. So the simplest
763 // way is to put phi at the beginning of the current cycle.
766 for (auto &Phi : MBB->phis())
767 CycleToMIs[getOriCycle(&Phi)].push_back(getOriMI(&Phi));
768 for (auto &MI : Range)
769 CycleToMIs[getOriCycle(&MI)].push_back(getOriMI(&MI));
770 // Each MI is assigned a separate ordered Id, which is used as a sort marker
771 // in the following expand process.
773 int Id = 0;
774 for (int Cycle = 0; Cycle < (int)II; ++Cycle) {
775 auto It = CycleToMIs.find(Cycle);
776 if (It == CycleToMIs.end())
777 continue;
778 for (auto *MI : It->second)
779 IssueOrder[MI] = Id++;
780 }
781 return IssueOrder;
782}
783
785 // At the first update, Offset is equal to SchedPhiNum. At this time, only
786 // BestII, BestOffset, and BaseII need to be updated.
787 if (Offset == SchedPhiNum) {
788 BestII = II;
790 BaseII = II;
791 return;
792 }
793 // The update will only continue if the II is smaller than BestII and the II
794 // is sufficiently small.
795 if ((II >= BestII) || (II + WindowDiffLimit > BaseII))
796 return;
797 BestII = II;
799 // Record the result of the current list scheduling, noting that each MI is
800 // stored unordered in SchedResult.
801 SchedResult.clear();
802 auto IssueOrder = getIssueOrder(Offset, II);
803 for (auto &Pair : OriToCycle) {
804 assert(IssueOrder.count(Pair.first) && "Cannot find original MI!");
805 SchedResult.push_back(std::make_tuple(Pair.first, Pair.second,
806 getOriStage(Pair.first, Offset),
807 IssueOrder[Pair.first]));
808 }
809}
810
812 // The MIs in the SchedResult are sorted by the issue order ID.
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);
817 });
818 // Use the scheduling infrastructure for expansion, noting that InstrChanges
819 // is not supported here.
820 DenseMap<MachineInstr *, int> Cycles, Stages;
821 std::vector<MachineInstr *> OrderedInsts;
822 for (auto &Info : SchedResult) {
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);
827 LLVM_DEBUG(dbgs() << "\tCycle " << Cycles[MI] << " [S." << Stages[MI]
828 << "]: " << *MI);
829 }
830 ModuloSchedule MS(*MF, &Loop, std::move(OrderedInsts), std::move(Cycles),
831 std::move(Stages));
832 ModuloScheduleExpander MSE(*MF, MS, *Context->LIS,
834 MSE.expand();
835 MSE.cleanup();
836}
837
840 for (MachineInstr &MI : *MBB)
841 for (const MachineOperand &MO : MI.operands()) {
842 if (!MO.isReg() || MO.getReg() == 0)
843 continue;
844 Register Reg = MO.getReg();
845 if (!is_contained(UsedRegs, Reg))
846 UsedRegs.push_back(Reg);
847 }
848 Context->LIS->repairIntervalsInRange(MBB, MBB->begin(), MBB->end(), UsedRegs);
849}
850
853 auto RegionBegin = MBB->begin();
854 std::advance(RegionBegin, Offset);
855 auto RegionEnd = RegionBegin;
856 std::advance(RegionEnd, Num);
857 return make_range(RegionBegin, RegionEnd);
858}
859
861 assert(TriToOri.count(NewMI) && "Cannot find original MI!");
862 auto *OriMI = TriToOri[NewMI].Ori;
863 assert(OriToCycle.count(OriMI) && "Cannot find schedule cycle!");
864 return OriToCycle[OriMI];
865}
866
868 assert(TriToOri.count(NewMI) && "Cannot find original MI!");
869 return TriToOri[NewMI].Ori;
870}
871
873 assert(llvm::is_contained(OriMIs, OriMI) && "Cannot find OriMI in OriMIs!");
874 // If there is no instruction fold, all MI stages are 0.
875 if (Offset == SchedPhiNum)
876 return 0;
877 // For those MIs with an ID less than the Offset, their stages are set to 0,
878 // while the rest are set to 1.
879 unsigned Id = 0;
880 for (auto *MI : OriMIs) {
881 if (MI->isDebugOrPseudoInstr())
882 continue;
883 if (MI == OriMI)
884 break;
885 ++Id;
886 }
887 return Id >= (size_t)Offset ? 1 : 0;
888}
889
891 assert(Phi->isPHI() && "Expecting PHI!");
892 Register AntiReg;
893 for (auto MO : Phi->uses()) {
894 if (MO.isReg())
895 AntiReg = MO.getReg();
896 else if (MO.isMBB() && MO.getMBB() == MBB)
897 return AntiReg;
898 }
899 return 0;
900}
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
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.
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.
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
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.
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...