RegisterFile.h 13 KB

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