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