2008-11-15 08:23:40 +08:00
|
|
|
//===---- LatencyPriorityQueue.cpp - A latency-oriented priority queue ----===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2008-11-15 08:23:40 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the LatencyPriorityQueue class, which is a
|
|
|
|
// SchedulingPriorityQueue that schedules using latency information to
|
|
|
|
// reduce the length of the critical path through the basic block.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-11-20 07:18:57 +08:00
|
|
|
#include "llvm/CodeGen/LatencyPriorityQueue.h"
|
2018-04-30 22:59:11 +08:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
2008-11-15 08:23:40 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 13:03:26 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2008-11-15 08:23:40 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-22 10:02:50 +08:00
|
|
|
#define DEBUG_TYPE "scheduler"
|
|
|
|
|
2008-11-15 08:23:40 +08:00
|
|
|
bool latency_sort::operator()(const SUnit *LHS, const SUnit *RHS) const {
|
2008-12-16 11:35:01 +08:00
|
|
|
// The isScheduleHigh flag allows nodes with wraparound dependencies that
|
|
|
|
// cannot easily be modeled as edges with latencies to be scheduled as
|
|
|
|
// soon as possible in a top-down schedule.
|
|
|
|
if (LHS->isScheduleHigh && !RHS->isScheduleHigh)
|
|
|
|
return false;
|
|
|
|
if (!LHS->isScheduleHigh && RHS->isScheduleHigh)
|
|
|
|
return true;
|
|
|
|
|
2008-11-15 08:23:40 +08:00
|
|
|
unsigned LHSNum = LHS->NodeNum;
|
|
|
|
unsigned RHSNum = RHS->NodeNum;
|
|
|
|
|
|
|
|
// The most important heuristic is scheduling the critical path.
|
|
|
|
unsigned LHSLatency = PQ->getLatency(LHSNum);
|
|
|
|
unsigned RHSLatency = PQ->getLatency(RHSNum);
|
|
|
|
if (LHSLatency < RHSLatency) return true;
|
|
|
|
if (LHSLatency > RHSLatency) return false;
|
2010-12-24 12:28:06 +08:00
|
|
|
|
2008-11-15 08:23:40 +08:00
|
|
|
// After that, if two nodes have identical latencies, look to see if one will
|
|
|
|
// unblock more other nodes than the other.
|
|
|
|
unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum);
|
|
|
|
unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum);
|
|
|
|
if (LHSBlocked < RHSBlocked) return true;
|
|
|
|
if (LHSBlocked > RHSBlocked) return false;
|
2010-12-24 12:28:06 +08:00
|
|
|
|
2008-11-15 08:23:40 +08:00
|
|
|
// Finally, just to provide a stable ordering, use the node number as a
|
|
|
|
// deciding factor.
|
2012-02-22 14:08:11 +08:00
|
|
|
return RHSNum < LHSNum;
|
2008-11-15 08:23:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor
|
|
|
|
/// of SU, return it, otherwise return null.
|
|
|
|
SUnit *LatencyPriorityQueue::getSingleUnscheduledPred(SUnit *SU) {
|
2014-04-14 08:51:57 +08:00
|
|
|
SUnit *OnlyAvailablePred = nullptr;
|
2021-02-14 12:41:39 +08:00
|
|
|
for (const SDep &P : SU->Preds) {
|
|
|
|
SUnit &Pred = *P.getSUnit();
|
2008-11-15 08:23:40 +08:00
|
|
|
if (!Pred.isScheduled) {
|
|
|
|
// We found an available, but not scheduled, predecessor. If it's the
|
|
|
|
// only one we have found, keep track of it... otherwise give up.
|
|
|
|
if (OnlyAvailablePred && OnlyAvailablePred != &Pred)
|
2014-04-14 08:51:57 +08:00
|
|
|
return nullptr;
|
2008-11-15 08:23:40 +08:00
|
|
|
OnlyAvailablePred = &Pred;
|
|
|
|
}
|
|
|
|
}
|
2010-12-24 12:28:06 +08:00
|
|
|
|
2008-11-15 08:23:40 +08:00
|
|
|
return OnlyAvailablePred;
|
|
|
|
}
|
|
|
|
|
2010-05-26 09:10:55 +08:00
|
|
|
void LatencyPriorityQueue::push(SUnit *SU) {
|
2008-11-15 08:23:40 +08:00
|
|
|
// Look at all of the successors of this node. Count the number of nodes that
|
|
|
|
// this node is the sole unscheduled node for.
|
|
|
|
unsigned NumNodesBlocking = 0;
|
|
|
|
for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
|
2009-11-04 04:57:50 +08:00
|
|
|
I != E; ++I) {
|
2008-12-10 06:54:47 +08:00
|
|
|
if (getSingleUnscheduledPred(I->getSUnit()) == SU)
|
2008-11-15 08:23:40 +08:00
|
|
|
++NumNodesBlocking;
|
2009-11-04 04:57:50 +08:00
|
|
|
}
|
2008-11-15 08:23:40 +08:00
|
|
|
NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking;
|
2010-12-24 12:28:06 +08:00
|
|
|
|
2010-05-27 02:52:00 +08:00
|
|
|
Queue.push_back(SU);
|
2008-11-15 08:23:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-08 07:00:49 +08:00
|
|
|
// scheduledNode - As nodes are scheduled, we look to see if there are any
|
2008-11-15 08:23:40 +08:00
|
|
|
// successor nodes that have a single unscheduled predecessor. If so, that
|
|
|
|
// single predecessor has a higher priority, since scheduling it will make
|
|
|
|
// the node available.
|
2012-03-08 07:00:49 +08:00
|
|
|
void LatencyPriorityQueue::scheduledNode(SUnit *SU) {
|
2021-02-14 12:41:39 +08:00
|
|
|
for (const SDep &Succ : SU->Succs)
|
|
|
|
AdjustPriorityOfUnscheduledPreds(Succ.getSUnit());
|
2008-11-15 08:23:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// AdjustPriorityOfUnscheduledPreds - One of the predecessors of SU was just
|
|
|
|
/// scheduled. If SU is not itself available, then there is at least one
|
|
|
|
/// predecessor node that has not been scheduled yet. If SU has exactly ONE
|
|
|
|
/// unscheduled predecessor, we want to increase its priority: it getting
|
|
|
|
/// scheduled will make this node available, so it is better than some other
|
|
|
|
/// node of the same priority that will not make a node available.
|
|
|
|
void LatencyPriorityQueue::AdjustPriorityOfUnscheduledPreds(SUnit *SU) {
|
2008-11-18 00:37:30 +08:00
|
|
|
if (SU->isAvailable) return; // All preds scheduled.
|
2010-12-24 12:28:06 +08:00
|
|
|
|
2008-11-15 08:23:40 +08:00
|
|
|
SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU);
|
2014-04-14 08:51:57 +08:00
|
|
|
if (!OnlyAvailablePred || !OnlyAvailablePred->isAvailable) return;
|
2010-12-24 12:28:06 +08:00
|
|
|
|
2008-11-15 08:23:40 +08:00
|
|
|
// Okay, we found a single predecessor that is available, but not scheduled.
|
|
|
|
// Since it is available, it must be in the priority queue. First remove it.
|
|
|
|
remove(OnlyAvailablePred);
|
|
|
|
|
|
|
|
// Reinsert the node into the priority queue, which recomputes its
|
|
|
|
// NumNodesSolelyBlocking value.
|
|
|
|
push(OnlyAvailablePred);
|
|
|
|
}
|
2010-05-27 02:52:00 +08:00
|
|
|
|
|
|
|
SUnit *LatencyPriorityQueue::pop() {
|
2014-04-14 08:51:57 +08:00
|
|
|
if (empty()) return nullptr;
|
2010-05-27 02:52:00 +08:00
|
|
|
std::vector<SUnit *>::iterator Best = Queue.begin();
|
2014-03-02 20:27:27 +08:00
|
|
|
for (std::vector<SUnit *>::iterator I = std::next(Queue.begin()),
|
2010-05-27 02:52:00 +08:00
|
|
|
E = Queue.end(); I != E; ++I)
|
|
|
|
if (Picker(*Best, *I))
|
|
|
|
Best = I;
|
|
|
|
SUnit *V = *Best;
|
2014-03-02 20:27:27 +08:00
|
|
|
if (Best != std::prev(Queue.end()))
|
2010-05-27 02:52:00 +08:00
|
|
|
std::swap(*Best, Queue.back());
|
|
|
|
Queue.pop_back();
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LatencyPriorityQueue::remove(SUnit *SU) {
|
|
|
|
assert(!Queue.empty() && "Queue is empty!");
|
2016-08-12 06:21:41 +08:00
|
|
|
std::vector<SUnit *>::iterator I = find(Queue, SU);
|
2017-11-16 18:18:07 +08:00
|
|
|
assert(I != Queue.end() && "Queue doesn't contain the SU being removed!");
|
2014-03-02 20:27:27 +08:00
|
|
|
if (I != std::prev(Queue.end()))
|
2010-05-27 02:52:00 +08:00
|
|
|
std::swap(*I, Queue.back());
|
|
|
|
Queue.pop_back();
|
|
|
|
}
|
2018-04-20 08:42:46 +08:00
|
|
|
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
LLVM_DUMP_METHOD void LatencyPriorityQueue::dump(ScheduleDAG *DAG) const {
|
|
|
|
dbgs() << "Latency Priority Queue\n";
|
|
|
|
dbgs() << " Number of Queue Entries: " << Queue.size() << "\n";
|
2018-09-19 08:23:35 +08:00
|
|
|
for (const SUnit *SU : Queue) {
|
2018-04-20 08:42:46 +08:00
|
|
|
dbgs() << " ";
|
2018-09-19 08:23:35 +08:00
|
|
|
DAG->dumpNode(*SU);
|
2018-04-20 08:42:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|