199ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick//===-- llvm/Target/TargetSchedule.cpp - Sched Machine Model ----*- C++ -*-===// 299ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// 399ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// The LLVM Compiler Infrastructure 499ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// 599ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// This file is distributed under the University of Illinois Open Source 699ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// License. See LICENSE.TXT for details. 799ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// 899ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick//===----------------------------------------------------------------------===// 999ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// 1099ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// This file implements a wrapper around MCSchedModel that allows the interface 1199ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// to benefit from information currently only available in TargetInstrInfo. 1299ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick// 1399ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick//===----------------------------------------------------------------------===// 1499ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick 1599ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick#include "llvm/CodeGen/TargetSchedule.h" 16d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Support/CommandLine.h" 17d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Support/raw_ostream.h" 1899ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick#include "llvm/Target/TargetInstrInfo.h" 1934301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick#include "llvm/Target/TargetRegisterInfo.h" 2099ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick#include "llvm/Target/TargetSubtargetInfo.h" 2199ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick 2299ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trickusing namespace llvm; 2399ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick 2472fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trickstatic cl::opt<bool> EnableSchedModel("schedmodel", cl::Hidden, cl::init(true), 2599ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick cl::desc("Use TargetSchedModel for latency lookup")); 2699ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick 2734301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trickstatic cl::opt<bool> EnableSchedItins("scheditins", cl::Hidden, cl::init(true), 2834301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick cl::desc("Use InstrItineraryData for latency lookup")); 2934301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 3042bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trickbool TargetSchedModel::hasInstrSchedModel() const { 3142bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trick return EnableSchedModel && SchedModel.hasInstrSchedModel(); 3242bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trick} 3342bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trick 3442bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trickbool TargetSchedModel::hasInstrItineraries() const { 3542bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trick return EnableSchedItins && !InstrItins.isEmpty(); 3642bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trick} 3742bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trick 388d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trickstatic unsigned gcd(unsigned Dividend, unsigned Divisor) { 398d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick // Dividend and Divisor will be naturally swapped as needed. 408d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick while(Divisor) { 418d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick unsigned Rem = Dividend % Divisor; 428d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick Dividend = Divisor; 438d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick Divisor = Rem; 448d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick }; 458d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick return Dividend; 468d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick} 478d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trickstatic unsigned lcm(unsigned A, unsigned B) { 488d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick unsigned LCM = (uint64_t(A) * B) / gcd(A, B); 498d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick assert((LCM >= A && LCM >= B) && "LCM overflow"); 508d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick return LCM; 518d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick} 528d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick 5399ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trickvoid TargetSchedModel::init(const MCSchedModel &sm, 5499ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick const TargetSubtargetInfo *sti, 5599ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick const TargetInstrInfo *tii) { 5699ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick SchedModel = sm; 5799ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick STI = sti; 5899ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick TII = tii; 5999ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick STI->initInstrItins(InstrItins); 608d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick 618d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick unsigned NumRes = SchedModel.getNumProcResourceKinds(); 628d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick ResourceFactors.resize(NumRes); 638d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick ResourceLCM = SchedModel.IssueWidth; 648d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick for (unsigned Idx = 0; Idx < NumRes; ++Idx) { 658d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick unsigned NumUnits = SchedModel.getProcResource(Idx)->NumUnits; 668d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick if (NumUnits > 0) 678d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick ResourceLCM = lcm(ResourceLCM, NumUnits); 688d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick } 698d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick MicroOpFactor = ResourceLCM / SchedModel.IssueWidth; 708d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick for (unsigned Idx = 0; Idx < NumRes; ++Idx) { 718d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick unsigned NumUnits = SchedModel.getProcResource(Idx)->NumUnits; 728d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick ResourceFactors[Idx] = NumUnits ? (ResourceLCM / NumUnits) : 0; 738d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick } 7499ab6c6035aec3c0e9b0cc5b76a4666fc5fd7b7bAndrew Trick} 7534301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 768d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trickunsigned TargetSchedModel::getNumMicroOps(const MachineInstr *MI, 778d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick const MCSchedClassDesc *SC) const { 78412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick if (hasInstrItineraries()) { 79412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick int UOps = InstrItins.getNumMicroOps(MI->getDesc().getSchedClass()); 80412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick return (UOps >= 0) ? UOps : TII->getNumMicroOps(&InstrItins, MI); 81412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick } 824903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick if (hasInstrSchedModel()) { 838d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick if (!SC) 848d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick SC = resolveSchedClass(MI); 858d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick if (SC->isValid()) 868d4abb2446f80986ad5136bbec30c5da18cd6f4bAndrew Trick return SC->NumMicroOps; 874903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick } 884903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick return MI->isTransient() ? 0 : 1; 89412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick} 90412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick 91fdd6fa89b960088b368231ec08e56a0c0b1e6930Andrew Trick// The machine model may explicitly specify an invalid latency, which 92fdd6fa89b960088b368231ec08e56a0c0b1e6930Andrew Trick// effectively means infinite latency. Since users of the TargetSchedule API 93fdd6fa89b960088b368231ec08e56a0c0b1e6930Andrew Trick// don't know how to handle this, we convert it to a very large latency that is 94fdd6fa89b960088b368231ec08e56a0c0b1e6930Andrew Trick// easy to distinguish when debugging the DAG but won't induce overflow. 95b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trickstatic unsigned capLatency(int Cycles) { 96fdd6fa89b960088b368231ec08e56a0c0b1e6930Andrew Trick return Cycles >= 0 ? Cycles : 1000; 97fdd6fa89b960088b368231ec08e56a0c0b1e6930Andrew Trick} 98fdd6fa89b960088b368231ec08e56a0c0b1e6930Andrew Trick 9934301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// Return the MCSchedClassDesc for this instruction. Some SchedClasses require 10034301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// evaluation of predicates that depend on instruction operands or flags. 10134301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trickconst MCSchedClassDesc *TargetSchedModel:: 10234301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew TrickresolveSchedClass(const MachineInstr *MI) const { 10334301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 10434301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick // Get the definition's scheduling class descriptor from this machine model. 10534301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick unsigned SchedClass = MI->getDesc().getSchedClass(); 10634301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SchedClass); 1076a22dba4854a8b3d7427f8493f663c1b52df4477Andrew Trick if (!SCDesc->isValid()) 1086a22dba4854a8b3d7427f8493f663c1b52df4477Andrew Trick return SCDesc; 10934301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 11034301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick#ifndef NDEBUG 11134301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick unsigned NIter = 0; 11234301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick#endif 11334301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick while (SCDesc->isVariant()) { 11434301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick assert(++NIter < 6 && "Variants are nested deeper than the magic number"); 11534301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 11634301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick SchedClass = STI->resolveSchedClass(SchedClass, MI, this); 11734301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick SCDesc = SchedModel.getSchedClassDesc(SchedClass); 11834301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick } 11934301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick return SCDesc; 12034301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick} 12134301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 12234301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// Find the def index of this operand. This index maps to the machine model and 12334301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// is independent of use operands. Def operands may be reordered with uses or 12434301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// merged with uses without affecting the def index (e.g. before/after 12534301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// regalloc). However, an instruction's def operands must never be reordered 12634301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// with respect to each other. 12734301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trickstatic unsigned findDefIdx(const MachineInstr *MI, unsigned DefOperIdx) { 12834301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick unsigned DefIdx = 0; 12934301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick for (unsigned i = 0; i != DefOperIdx; ++i) { 13034301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick const MachineOperand &MO = MI->getOperand(i); 13134301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick if (MO.isReg() && MO.isDef()) 13234301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick ++DefIdx; 13334301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick } 13434301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick return DefIdx; 13534301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick} 13634301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 13734301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// Find the use index of this operand. This is independent of the instruction's 13834301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick/// def operands. 1393918cade8f7c0a9ff4e3c5799a55846d8f6e3fd4Andrew Trick/// 1403918cade8f7c0a9ff4e3c5799a55846d8f6e3fd4Andrew Trick/// Note that uses are not determined by the operand's isUse property, which 1413918cade8f7c0a9ff4e3c5799a55846d8f6e3fd4Andrew Trick/// is simply the inverse of isDef. Here we consider any readsReg operand to be 1423918cade8f7c0a9ff4e3c5799a55846d8f6e3fd4Andrew Trick/// a "use". The machine model allows an operand to be both a Def and Use. 14334301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trickstatic unsigned findUseIdx(const MachineInstr *MI, unsigned UseOperIdx) { 14434301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick unsigned UseIdx = 0; 14534301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick for (unsigned i = 0; i != UseOperIdx; ++i) { 14634301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick const MachineOperand &MO = MI->getOperand(i); 1473918cade8f7c0a9ff4e3c5799a55846d8f6e3fd4Andrew Trick if (MO.isReg() && MO.readsReg()) 14834301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick ++UseIdx; 14934301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick } 15034301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick return UseIdx; 15134301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick} 15234301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 15334301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick// Top-level API for clients that know the operand indices. 15434301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trickunsigned TargetSchedModel::computeOperandLatency( 15534301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick const MachineInstr *DefMI, unsigned DefOperIdx, 156b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick const MachineInstr *UseMI, unsigned UseOperIdx) const { 15734301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 158b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick if (!hasInstrSchedModel() && !hasInstrItineraries()) 15937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines return TII->defaultDefLatency(SchedModel, DefMI); 16034301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 16142bb106118db51393c2524c8b0c7f7ba6674cfd7Andrew Trick if (hasInstrItineraries()) { 16272fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick int OperLatency = 0; 16372fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick if (UseMI) { 164b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick OperLatency = TII->getOperandLatency(&InstrItins, DefMI, DefOperIdx, 165b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick UseMI, UseOperIdx); 16634301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick } 16772fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick else { 16872fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick unsigned DefClass = DefMI->getDesc().getSchedClass(); 16972fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick OperLatency = InstrItins.getOperandCycle(DefClass, DefOperIdx); 1703918cade8f7c0a9ff4e3c5799a55846d8f6e3fd4Andrew Trick } 17172fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick if (OperLatency >= 0) 17272fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick return OperLatency; 17334301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick 17472fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick // No operand latency was found. 17572fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick unsigned InstrLatency = TII->getInstrLatency(&InstrItins, DefMI); 17672fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick 17772fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick // Expected latency is the max of the stage latency and itinerary props. 178c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick // Rather than directly querying InstrItins stage latency, we call a TII 179c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick // hook to allow subtargets to specialize latency. This hook is only 180c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick // applicable to the InstrItins model. InstrSchedModel should model all 181c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick // special cases without TII hooks. 182b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick InstrLatency = std::max(InstrLatency, 18337ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines TII->defaultDefLatency(SchedModel, DefMI)); 18472fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick return InstrLatency; 18534301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick } 186b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick // hasInstrSchedModel() 18772fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI); 18872fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick unsigned DefIdx = findDefIdx(DefMI, DefOperIdx); 18972fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick if (DefIdx < SCDesc->NumWriteLatencyEntries) { 19072fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick // Lookup the definition's write latency in SubtargetInfo. 19172fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick const MCWriteLatencyEntry *WLEntry = 19272fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick STI->getWriteLatencyEntry(SCDesc, DefIdx); 19372fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick unsigned WriteID = WLEntry->WriteResourceID; 194b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick unsigned Latency = capLatency(WLEntry->Cycles); 19572fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick if (!UseMI) 19672fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick return Latency; 19772fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick 19872fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick // Lookup the use's latency adjustment in SubtargetInfo. 19972fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick const MCSchedClassDesc *UseDesc = resolveSchedClass(UseMI); 20072fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick if (UseDesc->NumReadAdvanceEntries == 0) 20172fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick return Latency; 20272fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick unsigned UseIdx = findUseIdx(UseMI, UseOperIdx); 20371b9d94d6ba2933df0f7936c44cdb344336d46efAndrew Trick int Advance = STI->getReadAdvanceCycles(UseDesc, UseIdx, WriteID); 20471b9d94d6ba2933df0f7936c44cdb344336d46efAndrew Trick if (Advance > 0 && (unsigned)Advance > Latency) // unsigned wrap 20571b9d94d6ba2933df0f7936c44cdb344336d46efAndrew Trick return 0; 20671b9d94d6ba2933df0f7936c44cdb344336d46efAndrew Trick return Latency - Advance; 20734301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick } 20872fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick // If DefIdx does not exist in the model (e.g. implicit defs), then return 20972fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick // unit latency (defaultDefLatency may be too conservative). 21072fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick#ifndef NDEBUG 21172fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick if (SCDesc->isValid() && !DefMI->getOperand(DefOperIdx).isImplicit() 212070156437752179833b1e5fddd50caa03fd7c12fAndrew Trick && !DefMI->getDesc().OpInfo[DefOperIdx].isOptionalDef() 213070156437752179833b1e5fddd50caa03fd7c12fAndrew Trick && SchedModel.isComplete()) { 21472fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick std::string Err; 21572fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick raw_string_ostream ss(Err); 21672fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick ss << "DefIdx " << DefIdx << " exceeds machine model writes for " 21772fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick << *DefMI; 21872fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick report_fatal_error(ss.str()); 21972fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick } 22072fd0a9448a9d9eced8f475741e4a1ee543253e0Andrew Trick#endif 22151f6747b23bf7c85e90f816bf9bfae3a1d4fd058Andrew Trick // FIXME: Automatically giving all implicit defs defaultDefLatency is 22251f6747b23bf7c85e90f816bf9bfae3a1d4fd058Andrew Trick // undesirable. We should only do it for defs that are known to the MC 22351f6747b23bf7c85e90f816bf9bfae3a1d4fd058Andrew Trick // desc like flags. Truly implicit defs should get 1 cycle latency. 22437ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines return DefMI->isTransient() ? 0 : TII->defaultDefLatency(SchedModel, DefMI); 22537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines} 22637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines 22737ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hinesunsigned TargetSchedModel::computeInstrLatency(unsigned Opcode) const { 22837ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines assert(hasInstrSchedModel() && "Only call this function with a SchedModel"); 22937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines 23037ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines unsigned SCIdx = TII->get(Opcode).getSchedClass(); 23137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SCIdx); 23237ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines unsigned Latency = 0; 23337ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines 23437ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines if (SCDesc->isValid() && !SCDesc->isVariant()) { 23537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries; 23637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines DefIdx != DefEnd; ++DefIdx) { 23737ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines // Lookup the definition's write latency in SubtargetInfo. 23837ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines const MCWriteLatencyEntry *WLEntry = 23937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines STI->getWriteLatencyEntry(SCDesc, DefIdx); 24037ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines Latency = std::max(Latency, capLatency(WLEntry->Cycles)); 24137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines } 24237ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines return Latency; 24337ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines } 24437ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines 24537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines assert(Latency && "No MI sched latency"); 24637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines return 0; 24734301ceca8913f3126339f332d3dc6f2d7ac0d78Andrew Trick} 248c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick 249d42730dc712026cbfb1322a979e0ac72cd31a19eArnold Schwaighoferunsigned 250d42730dc712026cbfb1322a979e0ac72cd31a19eArnold SchwaighoferTargetSchedModel::computeInstrLatency(const MachineInstr *MI, 251d42730dc712026cbfb1322a979e0ac72cd31a19eArnold Schwaighofer bool UseDefaultDefLatency) const { 25282d46aec62f127856f4bfeb30f80aa12dd74bae0Andrew Trick // For the itinerary model, fall back to the old subtarget hook. 25382d46aec62f127856f4bfeb30f80aa12dd74bae0Andrew Trick // Allow subtargets to compute Bundle latencies outside the machine model. 254d42730dc712026cbfb1322a979e0ac72cd31a19eArnold Schwaighofer if (hasInstrItineraries() || MI->isBundle() || 255d42730dc712026cbfb1322a979e0ac72cd31a19eArnold Schwaighofer (!hasInstrSchedModel() && !UseDefaultDefLatency)) 256c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick return TII->getInstrLatency(&InstrItins, MI); 25782d46aec62f127856f4bfeb30f80aa12dd74bae0Andrew Trick 258c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick if (hasInstrSchedModel()) { 259c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick const MCSchedClassDesc *SCDesc = resolveSchedClass(MI); 2604903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick if (SCDesc->isValid()) { 2614903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick unsigned Latency = 0; 2624903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries; 2634903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick DefIdx != DefEnd; ++DefIdx) { 2644903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick // Lookup the definition's write latency in SubtargetInfo. 2654903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick const MCWriteLatencyEntry *WLEntry = 2664903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick STI->getWriteLatencyEntry(SCDesc, DefIdx); 267b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick Latency = std::max(Latency, capLatency(WLEntry->Cycles)); 2684903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick } 2694903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick return Latency; 270c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick } 271c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick } 27237ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines return TII->defaultDefLatency(SchedModel, MI); 273c0dfffa448ad7ab647779bc3e7f2aee5c76cb31bAndrew Trick} 274412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick 275412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trickunsigned TargetSchedModel:: 276412cd2f81374865dfa708bef6d5b896ca10dece0Andrew TrickcomputeOutputLatency(const MachineInstr *DefMI, unsigned DefOperIdx, 277412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick const MachineInstr *DepMI) const { 278b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick if (SchedModel.MicroOpBufferSize <= 1) 279412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick return 1; 280412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick 281b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick // MicroOpBufferSize > 1 indicates an out-of-order processor that can dispatch 282412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // WAW dependencies in the same cycle. 283412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick 284412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // Treat predication as a data dependency for out-of-order cpus. In-order 285412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // cpus do not need to treat predicated writes specially. 286412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // 287412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // TODO: The following hack exists because predication passes do not 288412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // correctly append imp-use operands, and readsReg() strangely returns false 289412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // for predicated defs. 290412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick unsigned Reg = DefMI->getOperand(DefOperIdx).getReg(); 291412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick const MachineFunction &MF = *DefMI->getParent()->getParent(); 29237ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); 293412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick if (!DepMI->readsRegister(Reg, TRI) && TII->isPredicated(DepMI)) 294412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick return computeInstrLatency(DefMI); 295412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick 296412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // If we have a per operand scheduling model, check if this def is writing 297412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick // an unbuffered resource. If so, it treated like an in-order cpu. 298412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick if (hasInstrSchedModel()) { 299412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI); 3004903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick if (SCDesc->isValid()) { 3014903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick for (const MCWriteProcResEntry *PRI = STI->getWriteProcResBegin(SCDesc), 3024903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick *PRE = STI->getWriteProcResEnd(SCDesc); PRI != PRE; ++PRI) { 303b86a0cdb674549d8493043331cecd9cbf53b80daAndrew Trick if (!SchedModel.getProcResource(PRI->ProcResourceIdx)->BufferSize) 3044903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick return 1; 3054903c15b7d92802a4f0f28928a89bb4c0d5e212fAndrew Trick } 306412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick } 307412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick } 308412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick return 0; 309412cd2f81374865dfa708bef6d5b896ca10dece0Andrew Trick} 310