[Hexagon] HexagonMachineScheduler should account for resources

The machine scheduler needs to account for available resources
more accurately in order to avoid scheduling an instruction that
forces a new packet to be created.

This occurs in two ways: First, an instruction without an available
resource may have a large priority due to other metrics and be
scheduled when there are other instructions with available resources.
Second, an instruction with a non-zero latency may become available
prematurely. In both these cases, we attempt change the priority
in order to allow a better instruction to be scheduled.

Patch by Brendon Cahoon.

llvm-svn: 275793
This commit is contained in:
Krzysztof Parzyszek 2016-07-18 14:52:13 +00:00
parent ab1b926bb9
commit 3467e9d0a9
2 changed files with 78 additions and 11 deletions

View File

@ -18,12 +18,20 @@
#include "llvm/CodeGen/ScheduleDAGMutation.h"
#include "llvm/IR/Function.h"
static cl::opt<bool> IgnoreBBRegPressure("ignore-bb-reg-pressure",
cl::Hidden, cl::ZeroOrMore, cl::init(false));
static cl::opt<bool> SchedPredsCloser("sched-preds-closer",
cl::Hidden, cl::ZeroOrMore, cl::init(true));
static cl::opt<bool> SchedRetvalOptimization("sched-retval-optimization",
cl::Hidden, cl::ZeroOrMore, cl::init(true));
// Check if the scheduler should penalize instructions that are available to
// early due to a zero-latency dependence.
static cl::opt<bool> CheckEarlyAvail("check-early-avail", cl::Hidden,
cl::ZeroOrMore, cl::init(true));
using namespace llvm;
#define DEBUG_TYPE "misched"
@ -573,15 +581,23 @@ int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU,
// If resources are available for it, multiply the
// chance of scheduling.
if (Top.ResourceModel->isResourceAvailable(SU))
if (Top.ResourceModel->isResourceAvailable(SU)) {
ResCount <<= FactorOne;
ResCount += PriorityThree;
DEBUG(if (verbose) dbgs() << "A|");
} else
DEBUG(if (verbose) dbgs() << " |");
} else {
ResCount += (SU->getDepth() * ScaleTwo);
// If resources are available for it, multiply the
// chance of scheduling.
if (Bot.ResourceModel->isResourceAvailable(SU))
if (Bot.ResourceModel->isResourceAvailable(SU)) {
ResCount <<= FactorOne;
ResCount += PriorityThree;
DEBUG(if (verbose) dbgs() << "A|");
} else
DEBUG(if (verbose) dbgs() << " |");
}
unsigned NumNodesBlocking = 0;
@ -590,23 +606,35 @@ int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU,
// Look at all of the successors of this node.
// Count the number of nodes that
// this node is the sole unscheduled node for.
for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
I != E; ++I)
if (getSingleUnscheduledPred(I->getSUnit()) == SU)
for (const SDep &SI : SU->Succs)
if (getSingleUnscheduledPred(SI.getSUnit()) == SU)
++NumNodesBlocking;
} else {
// How many unscheduled predecessors block this node?
for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
I != E; ++I)
if (getSingleUnscheduledSucc(I->getSUnit()) == SU)
for (const SDep &PI : SU->Preds)
if (getSingleUnscheduledSucc(PI.getSUnit()) == SU)
++NumNodesBlocking;
}
ResCount += (NumNodesBlocking * ScaleTwo);
// Factor in reg pressure as a heuristic.
ResCount -= (Delta.Excess.getUnitInc()*PriorityTwo);
ResCount -= (Delta.CriticalMax.getUnitInc()*PriorityTwo);
if (!IgnoreBBRegPressure) {
// Decrease priority by the amount that register pressure exceeds the limit.
ResCount -= (Delta.Excess.getUnitInc()*PriorityOne);
// Decrease priority if register pressure exceeds the limit.
ResCount -= (Delta.CriticalMax.getUnitInc()*PriorityOne);
// Decrease priority slightly if register pressure would increase over the
// current maximum.
ResCount -= (Delta.CurrentMax.getUnitInc()*PriorityTwo);
DEBUG(if (verbose) {
dbgs() << "RP " << Delta.Excess.getUnitInc() << "/"
<< Delta.CriticalMax.getUnitInc() <<"/"
<< Delta.CurrentMax.getUnitInc() << ")|";
});
}
// Give a little extra priority to a .cur instruction if there is a resource
// available for it.
auto &QST = DAG->MF.getSubtarget<HexagonSubtarget>();
auto &QII = *QST.getInstrInfo();
@ -660,6 +688,46 @@ int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU,
}
}
// If the instruction has a non-zero latency dependence with an instruction in
// the current packet, then it should not be scheduled yet. The case occurs
// when the dependent instruction is scheduled in a new packet, so the
// scheduler updates the current cycle and pending instructions become
// available.
if (CheckEarlyAvail) {
if (Q.getID() == TopQID) {
for (const auto &PI : SU->Preds) {
if (PI.getLatency() > 0 &&
Top.ResourceModel->isInPacket(PI.getSUnit())) {
ResCount -= PriorityOne;
DEBUG(if (verbose) dbgs() << "D|");
}
}
} else {
for (const auto &SI : SU->Succs) {
if (SI.getLatency() > 0 &&
Bot.ResourceModel->isInPacket(SI.getSUnit())) {
ResCount -= PriorityOne;
DEBUG(if (verbose) dbgs() << "D|");
}
}
}
}
// Give less preference to an instruction that will cause a stall with
// an instruction in the previous packet.
if (QII.isV60VectorInstruction(Instr)) {
// Check for stalls in the previous packet.
if (Q.getID() == TopQID) {
for (auto J : Top.ResourceModel->OldPacket)
if (QII.producesStall(J->getInstr(), Instr))
ResCount -= PriorityOne;
} else {
for (auto J : Bot.ResourceModel->OldPacket)
if (QII.producesStall(Instr, J->getInstr()))
ResCount -= PriorityOne;
}
}
DEBUG(if (verbose) dbgs() << " Total(" << ResCount << ")");
return ResCount;

View File

@ -1,4 +1,3 @@
; XFAIL: *
; RUN: llc -march=hexagon -mcpu=hexagonv60 -enable-hexagon-hvx-double \
; RUN: -hexagon-bit=0 < %s | FileCheck %s