blob: 8d0bb0f529d1463369d9bae509a718c30f1a4f1e [file] [log] [blame]
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +00001//===--------------------- Instruction.h ------------------------*- 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/// \file
10///
11/// This file defines abstractions used by the Backend to model register reads,
12/// register writes and instructions.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_TOOLS_LLVM_MCA_INSTRUCTION_H
17#define LLVM_TOOLS_LLVM_MCA_INSTRUCTION_H
18
19#include "llvm/Support/MathExtras.h"
20#include <memory>
21#include <set>
22#include <vector>
23
24namespace mca {
25
26struct WriteDescriptor;
27struct ReadDescriptor;
28class WriteState;
29class ReadState;
30
31constexpr int UNKNOWN_CYCLES = -512;
32
33/// \brief A register write descriptor.
34struct WriteDescriptor {
35 int OpIndex; // Operand index. -1 if this is an implicit write.
36 // Write latency. Number of cycles before write-back stage.
37 int Latency;
38 // This field is set to a value different than zero only if this
39 // is an implicit definition.
40 unsigned RegisterID;
41 // True if this write generates a partial update of a super-registers.
42 // On X86, this flag is set by byte/word writes on GPR registers. Also,
43 // a write of an XMM register only partially updates the corresponding
44 // YMM super-register if the write is associated to a legacy SSE instruction.
45 bool FullyUpdatesSuperRegs;
46 // Instruction itineraries would set this field to the SchedClass ID.
47 // Otherwise, it defaults to the WriteResourceID from teh MCWriteLatencyEntry
48 // element associated to this write.
49 // When computing read latencies, this value is matched against the
50 // "ReadAdvance" information. The hardware backend may implement
51 // dedicated forwarding paths to quickly propagate write results to dependent
52 // instructions waiting in the reservation station (effectively bypassing the
53 // write-back stage).
54 unsigned SClassOrWriteResourceID;
55 // True only if this is a write obtained from an optional definition.
56 // Optional definitions are allowed to reference regID zero (i.e. "no
57 // register").
58 bool IsOptionalDef;
59};
60
61/// \brief A register read descriptor.
62struct ReadDescriptor {
63 // This field defaults to -1 if this is an implicit read.
64 int OpIndex;
65 // This field is only set if this is an implicit read.
66 unsigned RegisterID;
67 // Scheduling Class Index. It is used to query the scheduling model for the
68 // MCSchedClassDesc object.
69 unsigned SchedClassID;
70 // True if there may be a local forwarding logic in hardware to serve a
71 // write used by this read. This information, along with SchedClassID, is
72 // used to dynamically check at Instruction creation time, if the input
73 // operands can benefit from a ReadAdvance bonus.
74 bool HasReadAdvanceEntries;
75};
76
77/// \brief Tracks uses of a register definition (e.g. register write).
78///
79/// Each implicit/explicit register write is associated with an instance of
80/// this class. A WriteState object tracks the dependent users of a
81/// register write. It also tracks how many cycles are left before the write
82/// back stage.
83class WriteState {
84 const WriteDescriptor &WD;
85 // On instruction issue, this field is set equal to the write latency.
86 // Before instruction issue, this field defaults to -512, a special
87 // value that represents an "unknown" number of cycles.
88 int CyclesLeft;
89
90 // Actual register defined by this write. This field is only used
91 // to speedup queries on the register file.
92 // For implicit writes, this field always matches the value of
93 // field RegisterID from WD.
94 unsigned RegisterID;
95
96 // A list of dependent reads. Users is a set of dependent
97 // reads. A dependent read is added to the set only if CyclesLeft
98 // is "unknown". As soon as CyclesLeft is 'known', each user in the set
99 // gets notified with the actual CyclesLeft.
100
101 // The 'second' element of a pair is a "ReadAdvance" number of cycles.
102 std::set<std::pair<ReadState *, int>> Users;
103
104public:
105 WriteState(const WriteDescriptor &Desc)
106 : WD(Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(Desc.RegisterID) {}
107 WriteState(const WriteState &Other) = delete;
108 WriteState &operator=(const WriteState &Other) = delete;
109
110 int getCyclesLeft() const { return CyclesLeft; }
111 unsigned getWriteResourceID() const { return WD.SClassOrWriteResourceID; }
112 unsigned getRegisterID() const { return RegisterID; }
113 void setRegisterID(unsigned ID) { RegisterID = ID; }
114
115 void addUser(ReadState *Use, int ReadAdvance);
116 bool fullyUpdatesSuperRegs() const { return WD.FullyUpdatesSuperRegs; }
117 bool isWrittenBack() const { return CyclesLeft == 0; }
118
119 // On every cycle, update CyclesLeft and notify dependent users.
120 void cycleEvent();
121 void onInstructionIssued();
122
123#ifndef NDEBUG
124 void dump() const;
125#endif
126};
127
128/// \brief Tracks register operand latency in cycles.
129///
130/// A read may be dependent on more than one write. This occurs when some
131/// writes only partially update the register associated to this read.
132class ReadState {
133 const ReadDescriptor &RD;
134 unsigned DependentWrites;
135 int CyclesLeft;
136 unsigned TotalCycles;
137
138public:
139 bool isReady() const {
140 if (DependentWrites)
141 return false;
142 return (CyclesLeft == UNKNOWN_CYCLES || CyclesLeft == 0);
143 }
144
145 ReadState(const ReadDescriptor &Desc)
146 : RD(Desc), DependentWrites(0), CyclesLeft(UNKNOWN_CYCLES),
147 TotalCycles(0) {}
148 ReadState(const ReadState &Other) = delete;
149 ReadState &operator=(const ReadState &Other) = delete;
150
151 const ReadDescriptor &getDescriptor() const { return RD; }
152 unsigned getSchedClass() const { return RD.SchedClassID; }
153 void cycleEvent();
154 void writeStartEvent(unsigned Cycles);
155 void setDependentWrites(unsigned Writes) { DependentWrites = Writes; }
156};
157
158/// \brief A sequence of cycles.
159///
160/// This class can be used as a building block to construct ranges of cycles.
161class CycleSegment {
162 unsigned Begin; // Inclusive.
163 unsigned End; // Exclusive.
164 bool Reserved; // Resources associated to this segment must be reserved.
165
166public:
167 CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
168 : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
169
170 bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
171 bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
172 bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
173 bool overlaps(const CycleSegment &CS) const {
174 return !startsAfter(CS) && !endsBefore(CS);
175 }
176 bool isExecuting() const { return Begin == 0 && End != 0; }
177 bool isExecuted() const { return End == 0; }
178 bool operator<(const CycleSegment &Other) const {
179 return Begin < Other.Begin;
180 }
181 CycleSegment &operator--(void) {
182 if (Begin)
183 Begin--;
184 if (End)
185 End--;
186 return *this;
187 }
188
189 bool isValid() const { return Begin <= End; }
190 unsigned size() const { return End - Begin; };
191 void Subtract(unsigned Cycles) {
192 assert(End >= Cycles);
193 End -= Cycles;
194 }
195
196 unsigned begin() const { return Begin; }
197 unsigned end() const { return End; }
198 void setEnd(unsigned NewEnd) { End = NewEnd; }
199 bool isReserved() const { return Reserved; }
200 void setReserved() { Reserved = true; }
201};
202
203/// \brief Helper used by class InstrDesc to describe how hardware resources
204/// are used.
205///
206/// This class describes how many resource units of a specific resource kind
207/// (and how many cycles) are "used" by an instruction.
208struct ResourceUsage {
209 CycleSegment CS;
210 unsigned NumUnits;
211 ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
212 : CS(Cycles), NumUnits(Units) {}
213 unsigned size() const { return CS.size(); }
214 bool isReserved() const { return CS.isReserved(); }
215 void setReserved() { CS.setReserved(); }
216};
217
218/// \brief An instruction descriptor
219struct InstrDesc {
220 std::vector<WriteDescriptor> Writes; // Implicit writes are at the end.
221 std::vector<ReadDescriptor> Reads; // Implicit reads are at the end.
222
223 // For every resource used by an instruction of this kind, this vector
224 // reports the number of "consumed cycles".
225 std::vector<std::pair<uint64_t, ResourceUsage>> Resources;
226
227 // A list of buffered resources consumed by this instruction.
228 std::vector<uint64_t> Buffers;
229 unsigned MaxLatency;
230 // Number of MicroOps for this instruction.
231 unsigned NumMicroOps;
232
233 bool MayLoad;
234 bool MayStore;
235 bool HasSideEffects;
236};
237
238/// An instruction dispatched to the out-of-order backend.
239///
240/// This class is used to monitor changes in the internal state of instructions
241/// that are dispatched by the DispatchUnit to the hardware schedulers.
242class Instruction {
243 const InstrDesc &Desc;
244
245 enum InstrStage {
246 IS_INVALID, // Instruction in an invalid state.
247 IS_AVAILABLE, // Instruction dispatched but operands are not ready.
248 IS_READY, // Instruction dispatched and operands ready.
249 IS_EXECUTING, // Instruction issued.
250 IS_EXECUTED, // Instruction executed. Values are written back.
251 IS_RETIRED // Instruction retired.
252 };
253
254 // The current instruction stage.
255 enum InstrStage Stage;
256
257 // This value defaults to the instruction latency. This instruction is
258 // considered executed when field CyclesLeft goes to zero.
259 int CyclesLeft;
260
261 // Retire Unit token ID for this instruction.
262 unsigned RCUTokenID;
263
264 using UniqueDef = std::unique_ptr<WriteState>;
265 using UniqueUse = std::unique_ptr<ReadState>;
266 using VecDefs = std::vector<UniqueDef>;
267 using VecUses = std::vector<UniqueUse>;
268
269 // Output dependencies.
270 // One entry per each implicit and explicit register definition.
271 VecDefs Defs;
272
273 // Input dependencies.
274 // One entry per each implicit and explicit register use.
275 VecUses Uses;
276
277 // This instruction has already been dispatched, and all operands are ready.
278 void setReady() {
279 assert(Stage == IS_AVAILABLE);
280 Stage = IS_READY;
281 }
282
283public:
284 Instruction(const InstrDesc &D)
285 : Desc(D), Stage(IS_INVALID), CyclesLeft(-1) {}
286 Instruction(const Instruction &Other) = delete;
287 Instruction &operator=(const Instruction &Other) = delete;
288
289 VecDefs &getDefs() { return Defs; }
290 const VecDefs &getDefs() const { return Defs; }
291 VecUses &getUses() { return Uses; }
292 const VecUses &getUses() const { return Uses; }
293 const InstrDesc &getDesc() const { return Desc; }
294
295 unsigned getRCUTokenID() const { return RCUTokenID; }
296 int getCyclesLeft() const { return CyclesLeft; }
297 void setCyclesLeft(int Cycles) { CyclesLeft = Cycles; }
298 void setRCUTokenID(unsigned TokenID) { RCUTokenID = TokenID; }
299
300 // Transition to the dispatch stage.
301 // No definition is updated because the instruction is not "executing".
302 void dispatch() {
303 assert(Stage == IS_INVALID);
304 Stage = IS_AVAILABLE;
305 }
306
307 // Instruction issued. Transition to the IS_EXECUTING state, and update
308 // all the definitions.
309 void execute();
310
311 void forceExecuted() {
312 assert((Stage == IS_INVALID && isZeroLatency()) ||
313 (Stage == IS_READY && Desc.MaxLatency == 0));
314 Stage = IS_EXECUTED;
315 }
316
317 // Checks if operands are available. If all operands area ready,
318 // then this forces a transition from IS_AVAILABLE to IS_READY.
319 bool isReady();
320
321 bool isDispatched() const { return Stage == IS_AVAILABLE; }
322 bool isExecuting() const { return Stage == IS_EXECUTING; }
323 bool isExecuted() const { return Stage == IS_EXECUTED; }
324 bool isZeroLatency() const;
325
326 void retire() {
327 assert(Stage == IS_EXECUTED);
328 Stage = IS_RETIRED;
329 }
330
331 void cycleEvent();
332};
333
334} // namespace mca
335
336#endif