/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- ResourcePriorityQueue.cpp - A DFA-oriented priority queue -*- C++ -*-==// |
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 | | // This file implements the ResourcePriorityQueue class, which is a |
10 | | // SchedulingPriorityQueue that prioritizes instructions using DFA state to |
11 | | // reduce the length of the critical path through the basic block |
12 | | // on VLIW platforms. |
13 | | // The scheduler is basically a top-down adaptable list scheduler with DFA |
14 | | // resource tracking added to the cost function. |
15 | | // DFA is queried as a state machine to model "packets/bundles" during |
16 | | // schedule. Currently packets/bundles are discarded at the end of |
17 | | // scheduling, affecting only order of instructions. |
18 | | // |
19 | | //===----------------------------------------------------------------------===// |
20 | | |
21 | | #include "llvm/CodeGen/ResourcePriorityQueue.h" |
22 | | #include "llvm/CodeGen/DFAPacketizer.h" |
23 | | #include "llvm/CodeGen/SelectionDAGISel.h" |
24 | | #include "llvm/CodeGen/SelectionDAGNodes.h" |
25 | | #include "llvm/CodeGen/TargetInstrInfo.h" |
26 | | #include "llvm/CodeGen/TargetLowering.h" |
27 | | #include "llvm/CodeGen/TargetRegisterInfo.h" |
28 | | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
29 | | #include "llvm/Support/CommandLine.h" |
30 | | |
31 | | using namespace llvm; |
32 | | |
33 | | #define DEBUG_TYPE "scheduler" |
34 | | |
35 | | static cl::opt<bool> |
36 | | DisableDFASched("disable-dfa-sched", cl::Hidden, |
37 | | cl::desc("Disable use of DFA during scheduling")); |
38 | | |
39 | | static cl::opt<int> RegPressureThreshold( |
40 | | "dfa-sched-reg-pressure-threshold", cl::Hidden, cl::init(5), |
41 | | cl::desc("Track reg pressure and switch priority to in-depth")); |
42 | | |
43 | | ResourcePriorityQueue::ResourcePriorityQueue(SelectionDAGISel *IS) |
44 | 0 | : Picker(this), InstrItins(IS->MF->getSubtarget().getInstrItineraryData()) { |
45 | 0 | const TargetSubtargetInfo &STI = IS->MF->getSubtarget(); |
46 | 0 | TRI = STI.getRegisterInfo(); |
47 | 0 | TLI = IS->TLI; |
48 | 0 | TII = STI.getInstrInfo(); |
49 | 0 | ResourcesModel.reset(TII->CreateTargetScheduleState(STI)); |
50 | | // This hard requirement could be relaxed, but for now |
51 | | // do not let it proceed. |
52 | 0 | assert(ResourcesModel && "Unimplemented CreateTargetScheduleState."); |
53 | | |
54 | 0 | unsigned NumRC = TRI->getNumRegClasses(); |
55 | 0 | RegLimit.resize(NumRC); |
56 | 0 | RegPressure.resize(NumRC); |
57 | 0 | std::fill(RegLimit.begin(), RegLimit.end(), 0); |
58 | 0 | std::fill(RegPressure.begin(), RegPressure.end(), 0); |
59 | 0 | for (const TargetRegisterClass *RC : TRI->regclasses()) |
60 | 0 | RegLimit[RC->getID()] = TRI->getRegPressureLimit(RC, *IS->MF); |
61 | |
|
62 | 0 | ParallelLiveRanges = 0; |
63 | 0 | HorizontalVerticalBalance = 0; |
64 | 0 | } |
65 | | |
66 | | unsigned |
67 | 0 | ResourcePriorityQueue::numberRCValPredInSU(SUnit *SU, unsigned RCId) { |
68 | 0 | unsigned NumberDeps = 0; |
69 | 0 | for (SDep &Pred : SU->Preds) { |
70 | 0 | if (Pred.isCtrl()) |
71 | 0 | continue; |
72 | | |
73 | 0 | SUnit *PredSU = Pred.getSUnit(); |
74 | 0 | const SDNode *ScegN = PredSU->getNode(); |
75 | |
|
76 | 0 | if (!ScegN) |
77 | 0 | continue; |
78 | | |
79 | | // If value is passed to CopyToReg, it is probably |
80 | | // live outside BB. |
81 | 0 | switch (ScegN->getOpcode()) { |
82 | 0 | default: break; |
83 | 0 | case ISD::TokenFactor: break; |
84 | 0 | case ISD::CopyFromReg: NumberDeps++; break; |
85 | 0 | case ISD::CopyToReg: break; |
86 | 0 | case ISD::INLINEASM: break; |
87 | 0 | case ISD::INLINEASM_BR: break; |
88 | 0 | } |
89 | 0 | if (!ScegN->isMachineOpcode()) |
90 | 0 | continue; |
91 | | |
92 | 0 | for (unsigned i = 0, e = ScegN->getNumValues(); i != e; ++i) { |
93 | 0 | MVT VT = ScegN->getSimpleValueType(i); |
94 | 0 | if (TLI->isTypeLegal(VT) |
95 | 0 | && (TLI->getRegClassFor(VT)->getID() == RCId)) { |
96 | 0 | NumberDeps++; |
97 | 0 | break; |
98 | 0 | } |
99 | 0 | } |
100 | 0 | } |
101 | 0 | return NumberDeps; |
102 | 0 | } |
103 | | |
104 | | unsigned ResourcePriorityQueue::numberRCValSuccInSU(SUnit *SU, |
105 | 0 | unsigned RCId) { |
106 | 0 | unsigned NumberDeps = 0; |
107 | 0 | for (const SDep &Succ : SU->Succs) { |
108 | 0 | if (Succ.isCtrl()) |
109 | 0 | continue; |
110 | | |
111 | 0 | SUnit *SuccSU = Succ.getSUnit(); |
112 | 0 | const SDNode *ScegN = SuccSU->getNode(); |
113 | 0 | if (!ScegN) |
114 | 0 | continue; |
115 | | |
116 | | // If value is passed to CopyToReg, it is probably |
117 | | // live outside BB. |
118 | 0 | switch (ScegN->getOpcode()) { |
119 | 0 | default: break; |
120 | 0 | case ISD::TokenFactor: break; |
121 | 0 | case ISD::CopyFromReg: break; |
122 | 0 | case ISD::CopyToReg: NumberDeps++; break; |
123 | 0 | case ISD::INLINEASM: break; |
124 | 0 | case ISD::INLINEASM_BR: break; |
125 | 0 | } |
126 | 0 | if (!ScegN->isMachineOpcode()) |
127 | 0 | continue; |
128 | | |
129 | 0 | for (unsigned i = 0, e = ScegN->getNumOperands(); i != e; ++i) { |
130 | 0 | const SDValue &Op = ScegN->getOperand(i); |
131 | 0 | MVT VT = Op.getNode()->getSimpleValueType(Op.getResNo()); |
132 | 0 | if (TLI->isTypeLegal(VT) |
133 | 0 | && (TLI->getRegClassFor(VT)->getID() == RCId)) { |
134 | 0 | NumberDeps++; |
135 | 0 | break; |
136 | 0 | } |
137 | 0 | } |
138 | 0 | } |
139 | 0 | return NumberDeps; |
140 | 0 | } |
141 | | |
142 | 0 | static unsigned numberCtrlDepsInSU(SUnit *SU) { |
143 | 0 | unsigned NumberDeps = 0; |
144 | 0 | for (const SDep &Succ : SU->Succs) |
145 | 0 | if (Succ.isCtrl()) |
146 | 0 | NumberDeps++; |
147 | |
|
148 | 0 | return NumberDeps; |
149 | 0 | } |
150 | | |
151 | 0 | static unsigned numberCtrlPredInSU(SUnit *SU) { |
152 | 0 | unsigned NumberDeps = 0; |
153 | 0 | for (SDep &Pred : SU->Preds) |
154 | 0 | if (Pred.isCtrl()) |
155 | 0 | NumberDeps++; |
156 | |
|
157 | 0 | return NumberDeps; |
158 | 0 | } |
159 | | |
160 | | /// |
161 | | /// Initialize nodes. |
162 | | /// |
163 | 0 | void ResourcePriorityQueue::initNodes(std::vector<SUnit> &sunits) { |
164 | 0 | SUnits = &sunits; |
165 | 0 | NumNodesSolelyBlocking.resize(SUnits->size(), 0); |
166 | |
|
167 | 0 | for (SUnit &SU : *SUnits) { |
168 | 0 | initNumRegDefsLeft(&SU); |
169 | 0 | SU.NodeQueueId = 0; |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | | /// This heuristic is used if DFA scheduling is not desired |
174 | | /// for some VLIW platform. |
175 | 0 | bool resource_sort::operator()(const SUnit *LHS, const SUnit *RHS) const { |
176 | | // The isScheduleHigh flag allows nodes with wraparound dependencies that |
177 | | // cannot easily be modeled as edges with latencies to be scheduled as |
178 | | // soon as possible in a top-down schedule. |
179 | 0 | if (LHS->isScheduleHigh && !RHS->isScheduleHigh) |
180 | 0 | return false; |
181 | | |
182 | 0 | if (!LHS->isScheduleHigh && RHS->isScheduleHigh) |
183 | 0 | return true; |
184 | | |
185 | 0 | unsigned LHSNum = LHS->NodeNum; |
186 | 0 | unsigned RHSNum = RHS->NodeNum; |
187 | | |
188 | | // The most important heuristic is scheduling the critical path. |
189 | 0 | unsigned LHSLatency = PQ->getLatency(LHSNum); |
190 | 0 | unsigned RHSLatency = PQ->getLatency(RHSNum); |
191 | 0 | if (LHSLatency < RHSLatency) return true; |
192 | 0 | if (LHSLatency > RHSLatency) return false; |
193 | | |
194 | | // After that, if two nodes have identical latencies, look to see if one will |
195 | | // unblock more other nodes than the other. |
196 | 0 | unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum); |
197 | 0 | unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum); |
198 | 0 | if (LHSBlocked < RHSBlocked) return true; |
199 | 0 | if (LHSBlocked > RHSBlocked) return false; |
200 | | |
201 | | // Finally, just to provide a stable ordering, use the node number as a |
202 | | // deciding factor. |
203 | 0 | return LHSNum < RHSNum; |
204 | 0 | } |
205 | | |
206 | | |
207 | | /// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor |
208 | | /// of SU, return it, otherwise return null. |
209 | 0 | SUnit *ResourcePriorityQueue::getSingleUnscheduledPred(SUnit *SU) { |
210 | 0 | SUnit *OnlyAvailablePred = nullptr; |
211 | 0 | for (const SDep &Pred : SU->Preds) { |
212 | 0 | SUnit &PredSU = *Pred.getSUnit(); |
213 | 0 | if (!PredSU.isScheduled) { |
214 | | // We found an available, but not scheduled, predecessor. If it's the |
215 | | // only one we have found, keep track of it... otherwise give up. |
216 | 0 | if (OnlyAvailablePred && OnlyAvailablePred != &PredSU) |
217 | 0 | return nullptr; |
218 | 0 | OnlyAvailablePred = &PredSU; |
219 | 0 | } |
220 | 0 | } |
221 | 0 | return OnlyAvailablePred; |
222 | 0 | } |
223 | | |
224 | 0 | void ResourcePriorityQueue::push(SUnit *SU) { |
225 | | // Look at all of the successors of this node. Count the number of nodes that |
226 | | // this node is the sole unscheduled node for. |
227 | 0 | unsigned NumNodesBlocking = 0; |
228 | 0 | for (const SDep &Succ : SU->Succs) |
229 | 0 | if (getSingleUnscheduledPred(Succ.getSUnit()) == SU) |
230 | 0 | ++NumNodesBlocking; |
231 | |
|
232 | 0 | NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking; |
233 | 0 | Queue.push_back(SU); |
234 | 0 | } |
235 | | |
236 | | /// Check if scheduling of this SU is possible |
237 | | /// in the current packet. |
238 | 0 | bool ResourcePriorityQueue::isResourceAvailable(SUnit *SU) { |
239 | 0 | if (!SU || !SU->getNode()) |
240 | 0 | return false; |
241 | | |
242 | | // If this is a compound instruction, |
243 | | // it is likely to be a call. Do not delay it. |
244 | 0 | if (SU->getNode()->getGluedNode()) |
245 | 0 | return true; |
246 | | |
247 | | // First see if the pipeline could receive this instruction |
248 | | // in the current cycle. |
249 | 0 | if (SU->getNode()->isMachineOpcode()) |
250 | 0 | switch (SU->getNode()->getMachineOpcode()) { |
251 | 0 | default: |
252 | 0 | if (!ResourcesModel->canReserveResources(&TII->get( |
253 | 0 | SU->getNode()->getMachineOpcode()))) |
254 | 0 | return false; |
255 | 0 | break; |
256 | 0 | case TargetOpcode::EXTRACT_SUBREG: |
257 | 0 | case TargetOpcode::INSERT_SUBREG: |
258 | 0 | case TargetOpcode::SUBREG_TO_REG: |
259 | 0 | case TargetOpcode::REG_SEQUENCE: |
260 | 0 | case TargetOpcode::IMPLICIT_DEF: |
261 | 0 | break; |
262 | 0 | } |
263 | | |
264 | | // Now see if there are no other dependencies |
265 | | // to instructions already in the packet. |
266 | 0 | for (const SUnit *S : Packet) |
267 | 0 | for (const SDep &Succ : S->Succs) { |
268 | | // Since we do not add pseudos to packets, might as well |
269 | | // ignore order deps. |
270 | 0 | if (Succ.isCtrl()) |
271 | 0 | continue; |
272 | | |
273 | 0 | if (Succ.getSUnit() == SU) |
274 | 0 | return false; |
275 | 0 | } |
276 | | |
277 | 0 | return true; |
278 | 0 | } |
279 | | |
280 | | /// Keep track of available resources. |
281 | 0 | void ResourcePriorityQueue::reserveResources(SUnit *SU) { |
282 | | // If this SU does not fit in the packet |
283 | | // start a new one. |
284 | 0 | if (!isResourceAvailable(SU) || SU->getNode()->getGluedNode()) { |
285 | 0 | ResourcesModel->clearResources(); |
286 | 0 | Packet.clear(); |
287 | 0 | } |
288 | |
|
289 | 0 | if (SU->getNode() && SU->getNode()->isMachineOpcode()) { |
290 | 0 | switch (SU->getNode()->getMachineOpcode()) { |
291 | 0 | default: |
292 | 0 | ResourcesModel->reserveResources(&TII->get( |
293 | 0 | SU->getNode()->getMachineOpcode())); |
294 | 0 | break; |
295 | 0 | case TargetOpcode::EXTRACT_SUBREG: |
296 | 0 | case TargetOpcode::INSERT_SUBREG: |
297 | 0 | case TargetOpcode::SUBREG_TO_REG: |
298 | 0 | case TargetOpcode::REG_SEQUENCE: |
299 | 0 | case TargetOpcode::IMPLICIT_DEF: |
300 | 0 | break; |
301 | 0 | } |
302 | 0 | Packet.push_back(SU); |
303 | 0 | } |
304 | | // Forcefully end packet for PseudoOps. |
305 | 0 | else { |
306 | 0 | ResourcesModel->clearResources(); |
307 | 0 | Packet.clear(); |
308 | 0 | } |
309 | | |
310 | | // If packet is now full, reset the state so in the next cycle |
311 | | // we start fresh. |
312 | 0 | if (Packet.size() >= InstrItins->SchedModel.IssueWidth) { |
313 | 0 | ResourcesModel->clearResources(); |
314 | 0 | Packet.clear(); |
315 | 0 | } |
316 | 0 | } |
317 | | |
318 | 0 | int ResourcePriorityQueue::rawRegPressureDelta(SUnit *SU, unsigned RCId) { |
319 | 0 | int RegBalance = 0; |
320 | |
|
321 | 0 | if (!SU || !SU->getNode() || !SU->getNode()->isMachineOpcode()) |
322 | 0 | return RegBalance; |
323 | | |
324 | | // Gen estimate. |
325 | 0 | for (unsigned i = 0, e = SU->getNode()->getNumValues(); i != e; ++i) { |
326 | 0 | MVT VT = SU->getNode()->getSimpleValueType(i); |
327 | 0 | if (TLI->isTypeLegal(VT) |
328 | 0 | && TLI->getRegClassFor(VT) |
329 | 0 | && TLI->getRegClassFor(VT)->getID() == RCId) |
330 | 0 | RegBalance += numberRCValSuccInSU(SU, RCId); |
331 | 0 | } |
332 | | // Kill estimate. |
333 | 0 | for (unsigned i = 0, e = SU->getNode()->getNumOperands(); i != e; ++i) { |
334 | 0 | const SDValue &Op = SU->getNode()->getOperand(i); |
335 | 0 | MVT VT = Op.getNode()->getSimpleValueType(Op.getResNo()); |
336 | 0 | if (isa<ConstantSDNode>(Op.getNode())) |
337 | 0 | continue; |
338 | | |
339 | 0 | if (TLI->isTypeLegal(VT) && TLI->getRegClassFor(VT) |
340 | 0 | && TLI->getRegClassFor(VT)->getID() == RCId) |
341 | 0 | RegBalance -= numberRCValPredInSU(SU, RCId); |
342 | 0 | } |
343 | 0 | return RegBalance; |
344 | 0 | } |
345 | | |
346 | | /// Estimates change in reg pressure from this SU. |
347 | | /// It is achieved by trivial tracking of defined |
348 | | /// and used vregs in dependent instructions. |
349 | | /// The RawPressure flag makes this function to ignore |
350 | | /// existing reg file sizes, and report raw def/use |
351 | | /// balance. |
352 | 0 | int ResourcePriorityQueue::regPressureDelta(SUnit *SU, bool RawPressure) { |
353 | 0 | int RegBalance = 0; |
354 | |
|
355 | 0 | if (!SU || !SU->getNode() || !SU->getNode()->isMachineOpcode()) |
356 | 0 | return RegBalance; |
357 | | |
358 | 0 | if (RawPressure) { |
359 | 0 | for (const TargetRegisterClass *RC : TRI->regclasses()) |
360 | 0 | RegBalance += rawRegPressureDelta(SU, RC->getID()); |
361 | 0 | } |
362 | 0 | else { |
363 | 0 | for (const TargetRegisterClass *RC : TRI->regclasses()) { |
364 | 0 | if ((RegPressure[RC->getID()] + |
365 | 0 | rawRegPressureDelta(SU, RC->getID()) > 0) && |
366 | 0 | (RegPressure[RC->getID()] + |
367 | 0 | rawRegPressureDelta(SU, RC->getID()) >= RegLimit[RC->getID()])) |
368 | 0 | RegBalance += rawRegPressureDelta(SU, RC->getID()); |
369 | 0 | } |
370 | 0 | } |
371 | |
|
372 | 0 | return RegBalance; |
373 | 0 | } |
374 | | |
375 | | // Constants used to denote relative importance of |
376 | | // heuristic components for cost computation. |
377 | | static const unsigned PriorityOne = 200; |
378 | | static const unsigned PriorityTwo = 50; |
379 | | static const unsigned PriorityThree = 15; |
380 | | static const unsigned PriorityFour = 5; |
381 | | static const unsigned ScaleOne = 20; |
382 | | static const unsigned ScaleTwo = 10; |
383 | | static const unsigned ScaleThree = 5; |
384 | | static const unsigned FactorOne = 2; |
385 | | |
386 | | /// Returns single number reflecting benefit of scheduling SU |
387 | | /// in the current cycle. |
388 | 0 | int ResourcePriorityQueue::SUSchedulingCost(SUnit *SU) { |
389 | | // Initial trivial priority. |
390 | 0 | int ResCount = 1; |
391 | | |
392 | | // Do not waste time on a node that is already scheduled. |
393 | 0 | if (SU->isScheduled) |
394 | 0 | return ResCount; |
395 | | |
396 | | // Forced priority is high. |
397 | 0 | if (SU->isScheduleHigh) |
398 | 0 | ResCount += PriorityOne; |
399 | | |
400 | | // Adaptable scheduling |
401 | | // A small, but very parallel |
402 | | // region, where reg pressure is an issue. |
403 | 0 | if (HorizontalVerticalBalance > RegPressureThreshold) { |
404 | | // Critical path first |
405 | 0 | ResCount += (SU->getHeight() * ScaleTwo); |
406 | | // If resources are available for it, multiply the |
407 | | // chance of scheduling. |
408 | 0 | if (isResourceAvailable(SU)) |
409 | 0 | ResCount <<= FactorOne; |
410 | | |
411 | | // Consider change to reg pressure from scheduling |
412 | | // this SU. |
413 | 0 | ResCount -= (regPressureDelta(SU,true) * ScaleOne); |
414 | 0 | } |
415 | | // Default heuristic, greeady and |
416 | | // critical path driven. |
417 | 0 | else { |
418 | | // Critical path first. |
419 | 0 | ResCount += (SU->getHeight() * ScaleTwo); |
420 | | // Now see how many instructions is blocked by this SU. |
421 | 0 | ResCount += (NumNodesSolelyBlocking[SU->NodeNum] * ScaleTwo); |
422 | | // If resources are available for it, multiply the |
423 | | // chance of scheduling. |
424 | 0 | if (isResourceAvailable(SU)) |
425 | 0 | ResCount <<= FactorOne; |
426 | |
|
427 | 0 | ResCount -= (regPressureDelta(SU) * ScaleTwo); |
428 | 0 | } |
429 | | |
430 | | // These are platform-specific things. |
431 | | // Will need to go into the back end |
432 | | // and accessed from here via a hook. |
433 | 0 | for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) { |
434 | 0 | if (N->isMachineOpcode()) { |
435 | 0 | const MCInstrDesc &TID = TII->get(N->getMachineOpcode()); |
436 | 0 | if (TID.isCall()) |
437 | 0 | ResCount += (PriorityTwo + (ScaleThree*N->getNumValues())); |
438 | 0 | } |
439 | 0 | else |
440 | 0 | switch (N->getOpcode()) { |
441 | 0 | default: break; |
442 | 0 | case ISD::TokenFactor: |
443 | 0 | case ISD::CopyFromReg: |
444 | 0 | case ISD::CopyToReg: |
445 | 0 | ResCount += PriorityFour; |
446 | 0 | break; |
447 | | |
448 | 0 | case ISD::INLINEASM: |
449 | 0 | case ISD::INLINEASM_BR: |
450 | 0 | ResCount += PriorityThree; |
451 | 0 | break; |
452 | 0 | } |
453 | 0 | } |
454 | 0 | return ResCount; |
455 | 0 | } |
456 | | |
457 | | |
458 | | /// Main resource tracking point. |
459 | 0 | void ResourcePriorityQueue::scheduledNode(SUnit *SU) { |
460 | | // Use NULL entry as an event marker to reset |
461 | | // the DFA state. |
462 | 0 | if (!SU) { |
463 | 0 | ResourcesModel->clearResources(); |
464 | 0 | Packet.clear(); |
465 | 0 | return; |
466 | 0 | } |
467 | | |
468 | 0 | const SDNode *ScegN = SU->getNode(); |
469 | | // Update reg pressure tracking. |
470 | | // First update current node. |
471 | 0 | if (ScegN->isMachineOpcode()) { |
472 | | // Estimate generated regs. |
473 | 0 | for (unsigned i = 0, e = ScegN->getNumValues(); i != e; ++i) { |
474 | 0 | MVT VT = ScegN->getSimpleValueType(i); |
475 | |
|
476 | 0 | if (TLI->isTypeLegal(VT)) { |
477 | 0 | const TargetRegisterClass *RC = TLI->getRegClassFor(VT); |
478 | 0 | if (RC) |
479 | 0 | RegPressure[RC->getID()] += numberRCValSuccInSU(SU, RC->getID()); |
480 | 0 | } |
481 | 0 | } |
482 | | // Estimate killed regs. |
483 | 0 | for (unsigned i = 0, e = ScegN->getNumOperands(); i != e; ++i) { |
484 | 0 | const SDValue &Op = ScegN->getOperand(i); |
485 | 0 | MVT VT = Op.getNode()->getSimpleValueType(Op.getResNo()); |
486 | |
|
487 | 0 | if (TLI->isTypeLegal(VT)) { |
488 | 0 | const TargetRegisterClass *RC = TLI->getRegClassFor(VT); |
489 | 0 | if (RC) { |
490 | 0 | if (RegPressure[RC->getID()] > |
491 | 0 | (numberRCValPredInSU(SU, RC->getID()))) |
492 | 0 | RegPressure[RC->getID()] -= numberRCValPredInSU(SU, RC->getID()); |
493 | 0 | else RegPressure[RC->getID()] = 0; |
494 | 0 | } |
495 | 0 | } |
496 | 0 | } |
497 | 0 | for (SDep &Pred : SU->Preds) { |
498 | 0 | if (Pred.isCtrl() || (Pred.getSUnit()->NumRegDefsLeft == 0)) |
499 | 0 | continue; |
500 | 0 | --Pred.getSUnit()->NumRegDefsLeft; |
501 | 0 | } |
502 | 0 | } |
503 | | |
504 | | // Reserve resources for this SU. |
505 | 0 | reserveResources(SU); |
506 | | |
507 | | // Adjust number of parallel live ranges. |
508 | | // Heuristic is simple - node with no data successors reduces |
509 | | // number of live ranges. All others, increase it. |
510 | 0 | unsigned NumberNonControlDeps = 0; |
511 | |
|
512 | 0 | for (const SDep &Succ : SU->Succs) { |
513 | 0 | adjustPriorityOfUnscheduledPreds(Succ.getSUnit()); |
514 | 0 | if (!Succ.isCtrl()) |
515 | 0 | NumberNonControlDeps++; |
516 | 0 | } |
517 | |
|
518 | 0 | if (!NumberNonControlDeps) { |
519 | 0 | if (ParallelLiveRanges >= SU->NumPreds) |
520 | 0 | ParallelLiveRanges -= SU->NumPreds; |
521 | 0 | else |
522 | 0 | ParallelLiveRanges = 0; |
523 | |
|
524 | 0 | } |
525 | 0 | else |
526 | 0 | ParallelLiveRanges += SU->NumRegDefsLeft; |
527 | | |
528 | | // Track parallel live chains. |
529 | 0 | HorizontalVerticalBalance += (SU->Succs.size() - numberCtrlDepsInSU(SU)); |
530 | 0 | HorizontalVerticalBalance -= (SU->Preds.size() - numberCtrlPredInSU(SU)); |
531 | 0 | } |
532 | | |
533 | 0 | void ResourcePriorityQueue::initNumRegDefsLeft(SUnit *SU) { |
534 | 0 | unsigned NodeNumDefs = 0; |
535 | 0 | for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) |
536 | 0 | if (N->isMachineOpcode()) { |
537 | 0 | const MCInstrDesc &TID = TII->get(N->getMachineOpcode()); |
538 | | // No register need be allocated for this. |
539 | 0 | if (N->getMachineOpcode() == TargetOpcode::IMPLICIT_DEF) { |
540 | 0 | NodeNumDefs = 0; |
541 | 0 | break; |
542 | 0 | } |
543 | 0 | NodeNumDefs = std::min(N->getNumValues(), TID.getNumDefs()); |
544 | 0 | } |
545 | 0 | else |
546 | 0 | switch(N->getOpcode()) { |
547 | 0 | default: break; |
548 | 0 | case ISD::CopyFromReg: |
549 | 0 | NodeNumDefs++; |
550 | 0 | break; |
551 | 0 | case ISD::INLINEASM: |
552 | 0 | case ISD::INLINEASM_BR: |
553 | 0 | NodeNumDefs++; |
554 | 0 | break; |
555 | 0 | } |
556 | | |
557 | 0 | SU->NumRegDefsLeft = NodeNumDefs; |
558 | 0 | } |
559 | | |
560 | | /// adjustPriorityOfUnscheduledPreds - One of the predecessors of SU was just |
561 | | /// scheduled. If SU is not itself available, then there is at least one |
562 | | /// predecessor node that has not been scheduled yet. If SU has exactly ONE |
563 | | /// unscheduled predecessor, we want to increase its priority: it getting |
564 | | /// scheduled will make this node available, so it is better than some other |
565 | | /// node of the same priority that will not make a node available. |
566 | 0 | void ResourcePriorityQueue::adjustPriorityOfUnscheduledPreds(SUnit *SU) { |
567 | 0 | if (SU->isAvailable) return; // All preds scheduled. |
568 | | |
569 | 0 | SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU); |
570 | 0 | if (!OnlyAvailablePred || !OnlyAvailablePred->isAvailable) |
571 | 0 | return; |
572 | | |
573 | | // Okay, we found a single predecessor that is available, but not scheduled. |
574 | | // Since it is available, it must be in the priority queue. First remove it. |
575 | 0 | remove(OnlyAvailablePred); |
576 | | |
577 | | // Reinsert the node into the priority queue, which recomputes its |
578 | | // NumNodesSolelyBlocking value. |
579 | 0 | push(OnlyAvailablePred); |
580 | 0 | } |
581 | | |
582 | | |
583 | | /// Main access point - returns next instructions |
584 | | /// to be placed in scheduling sequence. |
585 | 0 | SUnit *ResourcePriorityQueue::pop() { |
586 | 0 | if (empty()) |
587 | 0 | return nullptr; |
588 | | |
589 | 0 | std::vector<SUnit *>::iterator Best = Queue.begin(); |
590 | 0 | if (!DisableDFASched) { |
591 | 0 | int BestCost = SUSchedulingCost(*Best); |
592 | 0 | for (auto I = std::next(Queue.begin()), E = Queue.end(); I != E; ++I) { |
593 | |
|
594 | 0 | if (SUSchedulingCost(*I) > BestCost) { |
595 | 0 | BestCost = SUSchedulingCost(*I); |
596 | 0 | Best = I; |
597 | 0 | } |
598 | 0 | } |
599 | 0 | } |
600 | | // Use default TD scheduling mechanism. |
601 | 0 | else { |
602 | 0 | for (auto I = std::next(Queue.begin()), E = Queue.end(); I != E; ++I) |
603 | 0 | if (Picker(*Best, *I)) |
604 | 0 | Best = I; |
605 | 0 | } |
606 | |
|
607 | 0 | SUnit *V = *Best; |
608 | 0 | if (Best != std::prev(Queue.end())) |
609 | 0 | std::swap(*Best, Queue.back()); |
610 | |
|
611 | 0 | Queue.pop_back(); |
612 | |
|
613 | 0 | return V; |
614 | 0 | } |
615 | | |
616 | | |
617 | 0 | void ResourcePriorityQueue::remove(SUnit *SU) { |
618 | 0 | assert(!Queue.empty() && "Queue is empty!"); |
619 | 0 | std::vector<SUnit *>::iterator I = find(Queue, SU); |
620 | 0 | if (I != std::prev(Queue.end())) |
621 | 0 | std::swap(*I, Queue.back()); |
622 | |
|
623 | 0 | Queue.pop_back(); |
624 | 0 | } |