LLVM 24.0.0git
SIMachineScheduler.cpp
Go to the documentation of this file.
1//===-- SIMachineScheduler.cpp - SI Scheduler Interface -------------------===//
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/// \file
10/// SI Machine Scheduler interface
11//
12//===----------------------------------------------------------------------===//
13
14#include "SIMachineScheduler.h"
15#include "SIInstrInfo.h"
18
19using namespace llvm;
20
21#define DEBUG_TYPE "machine-scheduler"
22
23// This scheduler implements a different scheduling algorithm than
24// GenericScheduler.
25//
26// There are several specific architecture behaviours that can't be modelled
27// for GenericScheduler:
28// . When accessing the result of an SGPR load instruction, you have to wait
29// for all the SGPR load instructions before your current instruction to
30// have finished.
31// . When accessing the result of an VGPR load instruction, you have to wait
32// for all the VGPR load instructions previous to the VGPR load instruction
33// you are interested in to finish.
34// . The less the register pressure, the best load latencies are hidden
35//
36// Moreover some specifities (like the fact a lot of instructions in the shader
37// have few dependencies) makes the generic scheduler have some unpredictable
38// behaviours. For example when register pressure becomes high, it can either
39// manage to prevent register pressure from going too high, or it can
40// increase register pressure even more than if it hadn't taken register
41// pressure into account.
42//
43// Also some other bad behaviours are generated, like loading at the beginning
44// of the shader a constant in VGPR you won't need until the end of the shader.
45//
46// The scheduling problem for SI can distinguish three main parts:
47// . Hiding high latencies (texture sampling, etc)
48// . Hiding low latencies (SGPR constant loading, etc)
49// . Keeping register usage low for better latency hiding and general
50// performance
51//
52// Some other things can also affect performance, but are hard to predict
53// (cache usage, the fact the HW can issue several instructions from different
54// wavefronts if different types, etc)
55//
56// This scheduler tries to solve the scheduling problem by dividing it into
57// simpler sub-problems. It divides the instructions into blocks, schedules
58// locally inside the blocks where it takes care of low latencies, and then
59// chooses the order of the blocks by taking care of high latencies.
60// Dividing the instructions into blocks helps control keeping register
61// usage low.
62//
63// First the instructions are put into blocks.
64// We want the blocks help control register usage and hide high latencies
65// later. To help control register usage, we typically want all local
66// computations, when for example you create a result that can be consumed
67// right away, to be contained in a block. Block inputs and outputs would
68// typically be important results that are needed in several locations of
69// the shader. Since we do want blocks to help hide high latencies, we want
70// the instructions inside the block to have a minimal set of dependencies
71// on high latencies. It will make it easy to pick blocks to hide specific
72// high latencies.
73// The block creation algorithm is divided into several steps, and several
74// variants can be tried during the scheduling process.
75//
76// Second the order of the instructions inside the blocks is chosen.
77// At that step we do take into account only register usage and hiding
78// low latency instructions
79//
80// Third the block order is chosen, there we try to hide high latencies
81// and keep register usage low.
82//
83// After the third step, a pass is done to improve the hiding of low
84// latencies.
85//
86// Actually when talking about 'low latency' or 'high latency' it includes
87// both the latency to get the cache (or global mem) data go to the register,
88// and the bandwidth limitations.
89// Increasing the number of active wavefronts helps hide the former, but it
90// doesn't solve the latter, thus why even if wavefront count is high, we have
91// to try have as many instructions hiding high latencies as possible.
92// The OpenCL doc says for example latency of 400 cycles for a global mem
93// access, which is hidden by 10 instructions if the wavefront count is 10.
94
95// Some figures taken from AMD docs:
96// Both texture and constant L1 caches are 4-way associative with 64 bytes
97// lines.
98// Constant cache is shared with 4 CUs.
99// For texture sampling, the address generation unit receives 4 texture
100// addresses per cycle, thus we could expect texture sampling latency to be
101// equivalent to 4 instructions in the very best case (a VGPR is 64 work items,
102// instructions in a wavefront group are executed every 4 cycles),
103// or 16 instructions if the other wavefronts associated to the 3 other VALUs
104// of the CU do texture sampling too. (Don't take these figures too seriously,
105// as I'm not 100% sure of the computation)
106// Data exports should get similar latency.
107// For constant loading, the cache is shader with 4 CUs.
108// The doc says "a throughput of 16B/cycle for each of the 4 Compute Unit"
109// I guess if the other CU don't read the cache, it can go up to 64B/cycle.
110// It means a simple s_buffer_load should take one instruction to hide, as
111// well as a s_buffer_loadx2 and potentially a s_buffer_loadx8 if on the same
112// cache line.
113//
114// As of today the driver doesn't preload the constants in cache, thus the
115// first loads get extra latency. The doc says global memory access can be
116// 300-600 cycles. We do not specially take that into account when scheduling
117// As we expect the driver to be able to preload the constants soon.
118
119// common code //
120
121#ifndef NDEBUG
122
123static const char *getReasonStr(SIScheduleCandReason Reason) {
124 switch (Reason) {
125 case NoCand: return "NOCAND";
126 case RegUsage: return "REGUSAGE";
127 case Latency: return "LATENCY";
128 case Successor: return "SUCCESSOR";
129 case Depth: return "DEPTH";
130 case NodeOrder: return "ORDER";
131 }
132 llvm_unreachable("Unknown reason!");
133}
134
135#endif
136
137namespace llvm::SISched {
138static bool tryLess(int TryVal, int CandVal,
139 SISchedulerCandidate &TryCand,
141 SIScheduleCandReason Reason) {
142 if (TryVal < CandVal) {
143 TryCand.Reason = Reason;
144 return true;
145 }
146 if (TryVal > CandVal) {
147 if (Cand.Reason > Reason)
148 Cand.Reason = Reason;
149 return true;
150 }
151 Cand.setRepeat(Reason);
152 return false;
153}
154
155static bool tryGreater(int TryVal, int CandVal,
156 SISchedulerCandidate &TryCand,
158 SIScheduleCandReason Reason) {
159 if (TryVal > CandVal) {
160 TryCand.Reason = Reason;
161 return true;
162 }
163 if (TryVal < CandVal) {
164 if (Cand.Reason > Reason)
165 Cand.Reason = Reason;
166 return true;
167 }
168 Cand.setRepeat(Reason);
169 return false;
170}
171} // end namespace llvm::SISched
172
173// SIScheduleBlock //
174
176 NodeNum2Index[SU->NodeNum] = SUnits.size();
177 SUnits.push_back(SU);
178}
179
180#ifndef NDEBUG
181void SIScheduleBlock::traceCandidate(const SISchedCandidate &Cand) {
182
183 dbgs() << " " << *Cand.SU << " " << getReasonStr(Cand.Reason);
184 dbgs() << '\n';
185}
186#endif
187
188void SIScheduleBlock::tryCandidateTopDown(SISchedCandidate &Cand,
189 SISchedCandidate &TryCand) {
190 // Initialize the candidate if needed.
191 if (!Cand.isValid()) {
192 TryCand.Reason = NodeOrder;
193 return;
194 }
195
196 if (Cand.SGPRUsage > 60 &&
197 SISched::tryLess(TryCand.SGPRUsage, Cand.SGPRUsage,
198 TryCand, Cand, RegUsage))
199 return;
200
201 // Schedule low latency instructions as top as possible.
202 // Order of priority is:
203 // . Low latency instructions which do not depend on other low latency
204 // instructions we haven't waited for
205 // . Other instructions which do not depend on low latency instructions
206 // we haven't waited for
207 // . Low latencies
208 // . All other instructions
209 // Goal is to get: low latency instructions - independent instructions
210 // - (eventually some more low latency instructions)
211 // - instructions that depend on the first low latency instructions.
212 // If in the block there is a lot of constant loads, the SGPR usage
213 // could go quite high, thus above the arbitrary limit of 60 will encourage
214 // use the already loaded constants (in order to release some SGPRs) before
215 // loading more.
216 if (SISched::tryLess(TryCand.HasLowLatencyNonWaitedParent,
217 Cand.HasLowLatencyNonWaitedParent,
218 TryCand, Cand, SIScheduleCandReason::Depth))
219 return;
220
221 if (SISched::tryGreater(TryCand.IsLowLatency, Cand.IsLowLatency,
222 TryCand, Cand, SIScheduleCandReason::Depth))
223 return;
224
225 if (TryCand.IsLowLatency &&
226 SISched::tryLess(TryCand.LowLatencyOffset, Cand.LowLatencyOffset,
227 TryCand, Cand, SIScheduleCandReason::Depth))
228 return;
229
230 if (SISched::tryLess(TryCand.VGPRUsage, Cand.VGPRUsage,
231 TryCand, Cand, RegUsage))
232 return;
233
234 // Fall through to original instruction order.
235 if (TryCand.SU->NodeNum < Cand.SU->NodeNum) {
236 TryCand.Reason = NodeOrder;
237 }
238}
239
240SUnit* SIScheduleBlock::pickNode() {
241 SISchedCandidate TopCand;
242
243 for (SUnit* SU : TopReadySUs) {
244 SISchedCandidate TryCand;
245 std::vector<unsigned> pressure;
246 std::vector<unsigned> MaxPressure;
247 // Predict register usage after this instruction.
248 TryCand.SU = SU;
249 TopRPTracker.getDownwardPressure(SU->getInstr(), pressure, MaxPressure);
250 TryCand.SGPRUsage = pressure[AMDGPU::RegisterPressureSets::SReg_32];
251 TryCand.VGPRUsage = pressure[AMDGPU::RegisterPressureSets::VGPR_32];
252 TryCand.IsLowLatency = DAG->IsLowLatencySU[SU->NodeNum];
253 TryCand.LowLatencyOffset = DAG->LowLatencyOffset[SU->NodeNum];
254 TryCand.HasLowLatencyNonWaitedParent =
255 HasLowLatencyNonWaitedParent[NodeNum2Index[SU->NodeNum]];
256 tryCandidateTopDown(TopCand, TryCand);
257 if (TryCand.Reason != NoCand)
258 TopCand.setBest(TryCand);
259 }
260
261 return TopCand.SU;
262}
263
264
265// Schedule something valid.
267 TopReadySUs.clear();
268 if (Scheduled)
269 undoSchedule();
270
271 for (SUnit* SU : SUnits) {
272 if (!SU->NumPredsLeft)
273 TopReadySUs.push_back(SU);
274 }
275
276 while (!TopReadySUs.empty()) {
277 SUnit *SU = TopReadySUs[0];
278 ScheduledSUnits.push_back(SU);
279 nodeScheduled(SU);
280 }
281
282 Scheduled = true;
283}
284
285// Returns if the register was set between first and last.
288 const LiveIntervals *LIS) {
289 for (const MachineInstr &MI : MRI->def_instructions(Reg)) {
290 if (MI.isDebugValue())
291 continue;
292 SlotIndex InstSlot = LIS->getInstructionIndex(MI).getRegSlot();
293 if (InstSlot >= First && InstSlot <= Last)
294 return true;
295 }
296 return false;
297}
298
299void SIScheduleBlock::initRegPressure(MachineBasicBlock::iterator BeginBlock,
301 IntervalPressure Pressure, BotPressure;
302 RegPressureTracker RPTracker(Pressure), BotRPTracker(BotPressure);
303 LiveIntervals *LIS = DAG->getLIS();
304 MachineRegisterInfo *MRI = DAG->getMRI();
305 DAG->initRPTracker(TopRPTracker);
306 DAG->initRPTracker(BotRPTracker);
307 DAG->initRPTracker(RPTracker);
308
309 // Goes though all SU. RPTracker captures what had to be alive for the SUs
310 // to execute, and what is still alive at the end.
311 for (SUnit* SU : ScheduledSUnits) {
312 RPTracker.setPos(SU->getInstr());
313 RPTracker.advance();
314 }
315
316 // Close the RPTracker to finalize live ins/outs.
317 RPTracker.closeRegion();
318
319 // Initialize the live ins and live outs.
320 TopRPTracker.addLiveRegs(RPTracker.getPressure().LiveInRegs);
321 BotRPTracker.addLiveRegs(RPTracker.getPressure().LiveOutRegs);
322
323 // Do not Track Physical Registers, because it messes up.
324 for (const auto &RegMaskPair : RPTracker.getPressure().LiveInRegs) {
325 if (RegMaskPair.VRegOrUnit.isVirtualReg())
326 LiveInRegs.insert(RegMaskPair.VRegOrUnit.asVirtualReg());
327 }
328 LiveOutRegs.clear();
329 // There is several possibilities to distinguish:
330 // 1) Reg is not input to any instruction in the block, but is output of one
331 // 2) 1) + read in the block and not needed after it
332 // 3) 1) + read in the block but needed in another block
333 // 4) Reg is input of an instruction but another block will read it too
334 // 5) Reg is input of an instruction and then rewritten in the block.
335 // result is not read in the block (implies used in another block)
336 // 6) Reg is input of an instruction and then rewritten in the block.
337 // result is read in the block and not needed in another block
338 // 7) Reg is input of an instruction and then rewritten in the block.
339 // result is read in the block but also needed in another block
340 // LiveInRegs will contains all the regs in situation 4, 5, 6, 7
341 // We want LiveOutRegs to contain only Regs whose content will be read after
342 // in another block, and whose content was written in the current block,
343 // that is we want it to get 1, 3, 5, 7
344 // Since we made the MIs of a block to be packed all together before
345 // scheduling, then the LiveIntervals were correct, and the RPTracker was
346 // able to correctly handle 5 vs 6, 2 vs 3.
347 // (Note: This is not sufficient for RPTracker to not do mistakes for case 4)
348 // The RPTracker's LiveOutRegs has 1, 3, (some correct or incorrect)4, 5, 7
349 // Comparing to LiveInRegs is not sufficient to differentiate 4 vs 5, 7
350 // The use of findDefBetween removes the case 4.
351 for (const auto &RegMaskPair : RPTracker.getPressure().LiveOutRegs) {
352 VirtRegOrUnit VRegOrUnit = RegMaskPair.VRegOrUnit;
353 if (VRegOrUnit.isVirtualReg() &&
354 isDefBetween(VRegOrUnit.asVirtualReg(),
355 LIS->getInstructionIndex(*BeginBlock).getRegSlot(),
356 LIS->getInstructionIndex(*EndBlock).getRegSlot(), MRI,
357 LIS)) {
358 LiveOutRegs.insert(VRegOrUnit.asVirtualReg());
359 }
360 }
361
362 // Pressure = sum_alive_registers register size
363 // Internally llvm will represent some registers as big 128 bits registers
364 // for example, but they actually correspond to 4 actual 32 bits registers.
365 // Thus Pressure is not equal to num_alive_registers * constant.
366 LiveInPressure = TopPressure.MaxSetPressure;
367 LiveOutPressure = BotPressure.MaxSetPressure;
368
369 // Prepares TopRPTracker for top down scheduling.
370 TopRPTracker.closeTop();
371}
372
375 if (!Scheduled)
376 fastSchedule();
377
378 // PreScheduling phase to set LiveIn and LiveOut.
379 initRegPressure(BeginBlock, EndBlock);
380 undoSchedule();
381
382 // Schedule for real now.
383
384 TopReadySUs.clear();
385
386 for (SUnit* SU : SUnits) {
387 if (!SU->NumPredsLeft)
388 TopReadySUs.push_back(SU);
389 }
390
391 while (!TopReadySUs.empty()) {
392 SUnit *SU = pickNode();
393 ScheduledSUnits.push_back(SU);
394 TopRPTracker.setPos(SU->getInstr());
395 TopRPTracker.advance();
396 nodeScheduled(SU);
397 }
398
399 // TODO: compute InternalAdditionalPressure.
400 InternalAdditionalPressure.resize(TopPressure.MaxSetPressure.size());
401
402 // Check everything is right.
403#ifndef NDEBUG
404 assert(SUnits.size() == ScheduledSUnits.size() &&
405 TopReadySUs.empty());
406 for (SUnit* SU : SUnits) {
407 assert(SU->isScheduled &&
408 SU->NumPredsLeft == 0);
409 }
410#endif
411
412 Scheduled = true;
413}
414
415void SIScheduleBlock::undoSchedule() {
416 for (SUnit* SU : SUnits) {
417 SU->isScheduled = false;
418 for (SDep& Succ : SU->Succs) {
419 if (BC->isSUInBlock(Succ.getSUnit(), ID))
420 undoReleaseSucc(SU, &Succ);
421 }
422 }
423 HasLowLatencyNonWaitedParent.assign(SUnits.size(), 0);
424 ScheduledSUnits.clear();
425 Scheduled = false;
426}
427
428void SIScheduleBlock::undoReleaseSucc(SUnit *SU, SDep *SuccEdge) {
429 SUnit *SuccSU = SuccEdge->getSUnit();
430
431 if (SuccEdge->isWeak()) {
432 ++SuccSU->WeakPredsLeft;
433 return;
434 }
435 ++SuccSU->NumPredsLeft;
436}
437
438void SIScheduleBlock::releaseSucc(SUnit *SU, SDep *SuccEdge) {
439 SUnit *SuccSU = SuccEdge->getSUnit();
440
441 if (SuccEdge->isWeak()) {
442 --SuccSU->WeakPredsLeft;
443 return;
444 }
445#ifndef NDEBUG
446 if (SuccSU->NumPredsLeft == 0) {
447 dbgs() << "*** Scheduling failed! ***\n";
448 DAG->dumpNode(*SuccSU);
449 dbgs() << " has been released too many times!\n";
450 llvm_unreachable(nullptr);
451 }
452#endif
453
454 --SuccSU->NumPredsLeft;
455}
456
457/// Release Successors of the SU that are in the block or not.
458void SIScheduleBlock::releaseSuccessors(SUnit *SU, bool InOrOutBlock) {
459 for (SDep& Succ : SU->Succs) {
460 SUnit *SuccSU = Succ.getSUnit();
461
462 if (SuccSU->NodeNum >= DAG->SUnits.size())
463 continue;
464
465 if (BC->isSUInBlock(SuccSU, ID) != InOrOutBlock)
466 continue;
467
468 releaseSucc(SU, &Succ);
469 if (SuccSU->NumPredsLeft == 0 && InOrOutBlock)
470 TopReadySUs.push_back(SuccSU);
471 }
472}
473
474void SIScheduleBlock::nodeScheduled(SUnit *SU) {
475 // Is in TopReadySUs
476 assert (!SU->NumPredsLeft);
477 std::vector<SUnit *>::iterator I = llvm::find(TopReadySUs, SU);
478 if (I == TopReadySUs.end()) {
479 dbgs() << "Data Structure Bug in SI Scheduler\n";
480 llvm_unreachable(nullptr);
481 }
482 TopReadySUs.erase(I);
483
484 releaseSuccessors(SU, true);
485 // Scheduling this node will trigger a wait,
486 // thus propagate to other instructions that they do not need to wait either.
487 if (HasLowLatencyNonWaitedParent[NodeNum2Index[SU->NodeNum]])
488 HasLowLatencyNonWaitedParent.assign(SUnits.size(), 0);
489
490 if (DAG->IsLowLatencySU[SU->NodeNum]) {
491 for (SDep& Succ : SU->Succs) {
492 std::map<unsigned, unsigned>::iterator I =
493 NodeNum2Index.find(Succ.getSUnit()->NodeNum);
494 if (I != NodeNum2Index.end())
495 HasLowLatencyNonWaitedParent[I->second] = 1;
496 }
497 }
498 SU->isScheduled = true;
499}
500
502 // We remove links from outside blocks to enable scheduling inside the block.
503 for (SUnit* SU : SUnits) {
504 releaseSuccessors(SU, false);
505 if (DAG->IsHighLatencySU[SU->NodeNum])
506 HighLatencyBlock = true;
507 }
508 HasLowLatencyNonWaitedParent.resize(SUnits.size(), 0);
509}
510
511// we maintain ascending order of IDs
513 unsigned PredID = Pred->getID();
514
515 // Check if not already predecessor.
516 for (SIScheduleBlock* P : Preds) {
517 if (PredID == P->getID())
518 return;
519 }
520 Preds.push_back(Pred);
521
522 assert(none_of(Succs,
523 [=](std::pair<SIScheduleBlock*,
525 return PredID == S.first->getID();
526 }) &&
527 "Loop in the Block Graph!");
528}
529
532 unsigned SuccID = Succ->getID();
533
534 // Check if not already predecessor.
535 for (std::pair<SIScheduleBlock*, SIScheduleBlockLinkKind> &S : Succs) {
536 if (SuccID == S.first->getID()) {
537 if (S.second == SIScheduleBlockLinkKind::NoData &&
539 S.second = Kind;
540 return;
541 }
542 }
543 if (Succ->isHighLatencyBlock())
544 ++NumHighLatencySuccessors;
545 Succs.emplace_back(Succ, Kind);
546
547 assert(none_of(Preds,
548 [=](SIScheduleBlock *P) { return SuccID == P->getID(); }) &&
549 "Loop in the Block Graph!");
550}
551
552#ifndef NDEBUG
554 dbgs() << "Block (" << ID << ")\n";
555 if (!full)
556 return;
557
558 dbgs() << "\nContains High Latency Instruction: "
559 << HighLatencyBlock << '\n';
560 dbgs() << "\nDepends On:\n";
561 for (SIScheduleBlock* P : Preds) {
562 P->printDebug(false);
563 }
564
565 dbgs() << "\nSuccessors:\n";
566 for (std::pair<SIScheduleBlock*, SIScheduleBlockLinkKind> S : Succs) {
567 if (S.second == SIScheduleBlockLinkKind::Data)
568 dbgs() << "(Data Dep) ";
569 S.first->printDebug(false);
570 }
571
572 if (Scheduled) {
573 dbgs() << "LiveInPressure "
574 << LiveInPressure[AMDGPU::RegisterPressureSets::SReg_32] << ' '
575 << LiveInPressure[AMDGPU::RegisterPressureSets::VGPR_32] << '\n';
576 dbgs() << "LiveOutPressure "
577 << LiveOutPressure[AMDGPU::RegisterPressureSets::SReg_32] << ' '
578 << LiveOutPressure[AMDGPU::RegisterPressureSets::VGPR_32] << "\n\n";
579 dbgs() << "LiveIns:\n";
580 for (Register Reg : LiveInRegs)
581 dbgs() << printReg(Reg, DAG->getTRI()) << ' ';
582
583 dbgs() << "\nLiveOuts:\n";
584 for (Register Reg : LiveOutRegs)
585 dbgs() << printReg(Reg, DAG->getTRI()) << ' ';
586 }
587
588 dbgs() << "\nInstructions:\n";
589 for (const SUnit* SU : SUnits)
590 DAG->dumpNode(*SU);
591
592 dbgs() << "///////////////////////\n";
593}
594#endif
595
596// SIScheduleBlockCreator //
597
600
603 std::map<SISchedulerBlockCreatorVariant, SIScheduleBlocks>::iterator B =
604 Blocks.find(BlockVariant);
605 if (B == Blocks.end()) {
607 createBlocksForVariant(BlockVariant);
608 topologicalSort();
609 scheduleInsideBlocks();
610 fillStats();
611 Res.Blocks = CurrentBlocks;
612 Res.TopDownIndex2Block = TopDownIndex2Block;
613 Res.TopDownBlock2Index = TopDownBlock2Index;
614 Blocks[BlockVariant] = Res;
615 return Res;
616 }
617 return B->second;
618}
619
621 if (SU->NodeNum >= DAG->SUnits.size())
622 return false;
623 return CurrentBlocks[Node2CurrentBlock[SU->NodeNum]]->getID() == ID;
624}
625
626void SIScheduleBlockCreator::colorHighLatenciesAlone() {
627 unsigned DAGSize = DAG->SUnits.size();
628
629 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
630 SUnit *SU = &DAG->SUnits[i];
631 if (DAG->IsHighLatencySU[SU->NodeNum]) {
632 CurrentColoring[SU->NodeNum] = NextReservedID++;
633 }
634 }
635}
636
637static bool
638hasDataDependencyPred(const SUnit &SU, const SUnit &FromSU) {
639 for (const auto &PredDep : SU.Preds) {
640 if (PredDep.getSUnit() == &FromSU &&
641 PredDep.getKind() == llvm::SDep::Data)
642 return true;
643 }
644 return false;
645}
646
647void SIScheduleBlockCreator::colorHighLatenciesGroups() {
648 unsigned DAGSize = DAG->SUnits.size();
649 unsigned NumHighLatencies = 0;
650 unsigned GroupSize;
651 int Color = NextReservedID;
652 unsigned Count = 0;
653 std::set<unsigned> FormingGroup;
654
655 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
656 SUnit *SU = &DAG->SUnits[i];
657 if (DAG->IsHighLatencySU[SU->NodeNum])
658 ++NumHighLatencies;
659 }
660
661 if (NumHighLatencies == 0)
662 return;
663
664 if (NumHighLatencies <= 6)
665 GroupSize = 2;
666 else if (NumHighLatencies <= 12)
667 GroupSize = 3;
668 else
669 GroupSize = 4;
670
671 for (unsigned SUNum : DAG->TopDownIndex2SU) {
672 const SUnit &SU = DAG->SUnits[SUNum];
673 if (DAG->IsHighLatencySU[SU.NodeNum]) {
674 unsigned CompatibleGroup = true;
675 int ProposedColor = Color;
676 std::vector<int> AdditionalElements;
677
678 // We don't want to put in the same block
679 // two high latency instructions that depend
680 // on each other.
681 // One way would be to check canAddEdge
682 // in both directions, but that currently is not
683 // enough because there the high latency order is
684 // enforced (via links).
685 // Instead, look at the dependencies between the
686 // high latency instructions and deduce if it is
687 // a data dependency or not.
688 for (unsigned j : FormingGroup) {
689 bool HasSubGraph;
690 std::vector<int> SubGraph;
691 // By construction (topological order), if SU and
692 // DAG->SUnits[j] are linked, DAG->SUnits[j] is necessary
693 // in the parent graph of SU.
694#ifndef NDEBUG
695 SubGraph = DAG->GetTopo()->GetSubGraph(SU, DAG->SUnits[j],
696 HasSubGraph);
697 assert(!HasSubGraph);
698#endif
699 SubGraph = DAG->GetTopo()->GetSubGraph(DAG->SUnits[j], SU,
700 HasSubGraph);
701 if (!HasSubGraph)
702 continue; // No dependencies between each other
703 if (SubGraph.size() > 5) {
704 // Too many elements would be required to be added to the block.
705 CompatibleGroup = false;
706 break;
707 }
708 // Check the type of dependency
709 for (unsigned k : SubGraph) {
710 // If in the path to join the two instructions,
711 // there is another high latency instruction,
712 // or instructions colored for another block
713 // abort the merge.
714 if (DAG->IsHighLatencySU[k] || (CurrentColoring[k] != ProposedColor &&
715 CurrentColoring[k] != 0)) {
716 CompatibleGroup = false;
717 break;
718 }
719 // If one of the SU in the subgraph depends on the result of SU j,
720 // there'll be a data dependency.
721 if (hasDataDependencyPred(DAG->SUnits[k], DAG->SUnits[j])) {
722 CompatibleGroup = false;
723 break;
724 }
725 }
726 if (!CompatibleGroup)
727 break;
728 // Same check for the SU
729 if (hasDataDependencyPred(SU, DAG->SUnits[j])) {
730 CompatibleGroup = false;
731 break;
732 }
733 // Add all the required instructions to the block
734 // These cannot live in another block (because they
735 // depend (order dependency) on one of the
736 // instruction in the block, and are required for the
737 // high latency instruction we add.
738 llvm::append_range(AdditionalElements, SubGraph);
739 }
740 if (CompatibleGroup) {
741 FormingGroup.insert(SU.NodeNum);
742 for (unsigned j : AdditionalElements)
743 CurrentColoring[j] = ProposedColor;
744 CurrentColoring[SU.NodeNum] = ProposedColor;
745 ++Count;
746 }
747 // Found one incompatible instruction,
748 // or has filled a big enough group.
749 // -> start a new one.
750 if (!CompatibleGroup) {
751 FormingGroup.clear();
752 Color = ++NextReservedID;
753 ProposedColor = Color;
754 FormingGroup.insert(SU.NodeNum);
755 CurrentColoring[SU.NodeNum] = ProposedColor;
756 Count = 0;
757 } else if (Count == GroupSize) {
758 FormingGroup.clear();
759 Color = ++NextReservedID;
760 ProposedColor = Color;
761 Count = 0;
762 }
763 }
764 }
765}
766
767void SIScheduleBlockCreator::colorComputeReservedDependencies() {
768 unsigned DAGSize = DAG->SUnits.size();
769 std::map<std::set<unsigned>, unsigned> ColorCombinations;
770
771 CurrentTopDownReservedDependencyColoring.clear();
772 CurrentBottomUpReservedDependencyColoring.clear();
773
774 CurrentTopDownReservedDependencyColoring.resize(DAGSize, 0);
775 CurrentBottomUpReservedDependencyColoring.resize(DAGSize, 0);
776
777 // Traverse TopDown, and give different colors to SUs depending
778 // on which combination of High Latencies they depend on.
779
780 for (unsigned SUNum : DAG->TopDownIndex2SU) {
781 SUnit *SU = &DAG->SUnits[SUNum];
782 std::set<unsigned> SUColors;
783
784 // Already given.
785 if (CurrentColoring[SU->NodeNum]) {
786 CurrentTopDownReservedDependencyColoring[SU->NodeNum] =
787 CurrentColoring[SU->NodeNum];
788 continue;
789 }
790
791 for (SDep& PredDep : SU->Preds) {
792 SUnit *Pred = PredDep.getSUnit();
793 if (PredDep.isWeak() || Pred->NodeNum >= DAGSize)
794 continue;
795 if (CurrentTopDownReservedDependencyColoring[Pred->NodeNum] > 0)
796 SUColors.insert(CurrentTopDownReservedDependencyColoring[Pred->NodeNum]);
797 }
798 // Color 0 by default.
799 if (SUColors.empty())
800 continue;
801 // Same color than parents.
802 if (SUColors.size() == 1 && *SUColors.begin() > DAGSize)
803 CurrentTopDownReservedDependencyColoring[SU->NodeNum] =
804 *SUColors.begin();
805 else {
806 auto [Pos, Inserted] =
807 ColorCombinations.try_emplace(SUColors, NextNonReservedID);
808 if (Inserted)
809 ++NextNonReservedID;
810 CurrentTopDownReservedDependencyColoring[SU->NodeNum] = Pos->second;
811 }
812 }
813
814 ColorCombinations.clear();
815
816 // Same as before, but BottomUp.
817
818 for (unsigned SUNum : DAG->BottomUpIndex2SU) {
819 SUnit *SU = &DAG->SUnits[SUNum];
820 std::set<unsigned> SUColors;
821
822 // Already given.
823 if (CurrentColoring[SU->NodeNum]) {
824 CurrentBottomUpReservedDependencyColoring[SU->NodeNum] =
825 CurrentColoring[SU->NodeNum];
826 continue;
827 }
828
829 for (SDep& SuccDep : SU->Succs) {
830 SUnit *Succ = SuccDep.getSUnit();
831 if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize)
832 continue;
833 if (CurrentBottomUpReservedDependencyColoring[Succ->NodeNum] > 0)
834 SUColors.insert(CurrentBottomUpReservedDependencyColoring[Succ->NodeNum]);
835 }
836 // Keep color 0.
837 if (SUColors.empty())
838 continue;
839 // Same color than parents.
840 if (SUColors.size() == 1 && *SUColors.begin() > DAGSize)
841 CurrentBottomUpReservedDependencyColoring[SU->NodeNum] =
842 *SUColors.begin();
843 else {
844 std::map<std::set<unsigned>, unsigned>::iterator Pos =
845 ColorCombinations.find(SUColors);
846 if (Pos != ColorCombinations.end()) {
847 CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = Pos->second;
848 } else {
849 CurrentBottomUpReservedDependencyColoring[SU->NodeNum] =
850 NextNonReservedID;
851 ColorCombinations[SUColors] = NextNonReservedID++;
852 }
853 }
854 }
855}
856
857void SIScheduleBlockCreator::colorAccordingToReservedDependencies() {
858 std::map<std::pair<unsigned, unsigned>, unsigned> ColorCombinations;
859
860 // Every combination of colors given by the top down
861 // and bottom up Reserved node dependency
862
863 for (const SUnit &SU : DAG->SUnits) {
864 std::pair<unsigned, unsigned> SUColors;
865
866 // High latency instructions: already given.
867 if (CurrentColoring[SU.NodeNum])
868 continue;
869
870 SUColors.first = CurrentTopDownReservedDependencyColoring[SU.NodeNum];
871 SUColors.second = CurrentBottomUpReservedDependencyColoring[SU.NodeNum];
872
873 auto [Pos, Inserted] =
874 ColorCombinations.try_emplace(SUColors, NextNonReservedID);
875 CurrentColoring[SU.NodeNum] = Pos->second;
876 if (Inserted)
877 NextNonReservedID++;
878 }
879}
880
881void SIScheduleBlockCreator::colorEndsAccordingToDependencies() {
882 unsigned DAGSize = DAG->SUnits.size();
883 std::vector<int> PendingColoring = CurrentColoring;
884
885 assert(DAGSize >= 1 &&
886 CurrentBottomUpReservedDependencyColoring.size() == DAGSize &&
887 CurrentTopDownReservedDependencyColoring.size() == DAGSize);
888 // If there is no reserved block at all, do nothing. We don't want
889 // everything in one block.
890 if (*llvm::max_element(CurrentBottomUpReservedDependencyColoring) == 0 &&
891 *llvm::max_element(CurrentTopDownReservedDependencyColoring) == 0)
892 return;
893
894 for (unsigned SUNum : DAG->BottomUpIndex2SU) {
895 SUnit *SU = &DAG->SUnits[SUNum];
896 std::set<unsigned> SUColors;
897 std::set<unsigned> SUColorsPending;
898
899 if (CurrentColoring[SU->NodeNum] <= (int)DAGSize)
900 continue;
901
902 if (CurrentBottomUpReservedDependencyColoring[SU->NodeNum] > 0 ||
903 CurrentTopDownReservedDependencyColoring[SU->NodeNum] > 0)
904 continue;
905
906 for (SDep& SuccDep : SU->Succs) {
907 SUnit *Succ = SuccDep.getSUnit();
908 if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize)
909 continue;
910 if (CurrentBottomUpReservedDependencyColoring[Succ->NodeNum] > 0 ||
911 CurrentTopDownReservedDependencyColoring[Succ->NodeNum] > 0)
912 SUColors.insert(CurrentColoring[Succ->NodeNum]);
913 SUColorsPending.insert(PendingColoring[Succ->NodeNum]);
914 }
915 // If there is only one child/parent block, and that block
916 // is not among the ones we are removing in this path, then
917 // merge the instruction to that block
918 if (SUColors.size() == 1 && SUColorsPending.size() == 1)
919 PendingColoring[SU->NodeNum] = *SUColors.begin();
920 else // TODO: Attribute new colors depending on color
921 // combination of children.
922 PendingColoring[SU->NodeNum] = NextNonReservedID++;
923 }
924 CurrentColoring = std::move(PendingColoring);
925}
926
927
928void SIScheduleBlockCreator::colorForceConsecutiveOrderInGroup() {
929 unsigned DAGSize = DAG->SUnits.size();
930 unsigned PreviousColor;
931 std::set<unsigned> SeenColors;
932
933 if (DAGSize <= 1)
934 return;
935
936 PreviousColor = CurrentColoring[0];
937
938 for (unsigned i = 1, e = DAGSize; i != e; ++i) {
939 SUnit *SU = &DAG->SUnits[i];
940 unsigned CurrentColor = CurrentColoring[i];
941 unsigned PreviousColorSave = PreviousColor;
942 assert(i == SU->NodeNum);
943
944 if (CurrentColor != PreviousColor)
945 SeenColors.insert(PreviousColor);
946 PreviousColor = CurrentColor;
947
948 if (CurrentColoring[SU->NodeNum] <= (int)DAGSize)
949 continue;
950
951 if (SeenColors.find(CurrentColor) == SeenColors.end())
952 continue;
953
954 if (PreviousColorSave != CurrentColor)
955 CurrentColoring[i] = NextNonReservedID++;
956 else
957 CurrentColoring[i] = CurrentColoring[i-1];
958 }
959}
960
961void SIScheduleBlockCreator::colorMergeConstantLoadsNextGroup() {
962 unsigned DAGSize = DAG->SUnits.size();
963
964 for (unsigned SUNum : DAG->BottomUpIndex2SU) {
965 SUnit *SU = &DAG->SUnits[SUNum];
966 std::set<unsigned> SUColors;
967
968 if (CurrentColoring[SU->NodeNum] <= (int)DAGSize)
969 continue;
970
971 // No predecessor: Vgpr constant loading.
972 // Low latency instructions usually have a predecessor (the address)
973 if (!SU->Preds.empty() && !DAG->IsLowLatencySU[SU->NodeNum])
974 continue;
975
976 for (SDep& SuccDep : SU->Succs) {
977 SUnit *Succ = SuccDep.getSUnit();
978 if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize)
979 continue;
980 SUColors.insert(CurrentColoring[Succ->NodeNum]);
981 }
982 if (SUColors.size() == 1)
983 CurrentColoring[SU->NodeNum] = *SUColors.begin();
984 }
985}
986
987void SIScheduleBlockCreator::colorMergeIfPossibleNextGroupOnlyForReserved() {
988 unsigned DAGSize = DAG->SUnits.size();
989
990 for (unsigned SUNum : DAG->BottomUpIndex2SU) {
991 SUnit *SU = &DAG->SUnits[SUNum];
992 std::set<unsigned> SUColors;
993
994 if (CurrentColoring[SU->NodeNum] <= (int)DAGSize)
995 continue;
996
997 for (SDep& SuccDep : SU->Succs) {
998 SUnit *Succ = SuccDep.getSUnit();
999 if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize)
1000 continue;
1001 SUColors.insert(CurrentColoring[Succ->NodeNum]);
1002 }
1003 if (SUColors.size() == 1 && *SUColors.begin() <= DAGSize)
1004 CurrentColoring[SU->NodeNum] = *SUColors.begin();
1005 }
1006}
1007
1008void SIScheduleBlockCreator::regroupNoUserInstructions() {
1009 unsigned DAGSize = DAG->SUnits.size();
1010 int GroupID = NextNonReservedID++;
1011
1012 for (unsigned SUNum : DAG->BottomUpIndex2SU) {
1013 SUnit *SU = &DAG->SUnits[SUNum];
1014 bool hasSuccessor = false;
1015
1016 if (CurrentColoring[SU->NodeNum] <= (int)DAGSize)
1017 continue;
1018
1019 for (SDep& SuccDep : SU->Succs) {
1020 SUnit *Succ = SuccDep.getSUnit();
1021 if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize)
1022 continue;
1023 hasSuccessor = true;
1024 }
1025 if (!hasSuccessor)
1026 CurrentColoring[SU->NodeNum] = GroupID;
1027 }
1028}
1029
1030void SIScheduleBlockCreator::colorExports() {
1031 unsigned ExportColor = NextNonReservedID++;
1032 SmallVector<unsigned, 8> ExpGroup;
1033
1034 // Put all exports together in a block.
1035 // The block will naturally end up being scheduled last,
1036 // thus putting exports at the end of the schedule, which
1037 // is better for performance.
1038 // However we must ensure, for safety, the exports can be put
1039 // together in the same block without any other instruction.
1040 // This could happen, for example, when scheduling after regalloc
1041 // if reloading a spilled register from memory using the same
1042 // register than used in a previous export.
1043 // If that happens, do not regroup the exports.
1044 for (unsigned SUNum : DAG->TopDownIndex2SU) {
1045 const SUnit &SU = DAG->SUnits[SUNum];
1046 if (SIInstrInfo::isEXP(*SU.getInstr())) {
1047 // SU is an export instruction. Check whether one of its successor
1048 // dependencies is a non-export, in which case we skip export grouping.
1049 for (const SDep &SuccDep : SU.Succs) {
1050 const SUnit *SuccSU = SuccDep.getSUnit();
1051 if (SuccDep.isWeak() || SuccSU->NodeNum >= DAG->SUnits.size()) {
1052 // Ignore these dependencies.
1053 continue;
1054 }
1055 assert(SuccSU->isInstr() &&
1056 "SUnit unexpectedly not representing an instruction!");
1057
1058 if (!SIInstrInfo::isEXP(*SuccSU->getInstr())) {
1059 // A non-export depends on us. Skip export grouping.
1060 // Note that this is a bit pessimistic: We could still group all other
1061 // exports that are not depended on by non-exports, directly or
1062 // indirectly. Simply skipping this particular export but grouping all
1063 // others would not account for indirect dependencies.
1064 return;
1065 }
1066 }
1067 ExpGroup.push_back(SUNum);
1068 }
1069 }
1070
1071 // The group can be formed. Give the color.
1072 for (unsigned j : ExpGroup)
1073 CurrentColoring[j] = ExportColor;
1074}
1075
1076void SIScheduleBlockCreator::createBlocksForVariant(SISchedulerBlockCreatorVariant BlockVariant) {
1077 unsigned DAGSize = DAG->SUnits.size();
1078 std::map<unsigned,unsigned> RealID;
1079
1080 CurrentBlocks.clear();
1081 CurrentColoring.clear();
1082 CurrentColoring.resize(DAGSize, 0);
1083 Node2CurrentBlock.clear();
1084
1085 // Restore links previous scheduling variant has overridden.
1086 DAG->restoreSULinksLeft();
1087
1088 NextReservedID = 1;
1089 NextNonReservedID = DAGSize + 1;
1090
1091 LLVM_DEBUG(dbgs() << "Coloring the graph\n");
1092
1094 colorHighLatenciesGroups();
1095 else
1096 colorHighLatenciesAlone();
1097 colorComputeReservedDependencies();
1098 colorAccordingToReservedDependencies();
1099 colorEndsAccordingToDependencies();
1101 colorForceConsecutiveOrderInGroup();
1102 regroupNoUserInstructions();
1103 colorMergeConstantLoadsNextGroup();
1104 colorMergeIfPossibleNextGroupOnlyForReserved();
1105 colorExports();
1106
1107 // Put SUs of same color into same block
1108 Node2CurrentBlock.resize(DAGSize, -1);
1109 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1110 SUnit *SU = &DAG->SUnits[i];
1111 unsigned Color = CurrentColoring[SU->NodeNum];
1112 auto [It, Inserted] = RealID.try_emplace(Color);
1113 if (Inserted) {
1114 int ID = CurrentBlocks.size();
1115 BlockPtrs.push_back(std::make_unique<SIScheduleBlock>(DAG, this, ID));
1116 CurrentBlocks.push_back(BlockPtrs.rbegin()->get());
1117 It->second = ID;
1118 }
1119 CurrentBlocks[It->second]->addUnit(SU);
1120 Node2CurrentBlock[SU->NodeNum] = It->second;
1121 }
1122
1123 // Build dependencies between blocks.
1124 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1125 SUnit *SU = &DAG->SUnits[i];
1126 int SUID = Node2CurrentBlock[i];
1127 for (SDep& SuccDep : SU->Succs) {
1128 SUnit *Succ = SuccDep.getSUnit();
1129 if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize)
1130 continue;
1131 if (Node2CurrentBlock[Succ->NodeNum] != SUID)
1132 CurrentBlocks[SUID]->addSucc(CurrentBlocks[Node2CurrentBlock[Succ->NodeNum]],
1133 SuccDep.isCtrl() ? NoData : Data);
1134 }
1135 for (SDep& PredDep : SU->Preds) {
1136 SUnit *Pred = PredDep.getSUnit();
1137 if (PredDep.isWeak() || Pred->NodeNum >= DAGSize)
1138 continue;
1139 if (Node2CurrentBlock[Pred->NodeNum] != SUID)
1140 CurrentBlocks[SUID]->addPred(CurrentBlocks[Node2CurrentBlock[Pred->NodeNum]]);
1141 }
1142 }
1143
1144 // Free root and leafs of all blocks to enable scheduling inside them.
1145 for (SIScheduleBlock *Block : CurrentBlocks)
1146 Block->finalizeUnits();
1147 LLVM_DEBUG({
1148 dbgs() << "Blocks created:\n\n";
1149 for (SIScheduleBlock *Block : CurrentBlocks)
1150 Block->printDebug(true);
1151 });
1152}
1153
1154// Two functions taken from Codegen/MachineScheduler.cpp
1155
1156/// Non-const version.
1160 for (; I != End; ++I) {
1161 if (!I->isDebugInstr())
1162 break;
1163 }
1164 return I;
1165}
1166
1167void SIScheduleBlockCreator::topologicalSort() {
1168 unsigned DAGSize = CurrentBlocks.size();
1169 std::vector<int> WorkList;
1170
1171 LLVM_DEBUG(dbgs() << "Topological Sort\n");
1172
1173 WorkList.reserve(DAGSize);
1174 TopDownIndex2Block.resize(DAGSize);
1175 TopDownBlock2Index.resize(DAGSize);
1176 BottomUpIndex2Block.resize(DAGSize);
1177
1178 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1179 SIScheduleBlock *Block = CurrentBlocks[i];
1180 unsigned Degree = Block->getSuccs().size();
1181 TopDownBlock2Index[i] = Degree;
1182 if (Degree == 0) {
1183 WorkList.push_back(i);
1184 }
1185 }
1186
1187 int Id = DAGSize;
1188 while (!WorkList.empty()) {
1189 int i = WorkList.back();
1190 SIScheduleBlock *Block = CurrentBlocks[i];
1191 WorkList.pop_back();
1192 TopDownBlock2Index[i] = --Id;
1193 TopDownIndex2Block[Id] = i;
1194 for (SIScheduleBlock* Pred : Block->getPreds()) {
1195 if (!--TopDownBlock2Index[Pred->getID()])
1196 WorkList.push_back(Pred->getID());
1197 }
1198 }
1199
1200#ifndef NDEBUG
1201 // Check correctness of the ordering.
1202 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1203 SIScheduleBlock *Block = CurrentBlocks[i];
1204 for (SIScheduleBlock* Pred : Block->getPreds()) {
1205 assert(TopDownBlock2Index[i] > TopDownBlock2Index[Pred->getID()] &&
1206 "Wrong Top Down topological sorting");
1207 }
1208 }
1209#endif
1210
1211 BottomUpIndex2Block = std::vector<int>(TopDownIndex2Block.rbegin(),
1212 TopDownIndex2Block.rend());
1213}
1214
1215void SIScheduleBlockCreator::scheduleInsideBlocks() {
1216 unsigned DAGSize = CurrentBlocks.size();
1217
1218 LLVM_DEBUG(dbgs() << "\nScheduling Blocks\n\n");
1219
1220 // We do schedule a valid scheduling such that a Block corresponds
1221 // to a range of instructions.
1222 LLVM_DEBUG(dbgs() << "First phase: Fast scheduling for Reg Liveness\n");
1223 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1224 SIScheduleBlock *Block = CurrentBlocks[i];
1225 Block->fastSchedule();
1226 }
1227
1228 // Note: the following code, and the part restoring previous position
1229 // is by far the most expensive operation of the Scheduler.
1230
1231 // Do not update CurrentTop.
1232 MachineBasicBlock::iterator CurrentTopFastSched = DAG->getCurrentTop();
1233 std::vector<MachineBasicBlock::iterator> PosOld;
1234 std::vector<MachineBasicBlock::iterator> PosNew;
1235 PosOld.reserve(DAG->SUnits.size());
1236 PosNew.reserve(DAG->SUnits.size());
1237
1238 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1239 int BlockIndice = TopDownIndex2Block[i];
1240 SIScheduleBlock *Block = CurrentBlocks[BlockIndice];
1241 std::vector<SUnit*> SUs = Block->getScheduledUnits();
1242
1243 for (SUnit* SU : SUs) {
1244 MachineInstr *MI = SU->getInstr();
1246 PosOld.push_back(Pos);
1247 if (&*CurrentTopFastSched == MI) {
1248 PosNew.push_back(Pos);
1249 CurrentTopFastSched = nextIfDebug(++CurrentTopFastSched,
1250 DAG->getCurrentBottom());
1251 } else {
1252 // Update the instruction stream.
1253 DAG->getBB()->splice(CurrentTopFastSched, DAG->getBB(), MI);
1254
1255 // Update LiveIntervals.
1256 // Note: Moving all instructions and calling handleMove every time
1257 // is the most cpu intensive operation of the scheduler.
1258 // It would gain a lot if there was a way to recompute the
1259 // LiveIntervals for the entire scheduling region.
1260 DAG->getLIS()->handleMove(*MI, /*UpdateFlags=*/true);
1261 PosNew.push_back(CurrentTopFastSched);
1262 }
1263 }
1264 }
1265
1266 // Now we have Block of SUs == Block of MI.
1267 // We do the final schedule for the instructions inside the block.
1268 // The property that all the SUs of the Block are grouped together as MI
1269 // is used for correct reg usage tracking.
1270 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1271 SIScheduleBlock *Block = CurrentBlocks[i];
1272 std::vector<SUnit*> SUs = Block->getScheduledUnits();
1273 Block->schedule((*SUs.begin())->getInstr(), (*SUs.rbegin())->getInstr());
1274 }
1275
1276 LLVM_DEBUG(dbgs() << "Restoring MI Pos\n");
1277 // Restore old ordering (which prevents a LIS->handleMove bug).
1278 for (unsigned i = PosOld.size(), e = 0; i != e; --i) {
1279 MachineBasicBlock::iterator POld = PosOld[i-1];
1280 MachineBasicBlock::iterator PNew = PosNew[i-1];
1281 if (PNew != POld) {
1282 // Update the instruction stream.
1283 DAG->getBB()->splice(POld, DAG->getBB(), PNew);
1284
1285 // Update LiveIntervals.
1286 DAG->getLIS()->handleMove(*POld, /*UpdateFlags=*/true);
1287 }
1288 }
1289
1290 LLVM_DEBUG({
1291 for (SIScheduleBlock *Block : CurrentBlocks)
1292 Block->printDebug(true);
1293 });
1294}
1295
1296void SIScheduleBlockCreator::fillStats() {
1297 unsigned DAGSize = CurrentBlocks.size();
1298
1299 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1300 int BlockIndice = TopDownIndex2Block[i];
1301 SIScheduleBlock *Block = CurrentBlocks[BlockIndice];
1302 if (Block->getPreds().empty())
1303 Block->Depth = 0;
1304 else {
1305 unsigned Depth = 0;
1306 for (SIScheduleBlock *Pred : Block->getPreds()) {
1307 if (Depth < Pred->Depth + Pred->getCost())
1308 Depth = Pred->Depth + Pred->getCost();
1309 }
1310 Block->Depth = Depth;
1311 }
1312 }
1313
1314 for (unsigned i = 0, e = DAGSize; i != e; ++i) {
1315 int BlockIndice = BottomUpIndex2Block[i];
1316 SIScheduleBlock *Block = CurrentBlocks[BlockIndice];
1317 if (Block->getSuccs().empty())
1318 Block->Height = 0;
1319 else {
1320 unsigned Height = 0;
1321 for (const auto &Succ : Block->getSuccs())
1322 Height = std::max(Height, Succ.first->Height + Succ.first->getCost());
1323 Block->Height = Height;
1324 }
1325 }
1326}
1327
1328// SIScheduleBlockScheduler //
1329
1332 SIScheduleBlocks BlocksStruct) :
1333 DAG(DAG), Variant(Variant), Blocks(BlocksStruct.Blocks),
1334 LastPosWaitedHighLatency(0), NumBlockScheduled(0), VregCurrentUsage(0),
1335 SregCurrentUsage(0), maxVregUsage(0), maxSregUsage(0) {
1336
1337 // Fill the usage of every output
1338 // Warning: while by construction we always have a link between two blocks
1339 // when one needs a result from the other, the number of users of an output
1340 // is not the sum of child blocks having as input the same virtual register.
1341 // Here is an example. A produces x and y. B eats x and produces x'.
1342 // C eats x' and y. The register coalescer may have attributed the same
1343 // virtual register to x and x'.
1344 // To count accurately, we do a topological sort. In case the register is
1345 // found for several parents, we increment the usage of the one with the
1346 // highest topological index.
1347 LiveOutRegsNumUsages.resize(Blocks.size());
1348 for (SIScheduleBlock *Block : Blocks) {
1349 for (Register Reg : Block->getInRegs()) {
1350 bool Found = false;
1351 int topoInd = -1;
1352 for (SIScheduleBlock* Pred: Block->getPreds()) {
1353 std::set<Register> PredOutRegs = Pred->getOutRegs();
1354 std::set<Register>::iterator RegPos = PredOutRegs.find(Reg);
1355
1356 if (RegPos != PredOutRegs.end()) {
1357 Found = true;
1358 if (topoInd < BlocksStruct.TopDownBlock2Index[Pred->getID()]) {
1359 topoInd = BlocksStruct.TopDownBlock2Index[Pred->getID()];
1360 }
1361 }
1362 }
1363
1364 if (!Found)
1365 continue;
1366
1367 int PredID = BlocksStruct.TopDownIndex2Block[topoInd];
1368 ++LiveOutRegsNumUsages[PredID][Reg];
1369 }
1370 }
1371
1372 LastPosHighLatencyParentScheduled.resize(Blocks.size(), 0);
1373 BlockNumPredsLeft.resize(Blocks.size());
1374 BlockNumSuccsLeft.resize(Blocks.size());
1375
1376 for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
1377 SIScheduleBlock *Block = Blocks[i];
1378 BlockNumPredsLeft[i] = Block->getPreds().size();
1379 BlockNumSuccsLeft[i] = Block->getSuccs().size();
1380 }
1381
1382#ifndef NDEBUG
1383 for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
1384 SIScheduleBlock *Block = Blocks[i];
1385 assert(Block->getID() == i);
1386 }
1387#endif
1388
1389 std::set<VirtRegOrUnit> InRegs = DAG->getInRegs();
1390 addLiveRegs(InRegs);
1391
1392 // Increase LiveOutRegsNumUsages for blocks
1393 // producing registers consumed in another
1394 // scheduling region.
1395 for (VirtRegOrUnit VRegOrUnit : DAG->getOutRegs()) {
1396 for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
1397 // Do reverse traversal
1398 int ID = BlocksStruct.TopDownIndex2Block[Blocks.size()-1-i];
1399 SIScheduleBlock *Block = Blocks[ID];
1400 const std::set<Register> &OutRegs = Block->getOutRegs();
1401
1402 if (!VRegOrUnit.isVirtualReg() ||
1403 OutRegs.find(VRegOrUnit.asVirtualReg()) == OutRegs.end())
1404 continue;
1405
1406 ++LiveOutRegsNumUsages[ID][VRegOrUnit.asVirtualReg()];
1407 break;
1408 }
1409 }
1410
1411 // Fill LiveRegsConsumers for regs that were already
1412 // defined before scheduling.
1413 for (SIScheduleBlock *Block : Blocks) {
1414 for (Register Reg : Block->getInRegs()) {
1415 bool Found = false;
1416 for (SIScheduleBlock* Pred: Block->getPreds()) {
1417 std::set<Register> PredOutRegs = Pred->getOutRegs();
1418 std::set<Register>::iterator RegPos = PredOutRegs.find(Reg);
1419
1420 if (RegPos != PredOutRegs.end()) {
1421 Found = true;
1422 break;
1423 }
1424 }
1425
1426 if (!Found)
1427 ++LiveRegsConsumers[Reg];
1428 }
1429 }
1430
1431 for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
1432 SIScheduleBlock *Block = Blocks[i];
1433 if (BlockNumPredsLeft[i] == 0) {
1434 ReadyBlocks.push_back(Block);
1435 }
1436 }
1437
1438 while (SIScheduleBlock *Block = pickBlock()) {
1439 BlocksScheduled.push_back(Block);
1440 blockScheduled(Block);
1441 }
1442
1443 LLVM_DEBUG(dbgs() << "Block Order:"; for (SIScheduleBlock *Block
1444 : BlocksScheduled) {
1445 dbgs() << ' ' << Block->getID();
1446 } dbgs() << '\n';);
1447}
1448
1449bool SIScheduleBlockScheduler::tryCandidateLatency(SIBlockSchedCandidate &Cand,
1450 SIBlockSchedCandidate &TryCand) {
1451 if (!Cand.isValid()) {
1452 TryCand.Reason = NodeOrder;
1453 return true;
1454 }
1455
1456 // Try to hide high latencies.
1457 if (SISched::tryLess(TryCand.LastPosHighLatParentScheduled,
1458 Cand.LastPosHighLatParentScheduled, TryCand, Cand, Latency))
1459 return true;
1460 // Schedule high latencies early so you can hide them better.
1461 if (SISched::tryGreater(TryCand.IsHighLatency, Cand.IsHighLatency,
1462 TryCand, Cand, Latency))
1463 return true;
1464 if (TryCand.IsHighLatency && SISched::tryGreater(TryCand.Height, Cand.Height,
1465 TryCand, Cand, Depth))
1466 return true;
1467 if (SISched::tryGreater(TryCand.NumHighLatencySuccessors,
1468 Cand.NumHighLatencySuccessors,
1469 TryCand, Cand, Successor))
1470 return true;
1471 return false;
1472}
1473
1474bool SIScheduleBlockScheduler::tryCandidateRegUsage(SIBlockSchedCandidate &Cand,
1475 SIBlockSchedCandidate &TryCand) {
1476 if (!Cand.isValid()) {
1477 TryCand.Reason = NodeOrder;
1478 return true;
1479 }
1480
1481 if (SISched::tryLess(TryCand.VGPRUsageDiff > 0, Cand.VGPRUsageDiff > 0,
1482 TryCand, Cand, RegUsage))
1483 return true;
1484 if (SISched::tryGreater(TryCand.NumSuccessors > 0,
1485 Cand.NumSuccessors > 0,
1486 TryCand, Cand, Successor))
1487 return true;
1488 if (SISched::tryGreater(TryCand.Height, Cand.Height, TryCand, Cand, Depth))
1489 return true;
1490 if (SISched::tryLess(TryCand.VGPRUsageDiff, Cand.VGPRUsageDiff,
1491 TryCand, Cand, RegUsage))
1492 return true;
1493 return false;
1494}
1495
1496SIScheduleBlock *SIScheduleBlockScheduler::pickBlock() {
1497 SIBlockSchedCandidate Cand;
1498 std::vector<SIScheduleBlock*>::iterator Best;
1499 SIScheduleBlock *Block;
1500 if (ReadyBlocks.empty())
1501 return nullptr;
1502
1503 DAG->fillVgprSgprCost(LiveRegs.begin(), LiveRegs.end(),
1504 VregCurrentUsage, SregCurrentUsage);
1505 if (VregCurrentUsage > maxVregUsage)
1506 maxVregUsage = VregCurrentUsage;
1507 if (SregCurrentUsage > maxSregUsage)
1508 maxSregUsage = SregCurrentUsage;
1509 LLVM_DEBUG({
1510 dbgs() << "Picking New Blocks\n";
1511 dbgs() << "Available: ";
1512 for (SIScheduleBlock *Block : ReadyBlocks)
1513 dbgs() << Block->getID() << ' ';
1514 dbgs() << "\nCurrent Live:\n";
1515 for (Register Reg : LiveRegs)
1516 dbgs() << printReg(Reg, DAG->getTRI()) << ' ';
1517 dbgs() << '\n';
1518 dbgs() << "Current VGPRs: " << VregCurrentUsage << '\n';
1519 dbgs() << "Current SGPRs: " << SregCurrentUsage << '\n';
1520 });
1521
1522 Cand.Block = nullptr;
1523 for (std::vector<SIScheduleBlock*>::iterator I = ReadyBlocks.begin(),
1524 E = ReadyBlocks.end(); I != E; ++I) {
1525 SIBlockSchedCandidate TryCand;
1526 TryCand.Block = *I;
1527 TryCand.IsHighLatency = TryCand.Block->isHighLatencyBlock();
1528 TryCand.VGPRUsageDiff =
1529 checkRegUsageImpact(TryCand.Block->getInRegs(),
1530 TryCand.Block->getOutRegs())[AMDGPU::RegisterPressureSets::VGPR_32];
1531 TryCand.NumSuccessors = TryCand.Block->getSuccs().size();
1532 TryCand.NumHighLatencySuccessors =
1533 TryCand.Block->getNumHighLatencySuccessors();
1534 TryCand.LastPosHighLatParentScheduled =
1535 (unsigned int) std::max<int> (0,
1536 LastPosHighLatencyParentScheduled[TryCand.Block->getID()] -
1537 LastPosWaitedHighLatency);
1538 TryCand.Height = TryCand.Block->Height;
1539 // Try not to increase VGPR usage too much, else we may spill.
1540 if (VregCurrentUsage > 120 ||
1542 if (!tryCandidateRegUsage(Cand, TryCand) &&
1544 tryCandidateLatency(Cand, TryCand);
1545 } else {
1546 if (!tryCandidateLatency(Cand, TryCand))
1547 tryCandidateRegUsage(Cand, TryCand);
1548 }
1549 if (TryCand.Reason != NoCand) {
1550 Cand.setBest(TryCand);
1551 Best = I;
1552 LLVM_DEBUG(dbgs() << "Best Current Choice: " << Cand.Block->getID() << ' '
1553 << getReasonStr(Cand.Reason) << '\n');
1554 }
1555 }
1556
1557 LLVM_DEBUG(dbgs() << "Picking: " << Cand.Block->getID() << '\n';
1558 dbgs() << "Is a block with high latency instruction: "
1559 << (Cand.IsHighLatency ? "yes\n" : "no\n");
1560 dbgs() << "Position of last high latency dependency: "
1561 << Cand.LastPosHighLatParentScheduled << '\n';
1562 dbgs() << "VGPRUsageDiff: " << Cand.VGPRUsageDiff << '\n';
1563 dbgs() << '\n';);
1564
1565 Block = Cand.Block;
1566 ReadyBlocks.erase(Best);
1567 return Block;
1568}
1569
1570// Tracking of currently alive registers to determine VGPR Usage.
1571
1572void SIScheduleBlockScheduler::addLiveRegs(std::set<VirtRegOrUnit> &Regs) {
1573 for (VirtRegOrUnit VRegOrUnit : Regs) {
1574 // For now only track virtual registers.
1575 if (!VRegOrUnit.isVirtualReg())
1576 continue;
1577 // If not already in the live set, then add it.
1578 (void)LiveRegs.insert(VRegOrUnit.asVirtualReg());
1579 }
1580}
1581
1582void SIScheduleBlockScheduler::decreaseLiveRegs(SIScheduleBlock *Block,
1583 std::set<Register> &Regs) {
1584 for (Register Reg : Regs) {
1585 // For now only track virtual registers.
1586 std::set<Register>::iterator Pos = LiveRegs.find(Reg);
1587 assert (Pos != LiveRegs.end() && // Reg must be live.
1588 LiveRegsConsumers.find(Reg) != LiveRegsConsumers.end() &&
1589 LiveRegsConsumers[Reg] >= 1);
1590 --LiveRegsConsumers[Reg];
1591 if (LiveRegsConsumers[Reg] == 0)
1592 LiveRegs.erase(Pos);
1593 }
1594}
1595
1596void SIScheduleBlockScheduler::releaseBlockSuccs(SIScheduleBlock *Parent) {
1597 for (const auto &Block : Parent->getSuccs()) {
1598 if (--BlockNumPredsLeft[Block.first->getID()] == 0)
1599 ReadyBlocks.push_back(Block.first);
1600
1601 if (Parent->isHighLatencyBlock() &&
1603 LastPosHighLatencyParentScheduled[Block.first->getID()] = NumBlockScheduled;
1604 }
1605}
1606
1607void SIScheduleBlockScheduler::blockScheduled(SIScheduleBlock *Block) {
1608 decreaseLiveRegs(Block, Block->getInRegs());
1609 LiveRegs.insert(Block->getOutRegs().begin(), Block->getOutRegs().end());
1610 releaseBlockSuccs(Block);
1611 for (const auto &RegP : LiveOutRegsNumUsages[Block->getID()]) {
1612 // We produce this register, thus it must not be previously alive.
1613 assert(LiveRegsConsumers.find(RegP.first) == LiveRegsConsumers.end() ||
1614 LiveRegsConsumers[RegP.first] == 0);
1615 LiveRegsConsumers[RegP.first] += RegP.second;
1616 }
1617 if (LastPosHighLatencyParentScheduled[Block->getID()] >
1618 (unsigned)LastPosWaitedHighLatency)
1619 LastPosWaitedHighLatency =
1620 LastPosHighLatencyParentScheduled[Block->getID()];
1621 ++NumBlockScheduled;
1622}
1623
1624std::vector<int>
1625SIScheduleBlockScheduler::checkRegUsageImpact(std::set<Register> &InRegs,
1626 std::set<Register> &OutRegs) {
1627 std::vector<int> DiffSetPressure;
1628 DiffSetPressure.assign(DAG->getTRI()->getNumRegPressureSets(), 0);
1629
1630 for (Register Reg : InRegs) {
1631 // For now only track virtual registers.
1632 if (!Reg.isVirtual())
1633 continue;
1634 if (LiveRegsConsumers[Reg] > 1)
1635 continue;
1636 PSetIterator PSetI = DAG->getMRI()->getPressureSets(VirtRegOrUnit(Reg));
1637 for (; PSetI.isValid(); ++PSetI) {
1638 DiffSetPressure[*PSetI] -= PSetI.getWeight();
1639 }
1640 }
1641
1642 for (Register Reg : OutRegs) {
1643 // For now only track virtual registers.
1644 if (!Reg.isVirtual())
1645 continue;
1646 PSetIterator PSetI = DAG->getMRI()->getPressureSets(VirtRegOrUnit(Reg));
1647 for (; PSetI.isValid(); ++PSetI) {
1648 DiffSetPressure[*PSetI] += PSetI.getWeight();
1649 }
1650 }
1651
1652 return DiffSetPressure;
1653}
1654
1655// SIScheduler //
1656
1658SIScheduler::scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant,
1659 SISchedulerBlockSchedulerVariant ScheduleVariant) {
1660 SIScheduleBlocks Blocks = BlockCreator.getBlocks(BlockVariant);
1661 SIScheduleBlockScheduler Scheduler(DAG, ScheduleVariant, Blocks);
1662 std::vector<SIScheduleBlock*> ScheduledBlocks;
1663 struct SIScheduleBlockResult Res;
1664
1665 ScheduledBlocks = Scheduler.getBlocks();
1666
1667 for (SIScheduleBlock *Block : ScheduledBlocks) {
1668 std::vector<SUnit*> SUs = Block->getScheduledUnits();
1669
1670 for (SUnit* SU : SUs)
1671 Res.SUs.push_back(SU->NodeNum);
1672 }
1673
1674 Res.MaxSGPRUsage = Scheduler.getSGPRUsage();
1675 Res.MaxVGPRUsage = Scheduler.getVGPRUsage();
1676 return Res;
1677}
1678
1679// SIScheduleDAGMI //
1680
1682 ScheduleDAGMILive(C, std::make_unique<GenericScheduler>(C)) {
1683 SITII = static_cast<const SIInstrInfo*>(TII);
1684 SITRI = static_cast<const SIRegisterInfo*>(TRI);
1685}
1686
1688
1689// Code adapted from scheduleDAG.cpp
1690// Does a topological sort over the SUs.
1691// Both TopDown and BottomUp
1692void SIScheduleDAGMI::topologicalSort() {
1694
1695 TopDownIndex2SU = std::vector<int>(Topo.begin(), Topo.end());
1696 BottomUpIndex2SU = std::vector<int>(Topo.rbegin(), Topo.rend());
1697}
1698
1699// Move low latencies further from their user without
1700// increasing SGPR usage (in general)
1701// This is to be replaced by a better pass that would
1702// take into account SGPR usage (based on VGPR Usage
1703// and the corresponding wavefront count), that would
1704// try to merge groups of loads if it make sense, etc
1705void SIScheduleDAGMI::moveLowLatencies() {
1706 unsigned DAGSize = SUnits.size();
1707 int LastLowLatencyUser = -1;
1708 int LastLowLatencyPos = -1;
1709
1710 for (unsigned i = 0, e = ScheduledSUnits.size(); i != e; ++i) {
1711 SUnit *SU = &SUnits[ScheduledSUnits[i]];
1712 bool IsLowLatencyUser = false;
1713 unsigned MinPos = 0;
1714
1715 for (SDep& PredDep : SU->Preds) {
1716 SUnit *Pred = PredDep.getSUnit();
1717 if (SITII->isLowLatencyInstruction(*Pred->getInstr())) {
1718 IsLowLatencyUser = true;
1719 }
1720 if (Pred->NodeNum >= DAGSize)
1721 continue;
1722 unsigned PredPos = ScheduledSUnitsInv[Pred->NodeNum];
1723 if (PredPos >= MinPos)
1724 MinPos = PredPos + 1;
1725 }
1726
1727 if (SITII->isLowLatencyInstruction(*SU->getInstr())) {
1728 unsigned BestPos = LastLowLatencyUser + 1;
1729 if ((int)BestPos <= LastLowLatencyPos)
1730 BestPos = LastLowLatencyPos + 1;
1731 if (BestPos < MinPos)
1732 BestPos = MinPos;
1733 if (BestPos < i) {
1734 for (unsigned u = i; u > BestPos; --u) {
1735 ++ScheduledSUnitsInv[ScheduledSUnits[u-1]];
1736 ScheduledSUnits[u] = ScheduledSUnits[u-1];
1737 }
1738 ScheduledSUnits[BestPos] = SU->NodeNum;
1739 ScheduledSUnitsInv[SU->NodeNum] = BestPos;
1740 }
1741 LastLowLatencyPos = BestPos;
1742 if (IsLowLatencyUser)
1743 LastLowLatencyUser = BestPos;
1744 } else if (IsLowLatencyUser) {
1745 LastLowLatencyUser = i;
1746 // Moves COPY instructions on which depends
1747 // the low latency instructions too.
1748 } else if (SU->getInstr()->getOpcode() == AMDGPU::COPY) {
1749 bool CopyForLowLat = false;
1750 for (SDep& SuccDep : SU->Succs) {
1751 SUnit *Succ = SuccDep.getSUnit();
1752 if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize)
1753 continue;
1754 if (SITII->isLowLatencyInstruction(*Succ->getInstr())) {
1755 CopyForLowLat = true;
1756 }
1757 }
1758 if (!CopyForLowLat)
1759 continue;
1760 if (MinPos < i) {
1761 for (unsigned u = i; u > MinPos; --u) {
1762 ++ScheduledSUnitsInv[ScheduledSUnits[u-1]];
1763 ScheduledSUnits[u] = ScheduledSUnits[u-1];
1764 }
1765 ScheduledSUnits[MinPos] = SU->NodeNum;
1766 ScheduledSUnitsInv[SU->NodeNum] = MinPos;
1767 }
1768 }
1769 }
1770}
1771
1773 for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
1774 SUnits[i].isScheduled = false;
1775 SUnits[i].WeakPredsLeft = SUnitsLinksBackup[i].WeakPredsLeft;
1776 SUnits[i].NumPredsLeft = SUnitsLinksBackup[i].NumPredsLeft;
1777 SUnits[i].WeakSuccsLeft = SUnitsLinksBackup[i].WeakSuccsLeft;
1778 SUnits[i].NumSuccsLeft = SUnitsLinksBackup[i].NumSuccsLeft;
1779 }
1780}
1781
1782// Return the Vgpr and Sgpr usage corresponding to some virtual registers.
1783template<typename _Iterator> void
1785 unsigned &VgprUsage, unsigned &SgprUsage) {
1786 VgprUsage = 0;
1787 SgprUsage = 0;
1788 for (_Iterator RegI = First; RegI != End; ++RegI) {
1789 Register Reg = *RegI;
1790 // For now only track virtual registers
1791 if (!Reg.isVirtual())
1792 continue;
1793 PSetIterator PSetI = MRI.getPressureSets(VirtRegOrUnit(Reg));
1794 for (; PSetI.isValid(); ++PSetI) {
1795 if (*PSetI == AMDGPU::RegisterPressureSets::VGPR_32)
1796 VgprUsage += PSetI.getWeight();
1797 else if (*PSetI == AMDGPU::RegisterPressureSets::SReg_32)
1798 SgprUsage += PSetI.getWeight();
1799 }
1800 }
1801}
1802
1804{
1805 SmallVector<SUnit*, 8> TopRoots, BotRoots;
1806 SIScheduleBlockResult Best, Temp;
1807 LLVM_DEBUG(dbgs() << "Preparing Scheduling\n");
1808
1811
1812 LLVM_DEBUG(dump());
1813 if (PrintDAGs)
1814 dump();
1815 if (ViewMISchedDAGs)
1816 viewGraph();
1817
1818 topologicalSort();
1819 findRootsAndBiasEdges(TopRoots, BotRoots);
1820 // We reuse several ScheduleDAGMI and ScheduleDAGMILive
1821 // functions, but to make them happy we must initialize
1822 // the default Scheduler implementation (even if we do not
1823 // run it)
1824 SchedImpl->initialize(this);
1825 initQueues(TopRoots, BotRoots);
1826
1827 // Fill some stats to help scheduling.
1828
1829 SUnitsLinksBackup = SUnits;
1830 IsLowLatencySU.clear();
1831 LowLatencyOffset.clear();
1832 IsHighLatencySU.clear();
1833
1834 IsLowLatencySU.resize(SUnits.size(), 0);
1835 LowLatencyOffset.resize(SUnits.size(), 0);
1836 IsHighLatencySU.resize(SUnits.size(), 0);
1837
1838 for (unsigned i = 0, e = (unsigned)SUnits.size(); i != e; ++i) {
1839 SUnit *SU = &SUnits[i];
1840 const MachineOperand *BaseLatOp;
1841 int64_t OffLatReg;
1842 if (SITII->isLowLatencyInstruction(*SU->getInstr())) {
1843 IsLowLatencySU[i] = 1;
1844 bool OffsetIsScalable;
1845 if (SITII->getMemOperandWithOffset(*SU->getInstr(), BaseLatOp, OffLatReg,
1846 OffsetIsScalable))
1847 LowLatencyOffset[i] = OffLatReg;
1848 } else if (SITII->isHighLatencyDef(SU->getInstr()->getOpcode()))
1849 IsHighLatencySU[i] = 1;
1850 }
1851
1852 SIScheduler Scheduler(this);
1855
1856 // if VGPR usage is extremely high, try other good performing variants
1857 // which could lead to lower VGPR usage
1858 if (Best.MaxVGPRUsage > 180) {
1859 static const std::pair<SISchedulerBlockCreatorVariant,
1861 Variants[] = {
1863// { LatenciesAlone, BlockRegUsage },
1865// { LatenciesGrouped, BlockRegUsageLatency },
1866// { LatenciesGrouped, BlockRegUsage },
1868// { LatenciesAlonePlusConsecutive, BlockRegUsageLatency },
1869// { LatenciesAlonePlusConsecutive, BlockRegUsage }
1870 };
1871 for (std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant> v : Variants) {
1872 Temp = Scheduler.scheduleVariant(v.first, v.second);
1873 if (Temp.MaxVGPRUsage < Best.MaxVGPRUsage)
1874 Best = Temp;
1875 }
1876 }
1877 // if VGPR usage is still extremely high, we may spill. Try other variants
1878 // which are less performing, but that could lead to lower VGPR usage.
1879 if (Best.MaxVGPRUsage > 200) {
1880 static const std::pair<SISchedulerBlockCreatorVariant,
1882 Variants[] = {
1883// { LatenciesAlone, BlockRegUsageLatency },
1885// { LatenciesGrouped, BlockLatencyRegUsage },
1888// { LatenciesAlonePlusConsecutive, BlockLatencyRegUsage },
1891 };
1892 for (std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant> v : Variants) {
1893 Temp = Scheduler.scheduleVariant(v.first, v.second);
1894 if (Temp.MaxVGPRUsage < Best.MaxVGPRUsage)
1895 Best = Temp;
1896 }
1897 }
1898
1899 ScheduledSUnits = Best.SUs;
1900 ScheduledSUnitsInv.resize(SUnits.size());
1901
1902 for (unsigned i = 0, e = (unsigned)SUnits.size(); i != e; ++i) {
1903 ScheduledSUnitsInv[ScheduledSUnits[i]] = i;
1904 }
1905
1906 moveLowLatencies();
1907
1908 // Tell the outside world about the result of the scheduling.
1909
1910 assert(TopRPTracker.getPos() == RegionBegin && "bad initial Top tracker");
1911 TopRPTracker.setPos(CurrentTop);
1912
1913 for (unsigned I : ScheduledSUnits) {
1914 SUnit *SU = &SUnits[I];
1915
1916 scheduleMI(SU, true);
1917
1918 LLVM_DEBUG(dbgs() << "Scheduling " << *SU << " " << *SU->getInstr());
1919 }
1920
1921 assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone.");
1922
1924
1925 LLVM_DEBUG({
1926 dbgs() << "*** Final schedule for "
1927 << printMBBReference(*begin()->getParent()) << " ***\n";
1928 dumpSchedule();
1929 dbgs() << '\n';
1930 });
1931}
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
PostRA Machine Instruction Scheduler
static MachineBasicBlock::const_iterator nextIfDebug(MachineBasicBlock::const_iterator I, MachineBasicBlock::const_iterator End)
If this iterator is a debug value, increment until reaching the End or a non-debug instruction.
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define P(N)
MachineRegisterInfo & MRI
Interface definition for SIInstrInfo.
static const char * getReasonStr(SIScheduleCandReason Reason)
static bool hasDataDependencyPred(const SUnit &SU, const SUnit &FromSU)
static bool isDefBetween(Register Reg, SlotIndex First, SlotIndex Last, const MachineRegisterInfo *MRI, const LiveIntervals *LIS)
SI Machine Scheduler interface.
#define LLVM_DEBUG(...)
Definition Debug.h:119
GenericScheduler shrinks the unscheduled zone using heuristics to balance the schedule.
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
MachineInstrBundleIterator< const MachineInstr > const_iterator
MachineInstrBundleIterator< MachineInstr > iterator
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
MachineOperand class - Representation of each machine instruction operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Iterate over the pressure sets affected by the given physical or virtual register.
unsigned getWeight() const
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Scheduling dependency.
Definition ScheduleDAG.h:54
SUnit * getSUnit() const
@ Data
Regular data dependence (aka true-dependence).
Definition ScheduleDAG.h:58
bool isWeak() const
Tests if this a weak dependence.
bool isCtrl() const
Shorthand for getKind() != SDep::Data.
static bool isEXP(const MachineInstr &MI)
bool isLowLatencyInstruction(const MachineInstr &MI) const
bool isSUInBlock(SUnit *SU, unsigned ID)
SIScheduleBlockCreator(SIScheduleDAGMI *DAG)
SIScheduleBlocks getBlocks(SISchedulerBlockCreatorVariant BlockVariant)
SIScheduleBlockScheduler(SIScheduleDAGMI *DAG, SISchedulerBlockSchedulerVariant Variant, SIScheduleBlocks BlocksStruct)
SIScheduleBlock(SIScheduleDAGMI *DAG, SIScheduleBlockCreator *BC, unsigned ID)
ArrayRef< std::pair< SIScheduleBlock *, SIScheduleBlockLinkKind > > getSuccs() const
void addPred(SIScheduleBlock *Pred)
void addSucc(SIScheduleBlock *Succ, SIScheduleBlockLinkKind Kind)
void schedule(MachineBasicBlock::iterator BeginBlock, MachineBasicBlock::iterator EndBlock)
void addUnit(SUnit *SU)
Functions for Block construction.
std::vector< int > BottomUpIndex2SU
std::vector< unsigned > IsHighLatencySU
std::vector< unsigned > LowLatencyOffset
std::vector< int > TopDownIndex2SU
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
void fillVgprSgprCost(_Iterator First, _Iterator End, unsigned &VgprUsage, unsigned &SgprUsage)
SIScheduleDAGMI(MachineSchedContext *C)
std::vector< unsigned > IsLowLatencySU
~SIScheduleDAGMI() override
struct SIScheduleBlockResult scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant, SISchedulerBlockSchedulerVariant ScheduleVariant)
SIScheduler(SIScheduleDAGMI *DAG)
Scheduling unit. This is a node in the scheduling DAG.
bool isInstr() const
Returns true if this SUnit refers to a machine instruction as opposed to an SDNode.
unsigned NodeNum
Entry # of node in the node vector.
bool isScheduled
True once scheduled.
unsigned NumPredsLeft
SmallVector< SDep, 4 > Succs
All sunit successors.
unsigned WeakPredsLeft
SmallVector< SDep, 4 > Preds
All sunit predecessors.
LLVM_ABI bool addPred(const SDep &D, bool Required=true)
Adds the specified edge as a pred of the current node if not already.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
ScheduleDAGTopologicalSort Topo
Topo - A topological ordering for SUnits which permits fast IsReachable and similar queries.
MachineBasicBlock::iterator begin() const
Returns an iterator to the top of the current scheduling region.
MachineBasicBlock::iterator RegionBegin
The beginning of the range to be scheduled.
void scheduleMI(SUnit *SU, bool IsTopNode)
Move an instruction and update register pressure.
void initQueues(ArrayRef< SUnit * > TopRoots, ArrayRef< SUnit * > BotRoots)
Release ExitSU predecessors and setup scheduler queues.
void buildDAGWithRegPressure()
Call ScheduleDAGInstrs::buildSchedGraph with register pressure tracking enabled.
ScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S)
void dump() const override
RegPressureTracker TopRPTracker
void dumpSchedule() const
dump the scheduled Sequence.
std::unique_ptr< MachineSchedStrategy > SchedImpl
void postProcessDAG()
Apply each ScheduleDAGMutation step in order.
void findRootsAndBiasEdges(SmallVectorImpl< SUnit * > &TopRoots, SmallVectorImpl< SUnit * > &BotRoots)
MachineBasicBlock::iterator CurrentBottom
The bottom of the unscheduled zone.
void viewGraph() override
Out-of-line implementation with no arguments is handy for gdb.
void placeDebugValues()
Reinsert debug_values recorded in ScheduleDAGInstrs::DbgValues.
MachineBasicBlock::iterator CurrentTop
The top of the unscheduled zone.
LLVM_ABI void InitDAGTopologicalSorting()
Creates the initial topological ordering from the DAG to be scheduled.
MachineRegisterInfo & MRI
Virtual/real register map.
const TargetInstrInfo * TII
Target instruction information.
std::vector< SUnit > SUnits
The scheduling units.
const TargetRegisterInfo * TRI
Target processor register info.
SlotIndex - An opaque wrapper around machine indexes.
Definition SlotIndexes.h:70
SlotIndex getRegSlot(bool EC=false) const
Returns the register use/def slot in the current instruction for a normal or early-clobber def.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Wrapper class representing a virtual register or register unit.
Definition Register.h:175
constexpr bool isVirtualReg() const
Definition Register.h:191
constexpr Register asVirtualReg() const
Definition Register.h:200
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static bool tryGreater(int TryVal, int CandVal, SISchedulerCandidate &TryCand, SISchedulerCandidate &Cand, SIScheduleCandReason Reason)
static bool tryLess(int TryVal, int CandVal, SISchedulerCandidate &TryCand, SISchedulerCandidate &Cand, SIScheduleCandReason Reason)
constexpr double e
This is an optimization pass for GlobalISel generic memory operations.
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1781
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2224
SISchedulerBlockSchedulerVariant
cl::opt< bool > ViewMISchedDAGs
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
SISchedulerBlockCreatorVariant
@ LatenciesAlonePlusConsecutive
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2104
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
cl::opt< bool > PrintDAGs
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
#define NDEBUG
Definition regutils.h:48
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...
std::vector< unsigned > MaxSetPressure
Map of max reg pressure indexed by pressure set ID, not class ID.
std::vector< unsigned > SUs
std::vector< int > TopDownIndex2Block
std::vector< SIScheduleBlock * > Blocks
std::vector< int > TopDownBlock2Index
SIScheduleCandReason Reason
void setRepeat(SIScheduleCandReason R)