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_pod
<MCSchedModel
>::value
,
24 "We shouldn't have a static constructor here");
25 const MCSchedModel
MCSchedModel::Default
= {DefaultIssueWidth
,
26 DefaultMicroOpBufferSize
,
27 DefaultLoopMicroOpBufferSize
,
30 DefaultMispredictPenalty
,
41 int MCSchedModel::computeInstrLatency(const MCSubtargetInfo
&STI
,
42 const MCSchedClassDesc
&SCDesc
) {
44 for (unsigned DefIdx
= 0, DefEnd
= SCDesc
.NumWriteLatencyEntries
;
45 DefIdx
!= DefEnd
; ++DefIdx
) {
46 // Lookup the definition's write latency in SubtargetInfo.
47 const MCWriteLatencyEntry
*WLEntry
=
48 STI
.getWriteLatencyEntry(&SCDesc
, DefIdx
);
49 // Early exit if we found an invalid latency.
50 if (WLEntry
->Cycles
< 0)
51 return WLEntry
->Cycles
;
52 Latency
= std::max(Latency
, static_cast<int>(WLEntry
->Cycles
));
57 int MCSchedModel::computeInstrLatency(const MCSubtargetInfo
&STI
,
58 unsigned SchedClass
) const {
59 const MCSchedClassDesc
&SCDesc
= *getSchedClassDesc(SchedClass
);
60 if (!SCDesc
.isValid())
62 if (!SCDesc
.isVariant())
63 return MCSchedModel::computeInstrLatency(STI
, SCDesc
);
65 llvm_unreachable("unsupported variant scheduling class");
68 int MCSchedModel::computeInstrLatency(const MCSubtargetInfo
&STI
,
69 const MCInstrInfo
&MCII
,
70 const MCInst
&Inst
) const {
71 unsigned SchedClass
= MCII
.get(Inst
.getOpcode()).getSchedClass();
72 const MCSchedClassDesc
*SCDesc
= getSchedClassDesc(SchedClass
);
73 if (!SCDesc
->isValid())
76 unsigned CPUID
= getProcessorID();
77 while (SCDesc
->isVariant()) {
78 SchedClass
= STI
.resolveVariantSchedClass(SchedClass
, &Inst
, &MCII
, CPUID
);
79 SCDesc
= getSchedClassDesc(SchedClass
);
83 return MCSchedModel::computeInstrLatency(STI
, *SCDesc
);
85 llvm_unreachable("unsupported variant scheduling class");
89 MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo
&STI
,
90 const MCSchedClassDesc
&SCDesc
) {
91 std::optional
<double> Throughput
;
92 const MCSchedModel
&SM
= STI
.getSchedModel();
93 const MCWriteProcResEntry
*I
= STI
.getWriteProcResBegin(&SCDesc
);
94 const MCWriteProcResEntry
*E
= STI
.getWriteProcResEnd(&SCDesc
);
98 unsigned NumUnits
= SM
.getProcResource(I
->ProcResourceIdx
)->NumUnits
;
99 double Temp
= NumUnits
* 1.0 / I
->Cycles
;
100 Throughput
= Throughput
? std::min(*Throughput
, Temp
) : Temp
;
103 return 1.0 / *Throughput
;
105 // If no throughput value was calculated, assume that we can execute at the
106 // maximum issue width scaled by number of micro-ops for the schedule class.
107 return ((double)SCDesc
.NumMicroOps
) / SM
.IssueWidth
;
111 MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo
&STI
,
112 const MCInstrInfo
&MCII
,
113 const MCInst
&Inst
) const {
114 unsigned SchedClass
= MCII
.get(Inst
.getOpcode()).getSchedClass();
115 const MCSchedClassDesc
*SCDesc
= getSchedClassDesc(SchedClass
);
117 // If there's no valid class, assume that the instruction executes/completes
118 // at the maximum issue width.
119 if (!SCDesc
->isValid())
120 return 1.0 / IssueWidth
;
122 unsigned CPUID
= getProcessorID();
123 while (SCDesc
->isVariant()) {
124 SchedClass
= STI
.resolveVariantSchedClass(SchedClass
, &Inst
, &MCII
, CPUID
);
125 SCDesc
= getSchedClassDesc(SchedClass
);
129 return MCSchedModel::getReciprocalThroughput(STI
, *SCDesc
);
131 llvm_unreachable("unsupported variant scheduling class");
135 MCSchedModel::getReciprocalThroughput(unsigned SchedClass
,
136 const InstrItineraryData
&IID
) {
137 std::optional
<double> Throughput
;
138 const InstrStage
*I
= IID
.beginStage(SchedClass
);
139 const InstrStage
*E
= IID
.endStage(SchedClass
);
140 for (; I
!= E
; ++I
) {
143 double Temp
= llvm::popcount(I
->getUnits()) * 1.0 / I
->getCycles();
144 Throughput
= Throughput
? std::min(*Throughput
, Temp
) : Temp
;
147 return 1.0 / *Throughput
;
149 // If there are no execution resources specified for this class, then assume
150 // that it can execute at the maximum default issue width.
151 return 1.0 / DefaultIssueWidth
;
155 MCSchedModel::getForwardingDelayCycles(ArrayRef
<MCReadAdvanceEntry
> Entries
,
156 unsigned WriteResourceID
) {
161 for (const MCReadAdvanceEntry
&E
: Entries
) {
162 if (E
.WriteResourceID
!= WriteResourceID
)
164 DelayCycles
= std::min(DelayCycles
, E
.Cycles
);
167 return std::abs(DelayCycles
);