blob: a87420df8c9e7c1d41aeb848d6c01cb08cc5559e [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:
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000105 WriteState(const WriteDescriptor &Desc, unsigned RegID)
106 : WD(Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID) {}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000107 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;
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000134 unsigned RegisterID;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000135 unsigned DependentWrites;
136 int CyclesLeft;
137 unsigned TotalCycles;
138
139public:
140 bool isReady() const {
141 if (DependentWrites)
142 return false;
143 return (CyclesLeft == UNKNOWN_CYCLES || CyclesLeft == 0);
144 }
145
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000146 ReadState(const ReadDescriptor &Desc, unsigned RegID)
147 : RD(Desc), RegisterID(RegID), DependentWrites(0),
148 CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0) {}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000149 ReadState(const ReadState &Other) = delete;
150 ReadState &operator=(const ReadState &Other) = delete;
151
152 const ReadDescriptor &getDescriptor() const { return RD; }
153 unsigned getSchedClass() const { return RD.SchedClassID; }
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000154 unsigned getRegisterID() const { return RegisterID; }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000155 void cycleEvent();
156 void writeStartEvent(unsigned Cycles);
157 void setDependentWrites(unsigned Writes) { DependentWrites = Writes; }
158};
159
160/// \brief A sequence of cycles.
161///
162/// This class can be used as a building block to construct ranges of cycles.
163class CycleSegment {
164 unsigned Begin; // Inclusive.
165 unsigned End; // Exclusive.
166 bool Reserved; // Resources associated to this segment must be reserved.
167
168public:
169 CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
170 : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
171
172 bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
173 bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
174 bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
175 bool overlaps(const CycleSegment &CS) const {
176 return !startsAfter(CS) && !endsBefore(CS);
177 }
178 bool isExecuting() const { return Begin == 0 && End != 0; }
179 bool isExecuted() const { return End == 0; }
180 bool operator<(const CycleSegment &Other) const {
181 return Begin < Other.Begin;
182 }
183 CycleSegment &operator--(void) {
184 if (Begin)
185 Begin--;
186 if (End)
187 End--;
188 return *this;
189 }
190
191 bool isValid() const { return Begin <= End; }
192 unsigned size() const { return End - Begin; };
193 void Subtract(unsigned Cycles) {
194 assert(End >= Cycles);
195 End -= Cycles;
196 }
197
198 unsigned begin() const { return Begin; }
199 unsigned end() const { return End; }
200 void setEnd(unsigned NewEnd) { End = NewEnd; }
201 bool isReserved() const { return Reserved; }
202 void setReserved() { Reserved = true; }
203};
204
205/// \brief Helper used by class InstrDesc to describe how hardware resources
206/// are used.
207///
208/// This class describes how many resource units of a specific resource kind
209/// (and how many cycles) are "used" by an instruction.
210struct ResourceUsage {
211 CycleSegment CS;
212 unsigned NumUnits;
213 ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
214 : CS(Cycles), NumUnits(Units) {}
215 unsigned size() const { return CS.size(); }
216 bool isReserved() const { return CS.isReserved(); }
217 void setReserved() { CS.setReserved(); }
218};
219
220/// \brief An instruction descriptor
221struct InstrDesc {
222 std::vector<WriteDescriptor> Writes; // Implicit writes are at the end.
223 std::vector<ReadDescriptor> Reads; // Implicit reads are at the end.
224
225 // For every resource used by an instruction of this kind, this vector
226 // reports the number of "consumed cycles".
227 std::vector<std::pair<uint64_t, ResourceUsage>> Resources;
228
229 // A list of buffered resources consumed by this instruction.
230 std::vector<uint64_t> Buffers;
231 unsigned MaxLatency;
232 // Number of MicroOps for this instruction.
233 unsigned NumMicroOps;
234
235 bool MayLoad;
236 bool MayStore;
237 bool HasSideEffects;
238};
239
240/// An instruction dispatched to the out-of-order backend.
241///
242/// This class is used to monitor changes in the internal state of instructions
243/// that are dispatched by the DispatchUnit to the hardware schedulers.
244class Instruction {
245 const InstrDesc &Desc;
246
247 enum InstrStage {
248 IS_INVALID, // Instruction in an invalid state.
249 IS_AVAILABLE, // Instruction dispatched but operands are not ready.
250 IS_READY, // Instruction dispatched and operands ready.
251 IS_EXECUTING, // Instruction issued.
252 IS_EXECUTED, // Instruction executed. Values are written back.
253 IS_RETIRED // Instruction retired.
254 };
255
256 // The current instruction stage.
257 enum InstrStage Stage;
258
259 // This value defaults to the instruction latency. This instruction is
260 // considered executed when field CyclesLeft goes to zero.
261 int CyclesLeft;
262
263 // Retire Unit token ID for this instruction.
264 unsigned RCUTokenID;
265
266 using UniqueDef = std::unique_ptr<WriteState>;
267 using UniqueUse = std::unique_ptr<ReadState>;
268 using VecDefs = std::vector<UniqueDef>;
269 using VecUses = std::vector<UniqueUse>;
270
271 // Output dependencies.
272 // One entry per each implicit and explicit register definition.
273 VecDefs Defs;
274
275 // Input dependencies.
276 // One entry per each implicit and explicit register use.
277 VecUses Uses;
278
279 // This instruction has already been dispatched, and all operands are ready.
280 void setReady() {
281 assert(Stage == IS_AVAILABLE);
282 Stage = IS_READY;
283 }
284
285public:
286 Instruction(const InstrDesc &D)
287 : Desc(D), Stage(IS_INVALID), CyclesLeft(-1) {}
288 Instruction(const Instruction &Other) = delete;
289 Instruction &operator=(const Instruction &Other) = delete;
290
291 VecDefs &getDefs() { return Defs; }
292 const VecDefs &getDefs() const { return Defs; }
293 VecUses &getUses() { return Uses; }
294 const VecUses &getUses() const { return Uses; }
295 const InstrDesc &getDesc() const { return Desc; }
296
297 unsigned getRCUTokenID() const { return RCUTokenID; }
298 int getCyclesLeft() const { return CyclesLeft; }
299 void setCyclesLeft(int Cycles) { CyclesLeft = Cycles; }
300 void setRCUTokenID(unsigned TokenID) { RCUTokenID = TokenID; }
301
302 // Transition to the dispatch stage.
303 // No definition is updated because the instruction is not "executing".
304 void dispatch() {
305 assert(Stage == IS_INVALID);
306 Stage = IS_AVAILABLE;
307 }
308
309 // Instruction issued. Transition to the IS_EXECUTING state, and update
310 // all the definitions.
311 void execute();
312
313 void forceExecuted() {
314 assert((Stage == IS_INVALID && isZeroLatency()) ||
315 (Stage == IS_READY && Desc.MaxLatency == 0));
316 Stage = IS_EXECUTED;
317 }
318
319 // Checks if operands are available. If all operands area ready,
320 // then this forces a transition from IS_AVAILABLE to IS_READY.
321 bool isReady();
322
323 bool isDispatched() const { return Stage == IS_AVAILABLE; }
324 bool isExecuting() const { return Stage == IS_EXECUTING; }
325 bool isExecuted() const { return Stage == IS_EXECUTED; }
326 bool isZeroLatency() const;
327
328 void retire() {
329 assert(Stage == IS_EXECUTED);
330 Stage = IS_RETIRED;
331 }
332
333 void cycleEvent();
334};
335
336} // namespace mca
337
338#endif