//===--------------------- RegisterFile.h -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// \file /// /// This file defines a register mapping file class. This class is responsible /// for managing hardware register files and the tracking of data dependencies /// between registers. /// //===----------------------------------------------------------------------===// #ifndef LLVM_TOOLS_LLVM_MCA_REGISTER_FILE_H #define LLVM_TOOLS_LLVM_MCA_REGISTER_FILE_H #include "HardwareUnit.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSchedule.h" namespace mca { class ReadState; class WriteState; class WriteRef; /// Manages hardware register files, and tracks register definitions for /// register renaming purposes. class RegisterFile : public HardwareUnit { const llvm::MCRegisterInfo &MRI; // Each register file is associated with an instance of // RegisterMappingTracker. // A RegisterMappingTracker keeps track of the number of physical registers // which have been dynamically allocated by the simulator. struct RegisterMappingTracker { // The total number of physical registers that are available in this // register file for register renaming purpouses. A value of zero for this // field means: this register file has an unbounded number of physical // registers. const unsigned NumPhysRegs; // Number of physical registers that are currently in use. unsigned NumUsedPhysRegs; RegisterMappingTracker(unsigned NumPhysRegisters) : NumPhysRegs(NumPhysRegisters), NumUsedPhysRegs(0) {} }; // A vector of register file descriptors. This set always contains at least // one entry. Entry at index #0 is reserved. That entry describes a register // file with an unbounded number of physical registers that "sees" all the // hardware registers declared by the target (i.e. all the register // definitions in the target specific `XYZRegisterInfo.td` - where `XYZ` is // the target name). // // Users can limit the number of physical registers that are available in // regsiter file #0 specifying command line flag `-register-file-size=<uint>`. llvm::SmallVector<RegisterMappingTracker, 4> RegisterFiles; // This type is used to propagate information about the owner of a register, // and the cost of allocating it in the PRF. Register cost is defined as the // number of physical registers consumed by the PRF to allocate a user // register. // // For example: on X86 BtVer2, a YMM register consumes 2 128-bit physical // registers. So, the cost of allocating a YMM register in BtVer2 is 2. using IndexPlusCostPairTy = std::pair<unsigned, unsigned>; // Struct RegisterRenamingInfo maps registers to register files. // There is a RegisterRenamingInfo object for every register defined by // the target. RegisteRenamingInfo objects are stored into vector // RegisterMappings, and register IDs can be used to reference them. struct RegisterRenamingInfo { IndexPlusCostPairTy IndexPlusCost; llvm::MCPhysReg RenameAs; }; // RegisterMapping objects are mainly used to track physical register // definitions. There is a RegisterMapping for every register defined by the // Target. For each register, a RegisterMapping pair contains a descriptor of // the last register write (in the form of a WriteRef object), as well as a // RegisterRenamingInfo to quickly identify owning register files. // // This implementation does not allow overlapping register files. The only // register file that is allowed to overlap with other register files is // register file #0. If we exclude register #0, every register is "owned" by // at most one register file. using RegisterMapping = std::pair<WriteRef, RegisterRenamingInfo>; // This map contains one entry for each register defined by the target. std::vector<RegisterMapping> RegisterMappings; // This method creates a new register file descriptor. // The new register file owns all of the registers declared by register // classes in the 'RegisterClasses' set. // // Processor models allow the definition of RegisterFile(s) via tablegen. For // example, this is a tablegen definition for a x86 register file for // XMM[0-15] and YMM[0-15], that allows up to 60 renames (each rename costs 1 // physical register). // // def FPRegisterFile : RegisterFile<60, [VR128RegClass, VR256RegClass]> // // Here FPRegisterFile contains all the registers defined by register class // VR128RegClass and VR256RegClass. FPRegisterFile implements 60 // registers which can be used for register renaming purpose. void addRegisterFile(llvm::ArrayRef<llvm::MCRegisterCostEntry> RegisterClasses, unsigned NumPhysRegs); // Consumes physical registers in each register file specified by the // `IndexPlusCostPairTy`. This method is called from `addRegisterMapping()`. void allocatePhysRegs(const RegisterRenamingInfo &Entry, llvm::MutableArrayRef<unsigned> UsedPhysRegs); // Releases previously allocated physical registers from the register file(s). // This method is called from `invalidateRegisterMapping()`. void freePhysRegs(const RegisterRenamingInfo &Entry, llvm::MutableArrayRef<unsigned> FreedPhysRegs); // Create an instance of RegisterMappingTracker for every register file // specified by the processor model. // If no register file is specified, then this method creates a default // register file with an unbounded number of physical registers. void initialize(const llvm::MCSchedModel &SM, unsigned NumRegs); public: RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri, unsigned NumRegs = 0); // This method updates the register mappings inserting a new register // definition. This method is also responsible for updating the number of // allocated physical registers in each register file modified by the write. // No physical regiser is allocated when flag ShouldAllocatePhysRegs is set. void addRegisterWrite(WriteRef Write, llvm::MutableArrayRef<unsigned> UsedPhysRegs, bool ShouldAllocatePhysRegs = true); // Removes write \param WS from the register mappings. // Physical registers may be released to reflect this update. void removeRegisterWrite(const WriteState &WS, llvm::MutableArrayRef<unsigned> FreedPhysRegs, bool ShouldFreePhysRegs = true); // Checks if there are enough physical registers in the register files. // Returns a "response mask" where each bit represents the response from a // different register file. A mask of all zeroes means that all register // files are available. Otherwise, the mask can be used to identify which // register file was busy. This sematic allows us to classify dispatch // stalls caused by the lack of register file resources. // // Current implementation can simulate up to 32 register files (including the // special register file at index #0). unsigned isAvailable(llvm::ArrayRef<unsigned> Regs) const; void collectWrites(llvm::SmallVectorImpl<WriteRef> &Writes, unsigned RegID) const; void updateOnRead(ReadState &RS, unsigned RegID); unsigned getNumRegisterFiles() const { return RegisterFiles.size(); } #ifndef NDEBUG void dump() const; #endif }; } // namespace mca #endif // LLVM_TOOLS_LLVM_MCA_REGISTER_FILE_H