1*0b57cec5SDimitry Andric //===- MCSchedule.cpp - Scheduling ------------------------------*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file defines the default scheduling model. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #include "llvm/MC/MCSchedule.h" 14*0b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 15*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 16*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h" 17*0b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 18*0b57cec5SDimitry Andric #include <type_traits> 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric using namespace llvm; 21*0b57cec5SDimitry Andric 22*0b57cec5SDimitry Andric static_assert(std::is_pod<MCSchedModel>::value, 23*0b57cec5SDimitry Andric "We shouldn't have a static constructor here"); 24*0b57cec5SDimitry Andric const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth, 25*0b57cec5SDimitry Andric DefaultMicroOpBufferSize, 26*0b57cec5SDimitry Andric DefaultLoopMicroOpBufferSize, 27*0b57cec5SDimitry Andric DefaultLoadLatency, 28*0b57cec5SDimitry Andric DefaultHighLatency, 29*0b57cec5SDimitry Andric DefaultMispredictPenalty, 30*0b57cec5SDimitry Andric false, 31*0b57cec5SDimitry Andric true, 32*0b57cec5SDimitry Andric 0, 33*0b57cec5SDimitry Andric nullptr, 34*0b57cec5SDimitry Andric nullptr, 35*0b57cec5SDimitry Andric 0, 36*0b57cec5SDimitry Andric 0, 37*0b57cec5SDimitry Andric nullptr, 38*0b57cec5SDimitry Andric nullptr}; 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI, 41*0b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc) { 42*0b57cec5SDimitry Andric int Latency = 0; 43*0b57cec5SDimitry Andric for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries; 44*0b57cec5SDimitry Andric DefIdx != DefEnd; ++DefIdx) { 45*0b57cec5SDimitry Andric // Lookup the definition's write latency in SubtargetInfo. 46*0b57cec5SDimitry Andric const MCWriteLatencyEntry *WLEntry = 47*0b57cec5SDimitry Andric STI.getWriteLatencyEntry(&SCDesc, DefIdx); 48*0b57cec5SDimitry Andric // Early exit if we found an invalid latency. 49*0b57cec5SDimitry Andric if (WLEntry->Cycles < 0) 50*0b57cec5SDimitry Andric return WLEntry->Cycles; 51*0b57cec5SDimitry Andric Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles)); 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric return Latency; 54*0b57cec5SDimitry Andric } 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI, 57*0b57cec5SDimitry Andric unsigned SchedClass) const { 58*0b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *getSchedClassDesc(SchedClass); 59*0b57cec5SDimitry Andric if (!SCDesc.isValid()) 60*0b57cec5SDimitry Andric return 0; 61*0b57cec5SDimitry Andric if (!SCDesc.isVariant()) 62*0b57cec5SDimitry Andric return MCSchedModel::computeInstrLatency(STI, SCDesc); 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric llvm_unreachable("unsupported variant scheduling class"); 65*0b57cec5SDimitry Andric } 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI, 68*0b57cec5SDimitry Andric const MCInstrInfo &MCII, 69*0b57cec5SDimitry Andric const MCInst &Inst) const { 70*0b57cec5SDimitry Andric unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass(); 71*0b57cec5SDimitry Andric const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass); 72*0b57cec5SDimitry Andric if (!SCDesc->isValid()) 73*0b57cec5SDimitry Andric return 0; 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric unsigned CPUID = getProcessorID(); 76*0b57cec5SDimitry Andric while (SCDesc->isVariant()) { 77*0b57cec5SDimitry Andric SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, CPUID); 78*0b57cec5SDimitry Andric SCDesc = getSchedClassDesc(SchedClass); 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric if (SchedClass) 82*0b57cec5SDimitry Andric return MCSchedModel::computeInstrLatency(STI, *SCDesc); 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric llvm_unreachable("unsupported variant scheduling class"); 85*0b57cec5SDimitry Andric } 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric double 88*0b57cec5SDimitry Andric MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI, 89*0b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc) { 90*0b57cec5SDimitry Andric Optional<double> Throughput; 91*0b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 92*0b57cec5SDimitry Andric const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc); 93*0b57cec5SDimitry Andric const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc); 94*0b57cec5SDimitry Andric for (; I != E; ++I) { 95*0b57cec5SDimitry Andric if (!I->Cycles) 96*0b57cec5SDimitry Andric continue; 97*0b57cec5SDimitry Andric unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits; 98*0b57cec5SDimitry Andric double Temp = NumUnits * 1.0 / I->Cycles; 99*0b57cec5SDimitry Andric Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp; 100*0b57cec5SDimitry Andric } 101*0b57cec5SDimitry Andric if (Throughput.hasValue()) 102*0b57cec5SDimitry Andric return 1.0 / Throughput.getValue(); 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric // If no throughput value was calculated, assume that we can execute at the 105*0b57cec5SDimitry Andric // maximum issue width scaled by number of micro-ops for the schedule class. 106*0b57cec5SDimitry Andric return ((double)SCDesc.NumMicroOps) / SM.IssueWidth; 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric double 110*0b57cec5SDimitry Andric MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI, 111*0b57cec5SDimitry Andric const MCInstrInfo &MCII, 112*0b57cec5SDimitry Andric const MCInst &Inst) const { 113*0b57cec5SDimitry Andric unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass(); 114*0b57cec5SDimitry Andric const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass); 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric // If there's no valid class, assume that the instruction executes/completes 117*0b57cec5SDimitry Andric // at the maximum issue width. 118*0b57cec5SDimitry Andric if (!SCDesc->isValid()) 119*0b57cec5SDimitry Andric return 1.0 / IssueWidth; 120*0b57cec5SDimitry Andric 121*0b57cec5SDimitry Andric unsigned CPUID = getProcessorID(); 122*0b57cec5SDimitry Andric while (SCDesc->isVariant()) { 123*0b57cec5SDimitry Andric SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, CPUID); 124*0b57cec5SDimitry Andric SCDesc = getSchedClassDesc(SchedClass); 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric if (SchedClass) 128*0b57cec5SDimitry Andric return MCSchedModel::getReciprocalThroughput(STI, *SCDesc); 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric llvm_unreachable("unsupported variant scheduling class"); 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric double 134*0b57cec5SDimitry Andric MCSchedModel::getReciprocalThroughput(unsigned SchedClass, 135*0b57cec5SDimitry Andric const InstrItineraryData &IID) { 136*0b57cec5SDimitry Andric Optional<double> Throughput; 137*0b57cec5SDimitry Andric const InstrStage *I = IID.beginStage(SchedClass); 138*0b57cec5SDimitry Andric const InstrStage *E = IID.endStage(SchedClass); 139*0b57cec5SDimitry Andric for (; I != E; ++I) { 140*0b57cec5SDimitry Andric if (!I->getCycles()) 141*0b57cec5SDimitry Andric continue; 142*0b57cec5SDimitry Andric double Temp = countPopulation(I->getUnits()) * 1.0 / I->getCycles(); 143*0b57cec5SDimitry Andric Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp; 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric if (Throughput.hasValue()) 146*0b57cec5SDimitry Andric return 1.0 / Throughput.getValue(); 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric // If there are no execution resources specified for this class, then assume 149*0b57cec5SDimitry Andric // that it can execute at the maximum default issue width. 150*0b57cec5SDimitry Andric return 1.0 / DefaultIssueWidth; 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric unsigned 154*0b57cec5SDimitry Andric MCSchedModel::getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries, 155*0b57cec5SDimitry Andric unsigned WriteResourceID) { 156*0b57cec5SDimitry Andric if (Entries.empty()) 157*0b57cec5SDimitry Andric return 0; 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric int DelayCycles = 0; 160*0b57cec5SDimitry Andric for (const MCReadAdvanceEntry &E : Entries) { 161*0b57cec5SDimitry Andric if (E.WriteResourceID != WriteResourceID) 162*0b57cec5SDimitry Andric continue; 163*0b57cec5SDimitry Andric DelayCycles = std::min(DelayCycles, E.Cycles); 164*0b57cec5SDimitry Andric } 165*0b57cec5SDimitry Andric 166*0b57cec5SDimitry Andric return std::abs(DelayCycles); 167*0b57cec5SDimitry Andric } 168