blob: 205c12c3079d9080f078dd26833c0f4bc56cfa07 [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"
Matt Davis6aa5dcd2018-05-01 23:04:01 +000020#include "RetireControlUnit.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000021#include "llvm/MC/MCRegisterInfo.h"
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +000022#include "llvm/MC/MCSubtargetInfo.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000023#include <map>
24
25namespace mca {
26
27class WriteState;
28class DispatchUnit;
29class Scheduler;
30class Backend;
31
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000032/// Manages hardware register files, and tracks data dependencies
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000033/// between registers.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000034class RegisterFile {
35 const llvm::MCRegisterInfo &MRI;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000036
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000037 // Each register file is described by an instance of RegisterMappingTracker.
38 // RegisterMappingTracker tracks the number of register mappings dynamically
39 // allocated during the execution.
40 struct RegisterMappingTracker {
41 // Total number of register mappings that are available for register
42 // renaming. A value of zero for this field means: this register file has
43 // an unbounded number of registers.
44 const unsigned TotalMappings;
45 // Number of mappings that are currently in use.
46 unsigned NumUsedMappings;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000047
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000048 RegisterMappingTracker(unsigned NumMappings)
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000049 : TotalMappings(NumMappings), NumUsedMappings(0) {}
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000050 };
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000051
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000052 // This is where information related to the various register files is kept.
53 // This set always contains at least one register file at index #0. That
54 // register file "sees" all the physical registers declared by the target, and
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +000055 // (by default) it allows an unbounded number of mappings.
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000056 // Users can limit the number of mappings that can be created by register file
57 // #0 through the command line flag `-register-file-size`.
58 llvm::SmallVector<RegisterMappingTracker, 4> RegisterFiles;
59
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +000060 // This pair is used to identify the owner of a physical register, as well as
61 // the cost of using that register file.
62 using IndexPlusCostPairTy = std::pair<unsigned, unsigned>;
63
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000064 // RegisterMapping objects are mainly used to track physical register
65 // definitions. A WriteState object describes a register definition, and it is
66 // used to track RAW dependencies (see Instruction.h). A RegisterMapping
67 // object also specifies the set of register files. The mapping between
68 // physreg and register files is done using a "register file mask".
69 //
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +000070 // A register file index identifies a user defined register file.
71 // There is one index per RegisterMappingTracker, and index #0 is reserved to
72 // the default unified register file.
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000073 //
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +000074 // This implementation does not allow overlapping register files. The only
75 // register file that is allowed to overlap with other register files is
76 // register file #0.
77 using RegisterMapping = std::pair<WriteState *, IndexPlusCostPairTy>;
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000078
79 // This map contains one entry for each physical register defined by the
80 // processor scheduling model.
81 std::vector<RegisterMapping> RegisterMappings;
82
83 // This method creates a new RegisterMappingTracker for a register file that
84 // contains all the physical registers specified by the register classes in
85 // the 'RegisterClasses' set.
86 //
87 // The long term goal is to let scheduling models optionally describe register
88 // files via tablegen definitions. This is still a work in progress.
89 // For example, here is how a tablegen definition for a x86 FP register file
90 // that features AVX might look like:
91 //
92 // def FPRegisterFile : RegisterFile<[VR128RegClass, VR256RegClass], 60>
93 //
94 // Here FPRegisterFile contains all the registers defined by register class
95 // VR128RegClass and VR256RegClass. FPRegisterFile implements 60
96 // registers which can be used for register renaming purpose.
97 //
98 // The list of register classes is then converted by the tablegen backend into
99 // a list of register class indices. That list, along with the number of
100 // available mappings, is then used to create a new RegisterMappingTracker.
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000101 void
102 addRegisterFile(llvm::ArrayRef<llvm::MCRegisterCostEntry> RegisterClasses,
103 unsigned NumPhysRegs);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000104
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000105 // Allocates register mappings in register file specified by the
106 // IndexPlusCostPairTy object. This method is called from addRegisterMapping.
107 void createNewMappings(IndexPlusCostPairTy IPC,
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000108 llvm::MutableArrayRef<unsigned> UsedPhysRegs);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000109
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000110 // Removes a previously allocated mapping from the register file referenced
111 // by the IndexPlusCostPairTy object. This method is called from
112 // invalidateRegisterMapping.
113 void removeMappings(IndexPlusCostPairTy IPC,
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000114 llvm::MutableArrayRef<unsigned> FreedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000115
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000116 // Create an instance of RegisterMappingTracker for every register file
117 // specified by the processor model.
118 // If no register file is specified, then this method creates a single
119 // register file with an unbounded number of registers.
120 void initialize(const llvm::MCSchedModel &SM, unsigned NumRegs);
121
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000122public:
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000123 RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri,
124 unsigned NumRegs = 0)
125 : MRI(mri), RegisterMappings(mri.getNumRegs(), {nullptr, {0, 0}}) {
126 initialize(SM, NumRegs);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000127 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000128
129 // Creates a new register mapping for RegID.
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000130 // This reserves a microarchitectural register in every register file that
131 // contains RegID.
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000132 void addRegisterMapping(WriteState &WS,
133 llvm::MutableArrayRef<unsigned> UsedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000134
135 // Invalidates register mappings associated to the input WriteState object.
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000136 // This releases previously allocated mappings for the physical register
137 // associated to the WriteState.
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000138 void invalidateRegisterMapping(const WriteState &WS,
139 llvm::MutableArrayRef<unsigned> FreedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000140
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000141 // Checks if there are enough microarchitectural registers in the register
142 // files. Returns a "response mask" where each bit is the response from a
143 // RegisterMappingTracker.
144 // For example: if all register files are available, then the response mask
145 // is a bitmask of all zeroes. If Instead register file #1 is not available,
146 // then the response mask is 0b10.
Andrea Di Biagio847accd2018-03-20 19:06:34 +0000147 unsigned isAvailable(llvm::ArrayRef<unsigned> Regs) const;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000148 void collectWrites(llvm::SmallVectorImpl<WriteState *> &Writes,
149 unsigned RegID) const;
150 void updateOnRead(ReadState &RS, unsigned RegID);
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000151
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000152 unsigned getNumRegisterFiles() const { return RegisterFiles.size(); }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000153
154#ifndef NDEBUG
155 void dump() const;
156#endif
157};
158
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000159// Implements the hardware dispatch logic.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000160//
161// This class is responsible for the dispatch stage, in which instructions are
162// dispatched in groups to the Scheduler. An instruction can be dispatched if
163// functional units are available.
164// To be more specific, an instruction can be dispatched to the Scheduler if:
165// 1) There are enough entries in the reorder buffer (implemented by class
166// RetireControlUnit) to accomodate all opcodes.
167// 2) There are enough temporaries to rename output register operands.
168// 3) There are enough entries available in the used buffered resource(s).
169//
170// The number of micro opcodes that can be dispatched in one cycle is limited by
171// the value of field 'DispatchWidth'. A "dynamic dispatch stall" occurs when
172// processor resources are not available (i.e. at least one of the
173// abovementioned checks fails). Dispatch stall events are counted during the
174// entire execution of the code, and displayed by the performance report when
175// flag '-verbose' is specified.
176//
177// If the number of micro opcodes of an instruction is bigger than
178// DispatchWidth, then it can only be dispatched at the beginning of one cycle.
179// The DispatchUnit will still have to wait for a number of cycles (depending on
180// the DispatchWidth and the number of micro opcodes) before it can serve other
181// instructions.
182class DispatchUnit {
183 unsigned DispatchWidth;
184 unsigned AvailableEntries;
185 unsigned CarryOver;
186 Scheduler *SC;
187
188 std::unique_ptr<RegisterFile> RAT;
189 std::unique_ptr<RetireControlUnit> RCU;
190 Backend *Owner;
191
Andrea Di Biagio9da4d6d2018-04-03 13:36:24 +0000192 bool checkRAT(unsigned Index, const Instruction &Inst);
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000193 bool checkRCU(unsigned Index, const InstrDesc &Desc);
194 bool checkScheduler(unsigned Index, const InstrDesc &Desc);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000195
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000196 void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000197 void notifyInstructionDispatched(unsigned IID,
198 llvm::ArrayRef<unsigned> UsedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000199
200public:
Andrea Di Biagioc74ad502018-04-05 15:41:41 +0000201 DispatchUnit(Backend *B, const llvm::MCSchedModel &SM,
202 const llvm::MCRegisterInfo &MRI, unsigned RegisterFileSize,
203 unsigned MaxDispatchWidth, Scheduler *Sched)
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000204 : DispatchWidth(MaxDispatchWidth), AvailableEntries(MaxDispatchWidth),
205 CarryOver(0U), SC(Sched),
Andrea Di Biagioc74ad502018-04-05 15:41:41 +0000206 RAT(llvm::make_unique<RegisterFile>(SM, MRI, RegisterFileSize)),
207 RCU(llvm::make_unique<RetireControlUnit>(SM, this)), Owner(B) {}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000208
209 unsigned getDispatchWidth() const { return DispatchWidth; }
210
211 bool isAvailable(unsigned NumEntries) const {
212 return NumEntries <= AvailableEntries || AvailableEntries == DispatchWidth;
213 }
214
215 bool isRCUEmpty() const { return RCU->isEmpty(); }
216
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000217 bool canDispatch(unsigned Index, const Instruction &Inst) {
Andrea Di Biagioaf904b92018-03-15 16:13:12 +0000218 const InstrDesc &Desc = Inst.getDesc();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000219 assert(isAvailable(Desc.NumMicroOps));
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000220 return checkRCU(Index, Desc) && checkRAT(Index, Inst) &&
221 checkScheduler(Index, Desc);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000222 }
223
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000224 void dispatch(unsigned IID, Instruction *I, const llvm::MCSubtargetInfo &STI);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000225
226 void collectWrites(llvm::SmallVectorImpl<WriteState *> &Vec,
227 unsigned RegID) const {
228 return RAT->collectWrites(Vec, RegID);
229 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000230
Andrea Di Biagio3e646442018-04-12 10:49:40 +0000231 void cycleEvent() {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000232 RCU->cycleEvent();
233 AvailableEntries =
234 CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver;
235 CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U;
236 }
237
238 void notifyInstructionRetired(unsigned Index);
239
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000240 void notifyDispatchStall(unsigned Index, unsigned EventType);
241
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000242 void onInstructionExecuted(unsigned TokenID) {
243 RCU->onInstructionExecuted(TokenID);
244 }
245
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000246#ifndef NDEBUG
247 void dump() const;
248#endif
249};
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000250} // namespace mca
251
252#endif