blob: 658b7fe4f891c6e6ad9a291b3daea1a90fa7b0c2 [file] [log] [blame]
Andrew Walbran16937d02019-10-22 13:54:20 +01001//===--------------------- Instruction.h ------------------------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8/// \file
9///
10/// This file defines abstractions used by the Pipeline to model register reads,
11/// register writes and instructions.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_MCA_INSTRUCTION_H
16#define LLVM_MCA_INSTRUCTION_H
17
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/SmallVector.h"
21#include "llvm/Support/MathExtras.h"
22
23#ifndef NDEBUG
24#include "llvm/Support/raw_ostream.h"
25#endif
26
27#include <memory>
28
29namespace llvm {
30
31namespace mca {
32
33constexpr int UNKNOWN_CYCLES = -512;
34
35/// A register write descriptor.
36struct WriteDescriptor {
37 // Operand index. The index is negative for implicit writes only.
38 // For implicit writes, the actual operand index is computed performing
39 // a bitwise not of the OpIndex.
40 int OpIndex;
41 // Write latency. Number of cycles before write-back stage.
42 unsigned Latency;
43 // This field is set to a value different than zero only if this
44 // is an implicit definition.
45 unsigned RegisterID;
46 // Instruction itineraries would set this field to the SchedClass ID.
47 // Otherwise, it defaults to the WriteResourceID from the 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 bool isImplicitWrite() const { return OpIndex < 0; };
61};
62
63/// A register read descriptor.
64struct ReadDescriptor {
65 // A MCOperand index. This is used by the Dispatch logic to identify register
66 // reads. Implicit reads have negative indices. The actual operand index of an
67 // implicit read is the bitwise not of field OpIndex.
68 int OpIndex;
69 // The actual "UseIdx". This is used to query the ReadAdvance table. Explicit
70 // uses always come first in the sequence of uses.
71 unsigned UseIndex;
72 // This field is only set if this is an implicit read.
73 unsigned RegisterID;
74 // Scheduling Class Index. It is used to query the scheduling model for the
75 // MCSchedClassDesc object.
76 unsigned SchedClassID;
77
78 bool isImplicitRead() const { return OpIndex < 0; };
79};
80
81class ReadState;
82
83/// Tracks uses of a register definition (e.g. register write).
84///
85/// Each implicit/explicit register write is associated with an instance of
86/// this class. A WriteState object tracks the dependent users of a
87/// register write. It also tracks how many cycles are left before the write
88/// back stage.
89class WriteState {
90 const WriteDescriptor *WD;
91 // On instruction issue, this field is set equal to the write latency.
92 // Before instruction issue, this field defaults to -512, a special
93 // value that represents an "unknown" number of cycles.
94 int CyclesLeft;
95
96 // Actual register defined by this write. This field is only used
97 // to speedup queries on the register file.
98 // For implicit writes, this field always matches the value of
99 // field RegisterID from WD.
100 unsigned RegisterID;
101
102 // Physical register file that serves register RegisterID.
103 unsigned PRFID;
104
105 // True if this write implicitly clears the upper portion of RegisterID's
106 // super-registers.
107 bool ClearsSuperRegs;
108
109 // True if this write is from a dependency breaking zero-idiom instruction.
110 bool WritesZero;
111
112 // True if this write has been eliminated at register renaming stage.
113 // Example: a register move doesn't consume scheduler/pipleline resources if
114 // it is eliminated at register renaming stage. It still consumes
115 // decode bandwidth, and ROB entries.
116 bool IsEliminated;
117
118 // This field is set if this is a partial register write, and it has a false
119 // dependency on any previous write of the same register (or a portion of it).
120 // DependentWrite must be able to complete before this write completes, so
121 // that we don't break the WAW, and the two writes can be merged together.
122 const WriteState *DependentWrite;
123
124 // A partial write that is in a false dependency with this write.
125 WriteState *PartialWrite;
126
127 unsigned DependentWriteCyclesLeft;
128
129 // A list of dependent reads. Users is a set of dependent
130 // reads. A dependent read is added to the set only if CyclesLeft
131 // is "unknown". As soon as CyclesLeft is 'known', each user in the set
132 // gets notified with the actual CyclesLeft.
133
134 // The 'second' element of a pair is a "ReadAdvance" number of cycles.
135 SmallVector<std::pair<ReadState *, int>, 4> Users;
136
137public:
138 WriteState(const WriteDescriptor &Desc, unsigned RegID,
139 bool clearsSuperRegs = false, bool writesZero = false)
140 : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
141 ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
142 IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
143 DependentWriteCyclesLeft(0) {}
144
145 WriteState(const WriteState &Other) = default;
146 WriteState &operator=(const WriteState &Other) = default;
147
148 int getCyclesLeft() const { return CyclesLeft; }
149 unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; }
150 unsigned getRegisterID() const { return RegisterID; }
151 unsigned getRegisterFileID() const { return PRFID; }
152 unsigned getLatency() const { return WD->Latency; }
153
154 void addUser(ReadState *Use, int ReadAdvance);
155 void addUser(WriteState *Use);
156
157 unsigned getDependentWriteCyclesLeft() const {
158 return DependentWriteCyclesLeft;
159 }
160
161 unsigned getNumUsers() const {
162 unsigned NumUsers = Users.size();
163 if (PartialWrite)
164 ++NumUsers;
165 return NumUsers;
166 }
167
168 bool clearsSuperRegisters() const { return ClearsSuperRegs; }
169 bool isWriteZero() const { return WritesZero; }
170 bool isEliminated() const { return IsEliminated; }
171
172 bool isReady() const {
173 if (getDependentWrite())
174 return false;
175 unsigned CyclesLeft = getDependentWriteCyclesLeft();
176 return !CyclesLeft || CyclesLeft < getLatency();
177 }
178
179 bool isExecuted() const {
180 return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0;
181 }
182
183 const WriteState *getDependentWrite() const { return DependentWrite; }
184 void setDependentWrite(WriteState *Other) { DependentWrite = Other; }
185 void writeStartEvent(unsigned Cycles) {
186 DependentWriteCyclesLeft = Cycles;
187 DependentWrite = nullptr;
188 }
189
190 void setWriteZero() { WritesZero = true; }
191 void setEliminated() {
192 assert(Users.empty() && "Write is in an inconsistent state.");
193 CyclesLeft = 0;
194 IsEliminated = true;
195 }
196
197 void setPRF(unsigned PRF) { PRFID = PRF; }
198
199 // On every cycle, update CyclesLeft and notify dependent users.
200 void cycleEvent();
201 void onInstructionIssued();
202
203#ifndef NDEBUG
204 void dump() const;
205#endif
206};
207
208/// Tracks register operand latency in cycles.
209///
210/// A read may be dependent on more than one write. This occurs when some
211/// writes only partially update the register associated to this read.
212class ReadState {
213 const ReadDescriptor *RD;
214 // Physical register identified associated to this read.
215 unsigned RegisterID;
216 // Physical register file that serves register RegisterID.
217 unsigned PRFID;
218 // Number of writes that contribute to the definition of RegisterID.
219 // In the absence of partial register updates, the number of DependentWrites
220 // cannot be more than one.
221 unsigned DependentWrites;
222 // Number of cycles left before RegisterID can be read. This value depends on
223 // the latency of all the dependent writes. It defaults to UNKNOWN_CYCLES.
224 // It gets set to the value of field TotalCycles only when the 'CyclesLeft' of
225 // every dependent write is known.
226 int CyclesLeft;
227 // This field is updated on every writeStartEvent(). When the number of
228 // dependent writes (i.e. field DependentWrite) is zero, this value is
229 // propagated to field CyclesLeft.
230 unsigned TotalCycles;
231 // This field is set to true only if there are no dependent writes, and
232 // there are no `CyclesLeft' to wait.
233 bool IsReady;
234 // True if this is a read from a known zero register.
235 bool IsZero;
236 // True if this register read is from a dependency-breaking instruction.
237 bool IndependentFromDef;
238
239public:
240 ReadState(const ReadDescriptor &Desc, unsigned RegID)
241 : RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0),
242 CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), IsReady(true),
243 IsZero(false), IndependentFromDef(false) {}
244
245 const ReadDescriptor &getDescriptor() const { return *RD; }
246 unsigned getSchedClass() const { return RD->SchedClassID; }
247 unsigned getRegisterID() const { return RegisterID; }
248 unsigned getRegisterFileID() const { return PRFID; }
249
250 bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
251 bool isReady() const { return IsReady; }
252 bool isImplicitRead() const { return RD->isImplicitRead(); }
253
254 bool isIndependentFromDef() const { return IndependentFromDef; }
255 void setIndependentFromDef() { IndependentFromDef = true; }
256
257 void cycleEvent();
258 void writeStartEvent(unsigned Cycles);
259 void setDependentWrites(unsigned Writes) {
260 DependentWrites = Writes;
261 IsReady = !Writes;
262 }
263
264 bool isReadZero() const { return IsZero; }
265 void setReadZero() { IsZero = true; }
266 void setPRF(unsigned ID) { PRFID = ID; }
267};
268
269/// A sequence of cycles.
270///
271/// This class can be used as a building block to construct ranges of cycles.
272class CycleSegment {
273 unsigned Begin; // Inclusive.
274 unsigned End; // Exclusive.
275 bool Reserved; // Resources associated to this segment must be reserved.
276
277public:
278 CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
279 : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
280
281 bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
282 bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
283 bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
284 bool overlaps(const CycleSegment &CS) const {
285 return !startsAfter(CS) && !endsBefore(CS);
286 }
287 bool isExecuting() const { return Begin == 0 && End != 0; }
288 bool isExecuted() const { return End == 0; }
289 bool operator<(const CycleSegment &Other) const {
290 return Begin < Other.Begin;
291 }
292 CycleSegment &operator--(void) {
293 if (Begin)
294 Begin--;
295 if (End)
296 End--;
297 return *this;
298 }
299
300 bool isValid() const { return Begin <= End; }
301 unsigned size() const { return End - Begin; };
302 void subtract(unsigned Cycles) {
303 assert(End >= Cycles);
304 End -= Cycles;
305 }
306
307 unsigned begin() const { return Begin; }
308 unsigned end() const { return End; }
309 void setEnd(unsigned NewEnd) { End = NewEnd; }
310 bool isReserved() const { return Reserved; }
311 void setReserved() { Reserved = true; }
312};
313
314/// Helper used by class InstrDesc to describe how hardware resources
315/// are used.
316///
317/// This class describes how many resource units of a specific resource kind
318/// (and how many cycles) are "used" by an instruction.
319struct ResourceUsage {
320 CycleSegment CS;
321 unsigned NumUnits;
322 ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
323 : CS(Cycles), NumUnits(Units) {}
324 unsigned size() const { return CS.size(); }
325 bool isReserved() const { return CS.isReserved(); }
326 void setReserved() { CS.setReserved(); }
327};
328
329/// An instruction descriptor
330struct InstrDesc {
331 SmallVector<WriteDescriptor, 4> Writes; // Implicit writes are at the end.
332 SmallVector<ReadDescriptor, 4> Reads; // Implicit reads are at the end.
333
334 // For every resource used by an instruction of this kind, this vector
335 // reports the number of "consumed cycles".
336 SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources;
337
338 // A list of buffered resources consumed by this instruction.
339 SmallVector<uint64_t, 4> Buffers;
340
341 unsigned UsedProcResUnits;
342 unsigned UsedProcResGroups;
343
344 unsigned MaxLatency;
345 // Number of MicroOps for this instruction.
346 unsigned NumMicroOps;
347 // SchedClassID used to construct this InstrDesc.
348 // This information is currently used by views to do fast queries on the
349 // subtarget when computing the reciprocal throughput.
350 unsigned SchedClassID;
351
352 bool MayLoad;
353 bool MayStore;
354 bool HasSideEffects;
355 bool BeginGroup;
356 bool EndGroup;
357
358 // True if all buffered resources are in-order, and there is at least one
359 // buffer which is a dispatch hazard (BufferSize = 0).
360 bool MustIssueImmediately;
361
362 // A zero latency instruction doesn't consume any scheduler resources.
363 bool isZeroLatency() const { return !MaxLatency && Resources.empty(); }
364
365 InstrDesc() = default;
366 InstrDesc(const InstrDesc &Other) = delete;
367 InstrDesc &operator=(const InstrDesc &Other) = delete;
368};
369
370/// Base class for instructions consumed by the simulation pipeline.
371///
372/// This class tracks data dependencies as well as generic properties
373/// of the instruction.
374class InstructionBase {
375 const InstrDesc &Desc;
376
377 // This field is set for instructions that are candidates for move
378 // elimination. For more information about move elimination, see the
379 // definition of RegisterMappingTracker in RegisterFile.h
380 bool IsOptimizableMove;
381
382 // Output dependencies.
383 // One entry per each implicit and explicit register definition.
384 SmallVector<WriteState, 4> Defs;
385
386 // Input dependencies.
387 // One entry per each implicit and explicit register use.
388 SmallVector<ReadState, 4> Uses;
389
390public:
391 InstructionBase(const InstrDesc &D) : Desc(D), IsOptimizableMove(false) {}
392
393 SmallVectorImpl<WriteState> &getDefs() { return Defs; }
394 const ArrayRef<WriteState> getDefs() const { return Defs; }
395 SmallVectorImpl<ReadState> &getUses() { return Uses; }
396 const ArrayRef<ReadState> getUses() const { return Uses; }
397 const InstrDesc &getDesc() const { return Desc; }
398
399 unsigned getLatency() const { return Desc.MaxLatency; }
400
401 bool hasDependentUsers() const {
402 return any_of(Defs,
403 [](const WriteState &Def) { return Def.getNumUsers() > 0; });
404 }
405
406 unsigned getNumUsers() const {
407 unsigned NumUsers = 0;
408 for (const WriteState &Def : Defs)
409 NumUsers += Def.getNumUsers();
410 return NumUsers;
411 }
412
413 // Returns true if this instruction is a candidate for move elimination.
414 bool isOptimizableMove() const { return IsOptimizableMove; }
415 void setOptimizableMove() { IsOptimizableMove = true; }
416};
417
418/// An instruction propagated through the simulated instruction pipeline.
419///
420/// This class is used to monitor changes to the internal state of instructions
421/// that are sent to the various components of the simulated hardware pipeline.
422class Instruction : public InstructionBase {
423 enum InstrStage {
424 IS_INVALID, // Instruction in an invalid state.
425 IS_DISPATCHED, // Instruction dispatched but operands are not ready.
426 IS_PENDING, // Instruction is not ready, but operand latency is known.
427 IS_READY, // Instruction dispatched and operands ready.
428 IS_EXECUTING, // Instruction issued.
429 IS_EXECUTED, // Instruction executed. Values are written back.
430 IS_RETIRED // Instruction retired.
431 };
432
433 // The current instruction stage.
434 enum InstrStage Stage;
435
436 // This value defaults to the instruction latency. This instruction is
437 // considered executed when field CyclesLeft goes to zero.
438 int CyclesLeft;
439
440 // Retire Unit token ID for this instruction.
441 unsigned RCUTokenID;
442
443public:
444 Instruction(const InstrDesc &D)
445 : InstructionBase(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES),
446 RCUTokenID(0) {}
447
448 unsigned getRCUTokenID() const { return RCUTokenID; }
449 int getCyclesLeft() const { return CyclesLeft; }
450
451 // Transition to the dispatch stage, and assign a RCUToken to this
452 // instruction. The RCUToken is used to track the completion of every
453 // register write performed by this instruction.
454 void dispatch(unsigned RCUTokenID);
455
456 // Instruction issued. Transition to the IS_EXECUTING state, and update
457 // all the definitions.
458 void execute();
459
460 // Force a transition from the IS_DISPATCHED state to the IS_READY or
461 // IS_PENDING state. State transitions normally occur either at the beginning
462 // of a new cycle (see method cycleEvent()), or as a result of another issue
463 // event. This method is called every time the instruction might have changed
464 // in state. It internally delegates to method updateDispatched() and
465 // updateWaiting().
466 void update();
467 bool updateDispatched();
468 bool updatePending();
469
470 bool isDispatched() const { return Stage == IS_DISPATCHED; }
471 bool isPending() const { return Stage == IS_PENDING; }
472 bool isReady() const { return Stage == IS_READY; }
473 bool isExecuting() const { return Stage == IS_EXECUTING; }
474 bool isExecuted() const { return Stage == IS_EXECUTED; }
475 bool isRetired() const { return Stage == IS_RETIRED; }
476
477 bool isEliminated() const {
478 return isReady() && getDefs().size() &&
479 all_of(getDefs(),
480 [](const WriteState &W) { return W.isEliminated(); });
481 }
482
483 // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED.
484 void forceExecuted();
485
486 void retire() {
487 assert(isExecuted() && "Instruction is in an invalid state!");
488 Stage = IS_RETIRED;
489 }
490
491 void cycleEvent();
492};
493
494/// An InstRef contains both a SourceMgr index and Instruction pair. The index
495/// is used as a unique identifier for the instruction. MCA will make use of
496/// this index as a key throughout MCA.
497class InstRef {
498 std::pair<unsigned, Instruction *> Data;
499
500public:
501 InstRef() : Data(std::make_pair(0, nullptr)) {}
502 InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(Index, I)) {}
503
504 bool operator==(const InstRef &Other) const { return Data == Other.Data; }
505
506 unsigned getSourceIndex() const { return Data.first; }
507 Instruction *getInstruction() { return Data.second; }
508 const Instruction *getInstruction() const { return Data.second; }
509
510 /// Returns true if this references a valid instruction.
511 operator bool() const { return Data.second != nullptr; }
512
513 /// Invalidate this reference.
514 void invalidate() { Data.second = nullptr; }
515
516#ifndef NDEBUG
517 void print(raw_ostream &OS) const { OS << getSourceIndex(); }
518#endif
519};
520
521#ifndef NDEBUG
522inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) {
523 IR.print(OS);
524 return OS;
525}
526#endif
527
528/// A reference to a register write.
529///
530/// This class is mainly used by the register file to describe register
531/// mappings. It correlates a register write to the source index of the
532/// defining instruction.
533class WriteRef {
534 std::pair<unsigned, WriteState *> Data;
535 static const unsigned INVALID_IID;
536
537public:
538 WriteRef() : Data(INVALID_IID, nullptr) {}
539 WriteRef(unsigned SourceIndex, WriteState *WS) : Data(SourceIndex, WS) {}
540
541 unsigned getSourceIndex() const { return Data.first; }
542 const WriteState *getWriteState() const { return Data.second; }
543 WriteState *getWriteState() { return Data.second; }
544 void invalidate() { Data.second = nullptr; }
545 bool isWriteZero() const {
546 assert(isValid() && "Invalid null WriteState found!");
547 return getWriteState()->isWriteZero();
548 }
549
550 /// Returns true if this register write has been executed, and the new
551 /// register value is therefore available to users.
552 bool isAvailable() const {
553 if (getSourceIndex() == INVALID_IID)
554 return false;
555 const WriteState *WS = getWriteState();
556 return !WS || WS->isExecuted();
557 }
558
559 bool isValid() const { return Data.first != INVALID_IID && Data.second; }
560 bool operator==(const WriteRef &Other) const { return Data == Other.Data; }
561
562#ifndef NDEBUG
563 void dump() const;
564#endif
565};
566
567} // namespace mca
568} // namespace llvm
569
570#endif // LLVM_MCA_INSTRUCTION_H