mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
misched: Use the TargetSchedModel interface wherever possible.
Allows the new machine model to be used for NumMicroOps and OutputLatency. Allows the HazardRecognizer to be disabled along with itineraries. llvm-svn: 165603
This commit is contained in:
parent
13b4f59560
commit
4ca94d939c
@ -31,7 +31,6 @@
|
|||||||
#include "llvm/CodeGen/RegisterPressure.h"
|
#include "llvm/CodeGen/RegisterPressure.h"
|
||||||
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
|
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
#include "llvm/MC/MCInstrItineraries.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -278,19 +277,6 @@ public:
|
|||||||
return RegionCriticalPSets;
|
return RegionCriticalPSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getIssueWidth - Return the max instructions per scheduling group.
|
|
||||||
unsigned getIssueWidth() const {
|
|
||||||
return (InstrItins && InstrItins->SchedModel)
|
|
||||||
? InstrItins->SchedModel->IssueWidth : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getNumMicroOps - Return the number of issue slots required for this MI.
|
|
||||||
unsigned getNumMicroOps(MachineInstr *MI) const {
|
|
||||||
if (!InstrItins) return 1;
|
|
||||||
int UOps = InstrItins->getNumMicroOps(MI->getDesc().getSchedClass());
|
|
||||||
return (UOps >= 0) ? UOps : TII->getNumMicroOps(InstrItins, MI);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Top-Level entry points for the schedule() driver...
|
// Top-Level entry points for the schedule() driver...
|
||||||
|
|
||||||
|
@ -570,11 +570,6 @@ namespace llvm {
|
|||||||
unsigned VerifyScheduledDAG(bool isBottomUp);
|
unsigned VerifyScheduledDAG(bool isBottomUp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
|
||||||
/// ComputeLatency - Compute node latency.
|
|
||||||
///
|
|
||||||
virtual void computeLatency(SUnit *SU) = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Return the MCInstrDesc of this SDNode or NULL.
|
// Return the MCInstrDesc of this SDNode or NULL.
|
||||||
const MCInstrDesc *getNodeDesc(const SDNode *Node) const;
|
const MCInstrDesc *getNodeDesc(const SDNode *Node) const;
|
||||||
|
@ -111,7 +111,6 @@ namespace llvm {
|
|||||||
const MachineLoopInfo &MLI;
|
const MachineLoopInfo &MLI;
|
||||||
const MachineDominatorTree &MDT;
|
const MachineDominatorTree &MDT;
|
||||||
const MachineFrameInfo *MFI;
|
const MachineFrameInfo *MFI;
|
||||||
const InstrItineraryData *InstrItins;
|
|
||||||
|
|
||||||
/// Live Intervals provides reaching defs in preRA scheduling.
|
/// Live Intervals provides reaching defs in preRA scheduling.
|
||||||
LiveIntervals *LIS;
|
LiveIntervals *LIS;
|
||||||
@ -187,6 +186,9 @@ namespace llvm {
|
|||||||
|
|
||||||
virtual ~ScheduleDAGInstrs() {}
|
virtual ~ScheduleDAGInstrs() {}
|
||||||
|
|
||||||
|
/// \brief Get the machine model for instruction scheduling.
|
||||||
|
const TargetSchedModel *getSchedModel() const { return &SchedModel; }
|
||||||
|
|
||||||
/// begin - Return an iterator to the top of the current scheduling region.
|
/// begin - Return an iterator to the top of the current scheduling region.
|
||||||
MachineBasicBlock::iterator begin() const { return RegionBegin; }
|
MachineBasicBlock::iterator begin() const { return RegionBegin; }
|
||||||
|
|
||||||
@ -227,10 +229,6 @@ namespace llvm {
|
|||||||
/// used by instructions in the fallthrough block.
|
/// used by instructions in the fallthrough block.
|
||||||
void addSchedBarrierDeps();
|
void addSchedBarrierDeps();
|
||||||
|
|
||||||
/// computeLatency - Compute node latency.
|
|
||||||
///
|
|
||||||
virtual void computeLatency(SUnit *SU);
|
|
||||||
|
|
||||||
/// schedule - Order nodes according to selected style, filling
|
/// schedule - Order nodes according to selected style, filling
|
||||||
/// in the Sequence member.
|
/// in the Sequence member.
|
||||||
///
|
///
|
||||||
|
@ -55,12 +55,29 @@ public:
|
|||||||
/// latency properties, but separate from the per-cycle itinerary data.
|
/// latency properties, but separate from the per-cycle itinerary data.
|
||||||
bool hasInstrSchedModel() const;
|
bool hasInstrSchedModel() const;
|
||||||
|
|
||||||
|
const MCSchedModel *getMCSchedModel() const { return &SchedModel; }
|
||||||
|
|
||||||
/// \brief Return true if this machine model includes cycle-to-cycle itinerary
|
/// \brief Return true if this machine model includes cycle-to-cycle itinerary
|
||||||
/// data.
|
/// data.
|
||||||
///
|
///
|
||||||
/// This models scheduling at each stage in the processor pipeline.
|
/// This models scheduling at each stage in the processor pipeline.
|
||||||
bool hasInstrItineraries() const;
|
bool hasInstrItineraries() const;
|
||||||
|
|
||||||
|
const InstrItineraryData *getInstrItineraries() const {
|
||||||
|
if (hasInstrItineraries())
|
||||||
|
return &InstrItins;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Identify the processor corresponding to the current subtarget.
|
||||||
|
unsigned getProcessorID() const { return SchedModel.getProcessorID(); }
|
||||||
|
|
||||||
|
/// \brief Maximum number of micro-ops that may be scheduled per cycle.
|
||||||
|
unsigned getIssueWidth() const { return SchedModel.IssueWidth; }
|
||||||
|
|
||||||
|
/// \brief Return the number of issue slots required for this MI.
|
||||||
|
unsigned getNumMicroOps(MachineInstr *MI) const;
|
||||||
|
|
||||||
/// \brief Compute operand latency based on the available machine model.
|
/// \brief Compute operand latency based on the available machine model.
|
||||||
///
|
///
|
||||||
/// Computes and return the latency of the given data dependent def and use
|
/// Computes and return the latency of the given data dependent def and use
|
||||||
@ -82,11 +99,12 @@ public:
|
|||||||
/// occasionally useful to help estimate instruction cost.
|
/// occasionally useful to help estimate instruction cost.
|
||||||
unsigned computeInstrLatency(const MachineInstr *MI) const;
|
unsigned computeInstrLatency(const MachineInstr *MI) const;
|
||||||
|
|
||||||
/// \brief Identify the processor corresponding to the current subtarget.
|
/// \brief Output dependency latency of a pair of defs of the same register.
|
||||||
unsigned getProcessorID() const { return SchedModel.getProcessorID(); }
|
///
|
||||||
|
/// This is typically one cycle.
|
||||||
|
unsigned computeOutputLatency(const MachineInstr *DefMI, unsigned DefIdx,
|
||||||
|
const MachineInstr *DepMI) const;
|
||||||
|
|
||||||
/// \brief Maximum number of micro-ops that may be scheduled per cycle.
|
|
||||||
unsigned getIssueWidth() const { return SchedModel.IssueWidth; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// getDefLatency is a helper for computeOperandLatency. Return the
|
/// getDefLatency is a helper for computeOperandLatency. Return the
|
||||||
|
@ -801,15 +801,6 @@ public:
|
|||||||
const MachineInstr *UseMI, unsigned UseIdx,
|
const MachineInstr *UseMI, unsigned UseIdx,
|
||||||
bool FindMin = false) const;
|
bool FindMin = false) const;
|
||||||
|
|
||||||
/// getOutputLatency - Compute and return the output dependency latency of a
|
|
||||||
/// a given pair of defs which both target the same register. This is usually
|
|
||||||
/// one.
|
|
||||||
virtual unsigned getOutputLatency(const InstrItineraryData *ItinData,
|
|
||||||
const MachineInstr *DefMI, unsigned DefIdx,
|
|
||||||
const MachineInstr *DepMI) const {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getInstrLatency - Compute the instruction latency of a given instruction.
|
/// getInstrLatency - Compute the instruction latency of a given instruction.
|
||||||
/// If the instruction has higher cost when predicated, it's returned via
|
/// If the instruction has higher cost when predicated, it's returned via
|
||||||
/// PredCost.
|
/// PredCost.
|
||||||
|
@ -652,6 +652,7 @@ class ConvergingScheduler : public MachineSchedStrategy {
|
|||||||
/// of "hazards" and other interlocks at the current cycle.
|
/// of "hazards" and other interlocks at the current cycle.
|
||||||
struct SchedBoundary {
|
struct SchedBoundary {
|
||||||
ScheduleDAGMI *DAG;
|
ScheduleDAGMI *DAG;
|
||||||
|
const TargetSchedModel *SchedModel;
|
||||||
|
|
||||||
ReadyQueue Available;
|
ReadyQueue Available;
|
||||||
ReadyQueue Pending;
|
ReadyQueue Pending;
|
||||||
@ -671,13 +672,18 @@ class ConvergingScheduler : public MachineSchedStrategy {
|
|||||||
/// Pending queues extend the ready queues with the same ID and the
|
/// Pending queues extend the ready queues with the same ID and the
|
||||||
/// PendingFlag set.
|
/// PendingFlag set.
|
||||||
SchedBoundary(unsigned ID, const Twine &Name):
|
SchedBoundary(unsigned ID, const Twine &Name):
|
||||||
DAG(0), Available(ID, Name+".A"),
|
DAG(0), SchedModel(0), Available(ID, Name+".A"),
|
||||||
Pending(ID << ConvergingScheduler::LogMaxQID, Name+".P"),
|
Pending(ID << ConvergingScheduler::LogMaxQID, Name+".P"),
|
||||||
CheckPending(false), HazardRec(0), CurrCycle(0), IssueCount(0),
|
CheckPending(false), HazardRec(0), CurrCycle(0), IssueCount(0),
|
||||||
MinReadyCycle(UINT_MAX), MaxMinLatency(0) {}
|
MinReadyCycle(UINT_MAX), MaxMinLatency(0) {}
|
||||||
|
|
||||||
~SchedBoundary() { delete HazardRec; }
|
~SchedBoundary() { delete HazardRec; }
|
||||||
|
|
||||||
|
void init(ScheduleDAGMI *dag, const TargetSchedModel *smodel) {
|
||||||
|
DAG = dag;
|
||||||
|
SchedModel = smodel;
|
||||||
|
}
|
||||||
|
|
||||||
bool isTop() const {
|
bool isTop() const {
|
||||||
return Available.getID() == ConvergingScheduler::TopQID;
|
return Available.getID() == ConvergingScheduler::TopQID;
|
||||||
}
|
}
|
||||||
@ -698,6 +704,7 @@ class ConvergingScheduler : public MachineSchedStrategy {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ScheduleDAGMI *DAG;
|
ScheduleDAGMI *DAG;
|
||||||
|
const TargetSchedModel *SchedModel;
|
||||||
const TargetRegisterInfo *TRI;
|
const TargetRegisterInfo *TRI;
|
||||||
|
|
||||||
// State of the top and bottom scheduled instruction boundaries.
|
// State of the top and bottom scheduled instruction boundaries.
|
||||||
@ -713,7 +720,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
ConvergingScheduler():
|
ConvergingScheduler():
|
||||||
DAG(0), TRI(0), Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {}
|
DAG(0), SchedModel(0), TRI(0), Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {}
|
||||||
|
|
||||||
virtual void initialize(ScheduleDAGMI *dag);
|
virtual void initialize(ScheduleDAGMI *dag);
|
||||||
|
|
||||||
@ -740,13 +747,15 @@ protected:
|
|||||||
|
|
||||||
void ConvergingScheduler::initialize(ScheduleDAGMI *dag) {
|
void ConvergingScheduler::initialize(ScheduleDAGMI *dag) {
|
||||||
DAG = dag;
|
DAG = dag;
|
||||||
|
SchedModel = DAG->getSchedModel();
|
||||||
TRI = DAG->TRI;
|
TRI = DAG->TRI;
|
||||||
Top.DAG = dag;
|
Top.init(DAG, SchedModel);
|
||||||
Bot.DAG = dag;
|
Bot.init(DAG, SchedModel);
|
||||||
|
|
||||||
// Initialize the HazardRecognizers.
|
// Initialize the HazardRecognizers. If itineraries don't exist, are empty, or
|
||||||
|
// are disabled, then these HazardRecs will be disabled.
|
||||||
|
const InstrItineraryData *Itin = SchedModel->getInstrItineraries();
|
||||||
const TargetMachine &TM = DAG->MF.getTarget();
|
const TargetMachine &TM = DAG->MF.getTarget();
|
||||||
const InstrItineraryData *Itin = TM.getInstrItineraryData();
|
|
||||||
Top.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG);
|
Top.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG);
|
||||||
Bot.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG);
|
Bot.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG);
|
||||||
|
|
||||||
@ -807,7 +816,8 @@ bool ConvergingScheduler::SchedBoundary::checkHazard(SUnit *SU) {
|
|||||||
if (HazardRec->isEnabled())
|
if (HazardRec->isEnabled())
|
||||||
return HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard;
|
return HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard;
|
||||||
|
|
||||||
if (IssueCount + DAG->getNumMicroOps(SU->getInstr()) > DAG->getIssueWidth())
|
unsigned uops = SchedModel->getNumMicroOps(SU->getInstr());
|
||||||
|
if (IssueCount + uops > SchedModel->getIssueWidth())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -828,7 +838,7 @@ void ConvergingScheduler::SchedBoundary::releaseNode(SUnit *SU,
|
|||||||
|
|
||||||
/// Move the boundary of scheduled code by one cycle.
|
/// Move the boundary of scheduled code by one cycle.
|
||||||
void ConvergingScheduler::SchedBoundary::bumpCycle() {
|
void ConvergingScheduler::SchedBoundary::bumpCycle() {
|
||||||
unsigned Width = DAG->getIssueWidth();
|
unsigned Width = SchedModel->getIssueWidth();
|
||||||
IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width;
|
IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width;
|
||||||
|
|
||||||
assert(MinReadyCycle < UINT_MAX && "MinReadyCycle uninitialized");
|
assert(MinReadyCycle < UINT_MAX && "MinReadyCycle uninitialized");
|
||||||
@ -866,8 +876,8 @@ void ConvergingScheduler::SchedBoundary::bumpNode(SUnit *SU) {
|
|||||||
}
|
}
|
||||||
// Check the instruction group dispatch limit.
|
// Check the instruction group dispatch limit.
|
||||||
// TODO: Check if this SU must end a dispatch group.
|
// TODO: Check if this SU must end a dispatch group.
|
||||||
IssueCount += DAG->getNumMicroOps(SU->getInstr());
|
IssueCount += SchedModel->getNumMicroOps(SU->getInstr());
|
||||||
if (IssueCount >= DAG->getIssueWidth()) {
|
if (IssueCount >= SchedModel->getIssueWidth()) {
|
||||||
DEBUG(dbgs() << "*** Max instrs at cycle " << CurrCycle << '\n');
|
DEBUG(dbgs() << "*** Max instrs at cycle " << CurrCycle << '\n');
|
||||||
bumpCycle();
|
bumpCycle();
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,7 @@ ScheduleDAGInstrs::ScheduleDAGInstrs(MachineFunction &mf,
|
|||||||
const MachineDominatorTree &mdt,
|
const MachineDominatorTree &mdt,
|
||||||
bool IsPostRAFlag,
|
bool IsPostRAFlag,
|
||||||
LiveIntervals *lis)
|
LiveIntervals *lis)
|
||||||
: ScheduleDAG(mf), MLI(mli), MDT(mdt), MFI(mf.getFrameInfo()),
|
: ScheduleDAG(mf), MLI(mli), MDT(mdt), MFI(mf.getFrameInfo()), LIS(lis),
|
||||||
InstrItins(mf.getTarget().getInstrItineraryData()), LIS(lis),
|
|
||||||
IsPostRA(IsPostRAFlag), CanHandleTerminators(false), FirstDbgValue(0) {
|
IsPostRA(IsPostRAFlag), CanHandleTerminators(false), FirstDbgValue(0) {
|
||||||
assert((IsPostRA || LIS) && "PreRA scheduling requires LiveIntervals");
|
assert((IsPostRA || LIS) && "PreRA scheduling requires LiveIntervals");
|
||||||
DbgValues.clear();
|
DbgValues.clear();
|
||||||
@ -292,8 +291,8 @@ void ScheduleDAGInstrs::addPhysRegDeps(SUnit *SU, unsigned OperIdx) {
|
|||||||
if (Kind == SDep::Anti)
|
if (Kind == SDep::Anti)
|
||||||
DefSU->addPred(SDep(SU, Kind, 0, /*Reg=*/*Alias));
|
DefSU->addPred(SDep(SU, Kind, 0, /*Reg=*/*Alias));
|
||||||
else {
|
else {
|
||||||
unsigned AOLat = TII->getOutputLatency(InstrItins, MI, OperIdx,
|
unsigned AOLat =
|
||||||
DefSU->getInstr());
|
SchedModel.computeOutputLatency(MI, OperIdx, DefSU->getInstr());
|
||||||
DefSU->addPred(SDep(SU, Kind, AOLat, /*Reg=*/*Alias));
|
DefSU->addPred(SDep(SU, Kind, AOLat, /*Reg=*/*Alias));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -363,8 +362,8 @@ void ScheduleDAGInstrs::addVRegDefDeps(SUnit *SU, unsigned OperIdx) {
|
|||||||
else {
|
else {
|
||||||
SUnit *DefSU = DefI->SU;
|
SUnit *DefSU = DefI->SU;
|
||||||
if (DefSU != SU && DefSU != &ExitSU) {
|
if (DefSU != SU && DefSU != &ExitSU) {
|
||||||
unsigned OutLatency = TII->getOutputLatency(InstrItins, MI, OperIdx,
|
unsigned OutLatency =
|
||||||
DefSU->getInstr());
|
SchedModel.computeOutputLatency(MI, OperIdx, DefSU->getInstr());
|
||||||
DefSU->addPred(SDep(SU, SDep::Output, OutLatency, Reg));
|
DefSU->addPred(SDep(SU, SDep::Output, OutLatency, Reg));
|
||||||
}
|
}
|
||||||
DefI->SU = SU;
|
DefI->SU = SU;
|
||||||
@ -650,7 +649,7 @@ void ScheduleDAGInstrs::initSUnits() {
|
|||||||
SU->isCommutable = MI->isCommutable();
|
SU->isCommutable = MI->isCommutable();
|
||||||
|
|
||||||
// Assign the Latency field of SU using target-provided information.
|
// Assign the Latency field of SU using target-provided information.
|
||||||
computeLatency(SU);
|
SU->Latency = SchedModel.computeInstrLatency(SU->getInstr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,21 +910,6 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
|
|||||||
PendingLoads.clear();
|
PendingLoads.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduleDAGInstrs::computeLatency(SUnit *SU) {
|
|
||||||
// Compute the latency for the node. We only provide a default for missing
|
|
||||||
// itineraries. Empty itineraries still have latency properties.
|
|
||||||
if (!InstrItins) {
|
|
||||||
SU->Latency = 1;
|
|
||||||
|
|
||||||
// Simplistic target-independent heuristic: assume that loads take
|
|
||||||
// extra time.
|
|
||||||
if (SU->getInstr()->mayLoad())
|
|
||||||
SU->Latency += 2;
|
|
||||||
} else {
|
|
||||||
SU->Latency = TII->getInstrLatency(InstrItins, SU->getInstr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScheduleDAGInstrs::dumpNode(const SUnit *SU) const {
|
void ScheduleDAGInstrs::dumpNode(const SUnit *SU) const {
|
||||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||||
SU->getInstr()->dump();
|
SU->getInstr()->dump();
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "llvm/CodeGen/TargetSchedule.h"
|
#include "llvm/CodeGen/TargetSchedule.h"
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
#include "llvm/Target/TargetRegisterInfo.h"
|
#include "llvm/Target/TargetRegisterInfo.h"
|
||||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
@ -44,6 +45,17 @@ void TargetSchedModel::init(const MCSchedModel &sm,
|
|||||||
STI->initInstrItins(InstrItins);
|
STI->initInstrItins(InstrItins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned TargetSchedModel::getNumMicroOps(MachineInstr *MI) const {
|
||||||
|
if (hasInstrItineraries()) {
|
||||||
|
int UOps = InstrItins.getNumMicroOps(MI->getDesc().getSchedClass());
|
||||||
|
return (UOps >= 0) ? UOps : TII->getNumMicroOps(&InstrItins, MI);
|
||||||
|
}
|
||||||
|
if (hasInstrSchedModel())
|
||||||
|
return resolveSchedClass(MI)->NumMicroOps;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// If we can determine the operand latency from the def only, without machine
|
/// If we can determine the operand latency from the def only, without machine
|
||||||
/// model or itinerary lookup, do so. Otherwise return -1.
|
/// model or itinerary lookup, do so. Otherwise return -1.
|
||||||
int TargetSchedModel::getDefLatency(const MachineInstr *DefMI,
|
int TargetSchedModel::getDefLatency(const MachineInstr *DefMI,
|
||||||
@ -209,3 +221,40 @@ unsigned TargetSchedModel::computeInstrLatency(const MachineInstr *MI) const {
|
|||||||
}
|
}
|
||||||
return TII->defaultDefLatency(&SchedModel, MI);
|
return TII->defaultDefLatency(&SchedModel, MI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned TargetSchedModel::
|
||||||
|
computeOutputLatency(const MachineInstr *DefMI, unsigned DefOperIdx,
|
||||||
|
const MachineInstr *DepMI) const {
|
||||||
|
// MinLatency == -1 is for in-order processors that always have unit
|
||||||
|
// MinLatency. MinLatency > 0 is for in-order processors with varying min
|
||||||
|
// latencies, but since this is not a RAW dep, we always use unit latency.
|
||||||
|
if (SchedModel.MinLatency != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// MinLatency == 0 indicates an out-of-order processor that can dispatch
|
||||||
|
// WAW dependencies in the same cycle.
|
||||||
|
|
||||||
|
// Treat predication as a data dependency for out-of-order cpus. In-order
|
||||||
|
// cpus do not need to treat predicated writes specially.
|
||||||
|
//
|
||||||
|
// TODO: The following hack exists because predication passes do not
|
||||||
|
// correctly append imp-use operands, and readsReg() strangely returns false
|
||||||
|
// for predicated defs.
|
||||||
|
unsigned Reg = DefMI->getOperand(DefOperIdx).getReg();
|
||||||
|
const MachineFunction &MF = *DefMI->getParent()->getParent();
|
||||||
|
const TargetRegisterInfo *TRI = MF.getTarget().getRegisterInfo();
|
||||||
|
if (!DepMI->readsRegister(Reg, TRI) && TII->isPredicated(DepMI))
|
||||||
|
return computeInstrLatency(DefMI);
|
||||||
|
|
||||||
|
// If we have a per operand scheduling model, check if this def is writing
|
||||||
|
// an unbuffered resource. If so, it treated like an in-order cpu.
|
||||||
|
if (hasInstrSchedModel()) {
|
||||||
|
const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI);
|
||||||
|
for (const MCWriteProcResEntry *PRI = STI->getWriteProcResBegin(SCDesc),
|
||||||
|
*PRE = STI->getWriteProcResEnd(SCDesc); PRI != PRE; ++PRI) {
|
||||||
|
if (!SchedModel.getProcResource(PRI->ProcResourceIdx)->IsBuffered)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -3550,18 +3550,6 @@ ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
|
|||||||
return Latency;
|
return Latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
|
||||||
ARMBaseInstrInfo::getOutputLatency(const InstrItineraryData *ItinData,
|
|
||||||
const MachineInstr *DefMI, unsigned DefIdx,
|
|
||||||
const MachineInstr *DepMI) const {
|
|
||||||
unsigned Reg = DefMI->getOperand(DefIdx).getReg();
|
|
||||||
if (DepMI->readsRegister(Reg, &getRegisterInfo()) || !isPredicated(DepMI))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// If the second MI is predicated, then there is an implicit use dependency.
|
|
||||||
return getInstrLatency(ItinData, DefMI);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned ARMBaseInstrInfo::getInstrLatency(const InstrItineraryData *ItinData,
|
unsigned ARMBaseInstrInfo::getInstrLatency(const InstrItineraryData *ItinData,
|
||||||
const MachineInstr *MI,
|
const MachineInstr *MI,
|
||||||
unsigned *PredCost) const {
|
unsigned *PredCost) const {
|
||||||
|
@ -229,10 +229,6 @@ public:
|
|||||||
SDNode *DefNode, unsigned DefIdx,
|
SDNode *DefNode, unsigned DefIdx,
|
||||||
SDNode *UseNode, unsigned UseIdx) const;
|
SDNode *UseNode, unsigned UseIdx) const;
|
||||||
|
|
||||||
virtual unsigned getOutputLatency(const InstrItineraryData *ItinData,
|
|
||||||
const MachineInstr *DefMI, unsigned DefIdx,
|
|
||||||
const MachineInstr *DepMI) const;
|
|
||||||
|
|
||||||
/// VFP/NEON execution domains.
|
/// VFP/NEON execution domains.
|
||||||
std::pair<uint16_t, uint16_t>
|
std::pair<uint16_t, uint16_t>
|
||||||
getExecutionDomain(const MachineInstr *MI) const;
|
getExecutionDomain(const MachineInstr *MI) const;
|
||||||
|
@ -128,7 +128,7 @@ bool VLIWResourceModel::reserveResources(SUnit *SU) {
|
|||||||
|
|
||||||
// If packet is now full, reset the state so in the next cycle
|
// If packet is now full, reset the state so in the next cycle
|
||||||
// we start fresh.
|
// we start fresh.
|
||||||
if (Packet.size() >= InstrItins->SchedModel->IssueWidth) {
|
if (Packet.size() >= SchedModel->getIssueWidth()) {
|
||||||
ResourcesModel->clearResources();
|
ResourcesModel->clearResources();
|
||||||
Packet.clear();
|
Packet.clear();
|
||||||
TotalPackets++;
|
TotalPackets++;
|
||||||
@ -186,18 +186,20 @@ void VLIWMachineScheduler::schedule() {
|
|||||||
|
|
||||||
void ConvergingVLIWScheduler::initialize(ScheduleDAGMI *dag) {
|
void ConvergingVLIWScheduler::initialize(ScheduleDAGMI *dag) {
|
||||||
DAG = static_cast<VLIWMachineScheduler*>(dag);
|
DAG = static_cast<VLIWMachineScheduler*>(dag);
|
||||||
|
SchedModel = DAG->getSchedModel();
|
||||||
TRI = DAG->TRI;
|
TRI = DAG->TRI;
|
||||||
Top.DAG = DAG;
|
Top.init(DAG, SchedModel);
|
||||||
Bot.DAG = DAG;
|
Bot.init(DAG, SchedModel);
|
||||||
|
|
||||||
// Initialize the HazardRecognizers.
|
// Initialize the HazardRecognizers. If itineraries don't exist, are empty, or
|
||||||
|
// are disabled, then these HazardRecs will be disabled.
|
||||||
|
const InstrItineraryData *Itin = DAG->getSchedModel()->getInstrItineraries();
|
||||||
const TargetMachine &TM = DAG->MF.getTarget();
|
const TargetMachine &TM = DAG->MF.getTarget();
|
||||||
const InstrItineraryData *Itin = TM.getInstrItineraryData();
|
|
||||||
Top.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG);
|
Top.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG);
|
||||||
Bot.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG);
|
Bot.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG);
|
||||||
|
|
||||||
Top.ResourceModel = new VLIWResourceModel(TM);
|
Top.ResourceModel = new VLIWResourceModel(TM, DAG->getSchedModel());
|
||||||
Bot.ResourceModel = new VLIWResourceModel(TM);
|
Bot.ResourceModel = new VLIWResourceModel(TM, DAG->getSchedModel());
|
||||||
|
|
||||||
assert((!llvm::ForceTopDown || !llvm::ForceBottomUp) &&
|
assert((!llvm::ForceTopDown || !llvm::ForceBottomUp) &&
|
||||||
"-misched-topdown incompatible with -misched-bottomup");
|
"-misched-topdown incompatible with -misched-bottomup");
|
||||||
@ -256,7 +258,8 @@ bool ConvergingVLIWScheduler::SchedBoundary::checkHazard(SUnit *SU) {
|
|||||||
if (HazardRec->isEnabled())
|
if (HazardRec->isEnabled())
|
||||||
return HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard;
|
return HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard;
|
||||||
|
|
||||||
if (IssueCount + DAG->getNumMicroOps(SU->getInstr()) > DAG->getIssueWidth())
|
unsigned uops = SchedModel->getNumMicroOps(SU->getInstr());
|
||||||
|
if (IssueCount + uops > SchedModel->getIssueWidth())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -278,7 +281,7 @@ void ConvergingVLIWScheduler::SchedBoundary::releaseNode(SUnit *SU,
|
|||||||
|
|
||||||
/// Move the boundary of scheduled code by one cycle.
|
/// Move the boundary of scheduled code by one cycle.
|
||||||
void ConvergingVLIWScheduler::SchedBoundary::bumpCycle() {
|
void ConvergingVLIWScheduler::SchedBoundary::bumpCycle() {
|
||||||
unsigned Width = DAG->getIssueWidth();
|
unsigned Width = SchedModel->getIssueWidth();
|
||||||
IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width;
|
IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width;
|
||||||
|
|
||||||
assert(MinReadyCycle < UINT_MAX && "MinReadyCycle uninitialized");
|
assert(MinReadyCycle < UINT_MAX && "MinReadyCycle uninitialized");
|
||||||
@ -321,7 +324,7 @@ void ConvergingVLIWScheduler::SchedBoundary::bumpNode(SUnit *SU) {
|
|||||||
|
|
||||||
// Check the instruction group dispatch limit.
|
// Check the instruction group dispatch limit.
|
||||||
// TODO: Check if this SU must end a dispatch group.
|
// TODO: Check if this SU must end a dispatch group.
|
||||||
IssueCount += DAG->getNumMicroOps(SU->getInstr());
|
IssueCount += SchedModel->getNumMicroOps(SU->getInstr());
|
||||||
if (startNewCycle) {
|
if (startNewCycle) {
|
||||||
DEBUG(dbgs() << "*** Max instrs at cycle " << CurrCycle << '\n');
|
DEBUG(dbgs() << "*** Max instrs at cycle " << CurrCycle << '\n');
|
||||||
bumpCycle();
|
bumpCycle();
|
||||||
|
@ -45,7 +45,7 @@ class VLIWResourceModel {
|
|||||||
/// definition of DFA by a target.
|
/// definition of DFA by a target.
|
||||||
DFAPacketizer *ResourcesModel;
|
DFAPacketizer *ResourcesModel;
|
||||||
|
|
||||||
const InstrItineraryData *InstrItins;
|
const TargetSchedModel *SchedModel;
|
||||||
|
|
||||||
/// Local packet/bundle model. Purely
|
/// Local packet/bundle model. Purely
|
||||||
/// internal to the MI schedulre at the time.
|
/// internal to the MI schedulre at the time.
|
||||||
@ -55,29 +55,15 @@ class VLIWResourceModel {
|
|||||||
unsigned TotalPackets;
|
unsigned TotalPackets;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VLIWResourceModel(MachineSchedContext *C, const InstrItineraryData *IID) :
|
VLIWResourceModel(const TargetMachine &TM, const TargetSchedModel *SM) :
|
||||||
InstrItins(IID), TotalPackets(0) {
|
SchedModel(SM), TotalPackets(0) {
|
||||||
const TargetMachine &TM = C->MF->getTarget();
|
|
||||||
ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL);
|
ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL);
|
||||||
|
|
||||||
// This hard requirement could be relaxed,
|
// This hard requirement could be relaxed,
|
||||||
// but for now do not let it proceed.
|
// but for now do not let it proceed.
|
||||||
assert(ResourcesModel && "Unimplemented CreateTargetScheduleState.");
|
assert(ResourcesModel && "Unimplemented CreateTargetScheduleState.");
|
||||||
|
|
||||||
Packet.resize(InstrItins->SchedModel->IssueWidth);
|
Packet.resize(SchedModel->getIssueWidth());
|
||||||
Packet.clear();
|
|
||||||
ResourcesModel->clearResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
VLIWResourceModel(const TargetMachine &TM) :
|
|
||||||
InstrItins(TM.getInstrItineraryData()), TotalPackets(0) {
|
|
||||||
ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL);
|
|
||||||
|
|
||||||
// This hard requirement could be relaxed,
|
|
||||||
// but for now do not let it proceed.
|
|
||||||
assert(ResourcesModel && "Unimplemented CreateTargetScheduleState.");
|
|
||||||
|
|
||||||
Packet.resize(InstrItins->SchedModel->IssueWidth);
|
|
||||||
Packet.clear();
|
Packet.clear();
|
||||||
ResourcesModel->clearResources();
|
ResourcesModel->clearResources();
|
||||||
}
|
}
|
||||||
@ -146,6 +132,7 @@ class ConvergingVLIWScheduler : public MachineSchedStrategy {
|
|||||||
/// of "hazards" and other interlocks at the current cycle.
|
/// of "hazards" and other interlocks at the current cycle.
|
||||||
struct SchedBoundary {
|
struct SchedBoundary {
|
||||||
VLIWMachineScheduler *DAG;
|
VLIWMachineScheduler *DAG;
|
||||||
|
const TargetSchedModel *SchedModel;
|
||||||
|
|
||||||
ReadyQueue Available;
|
ReadyQueue Available;
|
||||||
ReadyQueue Pending;
|
ReadyQueue Pending;
|
||||||
@ -166,7 +153,7 @@ class ConvergingVLIWScheduler : public MachineSchedStrategy {
|
|||||||
/// Pending queues extend the ready queues with the same ID and the
|
/// Pending queues extend the ready queues with the same ID and the
|
||||||
/// PendingFlag set.
|
/// PendingFlag set.
|
||||||
SchedBoundary(unsigned ID, const Twine &Name):
|
SchedBoundary(unsigned ID, const Twine &Name):
|
||||||
DAG(0), Available(ID, Name+".A"),
|
DAG(0), SchedModel(0), Available(ID, Name+".A"),
|
||||||
Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name+".P"),
|
Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name+".P"),
|
||||||
CheckPending(false), HazardRec(0), ResourceModel(0),
|
CheckPending(false), HazardRec(0), ResourceModel(0),
|
||||||
CurrCycle(0), IssueCount(0),
|
CurrCycle(0), IssueCount(0),
|
||||||
@ -177,6 +164,11 @@ class ConvergingVLIWScheduler : public MachineSchedStrategy {
|
|||||||
delete HazardRec;
|
delete HazardRec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init(VLIWMachineScheduler *dag, const TargetSchedModel *smodel) {
|
||||||
|
DAG = dag;
|
||||||
|
SchedModel = smodel;
|
||||||
|
}
|
||||||
|
|
||||||
bool isTop() const {
|
bool isTop() const {
|
||||||
return Available.getID() == ConvergingVLIWScheduler::TopQID;
|
return Available.getID() == ConvergingVLIWScheduler::TopQID;
|
||||||
}
|
}
|
||||||
@ -197,6 +189,7 @@ class ConvergingVLIWScheduler : public MachineSchedStrategy {
|
|||||||
};
|
};
|
||||||
|
|
||||||
VLIWMachineScheduler *DAG;
|
VLIWMachineScheduler *DAG;
|
||||||
|
const TargetSchedModel *SchedModel;
|
||||||
const TargetRegisterInfo *TRI;
|
const TargetRegisterInfo *TRI;
|
||||||
|
|
||||||
// State of the top and bottom scheduled instruction boundaries.
|
// State of the top and bottom scheduled instruction boundaries.
|
||||||
@ -212,7 +205,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
ConvergingVLIWScheduler():
|
ConvergingVLIWScheduler():
|
||||||
DAG(0), TRI(0), Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {}
|
DAG(0), SchedModel(0), TRI(0), Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {}
|
||||||
|
|
||||||
virtual void initialize(ScheduleDAGMI *dag);
|
virtual void initialize(ScheduleDAGMI *dag);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user