blob: a4dd753975c2a0adaa7e802b9efbabd4d8843184 [file] [log] [blame]
Eugene Zelenkofa912a72017-02-27 22:45:06 +00001//===- llvm/Target/TargetSchedule.cpp - Sched Machine Model ---------------===//
Andrew Trickd2a19da2012-09-14 20:26:46 +00002//
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 implements a wrapper around MCSchedModel that allows the interface
11// to benefit from information currently only available in TargetInstrInfo.
12//
13//===----------------------------------------------------------------------===//
14
Eugene Zelenkofa912a72017-02-27 22:45:06 +000015#include "llvm/CodeGen/MachineFunction.h"
16#include "llvm/CodeGen/MachineInstr.h"
17#include "llvm/CodeGen/MachineOperand.h"
Andrew Trickd2a19da2012-09-14 20:26:46 +000018#include "llvm/CodeGen/TargetSchedule.h"
Eugene Zelenkofa912a72017-02-27 22:45:06 +000019#include "llvm/MC/MCInstrDesc.h"
20#include "llvm/MC/MCInstrItineraries.h"
21#include "llvm/MC/MCSchedule.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000022#include "llvm/Support/CommandLine.h"
Eugene Zelenkofa912a72017-02-27 22:45:06 +000023#include "llvm/Support/ErrorHandling.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000024#include "llvm/Support/raw_ostream.h"
Andrew Trickd2a19da2012-09-14 20:26:46 +000025#include "llvm/Target/TargetInstrInfo.h"
Andrew Trick6e6d5972012-09-18 04:03:34 +000026#include "llvm/Target/TargetRegisterInfo.h"
Andrew Trickd2a19da2012-09-14 20:26:46 +000027#include "llvm/Target/TargetSubtargetInfo.h"
Eugene Zelenkofa912a72017-02-27 22:45:06 +000028#include <algorithm>
29#include <cassert>
30#include <cstdint>
Andrew Trickd2a19da2012-09-14 20:26:46 +000031
32using namespace llvm;
33
Andrew Trick8abcf4d2012-10-04 00:24:34 +000034static cl::opt<bool> EnableSchedModel("schedmodel", cl::Hidden, cl::init(true),
Andrew Trickd2a19da2012-09-14 20:26:46 +000035 cl::desc("Use TargetSchedModel for latency lookup"));
36
Andrew Trick6e6d5972012-09-18 04:03:34 +000037static cl::opt<bool> EnableSchedItins("scheditins", cl::Hidden, cl::init(true),
38 cl::desc("Use InstrItineraryData for latency lookup"));
39
Andrew Trickcfcf5202012-10-09 23:44:26 +000040bool TargetSchedModel::hasInstrSchedModel() const {
41 return EnableSchedModel && SchedModel.hasInstrSchedModel();
42}
43
44bool TargetSchedModel::hasInstrItineraries() const {
45 return EnableSchedItins && !InstrItins.isEmpty();
46}
47
Andrew Tricke96390e2012-11-06 07:10:38 +000048static unsigned gcd(unsigned Dividend, unsigned Divisor) {
49 // Dividend and Divisor will be naturally swapped as needed.
Eugene Zelenkofa912a72017-02-27 22:45:06 +000050 while (Divisor) {
Andrew Tricke96390e2012-11-06 07:10:38 +000051 unsigned Rem = Dividend % Divisor;
52 Dividend = Divisor;
53 Divisor = Rem;
54 };
55 return Dividend;
56}
Eugene Zelenkofa912a72017-02-27 22:45:06 +000057
Andrew Tricke96390e2012-11-06 07:10:38 +000058static unsigned lcm(unsigned A, unsigned B) {
59 unsigned LCM = (uint64_t(A) * B) / gcd(A, B);
60 assert((LCM >= A && LCM >= B) && "LCM overflow");
61 return LCM;
62}
63
Andrew Trickd2a19da2012-09-14 20:26:46 +000064void TargetSchedModel::init(const MCSchedModel &sm,
65 const TargetSubtargetInfo *sti,
66 const TargetInstrInfo *tii) {
67 SchedModel = sm;
68 STI = sti;
69 TII = tii;
70 STI->initInstrItins(InstrItins);
Andrew Tricke96390e2012-11-06 07:10:38 +000071
72 unsigned NumRes = SchedModel.getNumProcResourceKinds();
73 ResourceFactors.resize(NumRes);
74 ResourceLCM = SchedModel.IssueWidth;
75 for (unsigned Idx = 0; Idx < NumRes; ++Idx) {
76 unsigned NumUnits = SchedModel.getProcResource(Idx)->NumUnits;
77 if (NumUnits > 0)
78 ResourceLCM = lcm(ResourceLCM, NumUnits);
79 }
80 MicroOpFactor = ResourceLCM / SchedModel.IssueWidth;
81 for (unsigned Idx = 0; Idx < NumRes; ++Idx) {
82 unsigned NumUnits = SchedModel.getProcResource(Idx)->NumUnits;
83 ResourceFactors[Idx] = NumUnits ? (ResourceLCM / NumUnits) : 0;
84 }
Andrew Trickd2a19da2012-09-14 20:26:46 +000085}
Andrew Trick6e6d5972012-09-18 04:03:34 +000086
Andrew Tricke96390e2012-11-06 07:10:38 +000087unsigned TargetSchedModel::getNumMicroOps(const MachineInstr *MI,
88 const MCSchedClassDesc *SC) const {
Andrew Trickdd79f0f2012-10-10 05:43:09 +000089 if (hasInstrItineraries()) {
90 int UOps = InstrItins.getNumMicroOps(MI->getDesc().getSchedClass());
Duncan P. N. Exon Smith9cfc75c2016-06-30 00:01:54 +000091 return (UOps >= 0) ? UOps : TII->getNumMicroOps(&InstrItins, *MI);
Andrew Trickdd79f0f2012-10-10 05:43:09 +000092 }
Andrew Trick5f35afb2012-10-11 05:37:06 +000093 if (hasInstrSchedModel()) {
Andrew Tricke96390e2012-11-06 07:10:38 +000094 if (!SC)
95 SC = resolveSchedClass(MI);
96 if (SC->isValid())
97 return SC->NumMicroOps;
Andrew Trick5f35afb2012-10-11 05:37:06 +000098 }
99 return MI->isTransient() ? 0 : 1;
Andrew Trickdd79f0f2012-10-10 05:43:09 +0000100}
101
Andrew Trick0b1d8d02012-10-17 17:27:10 +0000102// The machine model may explicitly specify an invalid latency, which
103// effectively means infinite latency. Since users of the TargetSchedule API
104// don't know how to handle this, we convert it to a very large latency that is
105// easy to distinguish when debugging the DAG but won't induce overflow.
Andrew Trickde2109e2013-06-15 04:49:57 +0000106static unsigned capLatency(int Cycles) {
Andrew Trick0b1d8d02012-10-17 17:27:10 +0000107 return Cycles >= 0 ? Cycles : 1000;
108}
109
Andrew Trick6e6d5972012-09-18 04:03:34 +0000110/// Return the MCSchedClassDesc for this instruction. Some SchedClasses require
111/// evaluation of predicates that depend on instruction operands or flags.
112const MCSchedClassDesc *TargetSchedModel::
113resolveSchedClass(const MachineInstr *MI) const {
Andrew Trick6e6d5972012-09-18 04:03:34 +0000114 // Get the definition's scheduling class descriptor from this machine model.
115 unsigned SchedClass = MI->getDesc().getSchedClass();
116 const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SchedClass);
Andrew Trickbe2bccb2013-04-13 06:07:45 +0000117 if (!SCDesc->isValid())
118 return SCDesc;
Andrew Trick6e6d5972012-09-18 04:03:34 +0000119
120#ifndef NDEBUG
121 unsigned NIter = 0;
122#endif
123 while (SCDesc->isVariant()) {
124 assert(++NIter < 6 && "Variants are nested deeper than the magic number");
125
126 SchedClass = STI->resolveSchedClass(SchedClass, MI, this);
127 SCDesc = SchedModel.getSchedClassDesc(SchedClass);
128 }
129 return SCDesc;
130}
131
132/// Find the def index of this operand. This index maps to the machine model and
133/// is independent of use operands. Def operands may be reordered with uses or
134/// merged with uses without affecting the def index (e.g. before/after
135/// regalloc). However, an instruction's def operands must never be reordered
136/// with respect to each other.
137static unsigned findDefIdx(const MachineInstr *MI, unsigned DefOperIdx) {
138 unsigned DefIdx = 0;
139 for (unsigned i = 0; i != DefOperIdx; ++i) {
140 const MachineOperand &MO = MI->getOperand(i);
141 if (MO.isReg() && MO.isDef())
142 ++DefIdx;
143 }
144 return DefIdx;
145}
146
147/// Find the use index of this operand. This is independent of the instruction's
148/// def operands.
Andrew Trickf2b70d92012-09-18 18:20:02 +0000149///
150/// Note that uses are not determined by the operand's isUse property, which
151/// is simply the inverse of isDef. Here we consider any readsReg operand to be
152/// a "use". The machine model allows an operand to be both a Def and Use.
Andrew Trick6e6d5972012-09-18 04:03:34 +0000153static unsigned findUseIdx(const MachineInstr *MI, unsigned UseOperIdx) {
154 unsigned UseIdx = 0;
155 for (unsigned i = 0; i != UseOperIdx; ++i) {
156 const MachineOperand &MO = MI->getOperand(i);
Matthias Braun3a133152016-08-24 02:32:29 +0000157 if (MO.isReg() && MO.readsReg() && !MO.isDef())
Andrew Trick6e6d5972012-09-18 04:03:34 +0000158 ++UseIdx;
159 }
160 return UseIdx;
161}
162
163// Top-level API for clients that know the operand indices.
164unsigned TargetSchedModel::computeOperandLatency(
165 const MachineInstr *DefMI, unsigned DefOperIdx,
Andrew Trickde2109e2013-06-15 04:49:57 +0000166 const MachineInstr *UseMI, unsigned UseOperIdx) const {
Andrew Trick6e6d5972012-09-18 04:03:34 +0000167
Andrew Trickde2109e2013-06-15 04:49:57 +0000168 if (!hasInstrSchedModel() && !hasInstrItineraries())
Duncan P. N. Exon Smith9cfc75c2016-06-30 00:01:54 +0000169 return TII->defaultDefLatency(SchedModel, *DefMI);
Andrew Trick6e6d5972012-09-18 04:03:34 +0000170
Andrew Trickcfcf5202012-10-09 23:44:26 +0000171 if (hasInstrItineraries()) {
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000172 int OperLatency = 0;
173 if (UseMI) {
Duncan P. N. Exon Smith9cfc75c2016-06-30 00:01:54 +0000174 OperLatency = TII->getOperandLatency(&InstrItins, *DefMI, DefOperIdx,
175 *UseMI, UseOperIdx);
Andrew Trick6e6d5972012-09-18 04:03:34 +0000176 }
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000177 else {
178 unsigned DefClass = DefMI->getDesc().getSchedClass();
179 OperLatency = InstrItins.getOperandCycle(DefClass, DefOperIdx);
180 }
181 if (OperLatency >= 0)
182 return OperLatency;
183
184 // No operand latency was found.
Duncan P. N. Exon Smith9cfc75c2016-06-30 00:01:54 +0000185 unsigned InstrLatency = TII->getInstrLatency(&InstrItins, *DefMI);
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000186
187 // Expected latency is the max of the stage latency and itinerary props.
Andrew Trick780fae82012-10-09 23:44:32 +0000188 // Rather than directly querying InstrItins stage latency, we call a TII
189 // hook to allow subtargets to specialize latency. This hook is only
190 // applicable to the InstrItins model. InstrSchedModel should model all
191 // special cases without TII hooks.
Duncan P. N. Exon Smith9cfc75c2016-06-30 00:01:54 +0000192 InstrLatency =
193 std::max(InstrLatency, TII->defaultDefLatency(SchedModel, *DefMI));
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000194 return InstrLatency;
195 }
Andrew Trickde2109e2013-06-15 04:49:57 +0000196 // hasInstrSchedModel()
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000197 const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI);
198 unsigned DefIdx = findDefIdx(DefMI, DefOperIdx);
199 if (DefIdx < SCDesc->NumWriteLatencyEntries) {
200 // Lookup the definition's write latency in SubtargetInfo.
201 const MCWriteLatencyEntry *WLEntry =
202 STI->getWriteLatencyEntry(SCDesc, DefIdx);
203 unsigned WriteID = WLEntry->WriteResourceID;
Andrew Trickde2109e2013-06-15 04:49:57 +0000204 unsigned Latency = capLatency(WLEntry->Cycles);
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000205 if (!UseMI)
206 return Latency;
207
208 // Lookup the use's latency adjustment in SubtargetInfo.
209 const MCSchedClassDesc *UseDesc = resolveSchedClass(UseMI);
210 if (UseDesc->NumReadAdvanceEntries == 0)
211 return Latency;
212 unsigned UseIdx = findUseIdx(UseMI, UseOperIdx);
Andrew Trick5d4861862013-06-17 21:45:18 +0000213 int Advance = STI->getReadAdvanceCycles(UseDesc, UseIdx, WriteID);
214 if (Advance > 0 && (unsigned)Advance > Latency) // unsigned wrap
215 return 0;
216 return Latency - Advance;
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000217 }
218 // If DefIdx does not exist in the model (e.g. implicit defs), then return
219 // unit latency (defaultDefLatency may be too conservative).
Andrew Trickf2b70d92012-09-18 18:20:02 +0000220#ifndef NDEBUG
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000221 if (SCDesc->isValid() && !DefMI->getOperand(DefOperIdx).isImplicit()
Andrew Trickb6854d82013-09-25 18:14:12 +0000222 && !DefMI->getDesc().OpInfo[DefOperIdx].isOptionalDef()
223 && SchedModel.isComplete()) {
Matthias Braun244a6772015-07-17 17:50:11 +0000224 errs() << "DefIdx " << DefIdx << " exceeds machine model writes for "
MinSeong Kim4a9a4e12016-01-05 14:50:15 +0000225 << *DefMI << " (Try with MCSchedModel.CompleteModel set to false)";
Matthias Braun244a6772015-07-17 17:50:11 +0000226 llvm_unreachable("incomplete machine model");
Andrew Trick8abcf4d2012-10-04 00:24:34 +0000227 }
Andrew Trickf2b70d92012-09-18 18:20:02 +0000228#endif
Andrew Trick60570172013-03-16 18:58:57 +0000229 // FIXME: Automatically giving all implicit defs defaultDefLatency is
230 // undesirable. We should only do it for defs that are known to the MC
231 // desc like flags. Truly implicit defs should get 1 cycle latency.
Duncan P. N. Exon Smith9cfc75c2016-06-30 00:01:54 +0000232 return DefMI->isTransient() ? 0 : TII->defaultDefLatency(SchedModel, *DefMI);
Andrew Trick6e6d5972012-09-18 04:03:34 +0000233}
Andrew Trick780fae82012-10-09 23:44:32 +0000234
Matthias Braun42e1e662015-05-14 18:01:13 +0000235unsigned
236TargetSchedModel::computeInstrLatency(const MCSchedClassDesc &SCDesc) const {
237 unsigned Latency = 0;
238 for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries;
239 DefIdx != DefEnd; ++DefIdx) {
240 // Lookup the definition's write latency in SubtargetInfo.
241 const MCWriteLatencyEntry *WLEntry =
242 STI->getWriteLatencyEntry(&SCDesc, DefIdx);
243 Latency = std::max(Latency, capLatency(WLEntry->Cycles));
244 }
245 return Latency;
246}
247
Gerolf Hoflehner5e1207e2014-08-03 21:35:39 +0000248unsigned TargetSchedModel::computeInstrLatency(unsigned Opcode) const {
249 assert(hasInstrSchedModel() && "Only call this function with a SchedModel");
250
251 unsigned SCIdx = TII->get(Opcode).getSchedClass();
252 const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SCIdx);
Gerolf Hoflehner5e1207e2014-08-03 21:35:39 +0000253
Matthias Braun42e1e662015-05-14 18:01:13 +0000254 if (SCDesc->isValid() && !SCDesc->isVariant())
255 return computeInstrLatency(*SCDesc);
Gerolf Hoflehner5e1207e2014-08-03 21:35:39 +0000256
Matthias Braun7a247f72015-05-14 18:33:29 +0000257 llvm_unreachable("No MI sched latency");
Gerolf Hoflehner5e1207e2014-08-03 21:35:39 +0000258}
259
Arnold Schwaighoferd2f96b92013-09-30 15:28:56 +0000260unsigned
261TargetSchedModel::computeInstrLatency(const MachineInstr *MI,
262 bool UseDefaultDefLatency) const {
Andrew Trickc334bd42012-10-10 05:43:18 +0000263 // For the itinerary model, fall back to the old subtarget hook.
264 // Allow subtargets to compute Bundle latencies outside the machine model.
Arnold Schwaighoferd2f96b92013-09-30 15:28:56 +0000265 if (hasInstrItineraries() || MI->isBundle() ||
266 (!hasInstrSchedModel() && !UseDefaultDefLatency))
Duncan P. N. Exon Smith9cfc75c2016-06-30 00:01:54 +0000267 return TII->getInstrLatency(&InstrItins, *MI);
Andrew Trickc334bd42012-10-10 05:43:18 +0000268
Andrew Trick780fae82012-10-09 23:44:32 +0000269 if (hasInstrSchedModel()) {
Andrew Trick780fae82012-10-09 23:44:32 +0000270 const MCSchedClassDesc *SCDesc = resolveSchedClass(MI);
Matthias Braun42e1e662015-05-14 18:01:13 +0000271 if (SCDesc->isValid())
272 return computeInstrLatency(*SCDesc);
Andrew Trick780fae82012-10-09 23:44:32 +0000273 }
Duncan P. N. Exon Smith9cfc75c2016-06-30 00:01:54 +0000274 return TII->defaultDefLatency(SchedModel, *MI);
Andrew Trick780fae82012-10-09 23:44:32 +0000275}
Andrew Trickdd79f0f2012-10-10 05:43:09 +0000276
277unsigned TargetSchedModel::
278computeOutputLatency(const MachineInstr *DefMI, unsigned DefOperIdx,
279 const MachineInstr *DepMI) const {
Junmo Park11811922016-06-21 08:09:58 +0000280 if (!SchedModel.isOutOfOrder())
Andrew Trickdd79f0f2012-10-10 05:43:09 +0000281 return 1;
282
Junmo Park11811922016-06-21 08:09:58 +0000283 // Out-of-order processor can dispatch WAW dependencies in the same cycle.
Andrew Trickdd79f0f2012-10-10 05:43:09 +0000284
285 // Treat predication as a data dependency for out-of-order cpus. In-order
286 // cpus do not need to treat predicated writes specially.
287 //
288 // TODO: The following hack exists because predication passes do not
289 // correctly append imp-use operands, and readsReg() strangely returns false
290 // for predicated defs.
291 unsigned Reg = DefMI->getOperand(DefOperIdx).getReg();
292 const MachineFunction &MF = *DefMI->getParent()->getParent();
Eric Christopherfc6de422014-08-05 02:39:49 +0000293 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
Duncan P. N. Exon Smith6307eb52016-02-23 02:46:52 +0000294 if (!DepMI->readsRegister(Reg, TRI) && TII->isPredicated(*DepMI))
Andrew Trickdd79f0f2012-10-10 05:43:09 +0000295 return computeInstrLatency(DefMI);
296
297 // If we have a per operand scheduling model, check if this def is writing
298 // an unbuffered resource. If so, it treated like an in-order cpu.
299 if (hasInstrSchedModel()) {
300 const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI);
Andrew Trick5f35afb2012-10-11 05:37:06 +0000301 if (SCDesc->isValid()) {
302 for (const MCWriteProcResEntry *PRI = STI->getWriteProcResBegin(SCDesc),
303 *PRE = STI->getWriteProcResEnd(SCDesc); PRI != PRE; ++PRI) {
Andrew Trickde2109e2013-06-15 04:49:57 +0000304 if (!SchedModel.getProcResource(PRI->ProcResourceIdx)->BufferSize)
Andrew Trick5f35afb2012-10-11 05:37:06 +0000305 return 1;
306 }
Andrew Trickdd79f0f2012-10-10 05:43:09 +0000307 }
308 }
309 return 0;
310}