blob: 929bd7f6046cc3e19dc45a8df25c08281f9c5e8e [file] [log] [blame]
Duncan P. N. Exon Smithd819fac2015-07-10 22:13:43 +00001//===- MCSchedule.cpp - Scheduling ------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the default scheduling model.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/MC/MCSchedule.h"
Andrea Di Biagioae5fb652018-05-31 13:30:42 +000015#include "llvm/MC/MCInst.h"
Andrea Di Biagiob5e23d12018-04-15 17:32:17 +000016#include "llvm/MC/MCInstrDesc.h"
17#include "llvm/MC/MCInstrInfo.h"
Andrea Di Biagiofe3b1d22018-03-13 15:22:13 +000018#include "llvm/MC/MCSubtargetInfo.h"
Duncan P. N. Exon Smith34b9a7dc2015-07-10 22:17:49 +000019#include <type_traits>
Duncan P. N. Exon Smithd819fac2015-07-10 22:13:43 +000020
21using namespace llvm;
22
23static_assert(std::is_pod<MCSchedModel>::value,
24 "We shouldn't have a static constructor here");
25const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth,
26 DefaultMicroOpBufferSize,
27 DefaultLoopMicroOpBufferSize,
28 DefaultLoadLatency,
29 DefaultHighLatency,
30 DefaultMispredictPenalty,
31 false,
32 true,
33 0,
34 nullptr,
35 nullptr,
36 0,
37 0,
Andrea Di Biagio46750802018-04-03 13:52:26 +000038 nullptr,
Duncan P. N. Exon Smithd819fac2015-07-10 22:13:43 +000039 nullptr};
Andrea Di Biagiofe3b1d22018-03-13 15:22:13 +000040
41int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
42 const MCSchedClassDesc &SCDesc) {
43 int Latency = 0;
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));
53 }
54 return Latency;
55}
Andrea Di Biagio0718ccc2018-03-13 16:28:55 +000056
Andrea Di Biagiob5e23d12018-04-15 17:32:17 +000057int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
58 unsigned SchedClass) const {
59 const MCSchedClassDesc &SCDesc = *getSchedClassDesc(SchedClass);
60 if (!SCDesc.isValid())
61 return 0;
62 if (!SCDesc.isVariant())
63 return MCSchedModel::computeInstrLatency(STI, SCDesc);
64
65 llvm_unreachable("unsupported variant scheduling class");
66}
Andrea Di Biagio0718ccc2018-03-13 16:28:55 +000067
Andrea Di Biagioae5fb652018-05-31 13:30:42 +000068int 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())
74 return 0;
75
76 unsigned CPUID = getProcessorID();
77 while (SCDesc->isVariant()) {
78 SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, CPUID);
79 SCDesc = getSchedClassDesc(SchedClass);
80 }
81
82 if (SchedClass)
83 return MCSchedModel::computeInstrLatency(STI, *SCDesc);
84
85 llvm_unreachable("unsupported variant scheduling class");
86}
87
Sanjay Patel863443f2018-06-05 23:34:45 +000088double
Andrea Di Biagio0718ccc2018-03-13 16:28:55 +000089MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI,
90 const MCSchedClassDesc &SCDesc) {
91 Optional<double> Throughput;
Andrea Di Biagiob5e23d12018-04-15 17:32:17 +000092 const MCSchedModel &SM = STI.getSchedModel();
93 const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc);
94 const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc);
95 for (; I != E; ++I) {
96 if (!I->Cycles)
97 continue;
98 unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits;
99 double Temp = NumUnits * 1.0 / I->Cycles;
100 Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp;
Andrea Di Biagio0718ccc2018-03-13 16:28:55 +0000101 }
Sanjay Patel863443f2018-06-05 23:34:45 +0000102 if (Throughput.hasValue())
103 return 1.0 / Throughput.getValue();
104
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;
Andrea Di Biagiob5e23d12018-04-15 17:32:17 +0000108}
Andrea Di Biagio0718ccc2018-03-13 16:28:55 +0000109
Sanjay Patel863443f2018-06-05 23:34:45 +0000110double
Andrea Di Biagioae5fb652018-05-31 13:30:42 +0000111MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI,
112 const MCInstrInfo &MCII,
113 const MCInst &Inst) const {
Andrea Di Biagioae5fb652018-05-31 13:30:42 +0000114 unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();
115 const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);
Sanjay Patel863443f2018-06-05 23:34:45 +0000116
117 // If there's no valid class, assume that the instruction executes/completes
118 // at the maximum issue width.
Andrea Di Biagioae5fb652018-05-31 13:30:42 +0000119 if (!SCDesc->isValid())
Sanjay Patel863443f2018-06-05 23:34:45 +0000120 return 1.0 / IssueWidth;
Andrea Di Biagioae5fb652018-05-31 13:30:42 +0000121
122 unsigned CPUID = getProcessorID();
123 while (SCDesc->isVariant()) {
124 SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, CPUID);
125 SCDesc = getSchedClassDesc(SchedClass);
126 }
127
128 if (SchedClass)
129 return MCSchedModel::getReciprocalThroughput(STI, *SCDesc);
130
131 llvm_unreachable("unsupported variant scheduling class");
132}
133
Sanjay Patel863443f2018-06-05 23:34:45 +0000134double
Andrea Di Biagiob5e23d12018-04-15 17:32:17 +0000135MCSchedModel::getReciprocalThroughput(unsigned SchedClass,
136 const InstrItineraryData &IID) {
137 Optional<double> Throughput;
138 const InstrStage *I = IID.beginStage(SchedClass);
139 const InstrStage *E = IID.endStage(SchedClass);
140 for (; I != E; ++I) {
141 if (!I->getCycles())
142 continue;
143 double Temp = countPopulation(I->getUnits()) * 1.0 / I->getCycles();
144 Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp;
145 }
Sanjay Patel863443f2018-06-05 23:34:45 +0000146 if (Throughput.hasValue())
147 return 1.0 / Throughput.getValue();
148
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;
Andrea Di Biagio0718ccc2018-03-13 16:28:55 +0000152}