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_REGISTER_FILE_H
17 #define LLVM_MCA_REGISTER_FILE_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 WriteRef;
32 
33 /// Manages hardware register files, and tracks register definitions for
34 /// register renaming purposes.
35 class RegisterFile : public HardwareUnit {
36   const MCRegisterInfo &MRI;
37 
38   // class RegisterMappingTracker is a  physical register file (PRF) descriptor.
39   // There is one RegisterMappingTracker for every PRF definition in the
40   // scheduling model.
41   //
42   // An instance of RegisterMappingTracker tracks the number of physical
43   // registers available for renaming. It also tracks  the number of register
44   // moves eliminated per cycle.
45   struct RegisterMappingTracker {
46     // The total number of physical registers that are available in this
47     // register file for register renaming purpouses.  A value of zero for this
48     // field means: this register file has an unbounded number of physical
49     // registers.
50     const unsigned NumPhysRegs;
51     // Number of physical registers that are currently in use.
52     unsigned NumUsedPhysRegs;
53 
54     // Maximum number of register moves that can be eliminated by this PRF every
55     // cycle. A value of zero means that there is no limit in the number of
56     // moves which can be eliminated every cycle.
57     const unsigned MaxMoveEliminatedPerCycle;
58 
59     // Number of register moves eliminated during this cycle.
60     //
61     // This value is increased by one every time a register move is eliminated.
62     // Every new cycle, this value is reset to zero.
63     // A move can be eliminated only if MaxMoveEliminatedPerCycle is zero, or if
64     // NumMoveEliminated is less than MaxMoveEliminatedPerCycle.
65     unsigned NumMoveEliminated;
66 
67     // If set, move elimination is restricted to zero-register moves only.
68     bool AllowZeroMoveEliminationOnly;
69 
70     RegisterMappingTracker(unsigned NumPhysRegisters,
71                            unsigned MaxMoveEliminated = 0U,
72                            bool AllowZeroMoveElimOnly = false)
73         : NumPhysRegs(NumPhysRegisters), NumUsedPhysRegs(0),
74           MaxMoveEliminatedPerCycle(MaxMoveEliminated), NumMoveEliminated(0U),
75           AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly) {}
76   };
77 
78   // A vector of register file descriptors.  This set always contains at least
79   // one entry. Entry at index #0 is reserved.  That entry describes a register
80   // file with an unbounded number of physical registers that "sees" all the
81   // hardware registers declared by the target (i.e. all the register
82   // definitions in the target specific `XYZRegisterInfo.td` - where `XYZ` is
83   // the target name).
84   //
85   // Users can limit the number of physical registers that are available in
86   // register file #0 specifying command line flag `-register-file-size=<uint>`.
87   SmallVector<RegisterMappingTracker, 4> RegisterFiles;
88 
89   // This type is used to propagate information about the owner of a register,
90   // and the cost of allocating it in the PRF. Register cost is defined as the
91   // number of physical registers consumed by the PRF to allocate a user
92   // register.
93   //
94   // For example: on X86 BtVer2, a YMM register consumes 2 128-bit physical
95   // registers. So, the cost of allocating a YMM register in BtVer2 is 2.
96   using IndexPlusCostPairTy = std::pair<unsigned, unsigned>;
97 
98   // Struct RegisterRenamingInfo is used to map logical registers to register
99   // files.
100   //
101   // There is a RegisterRenamingInfo object for every logical register defined
102   // by the target. RegisteRenamingInfo objects are stored into vector
103   // `RegisterMappings`, and MCPhysReg IDs can be used to reference
104   // elements in that vector.
105   //
106   // Each RegisterRenamingInfo is owned by a PRF, and field `IndexPlusCost`
107   // specifies both the owning PRF, as well as the number of physical registers
108   // consumed at register renaming stage.
109   //
110   // Field `AllowMoveElimination` is set for registers that are used as
111   // destination by optimizable register moves.
112   //
113   // Field `AliasRegID` is set by writes from register moves that have been
114   // eliminated at register renaming stage. A move eliminated at register
115   // renaming stage is effectively bypassed, and its write aliases the source
116   // register definition.
117   struct RegisterRenamingInfo {
118     IndexPlusCostPairTy IndexPlusCost;
119     MCPhysReg RenameAs;
120     MCPhysReg AliasRegID;
121     bool AllowMoveElimination;
122     RegisterRenamingInfo()
123         : IndexPlusCost(std::make_pair(0U, 1U)), RenameAs(0U), AliasRegID(0U),
124           AllowMoveElimination(false) {}
125   };
126 
127   // RegisterMapping objects are mainly used to track physical register
128   // definitions and resolve data dependencies.
129   //
130   // Every register declared by the Target is associated with an instance of
131   // RegisterMapping. RegisterMapping objects keep track of writes to a logical
132   // register.  That information is used by class RegisterFile to resolve data
133   // dependencies, and correctly set latencies for register uses.
134   //
135   // This implementation does not allow overlapping register files. The only
136   // register file that is allowed to overlap with other register files is
137   // register file #0. If we exclude register #0, every register is "owned" by
138   // at most one register file.
139   using RegisterMapping = std::pair<WriteRef, RegisterRenamingInfo>;
140 
141   // There is one entry per each register defined by the target.
142   std::vector<RegisterMapping> RegisterMappings;
143 
144   // Used to track zero registers. There is one bit for each register defined by
145   // the target. Bits are set for registers that are known to be zero.
146   APInt ZeroRegisters;
147 
148   // This method creates a new register file descriptor.
149   // The new register file owns all of the registers declared by register
150   // classes in the 'RegisterClasses' set.
151   //
152   // Processor models allow the definition of RegisterFile(s) via tablegen. For
153   // example, this is a tablegen definition for a x86 register file for
154   // XMM[0-15] and YMM[0-15], that allows up to 60 renames (each rename costs 1
155   // physical register).
156   //
157   //    def FPRegisterFile : RegisterFile<60, [VR128RegClass, VR256RegClass]>
158   //
159   // Here FPRegisterFile contains all the registers defined by register class
160   // VR128RegClass and VR256RegClass. FPRegisterFile implements 60
161   // registers which can be used for register renaming purpose.
162   void addRegisterFile(const MCRegisterFileDesc &RF,
163                        ArrayRef<MCRegisterCostEntry> Entries);
164 
165   // Consumes physical registers in each register file specified by the
166   // `IndexPlusCostPairTy`. This method is called from `addRegisterMapping()`.
167   void allocatePhysRegs(const RegisterRenamingInfo &Entry,
168                         MutableArrayRef<unsigned> UsedPhysRegs);
169 
170   // Releases previously allocated physical registers from the register file(s).
171   // This method is called from `invalidateRegisterMapping()`.
172   void freePhysRegs(const RegisterRenamingInfo &Entry,
173                     MutableArrayRef<unsigned> FreedPhysRegs);
174 
175   // Collects writes that are in a RAW dependency with RS.
176   // This method is called from `addRegisterRead()`.
177   void collectWrites(const ReadState &RS,
178                      SmallVectorImpl<WriteRef> &Writes) const;
179 
180   // Create an instance of RegisterMappingTracker for every register file
181   // specified by the processor model.
182   // If no register file is specified, then this method creates a default
183   // register file with an unbounded number of physical registers.
184   void initialize(const MCSchedModel &SM, unsigned NumRegs);
185 
186 public:
187   RegisterFile(const MCSchedModel &SM, const MCRegisterInfo &mri,
188                unsigned NumRegs = 0);
189 
190   // This method updates the register mappings inserting a new register
191   // definition. This method is also responsible for updating the number of
192   // allocated physical registers in each register file modified by the write.
193   // No physical regiser is allocated if this write is from a zero-idiom.
194   void addRegisterWrite(WriteRef Write, MutableArrayRef<unsigned> UsedPhysRegs);
195 
196   // Collect writes that are in a data dependency with RS, and update RS
197   // internal state.
198   void addRegisterRead(ReadState &RS, const MCSubtargetInfo &STI) const;
199 
200   // Removes write \param WS from the register mappings.
201   // Physical registers may be released to reflect this update.
202   // No registers are released if this write is from a zero-idiom.
203   void removeRegisterWrite(const WriteState &WS,
204                            MutableArrayRef<unsigned> FreedPhysRegs);
205 
206   // Returns true if a move from RS to WS can be eliminated.
207   // On success, it updates WriteState by setting flag `WS.isEliminated`.
208   // If RS is a read from a zero register, and WS is eliminated, then
209   // `WS.WritesZero` is also set, so that method addRegisterWrite() would not
210   // reserve a physical register for it.
211   bool tryEliminateMove(WriteState &WS, ReadState &RS);
212 
213   // Checks if there are enough physical registers in the register files.
214   // Returns a "response mask" where each bit represents the response from a
215   // different register file.  A mask of all zeroes means that all register
216   // files are available.  Otherwise, the mask can be used to identify which
217   // register file was busy.  This sematic allows us to classify dispatch
218   // stalls caused by the lack of register file resources.
219   //
220   // Current implementation can simulate up to 32 register files (including the
221   // special register file at index #0).
222   unsigned isAvailable(ArrayRef<MCPhysReg> Regs) const;
223 
224   // Returns the number of PRFs implemented by this processor.
225   unsigned getNumRegisterFiles() const { return RegisterFiles.size(); }
226 
227   // Notify each PRF that a new cycle just started.
228   void cycleStart();
229 
230 #ifndef NDEBUG
231   void dump() const;
232 #endif
233 };
234 
235 } // namespace mca
236 } // namespace llvm
237 
238 #endif // LLVM_MCA_REGISTER_FILE_H
239