Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:16

0001 //===--------------------- RegisterFile.h -----------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 ///
0010 /// This file defines a register mapping file class.  This class is responsible
0011 /// for managing hardware register files and the tracking of data dependencies
0012 /// between registers.
0013 ///
0014 //===----------------------------------------------------------------------===//
0015 
0016 #ifndef LLVM_MCA_HARDWAREUNITS_REGISTERFILE_H
0017 #define LLVM_MCA_HARDWAREUNITS_REGISTERFILE_H
0018 
0019 #include "llvm/ADT/APInt.h"
0020 #include "llvm/ADT/SmallVector.h"
0021 #include "llvm/MC/MCRegisterInfo.h"
0022 #include "llvm/MC/MCSchedule.h"
0023 #include "llvm/MC/MCSubtargetInfo.h"
0024 #include "llvm/MCA/HardwareUnits/HardwareUnit.h"
0025 
0026 namespace llvm {
0027 namespace mca {
0028 
0029 class ReadState;
0030 class WriteState;
0031 class Instruction;
0032 
0033 /// A reference to a register write.
0034 ///
0035 /// This class is mainly used by the register file to describe register
0036 /// mappings. It correlates a register write to the source index of the
0037 /// defining instruction.
0038 class WriteRef {
0039   unsigned IID;
0040   unsigned WriteBackCycle;
0041   unsigned WriteResID;
0042   MCPhysReg RegisterID;
0043   WriteState *Write;
0044 
0045   static const unsigned INVALID_IID;
0046 
0047 public:
0048   WriteRef()
0049       : IID(INVALID_IID), WriteBackCycle(), WriteResID(), RegisterID(),
0050         Write() {}
0051   WriteRef(unsigned SourceIndex, WriteState *WS);
0052 
0053   unsigned getSourceIndex() const { return IID; }
0054   unsigned getWriteBackCycle() const;
0055 
0056   const WriteState *getWriteState() const { return Write; }
0057   WriteState *getWriteState() { return Write; }
0058   unsigned getWriteResourceID() const;
0059   MCPhysReg getRegisterID() const;
0060 
0061   void commit();
0062   void notifyExecuted(unsigned Cycle);
0063 
0064   bool hasKnownWriteBackCycle() const;
0065   bool isWriteZero() const;
0066   bool isValid() const { return getSourceIndex() != INVALID_IID; }
0067 
0068   /// Returns true if this register write has been executed, and the new
0069   /// register value is therefore available to users.
0070   bool isAvailable() const { return hasKnownWriteBackCycle(); }
0071 
0072   bool operator==(const WriteRef &Other) const {
0073     return Write && Other.Write && Write == Other.Write;
0074   }
0075 
0076 #ifndef NDEBUG
0077   void dump() const;
0078 #endif
0079 };
0080 
0081 /// Manages hardware register files, and tracks register definitions for
0082 /// register renaming purposes.
0083 class RegisterFile : public HardwareUnit {
0084   const MCRegisterInfo &MRI;
0085 
0086   // class RegisterMappingTracker is a  physical register file (PRF) descriptor.
0087   // There is one RegisterMappingTracker for every PRF definition in the
0088   // scheduling model.
0089   //
0090   // An instance of RegisterMappingTracker tracks the number of physical
0091   // registers available for renaming. It also tracks  the number of register
0092   // moves eliminated per cycle.
0093   struct RegisterMappingTracker {
0094     // The total number of physical registers that are available in this
0095     // register file for register renaming purpouses.  A value of zero for this
0096     // field means: this register file has an unbounded number of physical
0097     // registers.
0098     const unsigned NumPhysRegs;
0099     // Number of physical registers that are currently in use.
0100     unsigned NumUsedPhysRegs;
0101 
0102     // Maximum number of register moves that can be eliminated by this PRF every
0103     // cycle. A value of zero means that there is no limit in the number of
0104     // moves which can be eliminated every cycle.
0105     const unsigned MaxMoveEliminatedPerCycle;
0106 
0107     // Number of register moves eliminated during this cycle.
0108     //
0109     // This value is increased by one every time a register move is eliminated.
0110     // Every new cycle, this value is reset to zero.
0111     // A move can be eliminated only if MaxMoveEliminatedPerCycle is zero, or if
0112     // NumMoveEliminated is less than MaxMoveEliminatedPerCycle.
0113     unsigned NumMoveEliminated;
0114 
0115     // If set, move elimination is restricted to zero-register moves only.
0116     bool AllowZeroMoveEliminationOnly;
0117 
0118     RegisterMappingTracker(unsigned NumPhysRegisters,
0119                            unsigned MaxMoveEliminated = 0U,
0120                            bool AllowZeroMoveElimOnly = false)
0121         : NumPhysRegs(NumPhysRegisters), NumUsedPhysRegs(0),
0122           MaxMoveEliminatedPerCycle(MaxMoveEliminated), NumMoveEliminated(0U),
0123           AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly) {}
0124   };
0125 
0126   // A vector of register file descriptors.  This set always contains at least
0127   // one entry. Entry at index #0 is reserved.  That entry describes a register
0128   // file with an unbounded number of physical registers that "sees" all the
0129   // hardware registers declared by the target (i.e. all the register
0130   // definitions in the target specific `XYZRegisterInfo.td` - where `XYZ` is
0131   // the target name).
0132   //
0133   // Users can limit the number of physical registers that are available in
0134   // register file #0 specifying command line flag `-register-file-size=<uint>`.
0135   SmallVector<RegisterMappingTracker, 4> RegisterFiles;
0136 
0137   // This type is used to propagate information about the owner of a register,
0138   // and the cost of allocating it in the PRF. Register cost is defined as the
0139   // number of physical registers consumed by the PRF to allocate a user
0140   // register.
0141   //
0142   // For example: on X86 BtVer2, a YMM register consumes 2 128-bit physical
0143   // registers. So, the cost of allocating a YMM register in BtVer2 is 2.
0144   using IndexPlusCostPairTy = std::pair<unsigned, unsigned>;
0145 
0146   // Struct RegisterRenamingInfo is used to map logical registers to register
0147   // files.
0148   //
0149   // There is a RegisterRenamingInfo object for every logical register defined
0150   // by the target. RegisteRenamingInfo objects are stored into vector
0151   // `RegisterMappings`, and MCPhysReg IDs can be used to reference
0152   // elements in that vector.
0153   //
0154   // Each RegisterRenamingInfo is owned by a PRF, and field `IndexPlusCost`
0155   // specifies both the owning PRF, as well as the number of physical registers
0156   // consumed at register renaming stage.
0157   //
0158   // Field `AllowMoveElimination` is set for registers that are used as
0159   // destination by optimizable register moves.
0160   //
0161   // Field `AliasRegID` is set by writes from register moves that have been
0162   // eliminated at register renaming stage. A move eliminated at register
0163   // renaming stage is effectively bypassed, and its write aliases the source
0164   // register definition.
0165   struct RegisterRenamingInfo {
0166     IndexPlusCostPairTy IndexPlusCost;
0167     MCPhysReg RenameAs;
0168     MCPhysReg AliasRegID;
0169     bool AllowMoveElimination;
0170     RegisterRenamingInfo()
0171         : IndexPlusCost(std::make_pair(0U, 1U)), RenameAs(0U), AliasRegID(0U),
0172           AllowMoveElimination(false) {}
0173   };
0174 
0175   // RegisterMapping objects are mainly used to track physical register
0176   // definitions and resolve data dependencies.
0177   //
0178   // Every register declared by the Target is associated with an instance of
0179   // RegisterMapping. RegisterMapping objects keep track of writes to a logical
0180   // register.  That information is used by class RegisterFile to resolve data
0181   // dependencies, and correctly set latencies for register uses.
0182   //
0183   // This implementation does not allow overlapping register files. The only
0184   // register file that is allowed to overlap with other register files is
0185   // register file #0. If we exclude register #0, every register is "owned" by
0186   // at most one register file.
0187   using RegisterMapping = std::pair<WriteRef, RegisterRenamingInfo>;
0188 
0189   // There is one entry per each register defined by the target.
0190   std::vector<RegisterMapping> RegisterMappings;
0191 
0192   // Used to track zero registers. There is one bit for each register defined by
0193   // the target. Bits are set for registers that are known to be zero.
0194   APInt ZeroRegisters;
0195 
0196   unsigned CurrentCycle;
0197 
0198   // This method creates a new register file descriptor.
0199   // The new register file owns all of the registers declared by register
0200   // classes in the 'RegisterClasses' set.
0201   //
0202   // Processor models allow the definition of RegisterFile(s) via tablegen. For
0203   // example, this is a tablegen definition for a x86 register file for
0204   // XMM[0-15] and YMM[0-15], that allows up to 60 renames (each rename costs 1
0205   // physical register).
0206   //
0207   //    def FPRegisterFile : RegisterFile<60, [VR128RegClass, VR256RegClass]>
0208   //
0209   // Here FPRegisterFile contains all the registers defined by register class
0210   // VR128RegClass and VR256RegClass. FPRegisterFile implements 60
0211   // registers which can be used for register renaming purpose.
0212   void addRegisterFile(const MCRegisterFileDesc &RF,
0213                        ArrayRef<MCRegisterCostEntry> Entries);
0214 
0215   // Consumes physical registers in each register file specified by the
0216   // `IndexPlusCostPairTy`. This method is called from `addRegisterMapping()`.
0217   void allocatePhysRegs(const RegisterRenamingInfo &Entry,
0218                         MutableArrayRef<unsigned> UsedPhysRegs);
0219 
0220   // Releases previously allocated physical registers from the register file(s).
0221   // This method is called from `invalidateRegisterMapping()`.
0222   void freePhysRegs(const RegisterRenamingInfo &Entry,
0223                     MutableArrayRef<unsigned> FreedPhysRegs);
0224 
0225   // Create an instance of RegisterMappingTracker for every register file
0226   // specified by the processor model.
0227   // If no register file is specified, then this method creates a default
0228   // register file with an unbounded number of physical registers.
0229   void initialize(const MCSchedModel &SM, unsigned NumRegs);
0230 
0231 public:
0232   RegisterFile(const MCSchedModel &SM, const MCRegisterInfo &mri,
0233                unsigned NumRegs = 0);
0234 
0235   // Collects writes that are in a RAW dependency with RS.
0236   void collectWrites(const MCSubtargetInfo &STI, const ReadState &RS,
0237                      SmallVectorImpl<WriteRef> &Writes,
0238                      SmallVectorImpl<WriteRef> &CommittedWrites) const;
0239   struct RAWHazard {
0240     MCPhysReg RegisterID = 0;
0241     int CyclesLeft = 0;
0242 
0243     RAWHazard() = default;
0244     bool isValid() const { return RegisterID; }
0245     bool hasUnknownCycles() const { return CyclesLeft < 0; }
0246   };
0247 
0248   RAWHazard checkRAWHazards(const MCSubtargetInfo &STI,
0249                             const ReadState &RS) const;
0250 
0251   // This method updates the register mappings inserting a new register
0252   // definition. This method is also responsible for updating the number of
0253   // allocated physical registers in each register file modified by the write.
0254   // No physical regiser is allocated if this write is from a zero-idiom.
0255   void addRegisterWrite(WriteRef Write, MutableArrayRef<unsigned> UsedPhysRegs);
0256 
0257   // Collect writes that are in a data dependency with RS, and update RS
0258   // internal state.
0259   void addRegisterRead(ReadState &RS, const MCSubtargetInfo &STI) const;
0260 
0261   // Removes write \param WS from the register mappings.
0262   // Physical registers may be released to reflect this update.
0263   // No registers are released if this write is from a zero-idiom.
0264   void removeRegisterWrite(const WriteState &WS,
0265                            MutableArrayRef<unsigned> FreedPhysRegs);
0266 
0267   // Returns true if the PRF at index `PRFIndex` can eliminate a move from RS to
0268   // WS.
0269   bool canEliminateMove(const WriteState &WS, const ReadState &RS,
0270                         unsigned PRFIndex) const;
0271 
0272   // Returns true if this instruction can be fully eliminated at register
0273   // renaming stage. On success, this method updates the internal state of each
0274   // WriteState by setting flag `WS.isEliminated`, and by propagating the zero
0275   // flag for known zero registers. It internally uses `canEliminateMove` to
0276   // determine if a read/write pair can be eliminated. By default, it assumes a
0277   // register swap if there is more than one register definition.
0278   bool tryEliminateMoveOrSwap(MutableArrayRef<WriteState> Writes,
0279                               MutableArrayRef<ReadState> Reads);
0280 
0281   // Checks if there are enough physical registers in the register files.
0282   // Returns a "response mask" where each bit represents the response from a
0283   // different register file.  A mask of all zeroes means that all register
0284   // files are available.  Otherwise, the mask can be used to identify which
0285   // register file was busy.  This sematic allows us to classify dispatch
0286   // stalls caused by the lack of register file resources.
0287   //
0288   // Current implementation can simulate up to 32 register files (including the
0289   // special register file at index #0).
0290   unsigned isAvailable(ArrayRef<MCPhysReg> Regs) const;
0291 
0292   // Returns the number of PRFs implemented by this processor.
0293   unsigned getNumRegisterFiles() const { return RegisterFiles.size(); }
0294 
0295   unsigned getElapsedCyclesFromWriteBack(const WriteRef &WR) const;
0296 
0297   void onInstructionExecuted(Instruction *IS);
0298 
0299   // Notify each PRF that a new cycle just started.
0300   void cycleStart();
0301 
0302   void cycleEnd() { ++CurrentCycle; }
0303 
0304 #ifndef NDEBUG
0305   void dump() const;
0306 #endif
0307 };
0308 
0309 } // namespace mca
0310 } // namespace llvm
0311 
0312 #endif // LLVM_MCA_HARDWAREUNITS_REGISTERFILE_H