clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name HexagonMachineScheduler.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Target/Hexagon -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Target/Hexagon -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/Target/Hexagon -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include -D NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Target/Hexagon -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e=. -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-09-04-040900-46481-1 -x c++ /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/Target/Hexagon/HexagonMachineScheduler.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "HexagonMachineScheduler.h" |
15 | #include "HexagonInstrInfo.h" |
16 | #include "HexagonSubtarget.h" |
17 | #include "llvm/ADT/SmallVector.h" |
18 | #include "llvm/CodeGen/DFAPacketizer.h" |
19 | #include "llvm/CodeGen/MachineBasicBlock.h" |
20 | #include "llvm/CodeGen/MachineFunction.h" |
21 | #include "llvm/CodeGen/MachineInstr.h" |
22 | #include "llvm/CodeGen/MachineLoopInfo.h" |
23 | #include "llvm/CodeGen/RegisterClassInfo.h" |
24 | #include "llvm/CodeGen/RegisterPressure.h" |
25 | #include "llvm/CodeGen/ScheduleDAG.h" |
26 | #include "llvm/CodeGen/ScheduleHazardRecognizer.h" |
27 | #include "llvm/CodeGen/TargetInstrInfo.h" |
28 | #include "llvm/CodeGen/TargetOpcodes.h" |
29 | #include "llvm/CodeGen/TargetRegisterInfo.h" |
30 | #include "llvm/CodeGen/TargetSchedule.h" |
31 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
32 | #include "llvm/IR/Function.h" |
33 | #include "llvm/Support/CommandLine.h" |
34 | #include "llvm/Support/Debug.h" |
35 | #include "llvm/Support/raw_ostream.h" |
36 | #include <algorithm> |
37 | #include <cassert> |
38 | #include <iomanip> |
39 | #include <limits> |
40 | #include <memory> |
41 | #include <sstream> |
42 | |
43 | using namespace llvm; |
44 | |
45 | #define DEBUG_TYPE "machine-scheduler" |
46 | |
47 | static cl::opt<bool> IgnoreBBRegPressure("ignore-bb-reg-pressure", |
48 | cl::Hidden, cl::ZeroOrMore, cl::init(false)); |
49 | |
50 | static cl::opt<bool> UseNewerCandidate("use-newer-candidate", |
51 | cl::Hidden, cl::ZeroOrMore, cl::init(true)); |
52 | |
53 | static cl::opt<unsigned> SchedDebugVerboseLevel("misched-verbose-level", |
54 | cl::Hidden, cl::ZeroOrMore, cl::init(1)); |
55 | |
56 | |
57 | |
58 | static cl::opt<bool> CheckEarlyAvail("check-early-avail", cl::Hidden, |
59 | cl::ZeroOrMore, cl::init(true)); |
60 | |
61 | |
62 | |
63 | |
64 | static cl::opt<float> RPThreshold("hexagon-reg-pressure", cl::Hidden, |
65 | cl::init(0.75f), cl::desc("High register pressure threhold.")); |
66 | |
67 | |
68 | static bool hasDependence(const SUnit *SUd, const SUnit *SUu, |
69 | const HexagonInstrInfo &QII) { |
70 | if (SUd->Succs.size() == 0) |
71 | return false; |
72 | |
73 | |
74 | if (QII.mayBeCurLoad(*SUd->getInstr())) |
75 | return false; |
76 | |
77 | if (QII.canExecuteInBundle(*SUd->getInstr(), *SUu->getInstr())) |
78 | return false; |
79 | |
80 | for (const auto &S : SUd->Succs) { |
81 | |
82 | |
83 | if (S.isCtrl()) |
84 | continue; |
85 | |
86 | if (S.getSUnit() == SUu && S.getLatency() > 0) |
87 | return true; |
88 | } |
89 | return false; |
90 | } |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | bool VLIWResourceModel::isResourceAvailable(SUnit *SU, bool IsTop) { |
98 | if (!SU || !SU->getInstr()) |
99 | return false; |
100 | |
101 | |
102 | |
103 | switch (SU->getInstr()->getOpcode()) { |
104 | default: |
105 | if (!ResourcesModel->canReserveResources(*SU->getInstr())) |
106 | return false; |
107 | break; |
108 | case TargetOpcode::EXTRACT_SUBREG: |
109 | case TargetOpcode::INSERT_SUBREG: |
110 | case TargetOpcode::SUBREG_TO_REG: |
111 | case TargetOpcode::REG_SEQUENCE: |
112 | case TargetOpcode::IMPLICIT_DEF: |
113 | case TargetOpcode::COPY: |
114 | case TargetOpcode::INLINEASM: |
115 | case TargetOpcode::INLINEASM_BR: |
116 | break; |
117 | } |
118 | |
119 | MachineBasicBlock *MBB = SU->getInstr()->getParent(); |
120 | auto &QST = MBB->getParent()->getSubtarget<HexagonSubtarget>(); |
121 | const auto &QII = *QST.getInstrInfo(); |
122 | |
123 | |
124 | |
125 | if (IsTop) { |
126 | for (unsigned i = 0, e = Packet.size(); i != e; ++i) |
127 | if (hasDependence(Packet[i], SU, QII)) |
128 | return false; |
129 | } else { |
130 | for (unsigned i = 0, e = Packet.size(); i != e; ++i) |
131 | if (hasDependence(SU, Packet[i], QII)) |
132 | return false; |
133 | } |
134 | return true; |
135 | } |
136 | |
137 | |
138 | bool VLIWResourceModel::reserveResources(SUnit *SU, bool IsTop) { |
139 | bool startNewCycle = false; |
140 | |
141 | if (!SU) { |
142 | ResourcesModel->clearResources(); |
143 | Packet.clear(); |
144 | TotalPackets++; |
145 | return false; |
146 | } |
147 | |
148 | |
149 | if (!isResourceAvailable(SU, IsTop) || |
150 | Packet.size() >= SchedModel->getIssueWidth()) { |
151 | ResourcesModel->clearResources(); |
152 | Packet.clear(); |
153 | TotalPackets++; |
154 | startNewCycle = true; |
155 | } |
156 | |
157 | switch (SU->getInstr()->getOpcode()) { |
158 | default: |
159 | ResourcesModel->reserveResources(*SU->getInstr()); |
160 | break; |
161 | case TargetOpcode::EXTRACT_SUBREG: |
162 | case TargetOpcode::INSERT_SUBREG: |
163 | case TargetOpcode::SUBREG_TO_REG: |
164 | case TargetOpcode::REG_SEQUENCE: |
165 | case TargetOpcode::IMPLICIT_DEF: |
166 | case TargetOpcode::KILL: |
167 | case TargetOpcode::CFI_INSTRUCTION: |
168 | case TargetOpcode::EH_LABEL: |
169 | case TargetOpcode::COPY: |
170 | case TargetOpcode::INLINEASM: |
171 | case TargetOpcode::INLINEASM_BR: |
172 | break; |
173 | } |
174 | Packet.push_back(SU); |
175 | |
176 | #ifndef NDEBUG |
177 | LLVM_DEBUG(dbgs() << "Packet[" << TotalPackets << "]:\n"); |
178 | for (unsigned i = 0, e = Packet.size(); i != e; ++i) { |
179 | LLVM_DEBUG(dbgs() << "\t[" << i << "] SU("); |
180 | LLVM_DEBUG(dbgs() << Packet[i]->NodeNum << ")\t"); |
181 | LLVM_DEBUG(Packet[i]->getInstr()->dump()); |
182 | } |
183 | #endif |
184 | |
185 | return startNewCycle; |
186 | } |
187 | |
188 | |
189 | |
190 | |
191 | void VLIWMachineScheduler::schedule() { |
192 | LLVM_DEBUG(dbgs() << "********** MI Converging Scheduling VLIW " |
193 | << printMBBReference(*BB) << " " << BB->getName() |
194 | << " in_func " << BB->getParent()->getName() |
195 | << " at loop depth " << MLI->getLoopDepth(BB) << " \n"); |
196 | |
197 | buildDAGWithRegPressure(); |
198 | |
199 | Topo.InitDAGTopologicalSorting(); |
200 | |
201 | |
202 | postprocessDAG(); |
203 | |
204 | SmallVector<SUnit*, 8> TopRoots, BotRoots; |
205 | findRootsAndBiasEdges(TopRoots, BotRoots); |
206 | |
207 | |
208 | SchedImpl->initialize(this); |
209 | |
210 | LLVM_DEBUG(unsigned maxH = 0; |
211 | for (unsigned su = 0, e = SUnits.size(); su != e; |
212 | ++su) if (SUnits[su].getHeight() > maxH) maxH = |
213 | SUnits[su].getHeight(); |
214 | dbgs() << "Max Height " << maxH << "\n";); |
215 | LLVM_DEBUG(unsigned maxD = 0; |
216 | for (unsigned su = 0, e = SUnits.size(); su != e; |
217 | ++su) if (SUnits[su].getDepth() > maxD) maxD = |
218 | SUnits[su].getDepth(); |
219 | dbgs() << "Max Depth " << maxD << "\n";); |
220 | LLVM_DEBUG(dump()); |
221 | |
222 | initQueues(TopRoots, BotRoots); |
223 | |
224 | bool IsTopNode = false; |
225 | while (true) { |
226 | LLVM_DEBUG( |
227 | dbgs() << "** VLIWMachineScheduler::schedule picking next node\n"); |
228 | SUnit *SU = SchedImpl->pickNode(IsTopNode); |
229 | if (!SU) break; |
230 | |
231 | if (!checkSchedLimit()) |
232 | break; |
233 | |
234 | scheduleMI(SU, IsTopNode); |
235 | |
236 | |
237 | SchedImpl->schedNode(SU, IsTopNode); |
238 | |
239 | updateQueues(SU, IsTopNode); |
240 | } |
241 | assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); |
242 | |
243 | placeDebugValues(); |
244 | |
245 | LLVM_DEBUG({ |
246 | dbgs() << "*** Final schedule for " |
247 | << printMBBReference(*begin()->getParent()) << " ***\n"; |
248 | dumpSchedule(); |
249 | dbgs() << '\n'; |
250 | }); |
251 | } |
252 | |
253 | void ConvergingVLIWScheduler::initialize(ScheduleDAGMI *dag) { |
254 | DAG = static_cast<VLIWMachineScheduler*>(dag); |
255 | SchedModel = DAG->getSchedModel(); |
256 | |
257 | Top.init(DAG, SchedModel); |
258 | Bot.init(DAG, SchedModel); |
259 | |
260 | |
261 | |
262 | const InstrItineraryData *Itin = DAG->getSchedModel()->getInstrItineraries(); |
263 | const TargetSubtargetInfo &STI = DAG->MF.getSubtarget(); |
264 | const TargetInstrInfo *TII = STI.getInstrInfo(); |
265 | delete Top.HazardRec; |
266 | delete Bot.HazardRec; |
267 | Top.HazardRec = TII->CreateTargetMIHazardRecognizer(Itin, DAG); |
268 | Bot.HazardRec = TII->CreateTargetMIHazardRecognizer(Itin, DAG); |
269 | |
270 | delete Top.ResourceModel; |
271 | delete Bot.ResourceModel; |
272 | Top.ResourceModel = new VLIWResourceModel(STI, DAG->getSchedModel()); |
273 | Bot.ResourceModel = new VLIWResourceModel(STI, DAG->getSchedModel()); |
274 | |
275 | const std::vector<unsigned> &MaxPressure = |
276 | DAG->getRegPressure().MaxSetPressure; |
277 | HighPressureSets.assign(MaxPressure.size(), 0); |
278 | for (unsigned i = 0, e = MaxPressure.size(); i < e; ++i) { |
279 | unsigned Limit = DAG->getRegClassInfo()->getRegPressureSetLimit(i); |
280 | HighPressureSets[i] = |
281 | ((float) MaxPressure[i] > ((float) Limit * RPThreshold)); |
282 | } |
283 | |
284 | assert((!ForceTopDown || !ForceBottomUp) && |
285 | "-misched-topdown incompatible with -misched-bottomup"); |
286 | } |
287 | |
288 | void ConvergingVLIWScheduler::releaseTopNode(SUnit *SU) { |
289 | if (SU->isScheduled) |
290 | return; |
291 | |
292 | for (const SDep &PI : SU->Preds) { |
293 | unsigned PredReadyCycle = PI.getSUnit()->TopReadyCycle; |
294 | unsigned MinLatency = PI.getLatency(); |
295 | #ifndef NDEBUG |
296 | Top.MaxMinLatency = std::max(MinLatency, Top.MaxMinLatency); |
297 | #endif |
298 | if (SU->TopReadyCycle < PredReadyCycle + MinLatency) |
299 | SU->TopReadyCycle = PredReadyCycle + MinLatency; |
300 | } |
301 | Top.releaseNode(SU, SU->TopReadyCycle); |
302 | } |
303 | |
304 | void ConvergingVLIWScheduler::releaseBottomNode(SUnit *SU) { |
305 | if (SU->isScheduled) |
306 | return; |
307 | |
308 | assert(SU->getInstr() && "Scheduled SUnit must have instr"); |
309 | |
310 | for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); |
311 | I != E; ++I) { |
312 | unsigned SuccReadyCycle = I->getSUnit()->BotReadyCycle; |
313 | unsigned MinLatency = I->getLatency(); |
314 | #ifndef NDEBUG |
315 | Bot.MaxMinLatency = std::max(MinLatency, Bot.MaxMinLatency); |
316 | #endif |
317 | if (SU->BotReadyCycle < SuccReadyCycle + MinLatency) |
318 | SU->BotReadyCycle = SuccReadyCycle + MinLatency; |
319 | } |
320 | Bot.releaseNode(SU, SU->BotReadyCycle); |
321 | } |
322 | |
323 | |
324 | |
325 | |
326 | |
327 | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 | bool ConvergingVLIWScheduler::VLIWSchedBoundary::checkHazard(SUnit *SU) { |
337 | if (HazardRec->isEnabled()) |
338 | return HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard; |
339 | |
340 | unsigned uops = SchedModel->getNumMicroOps(SU->getInstr()); |
341 | if (IssueCount + uops > SchedModel->getIssueWidth()) |
342 | return true; |
343 | |
344 | return false; |
345 | } |
346 | |
347 | void ConvergingVLIWScheduler::VLIWSchedBoundary::releaseNode(SUnit *SU, |
348 | unsigned ReadyCycle) { |
349 | if (ReadyCycle < MinReadyCycle) |
350 | MinReadyCycle = ReadyCycle; |
351 | |
352 | |
353 | |
354 | if (ReadyCycle > CurrCycle || checkHazard(SU)) |
355 | |
356 | Pending.push(SU); |
357 | else |
358 | Available.push(SU); |
359 | } |
360 | |
361 | |
362 | void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpCycle() { |
363 | unsigned Width = SchedModel->getIssueWidth(); |
364 | IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width; |
365 | |
366 | assert(MinReadyCycle < std::numeric_limits<unsigned>::max() && |
367 | "MinReadyCycle uninitialized"); |
368 | unsigned NextCycle = std::max(CurrCycle + 1, MinReadyCycle); |
369 | |
370 | if (!HazardRec->isEnabled()) { |
371 | |
372 | CurrCycle = NextCycle; |
373 | } else { |
374 | |
375 | for (; CurrCycle != NextCycle; ++CurrCycle) { |
376 | if (isTop()) |
377 | HazardRec->AdvanceCycle(); |
378 | else |
379 | HazardRec->RecedeCycle(); |
380 | } |
381 | } |
382 | CheckPending = true; |
383 | |
384 | LLVM_DEBUG(dbgs() << "*** Next cycle " << Available.getName() << " cycle " |
385 | << CurrCycle << '\n'); |
386 | } |
387 | |
388 | |
389 | void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpNode(SUnit *SU) { |
390 | bool startNewCycle = false; |
391 | |
392 | |
393 | if (HazardRec->isEnabled()) { |
394 | if (!isTop() && SU->isCall) { |
395 | |
396 | |
397 | HazardRec->Reset(); |
398 | } |
399 | HazardRec->EmitInstruction(SU); |
400 | } |
401 | |
402 | |
403 | startNewCycle = ResourceModel->reserveResources(SU, isTop()); |
404 | |
405 | |
406 | |
407 | IssueCount += SchedModel->getNumMicroOps(SU->getInstr()); |
408 | if (startNewCycle) { |
409 | LLVM_DEBUG(dbgs() << "*** Max instrs at cycle " << CurrCycle << '\n'); |
410 | bumpCycle(); |
411 | } |
412 | else |
413 | LLVM_DEBUG(dbgs() << "*** IssueCount " << IssueCount << " at cycle " |
414 | << CurrCycle << '\n'); |
415 | } |
416 | |
417 | |
418 | |
419 | void ConvergingVLIWScheduler::VLIWSchedBoundary::releasePending() { |
420 | |
421 | if (Available.empty()) |
422 | MinReadyCycle = std::numeric_limits<unsigned>::max(); |
423 | |
424 | |
425 | |
426 | for (unsigned i = 0, e = Pending.size(); i != e; ++i) { |
427 | SUnit *SU = *(Pending.begin()+i); |
428 | unsigned ReadyCycle = isTop() ? SU->TopReadyCycle : SU->BotReadyCycle; |
429 | |
430 | if (ReadyCycle < MinReadyCycle) |
431 | MinReadyCycle = ReadyCycle; |
432 | |
433 | if (ReadyCycle > CurrCycle) |
434 | continue; |
435 | |
436 | if (checkHazard(SU)) |
437 | continue; |
438 | |
439 | Available.push(SU); |
440 | Pending.remove(Pending.begin()+i); |
441 | --i; --e; |
442 | } |
443 | CheckPending = false; |
444 | } |
445 | |
446 | |
447 | void ConvergingVLIWScheduler::VLIWSchedBoundary::removeReady(SUnit *SU) { |
448 | if (Available.isInQueue(SU)) |
449 | Available.remove(Available.find(SU)); |
450 | else { |
451 | assert(Pending.isInQueue(SU) && "bad ready count"); |
452 | Pending.remove(Pending.find(SU)); |
453 | } |
454 | } |
455 | |
456 | |
457 | |
458 | |
459 | SUnit *ConvergingVLIWScheduler::VLIWSchedBoundary::pickOnlyChoice() { |
460 | if (CheckPending) |
| 12 | | Assuming field 'CheckPending' is false | |
|
| |
461 | releasePending(); |
462 | |
463 | auto AdvanceCycle = [this]() { |
464 | if (Available.empty()) |
465 | return true; |
466 | if (Available.size() == 1 && Pending.size() > 0) |
467 | return !ResourceModel->isResourceAvailable(*Available.begin(), isTop()) || |
468 | getWeakLeft(*Available.begin(), isTop()) != 0; |
469 | return false; |
470 | }; |
471 | for (unsigned i = 0; AdvanceCycle(); ++i) { |
| 14 | | Loop condition is false. Execution continues on line 478 | |
|
472 | assert(i <= (HazardRec->getMaxLookAhead() + MaxMinLatency) && |
473 | "permanent hazard"); (void)i; |
474 | ResourceModel->reserveResources(nullptr, isTop()); |
475 | bumpCycle(); |
476 | releasePending(); |
477 | } |
478 | if (Available.size() == 1) |
| 15 | | Assuming the condition is false | |
|
| |
479 | return *Available.begin(); |
480 | return nullptr; |
| 17 | | Returning null pointer, which participates in a condition later | |
|
481 | } |
482 | |
483 | #ifndef NDEBUG |
484 | void ConvergingVLIWScheduler::traceCandidate(const char *Label, |
485 | const ReadyQueue &Q, SUnit *SU, int Cost, PressureChange P) { |
486 | dbgs() << Label << " " << Q.getName() << " "; |
487 | if (P.isValid()) |
488 | dbgs() << DAG->TRI->getRegPressureSetName(P.getPSet()) << ":" |
489 | << P.getUnitInc() << " "; |
490 | else |
491 | dbgs() << " "; |
492 | dbgs() << "cost(" << Cost << ")\t"; |
493 | DAG->dumpNode(*SU); |
494 | } |
495 | |
496 | |
497 | void ConvergingVLIWScheduler::readyQueueVerboseDump( |
498 | const RegPressureTracker &RPTracker, SchedCandidate &Candidate, |
499 | ReadyQueue &Q) { |
500 | RegPressureTracker &TempTracker = const_cast<RegPressureTracker &>(RPTracker); |
501 | |
502 | dbgs() << ">>> " << Q.getName() << "\n"; |
503 | for (ReadyQueue::iterator I = Q.begin(), E = Q.end(); I != E; ++I) { |
504 | RegPressureDelta RPDelta; |
505 | TempTracker.getMaxPressureDelta((*I)->getInstr(), RPDelta, |
506 | DAG->getRegionCriticalPSets(), |
507 | DAG->getRegPressure().MaxSetPressure); |
508 | std::stringstream dbgstr; |
509 | dbgstr << "SU(" << std::setw(3) << (*I)->NodeNum << ")"; |
510 | dbgs() << dbgstr.str(); |
511 | SchedulingCost(Q, *I, Candidate, RPDelta, true); |
512 | dbgs() << "\t"; |
513 | (*I)->getInstr()->dump(); |
514 | } |
515 | dbgs() << "\n"; |
516 | } |
517 | #endif |
518 | |
519 | |
520 | |
521 | static inline bool isSingleUnscheduledPred(SUnit *SU, SUnit *SU2) { |
522 | if (SU->NumPredsLeft == 0) |
523 | return false; |
524 | |
525 | for (auto &Pred : SU->Preds) { |
526 | |
527 | if (!Pred.getSUnit()->isScheduled && (Pred.getSUnit() != SU2)) |
528 | return false; |
529 | } |
530 | |
531 | return true; |
532 | } |
533 | |
534 | |
535 | |
536 | static inline bool isSingleUnscheduledSucc(SUnit *SU, SUnit *SU2) { |
537 | if (SU->NumSuccsLeft == 0) |
538 | return false; |
539 | |
540 | for (auto &Succ : SU->Succs) { |
541 | |
542 | if (!Succ.getSUnit()->isScheduled && (Succ.getSUnit() != SU2)) |
543 | return false; |
544 | } |
545 | return true; |
546 | } |
547 | |
548 | |
549 | |
550 | |
551 | |
552 | |
553 | int ConvergingVLIWScheduler::pressureChange(const SUnit *SU, bool isBotUp) { |
554 | PressureDiff &PD = DAG->getPressureDiff(SU); |
555 | for (auto &P : PD) { |
556 | if (!P.isValid()) |
557 | continue; |
558 | |
559 | |
560 | |
561 | if (HighPressureSets[P.getPSet()]) |
562 | return (isBotUp ? P.getUnitInc() : -P.getUnitInc()); |
563 | } |
564 | return 0; |
565 | } |
566 | |
567 | |
568 | |
569 | static const unsigned PriorityOne = 200; |
570 | static const unsigned PriorityTwo = 50; |
571 | static const unsigned PriorityThree = 75; |
572 | static const unsigned ScaleTwo = 10; |
573 | |
574 | |
575 | |
576 | int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU, |
577 | SchedCandidate &Candidate, |
578 | RegPressureDelta &Delta, |
579 | bool verbose) { |
580 | |
581 | int ResCount = 1; |
582 | |
583 | |
584 | if (!SU || SU->isScheduled) |
585 | return ResCount; |
586 | |
587 | LLVM_DEBUG(if (verbose) dbgs() |
588 | << ((Q.getID() == TopQID) ? "(top|" : "(bot|")); |
589 | |
590 | if (SU->isScheduleHigh) { |
591 | ResCount += PriorityOne; |
592 | LLVM_DEBUG(dbgs() << "H|"); |
593 | } |
594 | |
595 | unsigned IsAvailableAmt = 0; |
596 | |
597 | if (Q.getID() == TopQID) { |
598 | if (Top.isLatencyBound(SU)) { |
599 | LLVM_DEBUG(if (verbose) dbgs() << "LB|"); |
600 | ResCount += (SU->getHeight() * ScaleTwo); |
601 | } |
602 | |
603 | LLVM_DEBUG(if (verbose) { |
604 | std::stringstream dbgstr; |
605 | dbgstr << "h" << std::setw(3) << SU->getHeight() << "|"; |
606 | dbgs() << dbgstr.str(); |
607 | }); |
608 | |
609 | |
610 | |
611 | if (Top.ResourceModel->isResourceAvailable(SU, true)) { |
612 | IsAvailableAmt = (PriorityTwo + PriorityThree); |
613 | ResCount += IsAvailableAmt; |
614 | LLVM_DEBUG(if (verbose) dbgs() << "A|"); |
615 | } else |
616 | LLVM_DEBUG(if (verbose) dbgs() << " |"); |
617 | } else { |
618 | if (Bot.isLatencyBound(SU)) { |
619 | LLVM_DEBUG(if (verbose) dbgs() << "LB|"); |
620 | ResCount += (SU->getDepth() * ScaleTwo); |
621 | } |
622 | |
623 | LLVM_DEBUG(if (verbose) { |
624 | std::stringstream dbgstr; |
625 | dbgstr << "d" << std::setw(3) << SU->getDepth() << "|"; |
626 | dbgs() << dbgstr.str(); |
627 | }); |
628 | |
629 | |
630 | |
631 | if (Bot.ResourceModel->isResourceAvailable(SU, false)) { |
632 | IsAvailableAmt = (PriorityTwo + PriorityThree); |
633 | ResCount += IsAvailableAmt; |
634 | LLVM_DEBUG(if (verbose) dbgs() << "A|"); |
635 | } else |
636 | LLVM_DEBUG(if (verbose) dbgs() << " |"); |
637 | } |
638 | |
639 | unsigned NumNodesBlocking = 0; |
640 | if (Q.getID() == TopQID) { |
641 | |
642 | |
643 | |
644 | |
645 | if (Top.isLatencyBound(SU)) |
646 | for (const SDep &SI : SU->Succs) |
647 | if (isSingleUnscheduledPred(SI.getSUnit(), SU)) |
648 | ++NumNodesBlocking; |
649 | } else { |
650 | |
651 | if (Bot.isLatencyBound(SU)) |
652 | for (const SDep &PI : SU->Preds) |
653 | if (isSingleUnscheduledSucc(PI.getSUnit(), SU)) |
654 | ++NumNodesBlocking; |
655 | } |
656 | ResCount += (NumNodesBlocking * ScaleTwo); |
657 | |
658 | LLVM_DEBUG(if (verbose) { |
659 | std::stringstream dbgstr; |
660 | dbgstr << "blk " << std::setw(2) << NumNodesBlocking << ")|"; |
661 | dbgs() << dbgstr.str(); |
662 | }); |
663 | |
664 | |
665 | if (!IgnoreBBRegPressure) { |
666 | |
667 | ResCount -= (Delta.Excess.getUnitInc()*PriorityOne); |
668 | |
669 | ResCount -= (Delta.CriticalMax.getUnitInc()*PriorityOne); |
670 | |
671 | |
672 | ResCount -= (Delta.CurrentMax.getUnitInc()*PriorityTwo); |
673 | |
674 | |
675 | |
676 | if (IsAvailableAmt && pressureChange(SU, Q.getID() != TopQID) > 0 && |
677 | (Delta.Excess.getUnitInc() || Delta.CriticalMax.getUnitInc() || |
678 | Delta.CurrentMax.getUnitInc())) |
679 | ResCount -= IsAvailableAmt; |
680 | LLVM_DEBUG(if (verbose) { |
681 | dbgs() << "RP " << Delta.Excess.getUnitInc() << "/" |
682 | << Delta.CriticalMax.getUnitInc() << "/" |
683 | << Delta.CurrentMax.getUnitInc() << ")|"; |
684 | }); |
685 | } |
686 | |
687 | |
688 | |
689 | auto &QST = DAG->MF.getSubtarget<HexagonSubtarget>(); |
690 | auto &QII = *QST.getInstrInfo(); |
691 | if (SU->isInstr() && QII.mayBeCurLoad(*SU->getInstr())) { |
692 | if (Q.getID() == TopQID && |
693 | Top.ResourceModel->isResourceAvailable(SU, true)) { |
694 | ResCount += PriorityTwo; |
695 | LLVM_DEBUG(if (verbose) dbgs() << "C|"); |
696 | } else if (Q.getID() == BotQID && |
697 | Bot.ResourceModel->isResourceAvailable(SU, false)) { |
698 | ResCount += PriorityTwo; |
699 | LLVM_DEBUG(if (verbose) dbgs() << "C|"); |
700 | } |
701 | } |
702 | |
703 | |
704 | |
705 | if (Q.getID() == TopQID && getWeakLeft(SU, true) == 0) { |
706 | for (const SDep &PI : SU->Preds) { |
707 | if (!PI.getSUnit()->getInstr()->isPseudo() && PI.isAssignedRegDep() && |
708 | PI.getLatency() == 0 && |
709 | Top.ResourceModel->isInPacket(PI.getSUnit())) { |
710 | ResCount += PriorityThree; |
711 | LLVM_DEBUG(if (verbose) dbgs() << "Z|"); |
712 | } |
713 | } |
714 | } else if (Q.getID() == BotQID && getWeakLeft(SU, false) == 0) { |
715 | for (const SDep &SI : SU->Succs) { |
716 | if (!SI.getSUnit()->getInstr()->isPseudo() && SI.isAssignedRegDep() && |
717 | SI.getLatency() == 0 && |
718 | Bot.ResourceModel->isInPacket(SI.getSUnit())) { |
719 | ResCount += PriorityThree; |
720 | LLVM_DEBUG(if (verbose) dbgs() << "Z|"); |
721 | } |
722 | } |
723 | } |
724 | |
725 | |
726 | |
727 | |
728 | |
729 | |
730 | if (CheckEarlyAvail) { |
731 | if (Q.getID() == TopQID) { |
732 | for (const auto &PI : SU->Preds) { |
733 | if (PI.getLatency() > 0 && |
734 | Top.ResourceModel->isInPacket(PI.getSUnit())) { |
735 | ResCount -= PriorityOne; |
736 | LLVM_DEBUG(if (verbose) dbgs() << "D|"); |
737 | } |
738 | } |
739 | } else { |
740 | for (const auto &SI : SU->Succs) { |
741 | if (SI.getLatency() > 0 && |
742 | Bot.ResourceModel->isInPacket(SI.getSUnit())) { |
743 | ResCount -= PriorityOne; |
744 | LLVM_DEBUG(if (verbose) dbgs() << "D|"); |
745 | } |
746 | } |
747 | } |
748 | } |
749 | |
750 | LLVM_DEBUG(if (verbose) { |
751 | std::stringstream dbgstr; |
752 | dbgstr << "Total " << std::setw(4) << ResCount << ")"; |
753 | dbgs() << dbgstr.str(); |
754 | }); |
755 | |
756 | return ResCount; |
757 | } |
758 | |
759 | |
760 | |
761 | |
762 | |
763 | |
764 | ConvergingVLIWScheduler::CandResult ConvergingVLIWScheduler:: |
765 | pickNodeFromQueue(VLIWSchedBoundary &Zone, const RegPressureTracker &RPTracker, |
766 | SchedCandidate &Candidate) { |
767 | ReadyQueue &Q = Zone.Available; |
768 | LLVM_DEBUG(if (SchedDebugVerboseLevel > 1) |
| 24 | | Loop condition is false. Exiting loop | |
|
769 | readyQueueVerboseDump(RPTracker, Candidate, Q); |
770 | else Q.dump();); |
771 | |
772 | |
773 | RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker); |
774 | |
775 | |
776 | CandResult FoundCandidate = NoCand; |
777 | for (ReadyQueue::iterator I = Q.begin(), E = Q.end(); I != E; ++I) { |
| 25 | | Loop condition is false. Execution continues on line 875 | |
|
778 | RegPressureDelta RPDelta; |
779 | TempTracker.getMaxPressureDelta((*I)->getInstr(), RPDelta, |
780 | DAG->getRegionCriticalPSets(), |
781 | DAG->getRegPressure().MaxSetPressure); |
782 | |
783 | int CurrentCost = SchedulingCost(Q, *I, Candidate, RPDelta, false); |
784 | |
785 | |
786 | if (!Candidate.SU) { |
787 | LLVM_DEBUG(traceCandidate("DCAND", Q, *I, CurrentCost)); |
788 | Candidate.SU = *I; |
789 | Candidate.RPDelta = RPDelta; |
790 | Candidate.SCost = CurrentCost; |
791 | FoundCandidate = NodeOrder; |
792 | continue; |
793 | } |
794 | |
795 | |
796 | |
797 | if (CurrentCost < 0 && Candidate.SCost < 0) { |
798 | if ((Q.getID() == TopQID && (*I)->NodeNum < Candidate.SU->NodeNum) |
799 | || (Q.getID() == BotQID && (*I)->NodeNum > Candidate.SU->NodeNum)) { |
800 | LLVM_DEBUG(traceCandidate("NCAND", Q, *I, CurrentCost)); |
801 | Candidate.SU = *I; |
802 | Candidate.RPDelta = RPDelta; |
803 | Candidate.SCost = CurrentCost; |
804 | FoundCandidate = NodeOrder; |
805 | } |
806 | continue; |
807 | } |
808 | |
809 | |
810 | if (CurrentCost > Candidate.SCost) { |
811 | LLVM_DEBUG(traceCandidate("CCAND", Q, *I, CurrentCost)); |
812 | Candidate.SU = *I; |
813 | Candidate.RPDelta = RPDelta; |
814 | Candidate.SCost = CurrentCost; |
815 | FoundCandidate = BestCost; |
816 | continue; |
817 | } |
818 | |
819 | |
820 | unsigned CurrWeak = getWeakLeft(*I, (Q.getID() == TopQID)); |
821 | unsigned CandWeak = getWeakLeft(Candidate.SU, (Q.getID() == TopQID)); |
822 | if (CurrWeak != CandWeak) { |
823 | if (CurrWeak < CandWeak) { |
824 | LLVM_DEBUG(traceCandidate("WCAND", Q, *I, CurrentCost)); |
825 | Candidate.SU = *I; |
826 | Candidate.RPDelta = RPDelta; |
827 | Candidate.SCost = CurrentCost; |
828 | FoundCandidate = Weak; |
829 | } |
830 | continue; |
831 | } |
832 | |
833 | if (CurrentCost == Candidate.SCost && Zone.isLatencyBound(*I)) { |
834 | unsigned CurrSize, CandSize; |
835 | if (Q.getID() == TopQID) { |
836 | CurrSize = (*I)->Succs.size(); |
837 | CandSize = Candidate.SU->Succs.size(); |
838 | } else { |
839 | CurrSize = (*I)->Preds.size(); |
840 | CandSize = Candidate.SU->Preds.size(); |
841 | } |
842 | if (CurrSize > CandSize) { |
843 | LLVM_DEBUG(traceCandidate("SPCAND", Q, *I, CurrentCost)); |
844 | Candidate.SU = *I; |
845 | Candidate.RPDelta = RPDelta; |
846 | Candidate.SCost = CurrentCost; |
847 | FoundCandidate = BestCost; |
848 | } |
849 | |
850 | |
851 | if (CurrSize != CandSize) |
852 | continue; |
853 | } |
854 | |
855 | |
856 | |
857 | |
858 | if (UseNewerCandidate && CurrentCost == Candidate.SCost) { |
859 | if ((Q.getID() == TopQID && (*I)->NodeNum < Candidate.SU->NodeNum) |
860 | || (Q.getID() == BotQID && (*I)->NodeNum > Candidate.SU->NodeNum)) { |
861 | LLVM_DEBUG(traceCandidate("TCAND", Q, *I, CurrentCost)); |
862 | Candidate.SU = *I; |
863 | Candidate.RPDelta = RPDelta; |
864 | Candidate.SCost = CurrentCost; |
865 | FoundCandidate = NodeOrder; |
866 | continue; |
867 | } |
868 | } |
869 | |
870 | |
871 | |
872 | if (FoundCandidate == NoCand) |
873 | continue; |
874 | } |
875 | return FoundCandidate; |
| 26 | | Returning without writing to 'Candidate.SU' | |
|
876 | } |
877 | |
878 | |
879 | SUnit *ConvergingVLIWScheduler::pickNodeBidrectional(bool &IsTopNode) { |
880 | |
881 | |
882 | if (SUnit *SU = Bot.pickOnlyChoice()) { |
883 | LLVM_DEBUG(dbgs() << "Picked only Bottom\n"); |
884 | IsTopNode = false; |
885 | return SU; |
886 | } |
887 | if (SUnit *SU = Top.pickOnlyChoice()) { |
888 | LLVM_DEBUG(dbgs() << "Picked only Top\n"); |
889 | IsTopNode = true; |
890 | return SU; |
891 | } |
892 | SchedCandidate BotCand; |
893 | |
894 | CandResult BotResult = pickNodeFromQueue(Bot, |
895 | DAG->getBotRPTracker(), BotCand); |
896 | assert(BotResult != NoCand && "failed to find the first candidate"); |
897 | |
898 | |
899 | |
900 | |
901 | |
902 | |
903 | |
904 | |
905 | if (BotResult == SingleExcess || BotResult == SingleCritical) { |
906 | LLVM_DEBUG(dbgs() << "Prefered Bottom Node\n"); |
907 | IsTopNode = false; |
908 | return BotCand.SU; |
909 | } |
910 | |
911 | SchedCandidate TopCand; |
912 | CandResult TopResult = pickNodeFromQueue(Top, |
913 | DAG->getTopRPTracker(), TopCand); |
914 | assert(TopResult != NoCand && "failed to find the first candidate"); |
915 | |
916 | if (TopResult == SingleExcess || TopResult == SingleCritical) { |
917 | LLVM_DEBUG(dbgs() << "Prefered Top Node\n"); |
918 | IsTopNode = true; |
919 | return TopCand.SU; |
920 | } |
921 | |
922 | |
923 | if (BotResult == SingleMax) { |
924 | LLVM_DEBUG(dbgs() << "Prefered Bottom Node SingleMax\n"); |
925 | IsTopNode = false; |
926 | return BotCand.SU; |
927 | } |
928 | if (TopResult == SingleMax) { |
929 | LLVM_DEBUG(dbgs() << "Prefered Top Node SingleMax\n"); |
930 | IsTopNode = true; |
931 | return TopCand.SU; |
932 | } |
933 | if (TopCand.SCost > BotCand.SCost) { |
934 | LLVM_DEBUG(dbgs() << "Prefered Top Node Cost\n"); |
935 | IsTopNode = true; |
936 | return TopCand.SU; |
937 | } |
938 | |
939 | LLVM_DEBUG(dbgs() << "Prefered Bottom in Node order\n"); |
940 | IsTopNode = false; |
941 | return BotCand.SU; |
942 | } |
943 | |
944 | |
945 | SUnit *ConvergingVLIWScheduler::pickNode(bool &IsTopNode) { |
946 | if (DAG->top() == DAG->bottom()) { |
| |
| 7 | | Returning from 'operator==' | |
|
| |
947 | assert(Top.Available.empty() && Top.Pending.empty() && |
948 | Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage"); |
949 | return nullptr; |
950 | } |
951 | SUnit *SU; |
952 | if (ForceTopDown) { |
| 9 | | Assuming the condition is true | |
|
| |
953 | SU = Top.pickOnlyChoice(); |
| 11 | | Calling 'VLIWSchedBoundary::pickOnlyChoice' | |
|
| 18 | | Returning from 'VLIWSchedBoundary::pickOnlyChoice' | |
|
954 | if (!SU) { |
| |
955 | SchedCandidate TopCand; |
| 20 | | Calling defaulted default constructor for 'SchedCandidate' | |
|
| 22 | | Returning from default constructor for 'SchedCandidate' | |
|
956 | CandResult TopResult = |
957 | pickNodeFromQueue(Top, DAG->getTopRPTracker(), TopCand); |
| 23 | | Calling 'ConvergingVLIWScheduler::pickNodeFromQueue' | |
|
| 27 | | Returning from 'ConvergingVLIWScheduler::pickNodeFromQueue' | |
|
958 | assert(TopResult != NoCand && "failed to find the first candidate"); |
959 | (void)TopResult; |
960 | SU = TopCand.SU; |
| 28 | | Null pointer value stored to 'SU' | |
|
961 | } |
962 | IsTopNode = true; |
963 | } else if (ForceBottomUp) { |
964 | SU = Bot.pickOnlyChoice(); |
965 | if (!SU) { |
966 | SchedCandidate BotCand; |
967 | CandResult BotResult = |
968 | pickNodeFromQueue(Bot, DAG->getBotRPTracker(), BotCand); |
969 | assert(BotResult != NoCand && "failed to find the first candidate"); |
970 | (void)BotResult; |
971 | SU = BotCand.SU; |
972 | } |
973 | IsTopNode = false; |
974 | } else { |
975 | SU = pickNodeBidrectional(IsTopNode); |
976 | } |
977 | if (SU->isTopReady()) |
| 29 | | Called C++ object pointer is null |
|
978 | Top.removeReady(SU); |
979 | if (SU->isBottomReady()) |
980 | Bot.removeReady(SU); |
981 | |
982 | LLVM_DEBUG(dbgs() << "*** " << (IsTopNode ? "Top" : "Bottom") |
983 | << " Scheduling instruction in cycle " |
984 | << (IsTopNode ? Top.CurrCycle : Bot.CurrCycle) << " (" |
985 | << reportPackets() << ")\n"; |
986 | DAG->dumpNode(*SU)); |
987 | return SU; |
988 | } |
989 | |
990 | |
991 | |
992 | |
993 | |
994 | void ConvergingVLIWScheduler::schedNode(SUnit *SU, bool IsTopNode) { |
995 | if (IsTopNode) { |
996 | Top.bumpNode(SU); |
997 | SU->TopReadyCycle = Top.CurrCycle; |
998 | } else { |
999 | Bot.bumpNode(SU); |
1000 | SU->BotReadyCycle = Bot.CurrCycle; |
1001 | } |
1002 | } |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #ifndef LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H |
14 | #define LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H |
15 | |
16 | #include "llvm/ADT/ilist.h" |
17 | #include "llvm/ADT/simple_ilist.h" |
18 | #include <cassert> |
19 | #include <iterator> |
20 | #include <type_traits> |
21 | |
22 | namespace llvm { |
23 | |
24 | template <class T, bool IsReverse> struct MachineInstrBundleIteratorTraits; |
25 | template <class T> struct MachineInstrBundleIteratorTraits<T, false> { |
26 | using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; |
27 | using instr_iterator = typename list_type::iterator; |
28 | using nonconst_instr_iterator = typename list_type::iterator; |
29 | using const_instr_iterator = typename list_type::const_iterator; |
30 | }; |
31 | template <class T> struct MachineInstrBundleIteratorTraits<T, true> { |
32 | using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; |
33 | using instr_iterator = typename list_type::reverse_iterator; |
34 | using nonconst_instr_iterator = typename list_type::reverse_iterator; |
35 | using const_instr_iterator = typename list_type::const_reverse_iterator; |
36 | }; |
37 | template <class T> struct MachineInstrBundleIteratorTraits<const T, false> { |
38 | using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; |
39 | using instr_iterator = typename list_type::const_iterator; |
40 | using nonconst_instr_iterator = typename list_type::iterator; |
41 | using const_instr_iterator = typename list_type::const_iterator; |
42 | }; |
43 | template <class T> struct MachineInstrBundleIteratorTraits<const T, true> { |
44 | using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; |
45 | using instr_iterator = typename list_type::const_reverse_iterator; |
46 | using nonconst_instr_iterator = typename list_type::reverse_iterator; |
47 | using const_instr_iterator = typename list_type::const_reverse_iterator; |
48 | }; |
49 | |
50 | template <bool IsReverse> struct MachineInstrBundleIteratorHelper; |
51 | template <> struct MachineInstrBundleIteratorHelper<false> { |
52 | |
53 | template <class Iterator> static Iterator getBundleBegin(Iterator I) { |
54 | if (!I.isEnd()) |
55 | while (I->isBundledWithPred()) |
56 | --I; |
57 | return I; |
58 | } |
59 | |
60 | |
61 | template <class Iterator> static Iterator getBundleFinal(Iterator I) { |
62 | if (!I.isEnd()) |
63 | while (I->isBundledWithSucc()) |
64 | ++I; |
65 | return I; |
66 | } |
67 | |
68 | |
69 | template <class Iterator> static void increment(Iterator &I) { |
70 | I = std::next(getBundleFinal(I)); |
71 | } |
72 | |
73 | |
74 | template <class Iterator> static void decrement(Iterator &I) { |
75 | I = getBundleBegin(std::prev(I)); |
76 | } |
77 | }; |
78 | |
79 | template <> struct MachineInstrBundleIteratorHelper<true> { |
80 | |
81 | template <class Iterator> static Iterator getBundleBegin(Iterator I) { |
82 | return MachineInstrBundleIteratorHelper<false>::getBundleBegin( |
83 | I.getReverse()) |
84 | .getReverse(); |
85 | } |
86 | |
87 | |
88 | template <class Iterator> static Iterator getBundleFinal(Iterator I) { |
89 | return MachineInstrBundleIteratorHelper<false>::getBundleFinal( |
90 | I.getReverse()) |
91 | .getReverse(); |
92 | } |
93 | |
94 | |
95 | template <class Iterator> static void increment(Iterator &I) { |
96 | I = getBundleBegin(std::next(I)); |
97 | } |
98 | |
99 | |
100 | template <class Iterator> static void decrement(Iterator &I) { |
101 | I = std::prev(getBundleFinal(I)); |
102 | } |
103 | }; |
104 | |
105 | |
106 | |
107 | template <typename Ty, bool IsReverse = false> |
108 | class MachineInstrBundleIterator : MachineInstrBundleIteratorHelper<IsReverse> { |
109 | using Traits = MachineInstrBundleIteratorTraits<Ty, IsReverse>; |
110 | using instr_iterator = typename Traits::instr_iterator; |
111 | |
112 | instr_iterator MII; |
113 | |
114 | public: |
115 | using value_type = typename instr_iterator::value_type; |
116 | using difference_type = typename instr_iterator::difference_type; |
117 | using pointer = typename instr_iterator::pointer; |
118 | using reference = typename instr_iterator::reference; |
119 | using const_pointer = typename instr_iterator::const_pointer; |
120 | using const_reference = typename instr_iterator::const_reference; |
121 | using iterator_category = std::bidirectional_iterator_tag; |
122 | |
123 | private: |
124 | using nonconst_instr_iterator = typename Traits::nonconst_instr_iterator; |
125 | using const_instr_iterator = typename Traits::const_instr_iterator; |
126 | using nonconst_iterator = |
127 | MachineInstrBundleIterator<typename nonconst_instr_iterator::value_type, |
128 | IsReverse>; |
129 | using reverse_iterator = MachineInstrBundleIterator<Ty, !IsReverse>; |
130 | |
131 | public: |
132 | MachineInstrBundleIterator(instr_iterator MI) : MII(MI) { |
133 | assert((!MI.getNodePtr() || MI.isEnd() || !MI->isBundledWithPred()) && |
134 | "It's not legal to initialize MachineInstrBundleIterator with a " |
135 | "bundled MI"); |
136 | } |
137 | |
138 | MachineInstrBundleIterator(reference MI) : MII(MI) { |
139 | assert(!MI.isBundledWithPred() && "It's not legal to initialize " |
140 | "MachineInstrBundleIterator with a " |
141 | "bundled MI"); |
142 | } |
143 | |
144 | MachineInstrBundleIterator(pointer MI) : MII(MI) { |
145 | |
146 | assert((!MI || !MI->isBundledWithPred()) && "It's not legal to initialize " |
147 | "MachineInstrBundleIterator " |
148 | "with a bundled MI"); |
149 | } |
150 | |
151 | |
152 | template <class OtherTy> |
153 | MachineInstrBundleIterator( |
154 | const MachineInstrBundleIterator<OtherTy, IsReverse> &I, |
155 | std::enable_if_t<std::is_convertible<OtherTy *, Ty *>::value, void *> = |
156 | nullptr) |
157 | : MII(I.getInstrIterator()) {} |
158 | |
159 | MachineInstrBundleIterator() : MII(nullptr) {} |
160 | |
161 | |
162 | |
163 | |
164 | |
165 | |
166 | |
167 | |
168 | |
169 | explicit MachineInstrBundleIterator( |
170 | const MachineInstrBundleIterator<Ty, !IsReverse> &I) |
171 | : MachineInstrBundleIterator(++I.getReverse()) {} |
172 | |
173 | |
174 | static MachineInstrBundleIterator getAtBundleBegin(instr_iterator MI) { |
175 | return MachineInstrBundleIteratorHelper<IsReverse>::getBundleBegin(MI); |
176 | } |
177 | |
178 | reference operator*() const { return *MII; } |
179 | pointer operator->() const { return &operator*(); } |
180 | |
181 | |
182 | bool isValid() const { return MII.getNodePtr(); } |
183 | |
184 | friend bool operator==(const MachineInstrBundleIterator &L, |
185 | const MachineInstrBundleIterator &R) { |
186 | return L.MII == R.MII; |
| |
| 5 | | Returning from 'operator==' | |
|
| 6 | | Returning zero, which participates in a condition later | |
|
187 | } |
188 | friend bool operator==(const MachineInstrBundleIterator &L, |
189 | const const_instr_iterator &R) { |
190 | return L.MII == R; |
191 | } |
192 | friend bool operator==(const const_instr_iterator &L, |
193 | const MachineInstrBundleIterator &R) { |
194 | return L == R.MII; |
195 | } |
196 | friend bool operator==(const MachineInstrBundleIterator &L, |
197 | const nonconst_instr_iterator &R) { |
198 | return L.MII == R; |
199 | } |
200 | friend bool operator==(const nonconst_instr_iterator &L, |
201 | const MachineInstrBundleIterator &R) { |
202 | return L == R.MII; |
203 | } |
204 | friend bool operator==(const MachineInstrBundleIterator &L, const_pointer R) { |
205 | return L == const_instr_iterator(R); |
206 | } |
207 | friend bool operator==(const_pointer L, const MachineInstrBundleIterator &R) { |
208 | return const_instr_iterator(L) == R; |
209 | } |
210 | friend bool operator==(const MachineInstrBundleIterator &L, |
211 | const_reference R) { |
212 | return L == &R; |
213 | } |
214 | friend bool operator==(const_reference L, |
215 | const MachineInstrBundleIterator &R) { |
216 | return &L == R; |
217 | } |
218 | |
219 | friend bool operator!=(const MachineInstrBundleIterator &L, |
220 | const MachineInstrBundleIterator &R) { |
221 | return !(L == R); |
222 | } |
223 | friend bool operator!=(const MachineInstrBundleIterator &L, |
224 | const const_instr_iterator &R) { |
225 | return !(L == R); |
226 | } |
227 | friend bool operator!=(const const_instr_iterator &L, |
228 | const MachineInstrBundleIterator &R) { |
229 | return !(L == R); |
230 | } |
231 | friend bool operator!=(const MachineInstrBundleIterator &L, |
232 | const nonconst_instr_iterator &R) { |
233 | return !(L == R); |
234 | } |
235 | friend bool operator!=(const nonconst_instr_iterator &L, |
236 | const MachineInstrBundleIterator &R) { |
237 | return !(L == R); |
238 | } |
239 | friend bool operator!=(const MachineInstrBundleIterator &L, const_pointer R) { |
240 | return !(L == R); |
241 | } |
242 | friend bool operator!=(const_pointer L, const MachineInstrBundleIterator &R) { |
243 | return !(L == R); |
244 | } |
245 | friend bool operator!=(const MachineInstrBundleIterator &L, |
246 | const_reference R) { |
247 | return !(L == R); |
248 | } |
249 | friend bool operator!=(const_reference L, |
250 | const MachineInstrBundleIterator &R) { |
251 | return !(L == R); |
252 | } |
253 | |
254 | |
255 | MachineInstrBundleIterator &operator--() { |
256 | this->decrement(MII); |
257 | return *this; |
258 | } |
259 | MachineInstrBundleIterator &operator++() { |
260 | this->increment(MII); |
261 | return *this; |
262 | } |
263 | MachineInstrBundleIterator operator--(int) { |
264 | MachineInstrBundleIterator Temp = *this; |
265 | --*this; |
266 | return Temp; |
267 | } |
268 | MachineInstrBundleIterator operator++(int) { |
269 | MachineInstrBundleIterator Temp = *this; |
270 | ++*this; |
271 | return Temp; |
272 | } |
273 | |
274 | instr_iterator getInstrIterator() const { return MII; } |
275 | |
276 | nonconst_iterator getNonConstIterator() const { return MII.getNonConst(); } |
277 | |
278 | |
279 | |
280 | |
281 | |
282 | |
283 | reverse_iterator getReverse() const { return MII.getReverse(); } |
284 | }; |
285 | |
286 | } |
287 | |
288 | #endif // LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #ifndef LLVM_ADT_ILIST_ITERATOR_H |
10 | #define LLVM_ADT_ILIST_ITERATOR_H |
11 | |
12 | #include "llvm/ADT/ilist_node.h" |
13 | #include <cassert> |
14 | #include <cstddef> |
15 | #include <iterator> |
16 | #include <type_traits> |
17 | |
18 | namespace llvm { |
19 | |
20 | namespace ilist_detail { |
21 | |
22 | |
23 | template <class OptionsT, bool IsConst> struct IteratorTraits; |
24 | template <class OptionsT> struct IteratorTraits<OptionsT, false> { |
25 | using value_type = typename OptionsT::value_type; |
26 | using pointer = typename OptionsT::pointer; |
27 | using reference = typename OptionsT::reference; |
28 | using node_pointer = ilist_node_impl<OptionsT> *; |
29 | using node_reference = ilist_node_impl<OptionsT> &; |
30 | }; |
31 | template <class OptionsT> struct IteratorTraits<OptionsT, true> { |
32 | using value_type = const typename OptionsT::value_type; |
33 | using pointer = typename OptionsT::const_pointer; |
34 | using reference = typename OptionsT::const_reference; |
35 | using node_pointer = const ilist_node_impl<OptionsT> *; |
36 | using node_reference = const ilist_node_impl<OptionsT> &; |
37 | }; |
38 | |
39 | template <bool IsReverse> struct IteratorHelper; |
40 | template <> struct IteratorHelper<false> : ilist_detail::NodeAccess { |
41 | using Access = ilist_detail::NodeAccess; |
42 | |
43 | template <class T> static void increment(T *&I) { I = Access::getNext(*I); } |
44 | template <class T> static void decrement(T *&I) { I = Access::getPrev(*I); } |
45 | }; |
46 | template <> struct IteratorHelper<true> : ilist_detail::NodeAccess { |
47 | using Access = ilist_detail::NodeAccess; |
48 | |
49 | template <class T> static void increment(T *&I) { I = Access::getPrev(*I); } |
50 | template <class T> static void decrement(T *&I) { I = Access::getNext(*I); } |
51 | }; |
52 | |
53 | } |
54 | |
55 | |
56 | template <class OptionsT, bool IsReverse, bool IsConst> |
57 | class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> { |
58 | friend ilist_iterator<OptionsT, IsReverse, !IsConst>; |
59 | friend ilist_iterator<OptionsT, !IsReverse, IsConst>; |
60 | friend ilist_iterator<OptionsT, !IsReverse, !IsConst>; |
61 | |
62 | using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>; |
63 | using Access = ilist_detail::SpecificNodeAccess<OptionsT>; |
64 | |
65 | public: |
66 | using value_type = typename Traits::value_type; |
67 | using pointer = typename Traits::pointer; |
68 | using reference = typename Traits::reference; |
69 | using difference_type = ptrdiff_t; |
70 | using iterator_category = std::bidirectional_iterator_tag; |
71 | using const_pointer = typename OptionsT::const_pointer; |
72 | using const_reference = typename OptionsT::const_reference; |
73 | |
74 | private: |
75 | using node_pointer = typename Traits::node_pointer; |
76 | using node_reference = typename Traits::node_reference; |
77 | |
78 | node_pointer NodePtr = nullptr; |
79 | |
80 | public: |
81 | |
82 | explicit ilist_iterator(node_reference N) : NodePtr(&N) {} |
83 | |
84 | explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {} |
85 | explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {} |
86 | ilist_iterator() = default; |
87 | |
88 | |
89 | |
90 | template <bool RHSIsConst> |
91 | ilist_iterator(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS, |
92 | std::enable_if_t<IsConst || !RHSIsConst, void *> = nullptr) |
93 | : NodePtr(RHS.NodePtr) {} |
94 | |
95 | |
96 | |
97 | template <bool RHSIsConst> |
98 | std::enable_if_t<IsConst || !RHSIsConst, ilist_iterator &> |
99 | operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) { |
100 | NodePtr = RHS.NodePtr; |
101 | return *this; |
102 | } |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | explicit ilist_iterator( |
113 | const ilist_iterator<OptionsT, !IsReverse, IsConst> &RHS) |
114 | : ilist_iterator(++RHS.getReverse()) {} |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const { |
122 | if (NodePtr) |
123 | return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr); |
124 | return ilist_iterator<OptionsT, !IsReverse, IsConst>(); |
125 | } |
126 | |
127 | |
128 | ilist_iterator<OptionsT, IsReverse, false> getNonConst() const { |
129 | if (NodePtr) |
130 | return ilist_iterator<OptionsT, IsReverse, false>( |
131 | const_cast<typename ilist_iterator<OptionsT, IsReverse, |
132 | false>::node_reference>(*NodePtr)); |
133 | return ilist_iterator<OptionsT, IsReverse, false>(); |
134 | } |
135 | |
136 | |
137 | reference operator*() const { |
138 | assert(!NodePtr->isKnownSentinel()); |
139 | return *Access::getValuePtr(NodePtr); |
140 | } |
141 | pointer operator->() const { return &operator*(); } |
142 | |
143 | |
144 | friend bool operator==(const ilist_iterator &LHS, const ilist_iterator &RHS) { |
145 | return LHS.NodePtr == RHS.NodePtr; |
| 3 | | Assuming 'LHS.NodePtr' is not equal to 'RHS.NodePtr' | |
|
| 4 | | Returning zero, which participates in a condition later | |
|
146 | } |
147 | friend bool operator!=(const ilist_iterator &LHS, const ilist_iterator &RHS) { |
148 | return LHS.NodePtr != RHS.NodePtr; |
149 | } |
150 | |
151 | |
152 | ilist_iterator &operator--() { |
153 | NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev(); |
154 | return *this; |
155 | } |
156 | ilist_iterator &operator++() { |
157 | NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext(); |
158 | return *this; |
159 | } |
160 | ilist_iterator operator--(int) { |
161 | ilist_iterator tmp = *this; |
162 | --*this; |
163 | return tmp; |
164 | } |
165 | ilist_iterator operator++(int) { |
166 | ilist_iterator tmp = *this; |
167 | ++*this; |
168 | return tmp; |
169 | } |
170 | |
171 | |
172 | node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); } |
173 | |
174 | |
175 | bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; } |
176 | }; |
177 | |
178 | template <typename From> struct simplify_type; |
179 | |
180 | |
181 | |
182 | |
183 | |
184 | template <class OptionsT, bool IsConst> |
185 | struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> { |
186 | using iterator = ilist_iterator<OptionsT, false, IsConst>; |
187 | using SimpleType = typename iterator::pointer; |
188 | |
189 | static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; } |
190 | }; |
191 | template <class OptionsT, bool IsConst> |
192 | struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>> |
193 | : simplify_type<ilist_iterator<OptionsT, false, IsConst>> {}; |
194 | |
195 | } |
196 | |
197 | #endif // LLVM_ADT_ILIST_ITERATOR_H |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONMACHINESCHEDULER_H |
14 | #define LLVM_LIB_TARGET_HEXAGON_HEXAGONMACHINESCHEDULER_H |
15 | |
16 | #include "llvm/ADT/STLExtras.h" |
17 | #include "llvm/ADT/Twine.h" |
18 | #include "llvm/CodeGen/DFAPacketizer.h" |
19 | #include "llvm/CodeGen/MachineScheduler.h" |
20 | #include "llvm/CodeGen/RegisterPressure.h" |
21 | #include "llvm/CodeGen/ScheduleHazardRecognizer.h" |
22 | #include "llvm/CodeGen/TargetInstrInfo.h" |
23 | #include "llvm/CodeGen/TargetSchedule.h" |
24 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
25 | #include <algorithm> |
26 | #include <cassert> |
27 | #include <limits> |
28 | #include <memory> |
29 | #include <vector> |
30 | |
31 | namespace llvm { |
32 | |
33 | class SUnit; |
34 | |
35 | class VLIWResourceModel { |
36 | |
37 | |
38 | |
39 | DFAPacketizer *ResourcesModel; |
40 | |
41 | const TargetSchedModel *SchedModel; |
42 | |
43 | |
44 | |
45 | std::vector<SUnit *> Packet; |
46 | |
47 | |
48 | unsigned TotalPackets = 0; |
49 | |
50 | public: |
51 | VLIWResourceModel(const TargetSubtargetInfo &STI, const TargetSchedModel *SM) |
52 | : SchedModel(SM) { |
53 | ResourcesModel = STI.getInstrInfo()->CreateTargetScheduleState(STI); |
54 | |
55 | |
56 | |
57 | assert(ResourcesModel && "Unimplemented CreateTargetScheduleState."); |
58 | |
59 | Packet.resize(SchedModel->getIssueWidth()); |
60 | Packet.clear(); |
61 | ResourcesModel->clearResources(); |
62 | } |
63 | |
64 | ~VLIWResourceModel() { |
65 | delete ResourcesModel; |
66 | } |
67 | |
68 | void resetPacketState() { |
69 | Packet.clear(); |
70 | } |
71 | |
72 | void resetDFA() { |
73 | ResourcesModel->clearResources(); |
74 | } |
75 | |
76 | void reset() { |
77 | Packet.clear(); |
78 | ResourcesModel->clearResources(); |
79 | } |
80 | |
81 | bool isResourceAvailable(SUnit *SU, bool IsTop); |
82 | bool reserveResources(SUnit *SU, bool IsTop); |
83 | unsigned getTotalPackets() const { return TotalPackets; } |
84 | bool isInPacket(SUnit *SU) const { return is_contained(Packet, SU); } |
85 | }; |
86 | |
87 | |
88 | |
89 | class VLIWMachineScheduler : public ScheduleDAGMILive { |
90 | public: |
91 | VLIWMachineScheduler(MachineSchedContext *C, |
92 | std::unique_ptr<MachineSchedStrategy> S) |
93 | : ScheduleDAGMILive(C, std::move(S)) {} |
94 | |
95 | |
96 | |
97 | void schedule() override; |
98 | |
99 | RegisterClassInfo *getRegClassInfo() { return RegClassInfo; } |
100 | int getBBSize() { return BB->size(); } |
101 | }; |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | class ConvergingVLIWScheduler : public MachineSchedStrategy { |
111 | |
112 | |
113 | struct SchedCandidate { |
114 | |
115 | SUnit *SU = nullptr; |
| 21 | | Null pointer value stored to 'TopCand.SU' | |
|
116 | |
117 | |
118 | RegPressureDelta RPDelta; |
119 | |
120 | |
121 | int SCost = 0; |
122 | |
123 | SchedCandidate() = default; |
124 | }; |
125 | |
126 | enum CandResult { |
127 | NoCand, NodeOrder, SingleExcess, SingleCritical, SingleMax, MultiPressure, |
128 | BestCost, Weak}; |
129 | |
130 | |
131 | |
132 | |
133 | struct VLIWSchedBoundary { |
134 | VLIWMachineScheduler *DAG = nullptr; |
135 | const TargetSchedModel *SchedModel = nullptr; |
136 | |
137 | ReadyQueue Available; |
138 | ReadyQueue Pending; |
139 | bool CheckPending = false; |
140 | |
141 | ScheduleHazardRecognizer *HazardRec = nullptr; |
142 | VLIWResourceModel *ResourceModel = nullptr; |
143 | |
144 | unsigned CurrCycle = 0; |
145 | unsigned IssueCount = 0; |
146 | unsigned CriticalPathLength = 0; |
147 | |
148 | |
149 | unsigned MinReadyCycle = std::numeric_limits<unsigned>::max(); |
150 | |
151 | |
152 | unsigned MaxMinLatency = 0; |
153 | |
154 | |
155 | |
156 | VLIWSchedBoundary(unsigned ID, const Twine &Name) |
157 | : Available(ID, Name+".A"), |
158 | Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name+".P") {} |
159 | |
160 | ~VLIWSchedBoundary() { |
161 | delete ResourceModel; |
162 | delete HazardRec; |
163 | } |
164 | |
165 | void init(VLIWMachineScheduler *dag, const TargetSchedModel *smodel) { |
166 | DAG = dag; |
167 | SchedModel = smodel; |
168 | CurrCycle = 0; |
169 | IssueCount = 0; |
170 | |
171 | |
172 | |
173 | |
174 | |
175 | CriticalPathLength = DAG->getBBSize() / SchedModel->getIssueWidth(); |
176 | if (DAG->getBBSize() < 50) |
177 | |
178 | |
179 | |
180 | CriticalPathLength >>= 1; |
181 | else { |
182 | |
183 | |
184 | unsigned MaxPath = 0; |
185 | for (auto &SU : DAG->SUnits) |
186 | MaxPath = std::max(MaxPath, isTop() ? SU.getHeight() : SU.getDepth()); |
187 | CriticalPathLength = std::max(CriticalPathLength, MaxPath) + 1; |
188 | } |
189 | } |
190 | |
191 | bool isTop() const { |
192 | return Available.getID() == ConvergingVLIWScheduler::TopQID; |
193 | } |
194 | |
195 | bool checkHazard(SUnit *SU); |
196 | |
197 | void releaseNode(SUnit *SU, unsigned ReadyCycle); |
198 | |
199 | void bumpCycle(); |
200 | |
201 | void bumpNode(SUnit *SU); |
202 | |
203 | void releasePending(); |
204 | |
205 | void removeReady(SUnit *SU); |
206 | |
207 | SUnit *pickOnlyChoice(); |
208 | |
209 | bool isLatencyBound(SUnit *SU) { |
210 | if (CurrCycle >= CriticalPathLength) |
211 | return true; |
212 | unsigned PathLength = isTop() ? SU->getHeight() : SU->getDepth(); |
213 | return CriticalPathLength - CurrCycle <= PathLength; |
214 | } |
215 | }; |
216 | |
217 | VLIWMachineScheduler *DAG = nullptr; |
218 | const TargetSchedModel *SchedModel = nullptr; |
219 | |
220 | |
221 | VLIWSchedBoundary Top; |
222 | VLIWSchedBoundary Bot; |
223 | |
224 | |
225 | std::vector<bool> HighPressureSets; |
226 | |
227 | public: |
228 | |
229 | enum { |
230 | TopQID = 1, |
231 | BotQID = 2, |
232 | LogMaxQID = 2 |
233 | }; |
234 | |
235 | ConvergingVLIWScheduler() : Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {} |
236 | |
237 | void initialize(ScheduleDAGMI *dag) override; |
238 | |
239 | SUnit *pickNode(bool &IsTopNode) override; |
240 | |
241 | void schedNode(SUnit *SU, bool IsTopNode) override; |
242 | |
243 | void releaseTopNode(SUnit *SU) override; |
244 | |
245 | void releaseBottomNode(SUnit *SU) override; |
246 | |
247 | unsigned reportPackets() { |
248 | return Top.ResourceModel->getTotalPackets() + |
249 | Bot.ResourceModel->getTotalPackets(); |
250 | } |
251 | |
252 | protected: |
253 | SUnit *pickNodeBidrectional(bool &IsTopNode); |
254 | |
255 | int pressureChange(const SUnit *SU, bool isBotUp); |
256 | |
257 | int SchedulingCost(ReadyQueue &Q, |
258 | SUnit *SU, SchedCandidate &Candidate, |
259 | RegPressureDelta &Delta, bool verbose); |
260 | |
261 | CandResult pickNodeFromQueue(VLIWSchedBoundary &Zone, |
262 | const RegPressureTracker &RPTracker, |
263 | SchedCandidate &Candidate); |
264 | #ifndef NDEBUG |
265 | void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU, |
266 | int Cost, PressureChange P = PressureChange()); |
267 | |
268 | void readyQueueVerboseDump(const RegPressureTracker &RPTracker, |
269 | SchedCandidate &Candidate, ReadyQueue &Q); |
270 | #endif |
271 | }; |
272 | |
273 | } |
274 | |
275 | #endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONMACHINESCHEDULER_H |