mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 11:02:59 +02:00
239 lines
10 KiB
C++
239 lines
10 KiB
C++
//===--------------------- RegisterFile.h -----------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \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_MCA_REGISTER_FILE_H
|
|
#define LLVM_MCA_REGISTER_FILE_H
|
|
|
|
#include "llvm/ADT/APInt.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
#include "llvm/MC/MCSchedule.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/MCA/HardwareUnits/HardwareUnit.h"
|
|
|
|
namespace llvm {
|
|
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 MCRegisterInfo &MRI;
|
|
|
|
// class RegisterMappingTracker is a physical register file (PRF) descriptor.
|
|
// There is one RegisterMappingTracker for every PRF definition in the
|
|
// scheduling model.
|
|
//
|
|
// An instance of RegisterMappingTracker tracks the number of physical
|
|
// registers available for renaming. It also tracks the number of register
|
|
// moves eliminated per cycle.
|
|
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;
|
|
|
|
// Maximum number of register moves that can be eliminated by this PRF every
|
|
// cycle. A value of zero means that there is no limit in the number of
|
|
// moves which can be eliminated every cycle.
|
|
const unsigned MaxMoveEliminatedPerCycle;
|
|
|
|
// Number of register moves eliminated during this cycle.
|
|
//
|
|
// This value is increased by one every time a register move is eliminated.
|
|
// Every new cycle, this value is reset to zero.
|
|
// A move can be eliminated only if MaxMoveEliminatedPerCycle is zero, or if
|
|
// NumMoveEliminated is less than MaxMoveEliminatedPerCycle.
|
|
unsigned NumMoveEliminated;
|
|
|
|
// If set, move elimination is restricted to zero-register moves only.
|
|
bool AllowZeroMoveEliminationOnly;
|
|
|
|
RegisterMappingTracker(unsigned NumPhysRegisters,
|
|
unsigned MaxMoveEliminated = 0U,
|
|
bool AllowZeroMoveElimOnly = false)
|
|
: NumPhysRegs(NumPhysRegisters), NumUsedPhysRegs(0),
|
|
MaxMoveEliminatedPerCycle(MaxMoveEliminated), NumMoveEliminated(0U),
|
|
AllowZeroMoveEliminationOnly(AllowZeroMoveElimOnly) {}
|
|
};
|
|
|
|
// 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
|
|
// register file #0 specifying command line flag `-register-file-size=<uint>`.
|
|
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 is used to map logical registers to register
|
|
// files.
|
|
//
|
|
// There is a RegisterRenamingInfo object for every logical register defined
|
|
// by the target. RegisteRenamingInfo objects are stored into vector
|
|
// `RegisterMappings`, and MCPhysReg IDs can be used to reference
|
|
// elements in that vector.
|
|
//
|
|
// Each RegisterRenamingInfo is owned by a PRF, and field `IndexPlusCost`
|
|
// specifies both the owning PRF, as well as the number of physical registers
|
|
// consumed at register renaming stage.
|
|
//
|
|
// Field `AllowMoveElimination` is set for registers that are used as
|
|
// destination by optimizable register moves.
|
|
//
|
|
// Field `AliasRegID` is set by writes from register moves that have been
|
|
// eliminated at register renaming stage. A move eliminated at register
|
|
// renaming stage is effectively bypassed, and its write aliases the source
|
|
// register definition.
|
|
struct RegisterRenamingInfo {
|
|
IndexPlusCostPairTy IndexPlusCost;
|
|
MCPhysReg RenameAs;
|
|
MCPhysReg AliasRegID;
|
|
bool AllowMoveElimination;
|
|
RegisterRenamingInfo()
|
|
: IndexPlusCost(std::make_pair(0U, 1U)), RenameAs(0U), AliasRegID(0U),
|
|
AllowMoveElimination(false) {}
|
|
};
|
|
|
|
// RegisterMapping objects are mainly used to track physical register
|
|
// definitions and resolve data dependencies.
|
|
//
|
|
// Every register declared by the Target is associated with an instance of
|
|
// RegisterMapping. RegisterMapping objects keep track of writes to a logical
|
|
// register. That information is used by class RegisterFile to resolve data
|
|
// dependencies, and correctly set latencies for register uses.
|
|
//
|
|
// 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>;
|
|
|
|
// There is one entry per each register defined by the target.
|
|
std::vector<RegisterMapping> RegisterMappings;
|
|
|
|
// Used to track zero registers. There is one bit for each register defined by
|
|
// the target. Bits are set for registers that are known to be zero.
|
|
APInt ZeroRegisters;
|
|
|
|
// 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(const MCRegisterFileDesc &RF,
|
|
ArrayRef<MCRegisterCostEntry> Entries);
|
|
|
|
// Consumes physical registers in each register file specified by the
|
|
// `IndexPlusCostPairTy`. This method is called from `addRegisterMapping()`.
|
|
void allocatePhysRegs(const RegisterRenamingInfo &Entry,
|
|
MutableArrayRef<unsigned> UsedPhysRegs);
|
|
|
|
// Releases previously allocated physical registers from the register file(s).
|
|
// This method is called from `invalidateRegisterMapping()`.
|
|
void freePhysRegs(const RegisterRenamingInfo &Entry,
|
|
MutableArrayRef<unsigned> FreedPhysRegs);
|
|
|
|
// Collects writes that are in a RAW dependency with RS.
|
|
// This method is called from `addRegisterRead()`.
|
|
void collectWrites(const ReadState &RS,
|
|
SmallVectorImpl<WriteRef> &Writes) const;
|
|
|
|
// 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 MCSchedModel &SM, unsigned NumRegs);
|
|
|
|
public:
|
|
RegisterFile(const MCSchedModel &SM, const 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 if this write is from a zero-idiom.
|
|
void addRegisterWrite(WriteRef Write, MutableArrayRef<unsigned> UsedPhysRegs);
|
|
|
|
// Collect writes that are in a data dependency with RS, and update RS
|
|
// internal state.
|
|
void addRegisterRead(ReadState &RS, const MCSubtargetInfo &STI) const;
|
|
|
|
// Removes write \param WS from the register mappings.
|
|
// Physical registers may be released to reflect this update.
|
|
// No registers are released if this write is from a zero-idiom.
|
|
void removeRegisterWrite(const WriteState &WS,
|
|
MutableArrayRef<unsigned> FreedPhysRegs);
|
|
|
|
// Returns true if a move from RS to WS can be eliminated.
|
|
// On success, it updates WriteState by setting flag `WS.isEliminated`.
|
|
// If RS is a read from a zero register, and WS is eliminated, then
|
|
// `WS.WritesZero` is also set, so that method addRegisterWrite() would not
|
|
// reserve a physical register for it.
|
|
bool tryEliminateMove(WriteState &WS, ReadState &RS);
|
|
|
|
// 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(ArrayRef<MCPhysReg> Regs) const;
|
|
|
|
// Returns the number of PRFs implemented by this processor.
|
|
unsigned getNumRegisterFiles() const { return RegisterFiles.size(); }
|
|
|
|
// Notify each PRF that a new cycle just started.
|
|
void cycleStart();
|
|
|
|
#ifndef NDEBUG
|
|
void dump() const;
|
|
#endif
|
|
};
|
|
|
|
} // namespace mca
|
|
} // namespace llvm
|
|
|
|
#endif // LLVM_MCA_REGISTER_FILE_H
|