1 //===--------------------- RegisterFile.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 a register mapping file class.  This class is responsible
11 /// for managing hardware register files and the tracking of data dependencies
12 /// between registers.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef LLVM_MCA_HARDWAREUNITS_REGISTERFILE_H
17 #define LLVM_MCA_HARDWAREUNITS_REGISTERFILE_H
18 
19 #include "llvm/ADT/APInt.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/MC/MCRegisterInfo.h"
22 #include "llvm/MC/MCSchedule.h"
23 #include "llvm/MC/MCSubtargetInfo.h"
24 #include "llvm/MCA/HardwareUnits/HardwareUnit.h"
25 
26 namespace llvm {
27 namespace mca {
28 
29 class ReadState;
30 class WriteState;
31 class Instruction;
32 
33 /// A reference to a register write.
34 ///
35 /// This class is mainly used by the register file to describe register
36 /// mappings. It correlates a register write to the source index of the
37 /// defining instruction.
38 class WriteRef {
39   unsigned IID;
40   unsigned WriteBackCycle;
41   unsigned WriteResID;
42   MCPhysReg RegisterID;
43   WriteState *Write;
44 
45   static const unsigned INVALID_IID;
46 
47 public:
48   WriteRef()
49       : IID(INVALID_IID), WriteBackCycle(), WriteResID(), RegisterID(),
50         Write() {}
51   WriteRef(unsigned SourceIndex, WriteState *WS);
52 
53   unsigned getSourceIndex() const { return IID; }
54   unsigned getWriteBackCycle() const;
55 
56   const WriteState *getWriteState() const { return Write; }
57   WriteState *getWriteState() { return Write; }
58   unsigned getWriteResourceID() const;
59   MCPhysReg getRegisterID() const;
60 
61   void commit();
62   void notifyExecuted(unsigned Cycle);
63 
64   bool hasKnownWriteBackCycle() const;
65   bool isWriteZero() const;
66   bool isValid() const { return getSourceIndex() != INVALID_IID; }
67 
68   /// Returns true if this register write has been executed, and the new
69   /// register value is therefore available to users.
70   bool isAvailable() const { return hasKnownWriteBackCycle(); }
71 
72   bool operator==(const WriteRef &Other) const {
73     return Write && Other.Write && Write == Other.Write;
74   }
75 
76 #ifndef NDEBUG
77   void dump() const;
78 #endif
79 };
80 
81 /// Manages hardware register files, and tracks register definitions for
82 /// register renaming purposes.
83 class RegisterFile : public HardwareUnit {
84   const MCRegisterInfo &MRI;
85 
86   // class RegisterMappingTracker is a  physical register file (PRF) descriptor.
87   // There is one RegisterMappingTracker for every PRF definition in the
88   // scheduling model.
89   //
90   // An instance of RegisterMappingTracker tracks the number of physical
91   // registers available for renaming. It also tracks  the number of register
92   // moves eliminated per cycle.
93   struct RegisterMappingTracker {
94     // The total number of physical registers that are available in this
95     // register file for register renaming purpouses.  A value of zero for this
96     // field means: this register file has an unbounded number of physical
97     // registers.
98     const unsigned NumPhysRegs;
99     // Number of physical registers that are currently in use.
100     unsigned NumUsedPhysRegs;
101 
102     // Maximum number of register moves that can be eliminated by this PRF every
103     // cycle. A value of zero means that there is no limit in the number of
104     // moves which can be eliminated every cycle.
105     const unsigned MaxMoveEliminatedPerCycle;
106 
107     // Number of register moves eliminated during this cycle.
108     //
109     // This value is increased by one every time a register move is eliminated.
110     // Every new cycle, this value is reset to zero.
111     // A move can be eliminated only if MaxMoveEliminatedPerCycle is zero, or if
112     // NumMoveEliminated is less than MaxMoveEliminatedPerCycle.
113     unsigned NumMoveEliminated;
114 
115     // If set, move elimination is restricted to zero-register moves only.
116     bool AllowZeroMoveEliminationOnly;
117 
118     RegisterMappingTracker(unsigned NumPhysRegisters,
119                            unsigned MaxMoveEliminated = 0U,
120                            bool AllowZeroMoveElimOnly = false)
121         : NumPhysRegs(NumPhysRegisters), NumUsedPhysRegs(0),
122           MaxMoveEliminatedPerCycle(MaxMoveEliminated), NumMoveEliminated(0U),
123           AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly) {}
124   };
125 
126   // A vector of register file descriptors.  This set always contains at least
127   // one entry. Entry at index #0 is reserved.  That entry describes a register
128   // file with an unbounded number of physical registers that "sees" all the
129   // hardware registers declared by the target (i.e. all the register
130   // definitions in the target specific `XYZRegisterInfo.td` - where `XYZ` is
131   // the target name).
132   //
133   // Users can limit the number of physical registers that are available in
134   // register file #0 specifying command line flag `-register-file-size=<uint>`.
135   SmallVector<RegisterMappingTracker, 4> RegisterFiles;
136 
137   // This type is used to propagate information about the owner of a register,
138   // and the cost of allocating it in the PRF. Register cost is defined as the
139   // number of physical registers consumed by the PRF to allocate a user
140   // register.
141   //
142   // For example: on X86 BtVer2, a YMM register consumes 2 128-bit physical
143   // registers. So, the cost of allocating a YMM register in BtVer2 is 2.
144   using IndexPlusCostPairTy = std::pair<unsigned, unsigned>;
145 
146   // Struct RegisterRenamingInfo is used to map logical registers to register
147   // files.
148   //
149   // There is a RegisterRenamingInfo object for every logical register defined
150   // by the target. RegisteRenamingInfo objects are stored into vector
151   // `RegisterMappings`, and MCPhysReg IDs can be used to reference
152   // elements in that vector.
153   //
154   // Each RegisterRenamingInfo is owned by a PRF, and field `IndexPlusCost`
155   // specifies both the owning PRF, as well as the number of physical registers
156   // consumed at register renaming stage.
157   //
158   // Field `AllowMoveElimination` is set for registers that are used as
159   // destination by optimizable register moves.
160   //
161   // Field `AliasRegID` is set by writes from register moves that have been
162   // eliminated at register renaming stage. A move eliminated at register
163   // renaming stage is effectively bypassed, and its write aliases the source
164   // register definition.
165   struct RegisterRenamingInfo {
166     IndexPlusCostPairTy IndexPlusCost;
167     MCPhysReg RenameAs;
168     MCPhysReg AliasRegID;
169     bool AllowMoveElimination;
170     RegisterRenamingInfo()
171         : IndexPlusCost(std::make_pair(0U, 1U)), RenameAs(0U), AliasRegID(0U),
172           AllowMoveElimination(false) {}
173   };
174 
175   // RegisterMapping objects are mainly used to track physical register
176   // definitions and resolve data dependencies.
177   //
178   // Every register declared by the Target is associated with an instance of
179   // RegisterMapping. RegisterMapping objects keep track of writes to a logical
180   // register.  That information is used by class RegisterFile to resolve data
181   // dependencies, and correctly set latencies for register uses.
182   //
183   // This implementation does not allow overlapping register files. The only
184   // register file that is allowed to overlap with other register files is
185   // register file #0. If we exclude register #0, every register is "owned" by
186   // at most one register file.
187   using RegisterMapping = std::pair<WriteRef, RegisterRenamingInfo>;
188 
189   // There is one entry per each register defined by the target.
190   std::vector<RegisterMapping> RegisterMappings;
191 
192   // Used to track zero registers. There is one bit for each register defined by
193   // the target. Bits are set for registers that are known to be zero.
194   APInt ZeroRegisters;
195 
196   unsigned CurrentCycle;
197 
198   // This method creates a new register file descriptor.
199   // The new register file owns all of the registers declared by register
200   // classes in the 'RegisterClasses' set.
201   //
202   // Processor models allow the definition of RegisterFile(s) via tablegen. For
203   // example, this is a tablegen definition for a x86 register file for
204   // XMM[0-15] and YMM[0-15], that allows up to 60 renames (each rename costs 1
205   // physical register).
206   //
207   //    def FPRegisterFile : RegisterFile<60, [VR128RegClass, VR256RegClass]>
208   //
209   // Here FPRegisterFile contains all the registers defined by register class
210   // VR128RegClass and VR256RegClass. FPRegisterFile implements 60
211   // registers which can be used for register renaming purpose.
212   void addRegisterFile(const MCRegisterFileDesc &RF,
213                        ArrayRef<MCRegisterCostEntry> Entries);
214 
215   // Consumes physical registers in each register file specified by the
216   // `IndexPlusCostPairTy`. This method is called from `addRegisterMapping()`.
217   void allocatePhysRegs(const RegisterRenamingInfo &Entry,
218                         MutableArrayRef<unsigned> UsedPhysRegs);
219 
220   // Releases previously allocated physical registers from the register file(s).
221   // This method is called from `invalidateRegisterMapping()`.
222   void freePhysRegs(const RegisterRenamingInfo &Entry,
223                     MutableArrayRef<unsigned> FreedPhysRegs);
224 
225   // Create an instance of RegisterMappingTracker for every register file
226   // specified by the processor model.
227   // If no register file is specified, then this method creates a default
228   // register file with an unbounded number of physical registers.
229   void initialize(const MCSchedModel &SM, unsigned NumRegs);
230 
231 public:
232   RegisterFile(const MCSchedModel &SM, const MCRegisterInfo &mri,
233                unsigned NumRegs = 0);
234 
235   // Collects writes that are in a RAW dependency with RS.
236   void collectWrites(const MCSubtargetInfo &STI, const ReadState &RS,
237                      SmallVectorImpl<WriteRef> &Writes,
238                      SmallVectorImpl<WriteRef> &CommittedWrites) const;
239   struct RAWHazard {
240     MCPhysReg RegisterID = 0;
241     int CyclesLeft = 0;
242 
243     RAWHazard() = default;
244     bool isValid() const { return RegisterID; }
245     bool hasUnknownCycles() const { return CyclesLeft < 0; }
246   };
247 
248   RAWHazard checkRAWHazards(const MCSubtargetInfo &STI,
249                             const ReadState &RS) const;
250 
251   // This method updates the register mappings inserting a new register
252   // definition. This method is also responsible for updating the number of
253   // allocated physical registers in each register file modified by the write.
254   // No physical regiser is allocated if this write is from a zero-idiom.
255   void addRegisterWrite(WriteRef Write, MutableArrayRef<unsigned> UsedPhysRegs);
256 
257   // Collect writes that are in a data dependency with RS, and update RS
258   // internal state.
259   void addRegisterRead(ReadState &RS, const MCSubtargetInfo &STI) const;
260 
261   // Removes write \param WS from the register mappings.
262   // Physical registers may be released to reflect this update.
263   // No registers are released if this write is from a zero-idiom.
264   void removeRegisterWrite(const WriteState &WS,
265                            MutableArrayRef<unsigned> FreedPhysRegs);
266 
267   // Returns true if the PRF at index `PRFIndex` can eliminate a move from RS to
268   // WS.
269   bool canEliminateMove(const WriteState &WS, const ReadState &RS,
270                         unsigned PRFIndex) const;
271 
272   // Returns true if this instruction can be fully eliminated at register
273   // renaming stage. On success, this method updates the internal state of each
274   // WriteState by setting flag `WS.isEliminated`, and by propagating the zero
275   // flag for known zero registers. It internally uses `canEliminateMove` to
276   // determine if a read/write pair can be eliminated. By default, it assumes a
277   // register swap if there is more than one register definition.
278   bool tryEliminateMoveOrSwap(MutableArrayRef<WriteState> Writes,
279                               MutableArrayRef<ReadState> Reads);
280 
281   // Checks if there are enough physical registers in the register files.
282   // Returns a "response mask" where each bit represents the response from a
283   // different register file.  A mask of all zeroes means that all register
284   // files are available.  Otherwise, the mask can be used to identify which
285   // register file was busy.  This sematic allows us to classify dispatch
286   // stalls caused by the lack of register file resources.
287   //
288   // Current implementation can simulate up to 32 register files (including the
289   // special register file at index #0).
290   unsigned isAvailable(ArrayRef<MCPhysReg> Regs) const;
291 
292   // Returns the number of PRFs implemented by this processor.
293   unsigned getNumRegisterFiles() const { return RegisterFiles.size(); }
294 
295   unsigned getElapsedCyclesFromWriteBack(const WriteRef &WR) const;
296 
297   void onInstructionExecuted(Instruction *IS);
298 
299   // Notify each PRF that a new cycle just started.
300   void cycleStart();
301 
302   void cycleEnd() { ++CurrentCycle; }
303 
304 #ifndef NDEBUG
305   void dump() const;
306 #endif
307 };
308 
309 } // namespace mca
310 } // namespace llvm
311 
312 #endif // LLVM_MCA_HARDWAREUNITS_REGISTERFILE_H
313