class MachineFunction;
class MachineRegisterInfo;
class MachineInstr;
+ struct MCSchedClassDesc;
class TargetRegisterInfo;
class ScheduleDAG;
class SDNode;
// this node was cloned.
// (SD scheduling only)
+ const MCSchedClassDesc *SchedClass; // NULL or resolved SchedClass.
+
// Preds/Succs - The SUnits before/after us in the graph.
SmallVector<SDep, 4> Preds; // All sunit predecessors.
SmallVector<SDep, 4> Succs; // All sunit successors.
/// SUnit - Construct an SUnit for pre-regalloc scheduling to represent
/// an SDNode and any nodes flagged to it.
SUnit(SDNode *node, unsigned nodenum)
- : Node(node), Instr(0), OrigNode(0), NodeNum(nodenum),
+ : Node(node), Instr(0), OrigNode(0), SchedClass(0), NodeNum(nodenum),
NodeQueueId(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0),
NumSuccsLeft(0), NumRegDefsLeft(0), Latency(0),
isVRegCycle(false), isCall(false), isCallOp(false), isTwoAddress(false),
/// SUnit - Construct an SUnit for post-regalloc scheduling to represent
/// a MachineInstr.
SUnit(MachineInstr *instr, unsigned nodenum)
- : Node(0), Instr(instr), OrigNode(0), NodeNum(nodenum),
+ : Node(0), Instr(instr), OrigNode(0), SchedClass(0), NodeNum(nodenum),
NodeQueueId(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0),
NumSuccsLeft(0), NumRegDefsLeft(0), Latency(0),
isVRegCycle(false), isCall(false), isCallOp(false), isTwoAddress(false),
/// SUnit - Construct a placeholder SUnit.
SUnit()
- : Node(0), Instr(0), OrigNode(0), NodeNum(~0u),
+ : Node(0), Instr(0), OrigNode(0), SchedClass(0), NodeNum(~0u),
NodeQueueId(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0),
NumSuccsLeft(0), NumRegDefsLeft(0), Latency(0),
isVRegCycle(false), isCall(false), isCallOp(false), isTwoAddress(false),
/// \brief Get the machine model for instruction scheduling.
const TargetSchedModel *getSchedModel() const { return &SchedModel; }
+ /// \brief Resolve and cache a resolved scheduling class for an SUnit.
+ const MCSchedClassDesc *getSchedClass(SUnit *SU) const {
+ if (!SU->SchedClass)
+ SU->SchedClass = SchedModel.resolveSchedClass(SU->getInstr());
+ return SU->SchedClass;
+ }
+
/// begin - Return an iterator to the top of the current scheduling region.
MachineBasicBlock::iterator begin() const { return RegionBegin; }
#ifndef LLVM_TARGET_TARGETSCHEDMODEL_H
#define LLVM_TARGET_TARGETSCHEDMODEL_H
+#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/MC/MCSchedule.h"
#include "llvm/MC/MCInstrItineraries.h"
+#include "llvm/ADT/SmallVector.h"
namespace llvm {
InstrItineraryData InstrItins;
const TargetSubtargetInfo *STI;
const TargetInstrInfo *TII;
+
+ SmallVector<unsigned, 16> ResourceFactors;
+ unsigned MicroOpFactor; // Multiply to normalize microops to resource units.
+ unsigned ResourceLCM; // Resource units per cycle. Latency normalization factor.
public:
TargetSchedModel(): STI(0), TII(0) {}
void init(const MCSchedModel &sm, const TargetSubtargetInfo *sti,
const TargetInstrInfo *tii);
+ /// Return the MCSchedClassDesc for this instruction.
+ const MCSchedClassDesc *resolveSchedClass(const MachineInstr *MI) const;
+
/// \brief TargetInstrInfo getter.
const TargetInstrInfo *getInstrInfo() const { return TII; }
unsigned getIssueWidth() const { return SchedModel.IssueWidth; }
/// \brief Return the number of issue slots required for this MI.
- unsigned getNumMicroOps(MachineInstr *MI) const;
+ unsigned getNumMicroOps(const MachineInstr *MI,
+ const MCSchedClassDesc *SC = 0) const;
+
+ /// \brief Get the number of kinds of resources for this target.
+ unsigned getNumProcResourceKinds() const {
+ return SchedModel.getNumProcResourceKinds();
+ }
+
+ /// \brief Get a processor resource by ID for convenience.
+ const MCProcResourceDesc *getProcResource(unsigned PIdx) const {
+ return SchedModel.getProcResource(PIdx);
+ }
+
+ typedef const MCWriteProcResEntry *ProcResIter;
+
+ // \brief Get an iterator into the processor resources consumed by this
+ // scheduling class.
+ ProcResIter getWriteProcResBegin(const MCSchedClassDesc *SC) const {
+ // The subtarget holds a single resource table for all processors.
+ return STI->getWriteProcResBegin(SC);
+ }
+ ProcResIter getWriteProcResEnd(const MCSchedClassDesc *SC) const {
+ return STI->getWriteProcResEnd(SC);
+ }
+
+ /// \brief Multiply the number of units consumed for a resource by this factor
+ /// to normalize it relative to other resources.
+ unsigned getResourceFactor(unsigned ResIdx) const {
+ return ResourceFactors[ResIdx];
+ }
+
+ /// \brief Multiply number of micro-ops by this factor to normalize it
+ /// relative to other resources.
+ unsigned getMicroOpFactor() const {
+ return MicroOpFactor;
+ }
+
+ /// \brief Multiply cycle count by this factor to normalize it relative to
+ /// other resources. This is the number of resource units per cycle.
+ unsigned getLatencyFactor() const {
+ return ResourceLCM;
+ }
/// \brief Compute operand latency based on the available machine model.
///
unsigned computeOutputLatency(const MachineInstr *DefMI, unsigned DefIdx,
const MachineInstr *DepMI) const;
-
private:
/// getDefLatency is a helper for computeOperandLatency. Return the
/// instruction's latency if operand lookup is not required.
/// Otherwise return -1.
int getDefLatency(const MachineInstr *DefMI, bool FindMin) const;
-
- /// Return the MCSchedClassDesc for this instruction.
- const MCSchedClassDesc *resolveSchedClass(const MachineInstr *MI) const;
};
} // namespace llvm
/// Does this machine model include instruction-level scheduling.
bool hasInstrSchedModel() const { return SchedClassTable; }
+ unsigned getNumProcResourceKinds() const {
+ return NumProcResourceKinds;
+ }
+
const MCProcResourceDesc *getProcResource(unsigned ProcResourceIdx) const {
assert(hasInstrSchedModel() && "No scheduling machine model");
return EnableSchedItins && !InstrItins.isEmpty();
}
+static unsigned gcd(unsigned Dividend, unsigned Divisor) {
+ // Dividend and Divisor will be naturally swapped as needed.
+ while(Divisor) {
+ unsigned Rem = Dividend % Divisor;
+ Dividend = Divisor;
+ Divisor = Rem;
+ };
+ return Dividend;
+}
+static unsigned lcm(unsigned A, unsigned B) {
+ unsigned LCM = (uint64_t(A) * B) / gcd(A, B);
+ assert((LCM >= A && LCM >= B) && "LCM overflow");
+ return LCM;
+}
+
void TargetSchedModel::init(const MCSchedModel &sm,
const TargetSubtargetInfo *sti,
const TargetInstrInfo *tii) {
STI = sti;
TII = tii;
STI->initInstrItins(InstrItins);
+
+ unsigned NumRes = SchedModel.getNumProcResourceKinds();
+ ResourceFactors.resize(NumRes);
+ ResourceLCM = SchedModel.IssueWidth;
+ for (unsigned Idx = 0; Idx < NumRes; ++Idx) {
+ unsigned NumUnits = SchedModel.getProcResource(Idx)->NumUnits;
+ if (NumUnits > 0)
+ ResourceLCM = lcm(ResourceLCM, NumUnits);
+ }
+ MicroOpFactor = ResourceLCM / SchedModel.IssueWidth;
+ for (unsigned Idx = 0; Idx < NumRes; ++Idx) {
+ unsigned NumUnits = SchedModel.getProcResource(Idx)->NumUnits;
+ ResourceFactors[Idx] = NumUnits ? (ResourceLCM / NumUnits) : 0;
+ }
}
-unsigned TargetSchedModel::getNumMicroOps(MachineInstr *MI) const {
+unsigned TargetSchedModel::getNumMicroOps(const MachineInstr *MI,
+ const MCSchedClassDesc *SC) const {
if (hasInstrItineraries()) {
int UOps = InstrItins.getNumMicroOps(MI->getDesc().getSchedClass());
return (UOps >= 0) ? UOps : TII->getNumMicroOps(&InstrItins, MI);
}
if (hasInstrSchedModel()) {
- const MCSchedClassDesc *SCDesc = resolveSchedClass(MI);
- if (SCDesc->isValid())
- return SCDesc->NumMicroOps;
+ if (!SC)
+ SC = resolveSchedClass(MI);
+ if (SC->isValid())
+ return SC->NumMicroOps;
}
return MI->isTransient() ? 0 : 1;
}