215 lines · cpp
1//===- MCSchedule.cpp - Scheduling ------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the default scheduling model.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/MC/MCSchedule.h"14#include "llvm/MC/MCInst.h"15#include "llvm/MC/MCInstrDesc.h"16#include "llvm/MC/MCInstrInfo.h"17#include "llvm/MC/MCSubtargetInfo.h"18#include <optional>19#include <type_traits>20 21using namespace llvm;22 23static_assert(std::is_trivial_v<MCSchedModel>,24 "MCSchedModel is required to be a trivial type");25const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth,26 DefaultMicroOpBufferSize,27 DefaultLoopMicroOpBufferSize,28 DefaultLoadLatency,29 DefaultHighLatency,30 DefaultMispredictPenalty,31 false,32 true,33 /*EnableIntervals=*/false,34 0,35 nullptr,36 nullptr,37 0,38 0,39 nullptr,40 nullptr,41 nullptr};42 43int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,44 const MCSchedClassDesc &SCDesc) {45 int Latency = 0;46 for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries;47 DefIdx != DefEnd; ++DefIdx) {48 // Lookup the definition's write latency in SubtargetInfo.49 const MCWriteLatencyEntry *WLEntry =50 STI.getWriteLatencyEntry(&SCDesc, DefIdx);51 // Early exit if we found an invalid latency.52 if (WLEntry->Cycles < 0)53 return WLEntry->Cycles;54 Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles));55 }56 return Latency;57}58 59int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,60 unsigned SchedClass) const {61 const MCSchedClassDesc &SCDesc = *getSchedClassDesc(SchedClass);62 if (!SCDesc.isValid())63 return 0;64 if (!SCDesc.isVariant())65 return MCSchedModel::computeInstrLatency(STI, SCDesc);66 67 llvm_unreachable("unsupported variant scheduling class");68}69 70int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,71 const MCInstrInfo &MCII,72 const MCInst &Inst) const {73 return MCSchedModel::computeInstrLatency<MCSubtargetInfo, MCInstrInfo,74 InstrItineraryData, MCInst>(75 STI, MCII, Inst,76 [&](const MCSchedClassDesc *SCDesc) -> const MCSchedClassDesc * {77 if (!SCDesc->isValid())78 return nullptr;79 80 unsigned CPUID = getProcessorID();81 unsigned SchedClass = 0;82 while (SCDesc->isVariant()) {83 SchedClass =84 STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);85 SCDesc = getSchedClassDesc(SchedClass);86 }87 88 if (!SchedClass) {89 assert(false && "unsupported variant scheduling class");90 return nullptr;91 }92 93 return SCDesc;94 });95}96 97double98MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI,99 const MCSchedClassDesc &SCDesc) {100 std::optional<double> MinThroughput;101 const MCSchedModel &SM = STI.getSchedModel();102 const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc);103 const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc);104 for (; I != E; ++I) {105 if (!I->ReleaseAtCycle || I->ReleaseAtCycle == I->AcquireAtCycle)106 continue;107 assert(I->ReleaseAtCycle > I->AcquireAtCycle && "invalid resource segment");108 unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits;109 double Throughput =110 double(NumUnits) / double(I->ReleaseAtCycle - I->AcquireAtCycle);111 MinThroughput =112 MinThroughput ? std::min(*MinThroughput, Throughput) : Throughput;113 }114 if (MinThroughput)115 return 1.0 / *MinThroughput;116 117 // If no throughput value was calculated, assume that we can execute at the118 // maximum issue width scaled by number of micro-ops for the schedule class.119 return ((double)SCDesc.NumMicroOps) / SM.IssueWidth;120}121 122double123MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI,124 const MCInstrInfo &MCII,125 const MCInst &Inst) const {126 unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();127 const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);128 129 // If there's no valid class, assume that the instruction executes/completes130 // at the maximum issue width.131 if (!SCDesc->isValid())132 return 1.0 / IssueWidth;133 134 unsigned CPUID = getProcessorID();135 while (SCDesc->isVariant()) {136 SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);137 SCDesc = getSchedClassDesc(SchedClass);138 }139 140 if (SchedClass)141 return MCSchedModel::getReciprocalThroughput(STI, *SCDesc);142 143 llvm_unreachable("unsupported variant scheduling class");144}145 146double147MCSchedModel::getReciprocalThroughput(unsigned SchedClass,148 const InstrItineraryData &IID) {149 std::optional<double> Throughput;150 const InstrStage *I = IID.beginStage(SchedClass);151 const InstrStage *E = IID.endStage(SchedClass);152 for (; I != E; ++I) {153 if (!I->getCycles())154 continue;155 double Temp = llvm::popcount(I->getUnits()) * 1.0 / I->getCycles();156 Throughput = Throughput ? std::min(*Throughput, Temp) : Temp;157 }158 if (Throughput)159 return 1.0 / *Throughput;160 161 // If there are no execution resources specified for this class, then assume162 // that it can execute at the maximum default issue width.163 return 1.0 / DefaultIssueWidth;164}165 166unsigned167MCSchedModel::getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries,168 unsigned WriteResourceID) {169 if (Entries.empty())170 return 0;171 172 int DelayCycles = 0;173 for (const MCReadAdvanceEntry &E : Entries) {174 if (E.WriteResourceID != WriteResourceID)175 continue;176 DelayCycles = std::min(DelayCycles, E.Cycles);177 }178 179 return std::abs(DelayCycles);180}181 182unsigned MCSchedModel::getBypassDelayCycles(const MCSubtargetInfo &STI,183 const MCSchedClassDesc &SCDesc) {184 185 ArrayRef<MCReadAdvanceEntry> Entries = STI.getReadAdvanceEntries(SCDesc);186 if (Entries.empty())187 return 0;188 189 unsigned MaxLatency = 0;190 unsigned WriteResourceID = 0;191 unsigned DefEnd = SCDesc.NumWriteLatencyEntries;192 193 for (unsigned DefIdx = 0; DefIdx != DefEnd; ++DefIdx) {194 // Lookup the definition's write latency in SubtargetInfo.195 const MCWriteLatencyEntry *WLEntry =196 STI.getWriteLatencyEntry(&SCDesc, DefIdx);197 unsigned Cycles = 0;198 // If latency is Invalid (<0), consider 0 cycle latency199 if (WLEntry->Cycles > 0)200 Cycles = (unsigned)WLEntry->Cycles;201 if (Cycles > MaxLatency) {202 MaxLatency = Cycles;203 WriteResourceID = WLEntry->WriteResourceID;204 }205 }206 207 for (const MCReadAdvanceEntry &E : Entries) {208 if (E.WriteResourceID == WriteResourceID)209 return E.Cycles;210 }211 212 // Unable to find WriteResourceID in MCReadAdvanceEntry Entries213 return 0;214}215