123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===--------------------- 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_HARDWAREUNITS_REGISTERFILE_H
- #define LLVM_MCA_HARDWAREUNITS_REGISTERFILE_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 Instruction;
- /// A reference to a register write.
- ///
- /// This class is mainly used by the register file to describe register
- /// mappings. It correlates a register write to the source index of the
- /// defining instruction.
- class WriteRef {
- unsigned IID;
- unsigned WriteBackCycle;
- unsigned WriteResID;
- MCPhysReg RegisterID;
- WriteState *Write;
- static const unsigned INVALID_IID;
- public:
- WriteRef()
- : IID(INVALID_IID), WriteBackCycle(), WriteResID(), RegisterID(),
- Write() {}
- WriteRef(unsigned SourceIndex, WriteState *WS);
- unsigned getSourceIndex() const { return IID; }
- unsigned getWriteBackCycle() const;
- const WriteState *getWriteState() const { return Write; }
- WriteState *getWriteState() { return Write; }
- unsigned getWriteResourceID() const;
- MCPhysReg getRegisterID() const;
- void commit();
- void notifyExecuted(unsigned Cycle);
- bool hasKnownWriteBackCycle() const;
- bool isWriteZero() const;
- bool isValid() const { return getSourceIndex() != INVALID_IID; }
- /// Returns true if this register write has been executed, and the new
- /// register value is therefore available to users.
- bool isAvailable() const { return hasKnownWriteBackCycle(); }
- bool operator==(const WriteRef &Other) const {
- return Write && Other.Write && Write == Other.Write;
- }
- #ifndef NDEBUG
- void dump() const;
- #endif
- };
- /// 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;
- unsigned CurrentCycle;
- // 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);
- // 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);
- // Collects writes that are in a RAW dependency with RS.
- void collectWrites(const MCSubtargetInfo &STI, const ReadState &RS,
- SmallVectorImpl<WriteRef> &Writes,
- SmallVectorImpl<WriteRef> &CommittedWrites) const;
- struct RAWHazard {
- MCPhysReg RegisterID;
- int CyclesLeft;
- RAWHazard() : RegisterID(), CyclesLeft() {}
- bool isValid() const { return RegisterID; }
- bool hasUnknownCycles() const { return CyclesLeft < 0; }
- };
- RAWHazard checkRAWHazards(const MCSubtargetInfo &STI,
- const ReadState &RS) const;
- // 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 the PRF at index `PRFIndex` can eliminate a move from RS to
- // WS.
- bool canEliminateMove(const WriteState &WS, const ReadState &RS,
- unsigned PRFIndex) const;
- // Returns true if this instruction can be fully eliminated at register
- // renaming stage. On success, this method updates the internal state of each
- // WriteState by setting flag `WS.isEliminated`, and by propagating the zero
- // flag for known zero registers. It internally uses `canEliminateMove` to
- // determine if a read/write pair can be eliminated. By default, it assumes a
- // register swap if there is more than one register definition.
- bool tryEliminateMoveOrSwap(MutableArrayRef<WriteState> Writes,
- MutableArrayRef<ReadState> Reads);
- // 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(); }
- unsigned getElapsedCyclesFromWriteBack(const WriteRef &WR) const;
- void onInstructionExecuted(Instruction *IS);
- // Notify each PRF that a new cycle just started.
- void cycleStart();
- void cycleEnd() { ++CurrentCycle; }
- #ifndef NDEBUG
- void dump() const;
- #endif
- };
- } // namespace mca
- } // namespace llvm
- #endif // LLVM_MCA_HARDWAREUNITS_REGISTERFILE_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|