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.
287 const MachineRegisterInfo *MRI,
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)
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,...
iterator_range< def_instr_iterator > def_instructions(Register Reg) const
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:66
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
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)