//===--------------------- 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