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: WriteRef()48 WriteRef() 49 : IID(INVALID_IID), WriteBackCycle(), WriteResID(), RegisterID(), 50 Write() {} 51 WriteRef(unsigned SourceIndex, WriteState *WS); 52 getSourceIndex()53 unsigned getSourceIndex() const { return IID; } 54 unsigned getWriteBackCycle() const; 55 getWriteState()56 const WriteState *getWriteState() const { return Write; } getWriteState()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; isValid()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. isAvailable()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) NumPhysRegsRegisterMappingTracker121 : 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; RegisterRenamingInfoRegisterRenamingInfo170 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; isValidRAWHazard244 bool isValid() const { return RegisterID; } hasUnknownCyclesRAWHazard245 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. getNumRegisterFiles()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 cycleEnd()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