1 //===- MCSchedule.cpp - Scheduling ------------------------------*- C++ -*-===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines the default scheduling model.
11 //===----------------------------------------------------------------------===//
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"
19 #include <type_traits>
23 static_assert(std::is_trivial_v
<MCSchedModel
>,
24 "MCSchedModel is required to be a trivial type");
25 const MCSchedModel
MCSchedModel::Default
= {DefaultIssueWidth
,
26 DefaultMicroOpBufferSize
,
27 DefaultLoopMicroOpBufferSize
,
30 DefaultMispredictPenalty
,
33 /*EnableIntervals=*/false,
42 int MCSchedModel::computeInstrLatency(const MCSubtargetInfo
&STI
,
43 const MCSchedClassDesc
&SCDesc
) {
45 for (unsigned DefIdx
= 0, DefEnd
= SCDesc
.NumWriteLatencyEntries
;
46 DefIdx
!= DefEnd
; ++DefIdx
) {
47 // Lookup the definition's write latency in SubtargetInfo.
48 const MCWriteLatencyEntry
*WLEntry
=
49 STI
.getWriteLatencyEntry(&SCDesc
, DefIdx
);
50 // Early exit if we found an invalid latency.
51 if (WLEntry
->Cycles
< 0)
52 return WLEntry
->Cycles
;
53 Latency
= std::max(Latency
, static_cast<int>(WLEntry
->Cycles
));
58 int MCSchedModel::computeInstrLatency(const MCSubtargetInfo
&STI
,
59 unsigned SchedClass
) const {
60 const MCSchedClassDesc
&SCDesc
= *getSchedClassDesc(SchedClass
);
61 if (!SCDesc
.isValid())
63 if (!SCDesc
.isVariant())
64 return MCSchedModel::computeInstrLatency(STI
, SCDesc
);
66 llvm_unreachable("unsupported variant scheduling class");
69 int MCSchedModel::computeInstrLatency(const MCSubtargetInfo
&STI
,
70 const MCInstrInfo
&MCII
,
71 const MCInst
&Inst
) const {
72 unsigned SchedClass
= MCII
.get(Inst
.getOpcode()).getSchedClass();
73 const MCSchedClassDesc
*SCDesc
= getSchedClassDesc(SchedClass
);
74 if (!SCDesc
->isValid())
77 unsigned CPUID
= getProcessorID();
78 while (SCDesc
->isVariant()) {
79 SchedClass
= STI
.resolveVariantSchedClass(SchedClass
, &Inst
, &MCII
, CPUID
);
80 SCDesc
= getSchedClassDesc(SchedClass
);
84 return MCSchedModel::computeInstrLatency(STI
, *SCDesc
);
86 llvm_unreachable("unsupported variant scheduling class");
90 MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo
&STI
,
91 const MCSchedClassDesc
&SCDesc
) {
92 std::optional
<double> Throughput
;
93 const MCSchedModel
&SM
= STI
.getSchedModel();
94 const MCWriteProcResEntry
*I
= STI
.getWriteProcResBegin(&SCDesc
);
95 const MCWriteProcResEntry
*E
= STI
.getWriteProcResEnd(&SCDesc
);
97 if (!I
->ReleaseAtCycle
)
99 unsigned NumUnits
= SM
.getProcResource(I
->ProcResourceIdx
)->NumUnits
;
100 double Temp
= NumUnits
* 1.0 / I
->ReleaseAtCycle
;
101 Throughput
= Throughput
? std::min(*Throughput
, Temp
) : Temp
;
104 return 1.0 / *Throughput
;
106 // If no throughput value was calculated, assume that we can execute at the
107 // maximum issue width scaled by number of micro-ops for the schedule class.
108 return ((double)SCDesc
.NumMicroOps
) / SM
.IssueWidth
;
112 MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo
&STI
,
113 const MCInstrInfo
&MCII
,
114 const MCInst
&Inst
) const {
115 unsigned SchedClass
= MCII
.get(Inst
.getOpcode()).getSchedClass();
116 const MCSchedClassDesc
*SCDesc
= getSchedClassDesc(SchedClass
);
118 // If there's no valid class, assume that the instruction executes/completes
119 // at the maximum issue width.
120 if (!SCDesc
->isValid())
121 return 1.0 / IssueWidth
;
123 unsigned CPUID
= getProcessorID();
124 while (SCDesc
->isVariant()) {
125 SchedClass
= STI
.resolveVariantSchedClass(SchedClass
, &Inst
, &MCII
, CPUID
);
126 SCDesc
= getSchedClassDesc(SchedClass
);
130 return MCSchedModel::getReciprocalThroughput(STI
, *SCDesc
);
132 llvm_unreachable("unsupported variant scheduling class");
136 MCSchedModel::getReciprocalThroughput(unsigned SchedClass
,
137 const InstrItineraryData
&IID
) {
138 std::optional
<double> Throughput
;
139 const InstrStage
*I
= IID
.beginStage(SchedClass
);
140 const InstrStage
*E
= IID
.endStage(SchedClass
);
141 for (; I
!= E
; ++I
) {
144 double Temp
= llvm::popcount(I
->getUnits()) * 1.0 / I
->getCycles();
145 Throughput
= Throughput
? std::min(*Throughput
, Temp
) : Temp
;
148 return 1.0 / *Throughput
;
150 // If there are no execution resources specified for this class, then assume
151 // that it can execute at the maximum default issue width.
152 return 1.0 / DefaultIssueWidth
;
156 MCSchedModel::getForwardingDelayCycles(ArrayRef
<MCReadAdvanceEntry
> Entries
,
157 unsigned WriteResourceID
) {
162 for (const MCReadAdvanceEntry
&E
: Entries
) {
163 if (E
.WriteResourceID
!= WriteResourceID
)
165 DelayCycles
= std::min(DelayCycles
, E
.Cycles
);
168 return std::abs(DelayCycles
);