blob: c08515d40a3a3046c9634a951b9e2d40ea83c746 [file] [log] [blame]
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +00001//===----------------------- Dispatch.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 implements classes that are used to model register files,
12/// reorder buffers and the hardware dispatch logic.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_TOOLS_LLVM_MCA_DISPATCH_H
17#define LLVM_TOOLS_LLVM_MCA_DISPATCH_H
18
19#include "Instruction.h"
20#include "llvm/MC/MCRegisterInfo.h"
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +000021#include "llvm/MC/MCSubtargetInfo.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000022#include <map>
23
24namespace mca {
25
26class WriteState;
27class DispatchUnit;
28class Scheduler;
29class Backend;
30
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000031/// \brief Manages hardware register files, and tracks data dependencies
32/// between registers.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000033class RegisterFile {
34 const llvm::MCRegisterInfo &MRI;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000035
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000036 // Each register file is described by an instance of RegisterMappingTracker.
37 // RegisterMappingTracker tracks the number of register mappings dynamically
38 // allocated during the execution.
39 struct RegisterMappingTracker {
40 // Total number of register mappings that are available for register
41 // renaming. A value of zero for this field means: this register file has
42 // an unbounded number of registers.
43 const unsigned TotalMappings;
44 // Number of mappings that are currently in use.
45 unsigned NumUsedMappings;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000046
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000047 RegisterMappingTracker(unsigned NumMappings)
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000048 : TotalMappings(NumMappings), NumUsedMappings(0) {}
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000049 };
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000050
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000051 // This is where information related to the various register files is kept.
52 // This set always contains at least one register file at index #0. That
53 // register file "sees" all the physical registers declared by the target, and
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +000054 // (by default) it allows an unbounded number of mappings.
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000055 // Users can limit the number of mappings that can be created by register file
56 // #0 through the command line flag `-register-file-size`.
57 llvm::SmallVector<RegisterMappingTracker, 4> RegisterFiles;
58
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +000059 // This pair is used to identify the owner of a physical register, as well as
60 // the cost of using that register file.
61 using IndexPlusCostPairTy = std::pair<unsigned, unsigned>;
62
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000063 // RegisterMapping objects are mainly used to track physical register
64 // definitions. A WriteState object describes a register definition, and it is
65 // used to track RAW dependencies (see Instruction.h). A RegisterMapping
66 // object also specifies the set of register files. The mapping between
67 // physreg and register files is done using a "register file mask".
68 //
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +000069 // A register file index identifies a user defined register file.
70 // There is one index per RegisterMappingTracker, and index #0 is reserved to
71 // the default unified register file.
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000072 //
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +000073 // This implementation does not allow overlapping register files. The only
74 // register file that is allowed to overlap with other register files is
75 // register file #0.
76 using RegisterMapping = std::pair<WriteState *, IndexPlusCostPairTy>;
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000077
78 // This map contains one entry for each physical register defined by the
79 // processor scheduling model.
80 std::vector<RegisterMapping> RegisterMappings;
81
82 // This method creates a new RegisterMappingTracker for a register file that
83 // contains all the physical registers specified by the register classes in
84 // the 'RegisterClasses' set.
85 //
86 // The long term goal is to let scheduling models optionally describe register
87 // files via tablegen definitions. This is still a work in progress.
88 // For example, here is how a tablegen definition for a x86 FP register file
89 // that features AVX might look like:
90 //
91 // def FPRegisterFile : RegisterFile<[VR128RegClass, VR256RegClass], 60>
92 //
93 // Here FPRegisterFile contains all the registers defined by register class
94 // VR128RegClass and VR256RegClass. FPRegisterFile implements 60
95 // registers which can be used for register renaming purpose.
96 //
97 // The list of register classes is then converted by the tablegen backend into
98 // a list of register class indices. That list, along with the number of
99 // available mappings, is then used to create a new RegisterMappingTracker.
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000100 void
101 addRegisterFile(llvm::ArrayRef<llvm::MCRegisterCostEntry> RegisterClasses,
102 unsigned NumPhysRegs);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000103
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000104 // Allocates register mappings in register file specified by the
105 // IndexPlusCostPairTy object. This method is called from addRegisterMapping.
106 void createNewMappings(IndexPlusCostPairTy IPC,
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000107 llvm::MutableArrayRef<unsigned> UsedPhysRegs);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000108
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000109 // Removes a previously allocated mapping from the register file referenced
110 // by the IndexPlusCostPairTy object. This method is called from
111 // invalidateRegisterMapping.
112 void removeMappings(IndexPlusCostPairTy IPC,
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000113 llvm::MutableArrayRef<unsigned> FreedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000114
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000115 // Create an instance of RegisterMappingTracker for every register file
116 // specified by the processor model.
117 // If no register file is specified, then this method creates a single
118 // register file with an unbounded number of registers.
119 void initialize(const llvm::MCSchedModel &SM, unsigned NumRegs);
120
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000121public:
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000122 RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri,
123 unsigned NumRegs = 0)
124 : MRI(mri), RegisterMappings(mri.getNumRegs(), {nullptr, {0, 0}}) {
125 initialize(SM, NumRegs);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000126 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000127
128 // Creates a new register mapping for RegID.
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000129 // This reserves a microarchitectural register in every register file that
130 // contains RegID.
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000131 void addRegisterMapping(WriteState &WS,
132 llvm::MutableArrayRef<unsigned> UsedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000133
134 // Invalidates register mappings associated to the input WriteState object.
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000135 // This releases previously allocated mappings for the physical register
136 // associated to the WriteState.
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000137 void invalidateRegisterMapping(const WriteState &WS,
138 llvm::MutableArrayRef<unsigned> FreedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000139
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000140 // Checks if there are enough microarchitectural registers in the register
141 // files. Returns a "response mask" where each bit is the response from a
142 // RegisterMappingTracker.
143 // For example: if all register files are available, then the response mask
144 // is a bitmask of all zeroes. If Instead register file #1 is not available,
145 // then the response mask is 0b10.
Andrea Di Biagio847accd2018-03-20 19:06:34 +0000146 unsigned isAvailable(llvm::ArrayRef<unsigned> Regs) const;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000147 void collectWrites(llvm::SmallVectorImpl<WriteState *> &Writes,
148 unsigned RegID) const;
149 void updateOnRead(ReadState &RS, unsigned RegID);
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000150
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000151 unsigned getNumRegisterFiles() const { return RegisterFiles.size(); }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000152
153#ifndef NDEBUG
154 void dump() const;
155#endif
156};
157
158/// \brief tracks which instructions are in-flight (i.e. dispatched but not
159/// retired) in the OoO backend.
160///
161/// This class checks on every cycle if/which instructions can be retired.
162/// Instructions are retired in program order.
163/// In the event of instruction retired, the DispatchUnit object that owns
164/// this RetireControlUnit gets notified.
165/// On instruction retired, register updates are all architecturally
166/// committed, and any temporary registers originally allocated for the
167/// retired instruction are freed.
168struct RetireControlUnit {
169 // A "token" (object of class RUToken) is created by the retire unit for every
170 // instruction dispatched to the schedulers. Flag 'Executed' is used to
171 // quickly check if an instruction has reached the write-back stage. A token
172 // also carries information related to the number of entries consumed by the
173 // instruction in the reorder buffer. The idea is that those entries will
174 // become available again once the instruction is retired. On every cycle,
175 // the RCU (Retire Control Unit) scans every token starting to search for
176 // instructions that are ready to retire. retired. Instructions are retired
177 // in program order. Only 'Executed' instructions are eligible for retire.
178 // Note that the size of the reorder buffer is defined by the scheduling model
179 // via field 'NumMicroOpBufferSize'.
180 struct RUToken {
181 unsigned Index; // Instruction index.
182 unsigned NumSlots; // Slots reserved to this instruction.
183 bool Executed; // True if the instruction is past the WB stage.
184 };
185
186private:
187 unsigned NextAvailableSlotIdx;
188 unsigned CurrentInstructionSlotIdx;
189 unsigned AvailableSlots;
190 unsigned MaxRetirePerCycle; // 0 means no limit.
191 std::vector<RUToken> Queue;
192 DispatchUnit *Owner;
193
194public:
Andrea Di Biagioc74ad502018-04-05 15:41:41 +0000195 RetireControlUnit(const llvm::MCSchedModel &SM, DispatchUnit *DU);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000196
197 bool isFull() const { return !AvailableSlots; }
198 bool isEmpty() const { return AvailableSlots == Queue.size(); }
199 bool isAvailable(unsigned Quantity = 1) const {
200 // Some instructions may declare a number of uOps which exceedes the size
201 // of the reorder buffer. To avoid problems, cap the amount of slots to
202 // the size of the reorder buffer.
203 Quantity = std::min(Quantity, static_cast<unsigned>(Queue.size()));
204 return AvailableSlots >= Quantity;
205 }
206
207 // Reserves a number of slots, and returns a new token.
208 unsigned reserveSlot(unsigned Index, unsigned NumMicroOps);
209
210 /// Retires instructions in program order.
211 void cycleEvent();
212
213 void onInstructionExecuted(unsigned TokenID);
214
215#ifndef NDEBUG
216 void dump() const;
217#endif
218};
219
220// \brief Implements the hardware dispatch logic.
221//
222// This class is responsible for the dispatch stage, in which instructions are
223// dispatched in groups to the Scheduler. An instruction can be dispatched if
224// functional units are available.
225// To be more specific, an instruction can be dispatched to the Scheduler if:
226// 1) There are enough entries in the reorder buffer (implemented by class
227// RetireControlUnit) to accomodate all opcodes.
228// 2) There are enough temporaries to rename output register operands.
229// 3) There are enough entries available in the used buffered resource(s).
230//
231// The number of micro opcodes that can be dispatched in one cycle is limited by
232// the value of field 'DispatchWidth'. A "dynamic dispatch stall" occurs when
233// processor resources are not available (i.e. at least one of the
234// abovementioned checks fails). Dispatch stall events are counted during the
235// entire execution of the code, and displayed by the performance report when
236// flag '-verbose' is specified.
237//
238// If the number of micro opcodes of an instruction is bigger than
239// DispatchWidth, then it can only be dispatched at the beginning of one cycle.
240// The DispatchUnit will still have to wait for a number of cycles (depending on
241// the DispatchWidth and the number of micro opcodes) before it can serve other
242// instructions.
243class DispatchUnit {
244 unsigned DispatchWidth;
245 unsigned AvailableEntries;
246 unsigned CarryOver;
247 Scheduler *SC;
248
249 std::unique_ptr<RegisterFile> RAT;
250 std::unique_ptr<RetireControlUnit> RCU;
251 Backend *Owner;
252
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000253 bool checkRAT(unsigned Index, const Instruction &Inst);
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000254 bool checkRCU(unsigned Index, const InstrDesc &Desc);
255 bool checkScheduler(unsigned Index, const InstrDesc &Desc);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000256
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000257 void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000258 void notifyInstructionDispatched(unsigned IID,
259 llvm::ArrayRef<unsigned> UsedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000260
261public:
Andrea Di Biagioc74ad502018-04-05 15:41:41 +0000262 DispatchUnit(Backend *B, const llvm::MCSchedModel &SM,
263 const llvm::MCRegisterInfo &MRI, unsigned RegisterFileSize,
264 unsigned MaxDispatchWidth, Scheduler *Sched)
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000265 : DispatchWidth(MaxDispatchWidth), AvailableEntries(MaxDispatchWidth),
266 CarryOver(0U), SC(Sched),
Andrea Di Biagioc74ad502018-04-05 15:41:41 +0000267 RAT(llvm::make_unique<RegisterFile>(SM, MRI, RegisterFileSize)),
268 RCU(llvm::make_unique<RetireControlUnit>(SM, this)), Owner(B) {}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000269
270 unsigned getDispatchWidth() const { return DispatchWidth; }
271
272 bool isAvailable(unsigned NumEntries) const {
273 return NumEntries <= AvailableEntries || AvailableEntries == DispatchWidth;
274 }
275
276 bool isRCUEmpty() const { return RCU->isEmpty(); }
277
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000278 bool canDispatch(unsigned Index, const Instruction &Inst) {
Andrea Di Biagioaf904b92018-03-15 16:13:12 +0000279 const InstrDesc &Desc = Inst.getDesc();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000280 assert(isAvailable(Desc.NumMicroOps));
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000281 return checkRCU(Index, Desc) && checkRAT(Index, Inst) &&
282 checkScheduler(Index, Desc);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000283 }
284
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000285 void dispatch(unsigned IID, Instruction *I, const llvm::MCSubtargetInfo &STI);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000286
287 void collectWrites(llvm::SmallVectorImpl<WriteState *> &Vec,
288 unsigned RegID) const {
289 return RAT->collectWrites(Vec, RegID);
290 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000291
Andrea Di Biagio3e646442018-04-12 10:49:40 +0000292 void cycleEvent() {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000293 RCU->cycleEvent();
294 AvailableEntries =
295 CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver;
296 CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U;
297 }
298
299 void notifyInstructionRetired(unsigned Index);
300
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000301 void notifyDispatchStall(unsigned Index, unsigned EventType);
302
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000303 void onInstructionExecuted(unsigned TokenID) {
304 RCU->onInstructionExecuted(TokenID);
305 }
306
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000307#ifndef NDEBUG
308 void dump() const;
309#endif
310};
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000311} // namespace mca
312
313#endif