/// Return true if this machine model includes an instruction-level scheduling
/// model. This is more detailed than the course grain IssueWidth and default
/// latency properties, but separate from the per-cycle itinerary data.
- bool hasInstrSchedModel() const {
- return SchedModel.hasInstrSchedModel();
- }
+ bool hasInstrSchedModel() const { return SchedModel.hasInstrSchedModel(); }
/// Return true if this machine model includes cycle-to-cycle itinerary
/// data. This models scheduling at each stage in the processor pipeline.
- bool hasInstrItineraries() const {
- return SchedModel.hasInstrItineraries();
- }
+ bool hasInstrItineraries() const { return !InstrItins.isEmpty(); }
+
+ /// computeOperandLatency - Compute and return the latency of the given data
+ /// dependent def and use when the operand indices are already known. UseMI
+ /// may be NULL for an unknown user.
+ ///
+ /// FindMin may be set to get the minimum vs. expected latency. Minimum
+ /// latency is used for scheduling groups, while expected latency is for
+ /// instruction cost and critical path.
+ unsigned computeOperandLatency(const MachineInstr *DefMI, unsigned DefOperIdx,
+ const MachineInstr *UseMI, unsigned UseOperIdx,
+ bool FindMin) const;
unsigned getProcessorID() const { return SchedModel.getProcessorID(); }
+
+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
/// If we can determine the operand latency from the def only, without itinerary
/// lookup, do so. Otherwise return -1.
-static int computeDefOperandLatency(
- const TargetInstrInfo *TII, const InstrItineraryData *ItinData,
- const MachineInstr *DefMI, bool FindMin) {
+int TargetInstrInfo::computeDefOperandLatency(
+ const InstrItineraryData *ItinData,
+ const MachineInstr *DefMI, bool FindMin) const {
// Let the target hook getInstrLatency handle missing itineraries.
if (!ItinData)
- return TII->getInstrLatency(ItinData, DefMI);
+ return getInstrLatency(ItinData, DefMI);
// Return a latency based on the itinerary properties and defining instruction
// if possible. Some common subtargets don't require per-operand latency,
// If MinLatency is valid, call getInstrLatency. This uses Stage latency if
// it exists before defaulting to MinLatency.
if (ItinData->SchedModel->MinLatency >= 0)
- return TII->getInstrLatency(ItinData, DefMI);
+ return getInstrLatency(ItinData, DefMI);
// If MinLatency is invalid, OperandLatency is interpreted as MinLatency.
// For empty itineraries, short-cirtuit the check and default to one cycle.
return 1;
}
else if(ItinData->isEmpty())
- return TII->defaultDefLatency(ItinData->SchedModel, DefMI);
+ return defaultDefLatency(ItinData->SchedModel, DefMI);
// ...operand lookup required
return -1;
const MachineInstr *UseMI, unsigned UseIdx,
bool FindMin) const {
- int DefLatency = computeDefOperandLatency(this, ItinData, DefMI, FindMin);
+ int DefLatency = computeDefOperandLatency(ItinData, DefMI, FindMin);
if (DefLatency >= 0)
return DefLatency;
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Support/CommandLine.h"
static cl::opt<bool> EnableSchedModel("schedmodel", cl::Hidden, cl::init(false),
cl::desc("Use TargetSchedModel for latency lookup"));
+static cl::opt<bool> EnableSchedItins("scheditins", cl::Hidden, cl::init(true),
+ cl::desc("Use InstrItineraryData for latency lookup"));
+
void TargetSchedModel::init(const MCSchedModel &sm,
const TargetSubtargetInfo *sti,
const TargetInstrInfo *tii) {
TII = tii;
STI->initInstrItins(InstrItins);
}
+
+/// If we can determine the operand latency from the def only, without machine
+/// model or itinerary lookup, do so. Otherwise return -1.
+int TargetSchedModel::getDefLatency(const MachineInstr *DefMI,
+ bool FindMin) const {
+
+ // Return a latency based on the itinerary properties and defining instruction
+ // if possible. Some common subtargets don't require per-operand latency,
+ // especially for minimum latencies.
+ if (FindMin) {
+ // If MinLatency is invalid, then use the itinerary for MinLatency. If no
+ // itinerary exists either, then use single cycle latency.
+ if (SchedModel.MinLatency < 0
+ && !(EnableSchedItins && hasInstrItineraries())) {
+ return 1;
+ }
+ return SchedModel.MinLatency;
+ }
+ else if (!(EnableSchedModel && hasInstrSchedModel())
+ && !(EnableSchedItins && hasInstrItineraries())) {
+ return TII->defaultDefLatency(&SchedModel, DefMI);
+ }
+ // ...operand lookup required
+ return -1;
+}
+
+/// Return the MCSchedClassDesc for this instruction. Some SchedClasses require
+/// evaluation of predicates that depend on instruction operands or flags.
+const MCSchedClassDesc *TargetSchedModel::
+resolveSchedClass(const MachineInstr *MI) const {
+
+ // Get the definition's scheduling class descriptor from this machine model.
+ unsigned SchedClass = MI->getDesc().getSchedClass();
+ const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SchedClass);
+
+#ifndef NDEBUG
+ unsigned NIter = 0;
+#endif
+ while (SCDesc->isVariant()) {
+ assert(++NIter < 6 && "Variants are nested deeper than the magic number");
+
+ SchedClass = STI->resolveSchedClass(SchedClass, MI, this);
+ SCDesc = SchedModel.getSchedClassDesc(SchedClass);
+ }
+ return SCDesc;
+}
+
+/// Find the def index of this operand. This index maps to the machine model and
+/// is independent of use operands. Def operands may be reordered with uses or
+/// merged with uses without affecting the def index (e.g. before/after
+/// regalloc). However, an instruction's def operands must never be reordered
+/// with respect to each other.
+static unsigned findDefIdx(const MachineInstr *MI, unsigned DefOperIdx) {
+ unsigned DefIdx = 0;
+ for (unsigned i = 0; i != DefOperIdx; ++i) {
+ const MachineOperand &MO = MI->getOperand(i);
+ if (MO.isReg() && MO.isDef())
+ ++DefIdx;
+ }
+ return DefIdx;
+}
+
+/// Find the use index of this operand. This is independent of the instruction's
+/// def operands.
+static unsigned findUseIdx(const MachineInstr *MI, unsigned UseOperIdx) {
+ unsigned UseIdx = 0;
+ for (unsigned i = 0; i != UseOperIdx; ++i) {
+ const MachineOperand &MO = MI->getOperand(i);
+ if (MO.isReg() && MO.isUse())
+ ++UseIdx;
+ }
+ return UseIdx;
+}
+
+// Top-level API for clients that know the operand indices.
+unsigned TargetSchedModel::computeOperandLatency(
+ const MachineInstr *DefMI, unsigned DefOperIdx,
+ const MachineInstr *UseMI, unsigned UseOperIdx,
+ bool FindMin) const {
+
+ int DefLatency = getDefLatency(DefMI, FindMin);
+ if (DefLatency >= 0)
+ return DefLatency;
+
+ if (!FindMin && EnableSchedModel && hasInstrSchedModel()) {
+ const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI);
+ unsigned DefIdx = findDefIdx(DefMI, DefOperIdx);
+ if (DefIdx < SCDesc->NumWriteLatencyEntries) {
+
+ // Lookup the definition's write latency in SubtargetInfo.
+ const MCWriteLatencyEntry *WLEntry =
+ STI->getWriteLatencyEntry(SCDesc, DefIdx);
+ unsigned WriteID = WLEntry->WriteResourceID;
+ unsigned Latency = WLEntry->Cycles;
+ if (!UseMI)
+ return Latency;
+
+ // Lookup the use's latency adjustment in SubtargetInfo.
+ const MCSchedClassDesc *UseDesc = resolveSchedClass(UseMI);
+ if (UseDesc->NumReadAdvanceEntries == 0)
+ return Latency;
+ unsigned UseIdx = findUseIdx(UseMI, UseOperIdx);
+ return Latency - STI->getReadAdvanceCycles(UseDesc, UseIdx, WriteID);
+ }
+ // If DefIdx does not exist in the model (e.g. implicit defs), then return
+ // unit latency (defaultDefLatency may be too conservative).
+ // TODO: For unknown defs, we may want to use the subtarget's model
+ // for WAW latency here instead of 1 cycle.
+ assert((!SCDesc->isValid() || DefMI->getOperand(DefOperIdx).isImplicit()) &&
+ "DefIdx exceeds machine model def operand list");
+ return 1;
+ }
+ assert(EnableSchedItins && hasInstrItineraries() &&
+ "operand latency requires itinerary");
+
+ int OperLatency = 0;
+ if (UseMI) {
+ OperLatency =
+ TII->getOperandLatency(&InstrItins, DefMI, DefOperIdx, UseMI, UseOperIdx);
+ }
+ else {
+ unsigned DefClass = DefMI->getDesc().getSchedClass();
+ OperLatency = InstrItins.getOperandCycle(DefClass, DefOperIdx);
+ }
+ if (OperLatency >= 0)
+ return OperLatency;
+
+ // No operand latency was found.
+ unsigned InstrLatency = TII->getInstrLatency(&InstrItins, DefMI);
+
+ // Expected latency is the max of the stage latency and itinerary props.
+ if (!FindMin)
+ InstrLatency = std::max(InstrLatency,
+ TII->defaultDefLatency(&SchedModel, DefMI));
+ return InstrLatency;
+}