xref: /src/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/ResourcePriorityQueue.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
163faed5bSDimitry Andric //===- ResourcePriorityQueue.cpp - A DFA-oriented priority queue -*- C++ -*-==//
263faed5bSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
663faed5bSDimitry Andric //
763faed5bSDimitry Andric //===----------------------------------------------------------------------===//
863faed5bSDimitry Andric //
963faed5bSDimitry Andric // This file implements the ResourcePriorityQueue class, which is a
1063faed5bSDimitry Andric // SchedulingPriorityQueue that prioritizes instructions using DFA state to
1163faed5bSDimitry Andric // reduce the length of the critical path through the basic block
1263faed5bSDimitry Andric // on VLIW platforms.
1363faed5bSDimitry Andric // The scheduler is basically a top-down adaptable list scheduler with DFA
1463faed5bSDimitry Andric // resource tracking added to the cost function.
1563faed5bSDimitry Andric // DFA is queried as a state machine to model "packets/bundles" during
1663faed5bSDimitry Andric // schedule. Currently packets/bundles are discarded at the end of
1763faed5bSDimitry Andric // scheduling, affecting only order of instructions.
1863faed5bSDimitry Andric //
1963faed5bSDimitry Andric //===----------------------------------------------------------------------===//
2063faed5bSDimitry Andric 
2163faed5bSDimitry Andric #include "llvm/CodeGen/ResourcePriorityQueue.h"
22cfca06d7SDimitry Andric #include "llvm/CodeGen/DFAPacketizer.h"
23cfca06d7SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h"
244a16efa3SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h"
25cfca06d7SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
26044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
27cfca06d7SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
28044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
2963faed5bSDimitry Andric #include "llvm/Support/CommandLine.h"
3063faed5bSDimitry Andric 
3163faed5bSDimitry Andric using namespace llvm;
3263faed5bSDimitry Andric 
335ca98fd9SDimitry Andric #define DEBUG_TYPE "scheduler"
345ca98fd9SDimitry Andric 
35145449b1SDimitry Andric static cl::opt<bool>
36145449b1SDimitry Andric     DisableDFASched("disable-dfa-sched", cl::Hidden,
3763faed5bSDimitry Andric                     cl::desc("Disable use of DFA during scheduling"));
3863faed5bSDimitry Andric 
3901095a5dSDimitry Andric static cl::opt<int> RegPressureThreshold(
40145449b1SDimitry Andric     "dfa-sched-reg-pressure-threshold", cl::Hidden, cl::init(5),
4163faed5bSDimitry Andric     cl::desc("Track reg pressure and switch priority to in-depth"));
4263faed5bSDimitry Andric 
ResourcePriorityQueue(SelectionDAGISel * IS)4367c32a98SDimitry Andric ResourcePriorityQueue::ResourcePriorityQueue(SelectionDAGISel *IS)
4467c32a98SDimitry Andric     : Picker(this), InstrItins(IS->MF->getSubtarget().getInstrItineraryData()) {
4567c32a98SDimitry Andric   const TargetSubtargetInfo &STI = IS->MF->getSubtarget();
4667c32a98SDimitry Andric   TRI = STI.getRegisterInfo();
4767c32a98SDimitry Andric   TLI = IS->TLI;
4867c32a98SDimitry Andric   TII = STI.getInstrInfo();
495a5ac124SDimitry Andric   ResourcesModel.reset(TII->CreateTargetScheduleState(STI));
5058b69754SDimitry Andric   // This hard requirement could be relaxed, but for now
51dd58ef01SDimitry Andric   // do not let it proceed.
5263faed5bSDimitry Andric   assert(ResourcesModel && "Unimplemented CreateTargetScheduleState.");
5363faed5bSDimitry Andric 
5463faed5bSDimitry Andric   unsigned NumRC = TRI->getNumRegClasses();
5563faed5bSDimitry Andric   RegLimit.resize(NumRC);
5663faed5bSDimitry Andric   RegPressure.resize(NumRC);
5763faed5bSDimitry Andric   std::fill(RegLimit.begin(), RegLimit.end(), 0);
5863faed5bSDimitry Andric   std::fill(RegPressure.begin(), RegPressure.end(), 0);
5971d5a254SDimitry Andric   for (const TargetRegisterClass *RC : TRI->regclasses())
6071d5a254SDimitry Andric     RegLimit[RC->getID()] = TRI->getRegPressureLimit(RC, *IS->MF);
6163faed5bSDimitry Andric 
6263faed5bSDimitry Andric   ParallelLiveRanges = 0;
6363faed5bSDimitry Andric   HorizontalVerticalBalance = 0;
6463faed5bSDimitry Andric }
6563faed5bSDimitry Andric 
6663faed5bSDimitry Andric unsigned
numberRCValPredInSU(SUnit * SU,unsigned RCId)6763faed5bSDimitry Andric ResourcePriorityQueue::numberRCValPredInSU(SUnit *SU, unsigned RCId) {
6863faed5bSDimitry Andric   unsigned NumberDeps = 0;
69c46e6a59SDimitry Andric   for (SDep &Pred : SU->Preds) {
70c46e6a59SDimitry Andric     if (Pred.isCtrl())
7163faed5bSDimitry Andric       continue;
7263faed5bSDimitry Andric 
73c46e6a59SDimitry Andric     SUnit *PredSU = Pred.getSUnit();
7463faed5bSDimitry Andric     const SDNode *ScegN = PredSU->getNode();
7563faed5bSDimitry Andric 
7663faed5bSDimitry Andric     if (!ScegN)
7763faed5bSDimitry Andric       continue;
7863faed5bSDimitry Andric 
7963faed5bSDimitry Andric     // If value is passed to CopyToReg, it is probably
8063faed5bSDimitry Andric     // live outside BB.
8163faed5bSDimitry Andric     switch (ScegN->getOpcode()) {
8263faed5bSDimitry Andric       default:  break;
8363faed5bSDimitry Andric       case ISD::TokenFactor:    break;
8463faed5bSDimitry Andric       case ISD::CopyFromReg:    NumberDeps++;  break;
8563faed5bSDimitry Andric       case ISD::CopyToReg:      break;
8663faed5bSDimitry Andric       case ISD::INLINEASM:      break;
87e6d15924SDimitry Andric       case ISD::INLINEASM_BR:   break;
8863faed5bSDimitry Andric     }
8963faed5bSDimitry Andric     if (!ScegN->isMachineOpcode())
9063faed5bSDimitry Andric       continue;
9163faed5bSDimitry Andric 
9263faed5bSDimitry Andric     for (unsigned i = 0, e = ScegN->getNumValues(); i != e; ++i) {
934a16efa3SDimitry Andric       MVT VT = ScegN->getSimpleValueType(i);
9463faed5bSDimitry Andric       if (TLI->isTypeLegal(VT)
9563faed5bSDimitry Andric           && (TLI->getRegClassFor(VT)->getID() == RCId)) {
9663faed5bSDimitry Andric         NumberDeps++;
9763faed5bSDimitry Andric         break;
9863faed5bSDimitry Andric       }
9963faed5bSDimitry Andric     }
10063faed5bSDimitry Andric   }
10163faed5bSDimitry Andric   return NumberDeps;
10263faed5bSDimitry Andric }
10363faed5bSDimitry Andric 
numberRCValSuccInSU(SUnit * SU,unsigned RCId)10463faed5bSDimitry Andric unsigned ResourcePriorityQueue::numberRCValSuccInSU(SUnit *SU,
10563faed5bSDimitry Andric                                                     unsigned RCId) {
10663faed5bSDimitry Andric   unsigned NumberDeps = 0;
107c46e6a59SDimitry Andric   for (const SDep &Succ : SU->Succs) {
108c46e6a59SDimitry Andric     if (Succ.isCtrl())
10963faed5bSDimitry Andric       continue;
11063faed5bSDimitry Andric 
111c46e6a59SDimitry Andric     SUnit *SuccSU = Succ.getSUnit();
11263faed5bSDimitry Andric     const SDNode *ScegN = SuccSU->getNode();
11363faed5bSDimitry Andric     if (!ScegN)
11463faed5bSDimitry Andric       continue;
11563faed5bSDimitry Andric 
11663faed5bSDimitry Andric     // If value is passed to CopyToReg, it is probably
11763faed5bSDimitry Andric     // live outside BB.
11863faed5bSDimitry Andric     switch (ScegN->getOpcode()) {
11963faed5bSDimitry Andric       default:  break;
12063faed5bSDimitry Andric       case ISD::TokenFactor:    break;
12163faed5bSDimitry Andric       case ISD::CopyFromReg:    break;
12263faed5bSDimitry Andric       case ISD::CopyToReg:      NumberDeps++;  break;
12363faed5bSDimitry Andric       case ISD::INLINEASM:      break;
124e6d15924SDimitry Andric       case ISD::INLINEASM_BR:   break;
12563faed5bSDimitry Andric     }
12663faed5bSDimitry Andric     if (!ScegN->isMachineOpcode())
12763faed5bSDimitry Andric       continue;
12863faed5bSDimitry Andric 
12963faed5bSDimitry Andric     for (unsigned i = 0, e = ScegN->getNumOperands(); i != e; ++i) {
13063faed5bSDimitry Andric       const SDValue &Op = ScegN->getOperand(i);
1314a16efa3SDimitry Andric       MVT VT = Op.getNode()->getSimpleValueType(Op.getResNo());
13263faed5bSDimitry Andric       if (TLI->isTypeLegal(VT)
13363faed5bSDimitry Andric           && (TLI->getRegClassFor(VT)->getID() == RCId)) {
13463faed5bSDimitry Andric         NumberDeps++;
13563faed5bSDimitry Andric         break;
13663faed5bSDimitry Andric       }
13763faed5bSDimitry Andric     }
13863faed5bSDimitry Andric   }
13963faed5bSDimitry Andric   return NumberDeps;
14063faed5bSDimitry Andric }
14163faed5bSDimitry Andric 
numberCtrlDepsInSU(SUnit * SU)14263faed5bSDimitry Andric static unsigned numberCtrlDepsInSU(SUnit *SU) {
14363faed5bSDimitry Andric   unsigned NumberDeps = 0;
144c46e6a59SDimitry Andric   for (const SDep &Succ : SU->Succs)
145c46e6a59SDimitry Andric     if (Succ.isCtrl())
14663faed5bSDimitry Andric       NumberDeps++;
14763faed5bSDimitry Andric 
14863faed5bSDimitry Andric   return NumberDeps;
14963faed5bSDimitry Andric }
15063faed5bSDimitry Andric 
numberCtrlPredInSU(SUnit * SU)15163faed5bSDimitry Andric static unsigned numberCtrlPredInSU(SUnit *SU) {
15263faed5bSDimitry Andric   unsigned NumberDeps = 0;
153c46e6a59SDimitry Andric   for (SDep &Pred : SU->Preds)
154c46e6a59SDimitry Andric     if (Pred.isCtrl())
15563faed5bSDimitry Andric       NumberDeps++;
15663faed5bSDimitry Andric 
15763faed5bSDimitry Andric   return NumberDeps;
15863faed5bSDimitry Andric }
15963faed5bSDimitry Andric 
16063faed5bSDimitry Andric ///
16163faed5bSDimitry Andric /// Initialize nodes.
16263faed5bSDimitry Andric ///
initNodes(std::vector<SUnit> & sunits)16363faed5bSDimitry Andric void ResourcePriorityQueue::initNodes(std::vector<SUnit> &sunits) {
16463faed5bSDimitry Andric   SUnits = &sunits;
16563faed5bSDimitry Andric   NumNodesSolelyBlocking.resize(SUnits->size(), 0);
16663faed5bSDimitry Andric 
16777fc4c14SDimitry Andric   for (SUnit &SU : *SUnits) {
16877fc4c14SDimitry Andric     initNumRegDefsLeft(&SU);
16977fc4c14SDimitry Andric     SU.NodeQueueId = 0;
17063faed5bSDimitry Andric   }
17163faed5bSDimitry Andric }
17263faed5bSDimitry Andric 
17363faed5bSDimitry Andric /// This heuristic is used if DFA scheduling is not desired
17463faed5bSDimitry Andric /// for some VLIW platform.
operator ()(const SUnit * LHS,const SUnit * RHS) const17563faed5bSDimitry Andric bool resource_sort::operator()(const SUnit *LHS, const SUnit *RHS) const {
17663faed5bSDimitry Andric   // The isScheduleHigh flag allows nodes with wraparound dependencies that
17763faed5bSDimitry Andric   // cannot easily be modeled as edges with latencies to be scheduled as
17863faed5bSDimitry Andric   // soon as possible in a top-down schedule.
17963faed5bSDimitry Andric   if (LHS->isScheduleHigh && !RHS->isScheduleHigh)
18063faed5bSDimitry Andric     return false;
18163faed5bSDimitry Andric 
18263faed5bSDimitry Andric   if (!LHS->isScheduleHigh && RHS->isScheduleHigh)
18363faed5bSDimitry Andric     return true;
18463faed5bSDimitry Andric 
18563faed5bSDimitry Andric   unsigned LHSNum = LHS->NodeNum;
18663faed5bSDimitry Andric   unsigned RHSNum = RHS->NodeNum;
18763faed5bSDimitry Andric 
18863faed5bSDimitry Andric   // The most important heuristic is scheduling the critical path.
18963faed5bSDimitry Andric   unsigned LHSLatency = PQ->getLatency(LHSNum);
19063faed5bSDimitry Andric   unsigned RHSLatency = PQ->getLatency(RHSNum);
19163faed5bSDimitry Andric   if (LHSLatency < RHSLatency) return true;
19263faed5bSDimitry Andric   if (LHSLatency > RHSLatency) return false;
19363faed5bSDimitry Andric 
19463faed5bSDimitry Andric   // After that, if two nodes have identical latencies, look to see if one will
19563faed5bSDimitry Andric   // unblock more other nodes than the other.
19663faed5bSDimitry Andric   unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum);
19763faed5bSDimitry Andric   unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum);
19863faed5bSDimitry Andric   if (LHSBlocked < RHSBlocked) return true;
19963faed5bSDimitry Andric   if (LHSBlocked > RHSBlocked) return false;
20063faed5bSDimitry Andric 
20163faed5bSDimitry Andric   // Finally, just to provide a stable ordering, use the node number as a
20263faed5bSDimitry Andric   // deciding factor.
20363faed5bSDimitry Andric   return LHSNum < RHSNum;
20463faed5bSDimitry Andric }
20563faed5bSDimitry Andric 
20663faed5bSDimitry Andric 
20763faed5bSDimitry Andric /// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor
20863faed5bSDimitry Andric /// of SU, return it, otherwise return null.
getSingleUnscheduledPred(SUnit * SU)20963faed5bSDimitry Andric SUnit *ResourcePriorityQueue::getSingleUnscheduledPred(SUnit *SU) {
2105ca98fd9SDimitry Andric   SUnit *OnlyAvailablePred = nullptr;
211c46e6a59SDimitry Andric   for (const SDep &Pred : SU->Preds) {
212c46e6a59SDimitry Andric     SUnit &PredSU = *Pred.getSUnit();
213c46e6a59SDimitry Andric     if (!PredSU.isScheduled) {
21463faed5bSDimitry Andric       // We found an available, but not scheduled, predecessor.  If it's the
21563faed5bSDimitry Andric       // only one we have found, keep track of it... otherwise give up.
216c46e6a59SDimitry Andric       if (OnlyAvailablePred && OnlyAvailablePred != &PredSU)
2175ca98fd9SDimitry Andric         return nullptr;
218c46e6a59SDimitry Andric       OnlyAvailablePred = &PredSU;
21963faed5bSDimitry Andric     }
22063faed5bSDimitry Andric   }
22163faed5bSDimitry Andric   return OnlyAvailablePred;
22263faed5bSDimitry Andric }
22363faed5bSDimitry Andric 
push(SUnit * SU)22463faed5bSDimitry Andric void ResourcePriorityQueue::push(SUnit *SU) {
22563faed5bSDimitry Andric   // Look at all of the successors of this node.  Count the number of nodes that
22663faed5bSDimitry Andric   // this node is the sole unscheduled node for.
22763faed5bSDimitry Andric   unsigned NumNodesBlocking = 0;
228c46e6a59SDimitry Andric   for (const SDep &Succ : SU->Succs)
229c46e6a59SDimitry Andric     if (getSingleUnscheduledPred(Succ.getSUnit()) == SU)
23063faed5bSDimitry Andric       ++NumNodesBlocking;
23163faed5bSDimitry Andric 
23263faed5bSDimitry Andric   NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking;
23363faed5bSDimitry Andric   Queue.push_back(SU);
23463faed5bSDimitry Andric }
23563faed5bSDimitry Andric 
23663faed5bSDimitry Andric /// Check if scheduling of this SU is possible
23763faed5bSDimitry Andric /// in the current packet.
isResourceAvailable(SUnit * SU)23863faed5bSDimitry Andric bool ResourcePriorityQueue::isResourceAvailable(SUnit *SU) {
23963faed5bSDimitry Andric   if (!SU || !SU->getNode())
24063faed5bSDimitry Andric     return false;
24163faed5bSDimitry Andric 
24263faed5bSDimitry Andric   // If this is a compound instruction,
24363faed5bSDimitry Andric   // it is likely to be a call. Do not delay it.
24463faed5bSDimitry Andric   if (SU->getNode()->getGluedNode())
24563faed5bSDimitry Andric     return true;
24663faed5bSDimitry Andric 
24763faed5bSDimitry Andric   // First see if the pipeline could receive this instruction
24863faed5bSDimitry Andric   // in the current cycle.
24963faed5bSDimitry Andric   if (SU->getNode()->isMachineOpcode())
25063faed5bSDimitry Andric     switch (SU->getNode()->getMachineOpcode()) {
25163faed5bSDimitry Andric     default:
25263faed5bSDimitry Andric       if (!ResourcesModel->canReserveResources(&TII->get(
25363faed5bSDimitry Andric           SU->getNode()->getMachineOpcode())))
25463faed5bSDimitry Andric            return false;
255c7dac04cSDimitry Andric       break;
25663faed5bSDimitry Andric     case TargetOpcode::EXTRACT_SUBREG:
25763faed5bSDimitry Andric     case TargetOpcode::INSERT_SUBREG:
25863faed5bSDimitry Andric     case TargetOpcode::SUBREG_TO_REG:
25963faed5bSDimitry Andric     case TargetOpcode::REG_SEQUENCE:
26063faed5bSDimitry Andric     case TargetOpcode::IMPLICIT_DEF:
26163faed5bSDimitry Andric         break;
26263faed5bSDimitry Andric     }
26363faed5bSDimitry Andric 
26463faed5bSDimitry Andric   // Now see if there are no other dependencies
265dd58ef01SDimitry Andric   // to instructions already in the packet.
266f65dcba8SDimitry Andric   for (const SUnit *S : Packet)
267f65dcba8SDimitry Andric     for (const SDep &Succ : S->Succs) {
26863faed5bSDimitry Andric       // Since we do not add pseudos to packets, might as well
269dd58ef01SDimitry Andric       // ignore order deps.
270c46e6a59SDimitry Andric       if (Succ.isCtrl())
27163faed5bSDimitry Andric         continue;
27263faed5bSDimitry Andric 
273c46e6a59SDimitry Andric       if (Succ.getSUnit() == SU)
27463faed5bSDimitry Andric         return false;
27563faed5bSDimitry Andric     }
27663faed5bSDimitry Andric 
27763faed5bSDimitry Andric   return true;
27863faed5bSDimitry Andric }
27963faed5bSDimitry Andric 
28063faed5bSDimitry Andric /// Keep track of available resources.
reserveResources(SUnit * SU)28163faed5bSDimitry Andric void ResourcePriorityQueue::reserveResources(SUnit *SU) {
28263faed5bSDimitry Andric   // If this SU does not fit in the packet
28363faed5bSDimitry Andric   // start a new one.
28463faed5bSDimitry Andric   if (!isResourceAvailable(SU) || SU->getNode()->getGluedNode()) {
28563faed5bSDimitry Andric     ResourcesModel->clearResources();
28663faed5bSDimitry Andric     Packet.clear();
28763faed5bSDimitry Andric   }
28863faed5bSDimitry Andric 
28963faed5bSDimitry Andric   if (SU->getNode() && SU->getNode()->isMachineOpcode()) {
29063faed5bSDimitry Andric     switch (SU->getNode()->getMachineOpcode()) {
29163faed5bSDimitry Andric     default:
29263faed5bSDimitry Andric       ResourcesModel->reserveResources(&TII->get(
29363faed5bSDimitry Andric         SU->getNode()->getMachineOpcode()));
29463faed5bSDimitry Andric       break;
29563faed5bSDimitry Andric     case TargetOpcode::EXTRACT_SUBREG:
29663faed5bSDimitry Andric     case TargetOpcode::INSERT_SUBREG:
29763faed5bSDimitry Andric     case TargetOpcode::SUBREG_TO_REG:
29863faed5bSDimitry Andric     case TargetOpcode::REG_SEQUENCE:
29963faed5bSDimitry Andric     case TargetOpcode::IMPLICIT_DEF:
30063faed5bSDimitry Andric       break;
30163faed5bSDimitry Andric     }
30263faed5bSDimitry Andric     Packet.push_back(SU);
30363faed5bSDimitry Andric   }
30463faed5bSDimitry Andric   // Forcefully end packet for PseudoOps.
30563faed5bSDimitry Andric   else {
30663faed5bSDimitry Andric     ResourcesModel->clearResources();
30763faed5bSDimitry Andric     Packet.clear();
30863faed5bSDimitry Andric   }
30963faed5bSDimitry Andric 
31063faed5bSDimitry Andric   // If packet is now full, reset the state so in the next cycle
31163faed5bSDimitry Andric   // we start fresh.
31267c32a98SDimitry Andric   if (Packet.size() >= InstrItins->SchedModel.IssueWidth) {
31363faed5bSDimitry Andric     ResourcesModel->clearResources();
31463faed5bSDimitry Andric     Packet.clear();
31563faed5bSDimitry Andric   }
31663faed5bSDimitry Andric }
31763faed5bSDimitry Andric 
rawRegPressureDelta(SUnit * SU,unsigned RCId)31801095a5dSDimitry Andric int ResourcePriorityQueue::rawRegPressureDelta(SUnit *SU, unsigned RCId) {
31901095a5dSDimitry Andric   int RegBalance = 0;
32063faed5bSDimitry Andric 
32163faed5bSDimitry Andric   if (!SU || !SU->getNode() || !SU->getNode()->isMachineOpcode())
32263faed5bSDimitry Andric     return RegBalance;
32363faed5bSDimitry Andric 
32463faed5bSDimitry Andric   // Gen estimate.
32563faed5bSDimitry Andric   for (unsigned i = 0, e = SU->getNode()->getNumValues(); i != e; ++i) {
3264a16efa3SDimitry Andric       MVT VT = SU->getNode()->getSimpleValueType(i);
32763faed5bSDimitry Andric       if (TLI->isTypeLegal(VT)
32863faed5bSDimitry Andric           && TLI->getRegClassFor(VT)
32963faed5bSDimitry Andric           && TLI->getRegClassFor(VT)->getID() == RCId)
33063faed5bSDimitry Andric         RegBalance += numberRCValSuccInSU(SU, RCId);
33163faed5bSDimitry Andric   }
33263faed5bSDimitry Andric   // Kill estimate.
33363faed5bSDimitry Andric   for (unsigned i = 0, e = SU->getNode()->getNumOperands(); i != e; ++i) {
33463faed5bSDimitry Andric       const SDValue &Op = SU->getNode()->getOperand(i);
3354a16efa3SDimitry Andric       MVT VT = Op.getNode()->getSimpleValueType(Op.getResNo());
33663faed5bSDimitry Andric       if (isa<ConstantSDNode>(Op.getNode()))
33763faed5bSDimitry Andric         continue;
33863faed5bSDimitry Andric 
33963faed5bSDimitry Andric       if (TLI->isTypeLegal(VT) && TLI->getRegClassFor(VT)
34063faed5bSDimitry Andric           && TLI->getRegClassFor(VT)->getID() == RCId)
34163faed5bSDimitry Andric         RegBalance -= numberRCValPredInSU(SU, RCId);
34263faed5bSDimitry Andric   }
34363faed5bSDimitry Andric   return RegBalance;
34463faed5bSDimitry Andric }
34563faed5bSDimitry Andric 
34663faed5bSDimitry Andric /// Estimates change in reg pressure from this SU.
34758b69754SDimitry Andric /// It is achieved by trivial tracking of defined
34863faed5bSDimitry Andric /// and used vregs in dependent instructions.
34963faed5bSDimitry Andric /// The RawPressure flag makes this function to ignore
35063faed5bSDimitry Andric /// existing reg file sizes, and report raw def/use
35163faed5bSDimitry Andric /// balance.
regPressureDelta(SUnit * SU,bool RawPressure)35201095a5dSDimitry Andric int ResourcePriorityQueue::regPressureDelta(SUnit *SU, bool RawPressure) {
35301095a5dSDimitry Andric   int RegBalance = 0;
35463faed5bSDimitry Andric 
35563faed5bSDimitry Andric   if (!SU || !SU->getNode() || !SU->getNode()->isMachineOpcode())
35663faed5bSDimitry Andric     return RegBalance;
35763faed5bSDimitry Andric 
35863faed5bSDimitry Andric   if (RawPressure) {
35971d5a254SDimitry Andric     for (const TargetRegisterClass *RC : TRI->regclasses())
36063faed5bSDimitry Andric       RegBalance += rawRegPressureDelta(SU, RC->getID());
36163faed5bSDimitry Andric   }
36263faed5bSDimitry Andric   else {
36371d5a254SDimitry Andric     for (const TargetRegisterClass *RC : TRI->regclasses()) {
36463faed5bSDimitry Andric       if ((RegPressure[RC->getID()] +
36563faed5bSDimitry Andric            rawRegPressureDelta(SU, RC->getID()) > 0) &&
36663faed5bSDimitry Andric           (RegPressure[RC->getID()] +
36763faed5bSDimitry Andric            rawRegPressureDelta(SU, RC->getID())  >= RegLimit[RC->getID()]))
36863faed5bSDimitry Andric         RegBalance += rawRegPressureDelta(SU, RC->getID());
36963faed5bSDimitry Andric     }
37063faed5bSDimitry Andric   }
37163faed5bSDimitry Andric 
37263faed5bSDimitry Andric   return RegBalance;
37363faed5bSDimitry Andric }
37463faed5bSDimitry Andric 
37563faed5bSDimitry Andric // Constants used to denote relative importance of
37663faed5bSDimitry Andric // heuristic components for cost computation.
37763faed5bSDimitry Andric static const unsigned PriorityOne = 200;
378f8af5cf6SDimitry Andric static const unsigned PriorityTwo = 50;
379f8af5cf6SDimitry Andric static const unsigned PriorityThree = 15;
380f8af5cf6SDimitry Andric static const unsigned PriorityFour = 5;
38163faed5bSDimitry Andric static const unsigned ScaleOne = 20;
38263faed5bSDimitry Andric static const unsigned ScaleTwo = 10;
38363faed5bSDimitry Andric static const unsigned ScaleThree = 5;
38463faed5bSDimitry Andric static const unsigned FactorOne = 2;
38563faed5bSDimitry Andric 
38663faed5bSDimitry Andric /// Returns single number reflecting benefit of scheduling SU
38763faed5bSDimitry Andric /// in the current cycle.
SUSchedulingCost(SUnit * SU)38801095a5dSDimitry Andric int ResourcePriorityQueue::SUSchedulingCost(SUnit *SU) {
38963faed5bSDimitry Andric   // Initial trivial priority.
39001095a5dSDimitry Andric   int ResCount = 1;
39163faed5bSDimitry Andric 
39263faed5bSDimitry Andric   // Do not waste time on a node that is already scheduled.
39363faed5bSDimitry Andric   if (SU->isScheduled)
39463faed5bSDimitry Andric     return ResCount;
39563faed5bSDimitry Andric 
39663faed5bSDimitry Andric   // Forced priority is high.
39763faed5bSDimitry Andric   if (SU->isScheduleHigh)
39863faed5bSDimitry Andric     ResCount += PriorityOne;
39963faed5bSDimitry Andric 
40063faed5bSDimitry Andric   // Adaptable scheduling
40163faed5bSDimitry Andric   // A small, but very parallel
40263faed5bSDimitry Andric   // region, where reg pressure is an issue.
40363faed5bSDimitry Andric   if (HorizontalVerticalBalance > RegPressureThreshold) {
40463faed5bSDimitry Andric     // Critical path first
40563faed5bSDimitry Andric     ResCount += (SU->getHeight() * ScaleTwo);
40663faed5bSDimitry Andric     // If resources are available for it, multiply the
40763faed5bSDimitry Andric     // chance of scheduling.
40863faed5bSDimitry Andric     if (isResourceAvailable(SU))
40963faed5bSDimitry Andric       ResCount <<= FactorOne;
41063faed5bSDimitry Andric 
41163faed5bSDimitry Andric     // Consider change to reg pressure from scheduling
41263faed5bSDimitry Andric     // this SU.
41363faed5bSDimitry Andric     ResCount -= (regPressureDelta(SU,true) * ScaleOne);
41463faed5bSDimitry Andric   }
41563faed5bSDimitry Andric   // Default heuristic, greeady and
41663faed5bSDimitry Andric   // critical path driven.
41763faed5bSDimitry Andric   else {
41863faed5bSDimitry Andric     // Critical path first.
41963faed5bSDimitry Andric     ResCount += (SU->getHeight() * ScaleTwo);
42063faed5bSDimitry Andric     // Now see how many instructions is blocked by this SU.
42163faed5bSDimitry Andric     ResCount += (NumNodesSolelyBlocking[SU->NodeNum] * ScaleTwo);
42263faed5bSDimitry Andric     // If resources are available for it, multiply the
42363faed5bSDimitry Andric     // chance of scheduling.
42463faed5bSDimitry Andric     if (isResourceAvailable(SU))
42563faed5bSDimitry Andric       ResCount <<= FactorOne;
42663faed5bSDimitry Andric 
42763faed5bSDimitry Andric     ResCount -= (regPressureDelta(SU) * ScaleTwo);
42863faed5bSDimitry Andric   }
42963faed5bSDimitry Andric 
4305ca98fd9SDimitry Andric   // These are platform-specific things.
43163faed5bSDimitry Andric   // Will need to go into the back end
43263faed5bSDimitry Andric   // and accessed from here via a hook.
43363faed5bSDimitry Andric   for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) {
43463faed5bSDimitry Andric     if (N->isMachineOpcode()) {
43563faed5bSDimitry Andric       const MCInstrDesc &TID = TII->get(N->getMachineOpcode());
43663faed5bSDimitry Andric       if (TID.isCall())
437f8af5cf6SDimitry Andric         ResCount += (PriorityTwo + (ScaleThree*N->getNumValues()));
43863faed5bSDimitry Andric     }
43963faed5bSDimitry Andric     else
44063faed5bSDimitry Andric       switch (N->getOpcode()) {
44163faed5bSDimitry Andric       default:  break;
44263faed5bSDimitry Andric       case ISD::TokenFactor:
44363faed5bSDimitry Andric       case ISD::CopyFromReg:
44463faed5bSDimitry Andric       case ISD::CopyToReg:
445f8af5cf6SDimitry Andric         ResCount += PriorityFour;
44663faed5bSDimitry Andric         break;
44763faed5bSDimitry Andric 
44863faed5bSDimitry Andric       case ISD::INLINEASM:
449e6d15924SDimitry Andric       case ISD::INLINEASM_BR:
450f8af5cf6SDimitry Andric         ResCount += PriorityThree;
45163faed5bSDimitry Andric         break;
45263faed5bSDimitry Andric       }
45363faed5bSDimitry Andric   }
45463faed5bSDimitry Andric   return ResCount;
45563faed5bSDimitry Andric }
45663faed5bSDimitry Andric 
45763faed5bSDimitry Andric 
45863faed5bSDimitry Andric /// Main resource tracking point.
scheduledNode(SUnit * SU)45963faed5bSDimitry Andric void ResourcePriorityQueue::scheduledNode(SUnit *SU) {
46063faed5bSDimitry Andric   // Use NULL entry as an event marker to reset
46163faed5bSDimitry Andric   // the DFA state.
46263faed5bSDimitry Andric   if (!SU) {
46363faed5bSDimitry Andric     ResourcesModel->clearResources();
46463faed5bSDimitry Andric     Packet.clear();
46563faed5bSDimitry Andric     return;
46663faed5bSDimitry Andric   }
46763faed5bSDimitry Andric 
46863faed5bSDimitry Andric   const SDNode *ScegN = SU->getNode();
46963faed5bSDimitry Andric   // Update reg pressure tracking.
47063faed5bSDimitry Andric   // First update current node.
47163faed5bSDimitry Andric   if (ScegN->isMachineOpcode()) {
47263faed5bSDimitry Andric     // Estimate generated regs.
47363faed5bSDimitry Andric     for (unsigned i = 0, e = ScegN->getNumValues(); i != e; ++i) {
4744a16efa3SDimitry Andric       MVT VT = ScegN->getSimpleValueType(i);
47563faed5bSDimitry Andric 
47663faed5bSDimitry Andric       if (TLI->isTypeLegal(VT)) {
47763faed5bSDimitry Andric         const TargetRegisterClass *RC = TLI->getRegClassFor(VT);
47863faed5bSDimitry Andric         if (RC)
47963faed5bSDimitry Andric           RegPressure[RC->getID()] += numberRCValSuccInSU(SU, RC->getID());
48063faed5bSDimitry Andric       }
48163faed5bSDimitry Andric     }
48263faed5bSDimitry Andric     // Estimate killed regs.
48363faed5bSDimitry Andric     for (unsigned i = 0, e = ScegN->getNumOperands(); i != e; ++i) {
48463faed5bSDimitry Andric       const SDValue &Op = ScegN->getOperand(i);
4854a16efa3SDimitry Andric       MVT VT = Op.getNode()->getSimpleValueType(Op.getResNo());
48663faed5bSDimitry Andric 
48763faed5bSDimitry Andric       if (TLI->isTypeLegal(VT)) {
48863faed5bSDimitry Andric         const TargetRegisterClass *RC = TLI->getRegClassFor(VT);
48963faed5bSDimitry Andric         if (RC) {
49063faed5bSDimitry Andric           if (RegPressure[RC->getID()] >
49163faed5bSDimitry Andric             (numberRCValPredInSU(SU, RC->getID())))
49263faed5bSDimitry Andric             RegPressure[RC->getID()] -= numberRCValPredInSU(SU, RC->getID());
49363faed5bSDimitry Andric           else RegPressure[RC->getID()] = 0;
49463faed5bSDimitry Andric         }
49563faed5bSDimitry Andric       }
49663faed5bSDimitry Andric     }
497c46e6a59SDimitry Andric     for (SDep &Pred : SU->Preds) {
498c46e6a59SDimitry Andric       if (Pred.isCtrl() || (Pred.getSUnit()->NumRegDefsLeft == 0))
49963faed5bSDimitry Andric         continue;
500c46e6a59SDimitry Andric       --Pred.getSUnit()->NumRegDefsLeft;
50163faed5bSDimitry Andric     }
50263faed5bSDimitry Andric   }
50363faed5bSDimitry Andric 
50463faed5bSDimitry Andric   // Reserve resources for this SU.
50563faed5bSDimitry Andric   reserveResources(SU);
50663faed5bSDimitry Andric 
50763faed5bSDimitry Andric   // Adjust number of parallel live ranges.
50863faed5bSDimitry Andric   // Heuristic is simple - node with no data successors reduces
50963faed5bSDimitry Andric   // number of live ranges. All others, increase it.
51063faed5bSDimitry Andric   unsigned NumberNonControlDeps = 0;
51163faed5bSDimitry Andric 
512c46e6a59SDimitry Andric   for (const SDep &Succ : SU->Succs) {
513c46e6a59SDimitry Andric     adjustPriorityOfUnscheduledPreds(Succ.getSUnit());
514c46e6a59SDimitry Andric     if (!Succ.isCtrl())
51563faed5bSDimitry Andric       NumberNonControlDeps++;
51663faed5bSDimitry Andric   }
51763faed5bSDimitry Andric 
51863faed5bSDimitry Andric   if (!NumberNonControlDeps) {
51963faed5bSDimitry Andric     if (ParallelLiveRanges >= SU->NumPreds)
52063faed5bSDimitry Andric       ParallelLiveRanges -= SU->NumPreds;
52163faed5bSDimitry Andric     else
52263faed5bSDimitry Andric       ParallelLiveRanges = 0;
52363faed5bSDimitry Andric 
52463faed5bSDimitry Andric   }
52563faed5bSDimitry Andric   else
52663faed5bSDimitry Andric     ParallelLiveRanges += SU->NumRegDefsLeft;
52763faed5bSDimitry Andric 
52863faed5bSDimitry Andric   // Track parallel live chains.
52963faed5bSDimitry Andric   HorizontalVerticalBalance += (SU->Succs.size() - numberCtrlDepsInSU(SU));
53063faed5bSDimitry Andric   HorizontalVerticalBalance -= (SU->Preds.size() - numberCtrlPredInSU(SU));
53163faed5bSDimitry Andric }
53263faed5bSDimitry Andric 
initNumRegDefsLeft(SUnit * SU)53363faed5bSDimitry Andric void ResourcePriorityQueue::initNumRegDefsLeft(SUnit *SU) {
53463faed5bSDimitry Andric   unsigned  NodeNumDefs = 0;
53563faed5bSDimitry Andric   for (SDNode *N = SU->getNode(); N; N = N->getGluedNode())
53663faed5bSDimitry Andric     if (N->isMachineOpcode()) {
53763faed5bSDimitry Andric       const MCInstrDesc &TID = TII->get(N->getMachineOpcode());
53863faed5bSDimitry Andric       // No register need be allocated for this.
53963faed5bSDimitry Andric       if (N->getMachineOpcode() == TargetOpcode::IMPLICIT_DEF) {
54063faed5bSDimitry Andric         NodeNumDefs = 0;
54163faed5bSDimitry Andric         break;
54263faed5bSDimitry Andric       }
54363faed5bSDimitry Andric       NodeNumDefs = std::min(N->getNumValues(), TID.getNumDefs());
54463faed5bSDimitry Andric     }
54563faed5bSDimitry Andric     else
54663faed5bSDimitry Andric       switch(N->getOpcode()) {
54763faed5bSDimitry Andric         default:     break;
54863faed5bSDimitry Andric         case ISD::CopyFromReg:
54963faed5bSDimitry Andric           NodeNumDefs++;
55063faed5bSDimitry Andric           break;
55163faed5bSDimitry Andric         case ISD::INLINEASM:
552e6d15924SDimitry Andric         case ISD::INLINEASM_BR:
55363faed5bSDimitry Andric           NodeNumDefs++;
55463faed5bSDimitry Andric           break;
55563faed5bSDimitry Andric       }
55663faed5bSDimitry Andric 
55763faed5bSDimitry Andric   SU->NumRegDefsLeft = NodeNumDefs;
55863faed5bSDimitry Andric }
55963faed5bSDimitry Andric 
56063faed5bSDimitry Andric /// adjustPriorityOfUnscheduledPreds - One of the predecessors of SU was just
56163faed5bSDimitry Andric /// scheduled.  If SU is not itself available, then there is at least one
56263faed5bSDimitry Andric /// predecessor node that has not been scheduled yet.  If SU has exactly ONE
56363faed5bSDimitry Andric /// unscheduled predecessor, we want to increase its priority: it getting
56463faed5bSDimitry Andric /// scheduled will make this node available, so it is better than some other
56563faed5bSDimitry Andric /// node of the same priority that will not make a node available.
adjustPriorityOfUnscheduledPreds(SUnit * SU)56663faed5bSDimitry Andric void ResourcePriorityQueue::adjustPriorityOfUnscheduledPreds(SUnit *SU) {
56763faed5bSDimitry Andric   if (SU->isAvailable) return;  // All preds scheduled.
56863faed5bSDimitry Andric 
56963faed5bSDimitry Andric   SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU);
5705ca98fd9SDimitry Andric   if (!OnlyAvailablePred || !OnlyAvailablePred->isAvailable)
57163faed5bSDimitry Andric     return;
57263faed5bSDimitry Andric 
57363faed5bSDimitry Andric   // Okay, we found a single predecessor that is available, but not scheduled.
57463faed5bSDimitry Andric   // Since it is available, it must be in the priority queue.  First remove it.
57563faed5bSDimitry Andric   remove(OnlyAvailablePred);
57663faed5bSDimitry Andric 
57763faed5bSDimitry Andric   // Reinsert the node into the priority queue, which recomputes its
57863faed5bSDimitry Andric   // NumNodesSolelyBlocking value.
57963faed5bSDimitry Andric   push(OnlyAvailablePred);
58063faed5bSDimitry Andric }
58163faed5bSDimitry Andric 
58263faed5bSDimitry Andric 
58363faed5bSDimitry Andric /// Main access point - returns next instructions
58463faed5bSDimitry Andric /// to be placed in scheduling sequence.
pop()58563faed5bSDimitry Andric SUnit *ResourcePriorityQueue::pop() {
58663faed5bSDimitry Andric   if (empty())
5875ca98fd9SDimitry Andric     return nullptr;
58863faed5bSDimitry Andric 
58963faed5bSDimitry Andric   std::vector<SUnit *>::iterator Best = Queue.begin();
59063faed5bSDimitry Andric   if (!DisableDFASched) {
59101095a5dSDimitry Andric     int BestCost = SUSchedulingCost(*Best);
592c46e6a59SDimitry Andric     for (auto I = std::next(Queue.begin()), E = Queue.end(); I != E; ++I) {
59363faed5bSDimitry Andric 
59463faed5bSDimitry Andric       if (SUSchedulingCost(*I) > BestCost) {
59563faed5bSDimitry Andric         BestCost = SUSchedulingCost(*I);
59663faed5bSDimitry Andric         Best = I;
59763faed5bSDimitry Andric       }
59863faed5bSDimitry Andric     }
59963faed5bSDimitry Andric   }
60063faed5bSDimitry Andric   // Use default TD scheduling mechanism.
60163faed5bSDimitry Andric   else {
602c46e6a59SDimitry Andric     for (auto I = std::next(Queue.begin()), E = Queue.end(); I != E; ++I)
60363faed5bSDimitry Andric       if (Picker(*Best, *I))
60463faed5bSDimitry Andric         Best = I;
60563faed5bSDimitry Andric   }
60663faed5bSDimitry Andric 
60763faed5bSDimitry Andric   SUnit *V = *Best;
6085ca98fd9SDimitry Andric   if (Best != std::prev(Queue.end()))
60963faed5bSDimitry Andric     std::swap(*Best, Queue.back());
61063faed5bSDimitry Andric 
61163faed5bSDimitry Andric   Queue.pop_back();
61263faed5bSDimitry Andric 
61363faed5bSDimitry Andric   return V;
61463faed5bSDimitry Andric }
61563faed5bSDimitry Andric 
61663faed5bSDimitry Andric 
remove(SUnit * SU)61763faed5bSDimitry Andric void ResourcePriorityQueue::remove(SUnit *SU) {
61863faed5bSDimitry Andric   assert(!Queue.empty() && "Queue is empty!");
619b915e9e0SDimitry Andric   std::vector<SUnit *>::iterator I = find(Queue, SU);
6205ca98fd9SDimitry Andric   if (I != std::prev(Queue.end()))
62163faed5bSDimitry Andric     std::swap(*I, Queue.back());
62263faed5bSDimitry Andric 
62363faed5bSDimitry Andric   Queue.pop_back();
62463faed5bSDimitry Andric }
625