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