Path: blob/main/contrib/llvm-project/llvm/lib/MC/MCSchedule.cpp
35234 views
//===- MCSchedule.cpp - Scheduling ------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the default scheduling model.9//10//===----------------------------------------------------------------------===//1112#include "llvm/MC/MCSchedule.h"13#include "llvm/MC/MCInst.h"14#include "llvm/MC/MCInstrDesc.h"15#include "llvm/MC/MCInstrInfo.h"16#include "llvm/MC/MCSubtargetInfo.h"17#include <optional>18#include <type_traits>1920using namespace llvm;2122static_assert(std::is_trivial_v<MCSchedModel>,23"MCSchedModel is required to be a trivial type");24const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth,25DefaultMicroOpBufferSize,26DefaultLoopMicroOpBufferSize,27DefaultLoadLatency,28DefaultHighLatency,29DefaultMispredictPenalty,30false,31true,32/*EnableIntervals=*/false,330,34nullptr,35nullptr,360,370,38nullptr,39nullptr};4041int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,42const MCSchedClassDesc &SCDesc) {43int Latency = 0;44for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries;45DefIdx != DefEnd; ++DefIdx) {46// Lookup the definition's write latency in SubtargetInfo.47const MCWriteLatencyEntry *WLEntry =48STI.getWriteLatencyEntry(&SCDesc, DefIdx);49// Early exit if we found an invalid latency.50if (WLEntry->Cycles < 0)51return WLEntry->Cycles;52Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles));53}54return Latency;55}5657int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,58unsigned SchedClass) const {59const MCSchedClassDesc &SCDesc = *getSchedClassDesc(SchedClass);60if (!SCDesc.isValid())61return 0;62if (!SCDesc.isVariant())63return MCSchedModel::computeInstrLatency(STI, SCDesc);6465llvm_unreachable("unsupported variant scheduling class");66}6768int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,69const MCInstrInfo &MCII,70const MCInst &Inst) const {71unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();72const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);73if (!SCDesc->isValid())74return 0;7576unsigned CPUID = getProcessorID();77while (SCDesc->isVariant()) {78SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);79SCDesc = getSchedClassDesc(SchedClass);80}8182if (SchedClass)83return MCSchedModel::computeInstrLatency(STI, *SCDesc);8485llvm_unreachable("unsupported variant scheduling class");86}8788double89MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI,90const MCSchedClassDesc &SCDesc) {91std::optional<double> Throughput;92const MCSchedModel &SM = STI.getSchedModel();93const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc);94const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc);95for (; I != E; ++I) {96if (!I->ReleaseAtCycle)97continue;98unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits;99double Temp = NumUnits * 1.0 / I->ReleaseAtCycle;100Throughput = Throughput ? std::min(*Throughput, Temp) : Temp;101}102if (Throughput)103return 1.0 / *Throughput;104105// If no throughput value was calculated, assume that we can execute at the106// maximum issue width scaled by number of micro-ops for the schedule class.107return ((double)SCDesc.NumMicroOps) / SM.IssueWidth;108}109110double111MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI,112const MCInstrInfo &MCII,113const MCInst &Inst) const {114unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();115const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);116117// If there's no valid class, assume that the instruction executes/completes118// at the maximum issue width.119if (!SCDesc->isValid())120return 1.0 / IssueWidth;121122unsigned CPUID = getProcessorID();123while (SCDesc->isVariant()) {124SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);125SCDesc = getSchedClassDesc(SchedClass);126}127128if (SchedClass)129return MCSchedModel::getReciprocalThroughput(STI, *SCDesc);130131llvm_unreachable("unsupported variant scheduling class");132}133134double135MCSchedModel::getReciprocalThroughput(unsigned SchedClass,136const InstrItineraryData &IID) {137std::optional<double> Throughput;138const InstrStage *I = IID.beginStage(SchedClass);139const InstrStage *E = IID.endStage(SchedClass);140for (; I != E; ++I) {141if (!I->getCycles())142continue;143double Temp = llvm::popcount(I->getUnits()) * 1.0 / I->getCycles();144Throughput = Throughput ? std::min(*Throughput, Temp) : Temp;145}146if (Throughput)147return 1.0 / *Throughput;148149// If there are no execution resources specified for this class, then assume150// that it can execute at the maximum default issue width.151return 1.0 / DefaultIssueWidth;152}153154unsigned155MCSchedModel::getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries,156unsigned WriteResourceID) {157if (Entries.empty())158return 0;159160int DelayCycles = 0;161for (const MCReadAdvanceEntry &E : Entries) {162if (E.WriteResourceID != WriteResourceID)163continue;164DelayCycles = std::min(DelayCycles, E.Cycles);165}166167return std::abs(DelayCycles);168}169170171