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 return MCSchedModel::computeInstrLatency
<MCSubtargetInfo
, MCInstrInfo
,
73 InstrItineraryData
, MCInst
>(
75 [&](const MCSchedClassDesc
*SCDesc
) -> const MCSchedClassDesc
* {
76 if (!SCDesc
->isValid())
79 unsigned CPUID
= getProcessorID();
80 unsigned SchedClass
= 0;
81 while (SCDesc
->isVariant()) {
83 STI
.resolveVariantSchedClass(SchedClass
, &Inst
, &MCII
, CPUID
);
84 SCDesc
= getSchedClassDesc(SchedClass
);
88 assert(false && "unsupported variant scheduling class");
97 MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo
&STI
,
98 const MCSchedClassDesc
&SCDesc
) {
99 std::optional
<double> Throughput
;
100 const MCSchedModel
&SM
= STI
.getSchedModel();
101 const MCWriteProcResEntry
*I
= STI
.getWriteProcResBegin(&SCDesc
);
102 const MCWriteProcResEntry
*E
= STI
.getWriteProcResEnd(&SCDesc
);
103 for (; I
!= E
; ++I
) {
104 if (!I
->ReleaseAtCycle
)
106 unsigned NumUnits
= SM
.getProcResource(I
->ProcResourceIdx
)->NumUnits
;
107 double Temp
= NumUnits
* 1.0 / I
->ReleaseAtCycle
;
108 Throughput
= Throughput
? std::min(*Throughput
, Temp
) : Temp
;
111 return 1.0 / *Throughput
;
113 // If no throughput value was calculated, assume that we can execute at the
114 // maximum issue width scaled by number of micro-ops for the schedule class.
115 return ((double)SCDesc
.NumMicroOps
) / SM
.IssueWidth
;
119 MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo
&STI
,
120 const MCInstrInfo
&MCII
,
121 const MCInst
&Inst
) const {
122 unsigned SchedClass
= MCII
.get(Inst
.getOpcode()).getSchedClass();
123 const MCSchedClassDesc
*SCDesc
= getSchedClassDesc(SchedClass
);
125 // If there's no valid class, assume that the instruction executes/completes
126 // at the maximum issue width.
127 if (!SCDesc
->isValid())
128 return 1.0 / IssueWidth
;
130 unsigned CPUID
= getProcessorID();
131 while (SCDesc
->isVariant()) {
132 SchedClass
= STI
.resolveVariantSchedClass(SchedClass
, &Inst
, &MCII
, CPUID
);
133 SCDesc
= getSchedClassDesc(SchedClass
);
137 return MCSchedModel::getReciprocalThroughput(STI
, *SCDesc
);
139 llvm_unreachable("unsupported variant scheduling class");
143 MCSchedModel::getReciprocalThroughput(unsigned SchedClass
,
144 const InstrItineraryData
&IID
) {
145 std::optional
<double> Throughput
;
146 const InstrStage
*I
= IID
.beginStage(SchedClass
);
147 const InstrStage
*E
= IID
.endStage(SchedClass
);
148 for (; I
!= E
; ++I
) {
151 double Temp
= llvm::popcount(I
->getUnits()) * 1.0 / I
->getCycles();
152 Throughput
= Throughput
? std::min(*Throughput
, Temp
) : Temp
;
155 return 1.0 / *Throughput
;
157 // If there are no execution resources specified for this class, then assume
158 // that it can execute at the maximum default issue width.
159 return 1.0 / DefaultIssueWidth
;
163 MCSchedModel::getForwardingDelayCycles(ArrayRef
<MCReadAdvanceEntry
> Entries
,
164 unsigned WriteResourceID
) {
169 for (const MCReadAdvanceEntry
&E
: Entries
) {
170 if (E
.WriteResourceID
!= WriteResourceID
)
172 DelayCycles
= std::min(DelayCycles
, E
.Cycles
);
175 return std::abs(DelayCycles
);