Index: tools/llvm-mca/CMakeLists.txt =================================================================== --- tools/llvm-mca/CMakeLists.txt +++ tools/llvm-mca/CMakeLists.txt @@ -23,6 +23,7 @@ InstructionTables.cpp LSUnit.cpp llvm-mca.cpp + RegisterFile.cpp RegisterFileStatistics.cpp ResourcePressureView.cpp RetireControlUnit.cpp Index: tools/llvm-mca/Dispatch.h =================================================================== --- tools/llvm-mca/Dispatch.h +++ tools/llvm-mca/Dispatch.h @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// /// \file /// -/// This file implements classes that are used to model register files, -/// reorder buffers and the hardware dispatch logic. +/// This file implements classes that are used to model reorder buffers and +/// the hardware dispatch logic. /// //===----------------------------------------------------------------------===// @@ -17,149 +17,15 @@ #define LLVM_TOOLS_LLVM_MCA_DISPATCH_H #include "Instruction.h" +#include "RegisterFile.h" #include "RetireControlUnit.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include namespace mca { class WriteState; -class DispatchUnit; class Scheduler; class Backend; -/// Manages hardware register files, and tracks data dependencies -/// between registers. -class RegisterFile { - const llvm::MCRegisterInfo &MRI; - - // Each register file is described by an instance of RegisterMappingTracker. - // RegisterMappingTracker tracks the number of register mappings dynamically - // allocated during the execution. - struct RegisterMappingTracker { - // Total number of register mappings that are available for register - // renaming. A value of zero for this field means: this register file has - // an unbounded number of registers. - const unsigned TotalMappings; - // Number of mappings that are currently in use. - unsigned NumUsedMappings; - - RegisterMappingTracker(unsigned NumMappings) - : TotalMappings(NumMappings), NumUsedMappings(0) {} - }; - - // This is where information related to the various register files is kept. - // This set always contains at least one register file at index #0. That - // register file "sees" all the physical registers declared by the target, and - // (by default) it allows an unbounded number of mappings. - // Users can limit the number of mappings that can be created by register file - // #0 through the command line flag `-register-file-size`. - llvm::SmallVector RegisterFiles; - - // This pair is used to identify the owner of a physical register, as well as - // the cost of using that register file. - using IndexPlusCostPairTy = std::pair; - - // RegisterMapping objects are mainly used to track physical register - // definitions. A WriteState object describes a register definition, and it is - // used to track RAW dependencies (see Instruction.h). A RegisterMapping - // object also specifies the set of register files. The mapping between - // physreg and register files is done using a "register file mask". - // - // A register file index identifies a user defined register file. - // There is one index per RegisterMappingTracker, and index #0 is reserved to - // the default unified register file. - // - // 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. - using RegisterMapping = std::pair; - - // This map contains one entry for each physical register defined by the - // processor scheduling model. - std::vector RegisterMappings; - - // This method creates a new RegisterMappingTracker for a register file that - // contains all the physical registers specified by the register classes in - // the 'RegisterClasses' set. - // - // The long term goal is to let scheduling models optionally describe register - // files via tablegen definitions. This is still a work in progress. - // For example, here is how a tablegen definition for a x86 FP register file - // that features AVX might look like: - // - // def FPRegisterFile : RegisterFile<[VR128RegClass, VR256RegClass], 60> - // - // 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. - // - // The list of register classes is then converted by the tablegen backend into - // a list of register class indices. That list, along with the number of - // available mappings, is then used to create a new RegisterMappingTracker. - void - addRegisterFile(llvm::ArrayRef RegisterClasses, - unsigned NumPhysRegs); - - // Allocates register mappings in register file specified by the - // IndexPlusCostPairTy object. This method is called from addRegisterMapping. - void allocatePhysRegs(IndexPlusCostPairTy IPC, - llvm::MutableArrayRef UsedPhysRegs); - - // Removes a previously allocated mapping from the register file referenced - // by the IndexPlusCostPairTy object. This method is called from - // invalidateRegisterMapping. - void freePhysRegs(IndexPlusCostPairTy IPC, - llvm::MutableArrayRef 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 single - // register file with an unbounded number of registers. - void initialize(const llvm::MCSchedModel &SM, unsigned NumRegs); - -public: - RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri, - unsigned NumRegs = 0) - : MRI(mri), RegisterMappings(mri.getNumRegs(), {nullptr, {0, 0}}) { - initialize(SM, NumRegs); - } - - // This method updates the data dependency graph by inserting a new register - // definition. This method is also responsible for updating the number of used - // physical registers in the register file(s). The number of physical - // registers is updated only if flag ShouldAllocatePhysRegs is set. - void addRegisterWrite(WriteState &WS, - llvm::MutableArrayRef UsedPhysRegs, - bool ShouldAllocatePhysRegs = true); - - // Updates the data dependency graph by removing a write. It also updates the - // internal state of the register file(s) by freeing physical registers. - // The number of physical registers is updated only if flag ShouldFreePhysRegs - // is set. - void removeRegisterWrite(const WriteState &WS, - llvm::MutableArrayRef FreedPhysRegs, - bool ShouldFreePhysRegs = true); - - // Checks if there are enough microarchitectural registers in the register - // files. Returns a "response mask" where each bit is the response from a - // RegisterMappingTracker. - // For example: if all register files are available, then the response mask - // is a bitmask of all zeroes. If Instead register file #1 is not available, - // then the response mask is 0b10. - unsigned isAvailable(llvm::ArrayRef Regs) const; - void collectWrites(llvm::SmallVectorImpl &Writes, - unsigned RegID) const; - void updateOnRead(ReadState &RS, unsigned RegID); - - unsigned getNumRegisterFiles() const { return RegisterFiles.size(); } - -#ifndef NDEBUG - void dump() const; -#endif -}; - // Implements the hardware dispatch logic. // // This class is responsible for the dispatch stage, in which instructions are Index: tools/llvm-mca/Dispatch.cpp =================================================================== --- tools/llvm-mca/Dispatch.cpp +++ tools/llvm-mca/Dispatch.cpp @@ -8,8 +8,7 @@ //===----------------------------------------------------------------------===// /// \file /// -/// This file implements methods declared by class RegisterFile and -/// DispatchUnit. +/// This file implements methods declared by the DispatchUnit class. /// //===----------------------------------------------------------------------===// @@ -25,240 +24,6 @@ namespace mca { -void RegisterFile::initialize(const MCSchedModel &SM, unsigned NumRegs) { - // Create a default register file that "sees" all the machine registers - // declared by the target. The number of physical registers in the default - // register file is set equal to `NumRegs`. A value of zero for `NumRegs` - // means: this register file has an unbounded number of physical registers. - addRegisterFile({} /* all registers */, NumRegs); - if (!SM.hasExtraProcessorInfo()) - return; - - // For each user defined register file, allocate a RegisterMappingTracker - // object. The size of every register file, as well as the mapping between - // register files and register classes is specified via tablegen. - const MCExtraProcessorInfo &Info = SM.getExtraProcessorInfo(); - for (unsigned I = 0, E = Info.NumRegisterFiles; I < E; ++I) { - const MCRegisterFileDesc &RF = Info.RegisterFiles[I]; - // Skip invalid register files with zero physical registers. - unsigned Length = RF.NumRegisterCostEntries; - if (!RF.NumPhysRegs) - continue; - // The cost of a register definition is equivalent to the number of - // physical registers that are allocated at register renaming stage. - const MCRegisterCostEntry *FirstElt = - &Info.RegisterCostTable[RF.RegisterCostEntryIdx]; - addRegisterFile(ArrayRef(FirstElt, Length), - RF.NumPhysRegs); - } -} - -void RegisterFile::addRegisterFile(ArrayRef Entries, - unsigned NumPhysRegs) { - // A default register file is always allocated at index #0. That register file - // is mainly used to count the total number of mappings created by all - // register files at runtime. Users can limit the number of available physical - // registers in register file #0 through the command line flag - // `-register-file-size`. - unsigned RegisterFileIndex = RegisterFiles.size(); - RegisterFiles.emplace_back(NumPhysRegs); - - // Special case where there is no register class identifier in the set. - // An empty set of register classes means: this register file contains all - // the physical registers specified by the target. - if (Entries.empty()) { - for (std::pair &Mapping : - RegisterMappings) - Mapping.second = std::make_pair(RegisterFileIndex, 1U); - return; - } - - // Now update the cost of individual registers. - for (const MCRegisterCostEntry &RCE : Entries) { - const MCRegisterClass &RC = MRI.getRegClass(RCE.RegisterClassID); - for (const MCPhysReg Reg : RC) { - IndexPlusCostPairTy &Entry = RegisterMappings[Reg].second; - if (Entry.first) { - // The only register file that is allowed to overlap is the default - // register file at index #0. The analysis is inaccurate if register - // files overlap. - errs() << "warning: register " << MRI.getName(Reg) - << " defined in multiple register files."; - } - Entry.first = RegisterFileIndex; - Entry.second = RCE.Cost; - } - } -} - -void RegisterFile::allocatePhysRegs(IndexPlusCostPairTy Entry, - MutableArrayRef UsedPhysRegs) { - unsigned RegisterFileIndex = Entry.first; - unsigned Cost = Entry.second; - if (RegisterFileIndex) { - RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; - RMT.NumUsedMappings += Cost; - UsedPhysRegs[RegisterFileIndex] += Cost; - } - - // Now update the default register mapping tracker. - RegisterFiles[0].NumUsedMappings += Cost; - UsedPhysRegs[0] += Cost; -} - -void RegisterFile::freePhysRegs(IndexPlusCostPairTy Entry, - MutableArrayRef FreedPhysRegs) { - unsigned RegisterFileIndex = Entry.first; - unsigned Cost = Entry.second; - if (RegisterFileIndex) { - RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; - RMT.NumUsedMappings -= Cost; - FreedPhysRegs[RegisterFileIndex] += Cost; - } - - // Now update the default register mapping tracker. - RegisterFiles[0].NumUsedMappings -= Cost; - FreedPhysRegs[0] += Cost; -} - -void RegisterFile::addRegisterWrite(WriteState &WS, - MutableArrayRef UsedPhysRegs, - bool ShouldAllocatePhysRegs) { - unsigned RegID = WS.getRegisterID(); - assert(RegID && "Adding an invalid register definition?"); - - RegisterMapping &Mapping = RegisterMappings[RegID]; - Mapping.first = &WS; - for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) - RegisterMappings[*I].first = &WS; - - // No physical registers are allocated for instructions that are optimized in - // hardware. For example, zero-latency data-dependency breaking instructions - // don't consume physical registers. - if (ShouldAllocatePhysRegs) - allocatePhysRegs(Mapping.second, UsedPhysRegs); - - // If this is a partial update, then we are done. - if (!WS.fullyUpdatesSuperRegs()) - return; - - for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) - RegisterMappings[*I].first = &WS; -} - -void RegisterFile::removeRegisterWrite(const WriteState &WS, - MutableArrayRef FreedPhysRegs, - bool ShouldFreePhysRegs) { - unsigned RegID = WS.getRegisterID(); - bool ShouldInvalidateSuperRegs = WS.fullyUpdatesSuperRegs(); - - assert(RegID != 0 && "Invalidating an already invalid register?"); - assert(WS.getCyclesLeft() != -512 && - "Invalidating a write of unknown cycles!"); - assert(WS.getCyclesLeft() <= 0 && "Invalid cycles left for this write!"); - RegisterMapping &Mapping = RegisterMappings[RegID]; - if (!Mapping.first) - return; - - if (ShouldFreePhysRegs) - freePhysRegs(Mapping.second, FreedPhysRegs); - - if (Mapping.first == &WS) - Mapping.first = nullptr; - - for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) - if (RegisterMappings[*I].first == &WS) - RegisterMappings[*I].first = nullptr; - - if (!ShouldInvalidateSuperRegs) - return; - - for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) - if (RegisterMappings[*I].first == &WS) - RegisterMappings[*I].first = nullptr; -} - -void RegisterFile::collectWrites(SmallVectorImpl &Writes, - unsigned RegID) const { - assert(RegID && RegID < RegisterMappings.size()); - WriteState *WS = RegisterMappings[RegID].first; - if (WS) { - LLVM_DEBUG(dbgs() << "Found a dependent use of RegID=" << RegID << '\n'); - Writes.push_back(WS); - } - - // Handle potential partial register updates. - for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) { - WS = RegisterMappings[*I].first; - if (WS && std::find(Writes.begin(), Writes.end(), WS) == Writes.end()) { - LLVM_DEBUG(dbgs() << "Found a dependent use of subReg " << *I - << " (part of " << RegID << ")\n"); - Writes.push_back(WS); - } - } -} - -unsigned RegisterFile::isAvailable(ArrayRef Regs) const { - SmallVector NumPhysRegs(getNumRegisterFiles()); - - // Find how many new mappings must be created for each register file. - for (const unsigned RegID : Regs) { - const IndexPlusCostPairTy &Entry = RegisterMappings[RegID].second; - if (Entry.first) - NumPhysRegs[Entry.first] += Entry.second; - NumPhysRegs[0] += Entry.second; - } - - unsigned Response = 0; - for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) { - unsigned NumRegs = NumPhysRegs[I]; - if (!NumRegs) - continue; - - const RegisterMappingTracker &RMT = RegisterFiles[I]; - if (!RMT.TotalMappings) { - // The register file has an unbounded number of microarchitectural - // registers. - continue; - } - - if (RMT.TotalMappings < NumRegs) { - // The current register file is too small. This may occur if the number of - // microarchitectural registers in register file #0 was changed by the - // users via flag -reg-file-size. Alternatively, the scheduling model - // specified a too small number of registers for this register file. - report_fatal_error( - "Not enough microarchitectural registers in the register file"); - } - - if (RMT.TotalMappings < (RMT.NumUsedMappings + NumRegs)) - Response |= (1U << I); - } - - return Response; -} - -#ifndef NDEBUG -void RegisterFile::dump() const { - for (unsigned I = 0, E = MRI.getNumRegs(); I < E; ++I) { - const RegisterMapping &RM = RegisterMappings[I]; - dbgs() << MRI.getName(I) << ", " << I << ", Map=" << RM.second.first - << ", "; - if (RM.first) - RM.first->dump(); - else - dbgs() << "(null)\n"; - } - - for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) { - dbgs() << "Register File #" << I; - const RegisterMappingTracker &RMT = RegisterFiles[I]; - dbgs() << "\n TotalMappings: " << RMT.TotalMappings - << "\n NumUsedMappings: " << RMT.NumUsedMappings << '\n'; - } -} -#endif - void DispatchUnit::notifyInstructionDispatched(const InstRef &IR, ArrayRef UsedRegs) { LLVM_DEBUG(dbgs() << "[E] Instruction Dispatched: " << IR << '\n'); Index: tools/llvm-mca/RegisterFile.h =================================================================== --- /dev/null +++ tools/llvm-mca/RegisterFile.h @@ -0,0 +1,162 @@ +//===--------------------- 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 "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" + +namespace mca { + +class ReadState; +class WriteState; + +/// Manages hardware register files, and tracks data dependencies +/// between registers. +class RegisterFile { + const llvm::MCRegisterInfo &MRI; + + // Each register file is described by an instance of RegisterMappingTracker. + // RegisterMappingTracker tracks the number of register mappings dynamically + // allocated during the execution. + struct RegisterMappingTracker { + // Total number of register mappings that are available for register + // renaming. A value of zero for this field means: this register file has + // an unbounded number of registers. + const unsigned TotalMappings; + // Number of mappings that are currently in use. + unsigned NumUsedMappings; + + RegisterMappingTracker(unsigned NumMappings) + : TotalMappings(NumMappings), NumUsedMappings(0) {} + }; + + // This is where information related to the various register files is kept. + // This set always contains at least one register file at index #0. That + // register file "sees" all the physical registers declared by the target, and + // (by default) it allows an unbounded number of mappings. + // Users can limit the number of mappings that can be created by register file + // #0 through the command line flag `-register-file-size`. + llvm::SmallVector RegisterFiles; + + // This pair is used to identify the owner of a physical register, as well as + // the cost of using that register file. + using IndexPlusCostPairTy = std::pair; + + // RegisterMapping objects are mainly used to track physical register + // definitions. A WriteState object describes a register definition, and it is + // used to track RAW dependencies (see Instruction.h). A RegisterMapping + // object also specifies the set of register files. The mapping between + // physreg and register files is done using a "register file mask". + // + // A register file index identifies a user defined register file. + // There is one index per RegisterMappingTracker, and index #0 is reserved to + // the default unified register file. + // + // 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. + using RegisterMapping = std::pair; + + // This map contains one entry for each physical register defined by the + // processor scheduling model. + std::vector RegisterMappings; + + // This method creates a new RegisterMappingTracker for a register file that + // contains all the physical registers specified by the register classes in + // the 'RegisterClasses' set. + // + // The long term goal is to let scheduling models optionally describe register + // files via tablegen definitions. This is still a work in progress. + // For example, here is how a tablegen definition for a x86 FP register file + // that features AVX might look like: + // + // def FPRegisterFile : RegisterFile<[VR128RegClass, VR256RegClass], 60> + // + // 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. + // + // The list of register classes is then converted by the tablegen backend into + // a list of register class indices. That list, along with the number of + // available mappings, is then used to create a new RegisterMappingTracker. + void + addRegisterFile(llvm::ArrayRef RegisterClasses, + unsigned NumPhysRegs); + + // Allocates register mappings in register file specified by the + // IndexPlusCostPairTy object. This method is called from addRegisterMapping. + void allocatePhysRegs(IndexPlusCostPairTy IPC, + llvm::MutableArrayRef UsedPhysRegs); + + // Removes a previously allocated mapping from the register file referenced + // by the IndexPlusCostPairTy object. This method is called from + // invalidateRegisterMapping. + void freePhysRegs(IndexPlusCostPairTy IPC, + llvm::MutableArrayRef 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 single + // register file with an unbounded number of registers. + void initialize(const llvm::MCSchedModel &SM, unsigned NumRegs); + +public: + RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri, + unsigned NumRegs = 0) + : MRI(mri), RegisterMappings(mri.getNumRegs(), {nullptr, {0, 0}}) { + initialize(SM, NumRegs); + } + + // This method updates the data dependency graph by inserting a new register + // definition. This method is also responsible for updating the number of used + // physical registers in the register file(s). The number of physical + // registers is updated only if flag ShouldAllocatePhysRegs is set. + void addRegisterWrite(WriteState &WS, + llvm::MutableArrayRef UsedPhysRegs, + bool ShouldAllocatePhysRegs = true); + + // Updates the data dependency graph by removing a write. It also updates the + // internal state of the register file(s) by freeing physical registers. + // The number of physical registers is updated only if flag ShouldFreePhysRegs + // is set. + void removeRegisterWrite(const WriteState &WS, + llvm::MutableArrayRef FreedPhysRegs, + bool ShouldFreePhysRegs = true); + + // Checks if there are enough microarchitectural registers in the register + // files. Returns a "response mask" where each bit is the response from a + // RegisterMappingTracker. + // For example: if all register files are available, then the response mask + // is a bitmask of all zeroes. If Instead register file #1 is not available, + // then the response mask is 0b10. + unsigned isAvailable(llvm::ArrayRef Regs) const; + void collectWrites(llvm::SmallVectorImpl &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 Index: tools/llvm-mca/RegisterFile.cpp =================================================================== --- /dev/null +++ tools/llvm-mca/RegisterFile.cpp @@ -0,0 +1,261 @@ +//===--------------------- RegisterFile.cpp ---------------------*- 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. +/// +//===----------------------------------------------------------------------===// + +#include "RegisterFile.h" +#include "Instruction.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +#define DEBUG_TYPE "llvm-mca" + +namespace mca { + +void RegisterFile::initialize(const MCSchedModel &SM, unsigned NumRegs) { + // Create a default register file that "sees" all the machine registers + // declared by the target. The number of physical registers in the default + // register file is set equal to `NumRegs`. A value of zero for `NumRegs` + // means: this register file has an unbounded number of physical registers. + addRegisterFile({} /* all registers */, NumRegs); + if (!SM.hasExtraProcessorInfo()) + return; + + // For each user defined register file, allocate a RegisterMappingTracker + // object. The size of every register file, as well as the mapping between + // register files and register classes is specified via tablegen. + const MCExtraProcessorInfo &Info = SM.getExtraProcessorInfo(); + for (unsigned I = 0, E = Info.NumRegisterFiles; I < E; ++I) { + const MCRegisterFileDesc &RF = Info.RegisterFiles[I]; + // Skip invalid register files with zero physical registers. + unsigned Length = RF.NumRegisterCostEntries; + if (!RF.NumPhysRegs) + continue; + // The cost of a register definition is equivalent to the number of + // physical registers that are allocated at register renaming stage. + const MCRegisterCostEntry *FirstElt = + &Info.RegisterCostTable[RF.RegisterCostEntryIdx]; + addRegisterFile(ArrayRef(FirstElt, Length), + RF.NumPhysRegs); + } +} + +void RegisterFile::addRegisterFile(ArrayRef Entries, + unsigned NumPhysRegs) { + // A default register file is always allocated at index #0. That register file + // is mainly used to count the total number of mappings created by all + // register files at runtime. Users can limit the number of available physical + // registers in register file #0 through the command line flag + // `-register-file-size`. + unsigned RegisterFileIndex = RegisterFiles.size(); + RegisterFiles.emplace_back(NumPhysRegs); + + // Special case where there is no register class identifier in the set. + // An empty set of register classes means: this register file contains all + // the physical registers specified by the target. + if (Entries.empty()) { + for (std::pair &Mapping : + RegisterMappings) + Mapping.second = std::make_pair(RegisterFileIndex, 1U); + return; + } + + // Now update the cost of individual registers. + for (const MCRegisterCostEntry &RCE : Entries) { + const MCRegisterClass &RC = MRI.getRegClass(RCE.RegisterClassID); + for (const MCPhysReg Reg : RC) { + IndexPlusCostPairTy &Entry = RegisterMappings[Reg].second; + if (Entry.first) { + // The only register file that is allowed to overlap is the default + // register file at index #0. The analysis is inaccurate if register + // files overlap. + errs() << "warning: register " << MRI.getName(Reg) + << " defined in multiple register files."; + } + Entry.first = RegisterFileIndex; + Entry.second = RCE.Cost; + } + } +} + +void RegisterFile::allocatePhysRegs(IndexPlusCostPairTy Entry, + MutableArrayRef UsedPhysRegs) { + unsigned RegisterFileIndex = Entry.first; + unsigned Cost = Entry.second; + if (RegisterFileIndex) { + RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; + RMT.NumUsedMappings += Cost; + UsedPhysRegs[RegisterFileIndex] += Cost; + } + + // Now update the default register mapping tracker. + RegisterFiles[0].NumUsedMappings += Cost; + UsedPhysRegs[0] += Cost; +} + +void RegisterFile::freePhysRegs(IndexPlusCostPairTy Entry, + MutableArrayRef FreedPhysRegs) { + unsigned RegisterFileIndex = Entry.first; + unsigned Cost = Entry.second; + if (RegisterFileIndex) { + RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; + RMT.NumUsedMappings -= Cost; + FreedPhysRegs[RegisterFileIndex] += Cost; + } + + // Now update the default register mapping tracker. + RegisterFiles[0].NumUsedMappings -= Cost; + FreedPhysRegs[0] += Cost; +} + +void RegisterFile::addRegisterWrite(WriteState &WS, + MutableArrayRef UsedPhysRegs, + bool ShouldAllocatePhysRegs) { + unsigned RegID = WS.getRegisterID(); + assert(RegID && "Adding an invalid register definition?"); + + RegisterMapping &Mapping = RegisterMappings[RegID]; + Mapping.first = &WS; + for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) + RegisterMappings[*I].first = &WS; + + // No physical registers are allocated for instructions that are optimized in + // hardware. For example, zero-latency data-dependency breaking instructions + // don't consume physical registers. + if (ShouldAllocatePhysRegs) + allocatePhysRegs(Mapping.second, UsedPhysRegs); + + // If this is a partial update, then we are done. + if (!WS.fullyUpdatesSuperRegs()) + return; + + for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) + RegisterMappings[*I].first = &WS; +} + +void RegisterFile::removeRegisterWrite(const WriteState &WS, + MutableArrayRef FreedPhysRegs, + bool ShouldFreePhysRegs) { + unsigned RegID = WS.getRegisterID(); + bool ShouldInvalidateSuperRegs = WS.fullyUpdatesSuperRegs(); + + assert(RegID != 0 && "Invalidating an already invalid register?"); + assert(WS.getCyclesLeft() != -512 && + "Invalidating a write of unknown cycles!"); + assert(WS.getCyclesLeft() <= 0 && "Invalid cycles left for this write!"); + RegisterMapping &Mapping = RegisterMappings[RegID]; + if (!Mapping.first) + return; + + if (ShouldFreePhysRegs) + freePhysRegs(Mapping.second, FreedPhysRegs); + + if (Mapping.first == &WS) + Mapping.first = nullptr; + + for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) + if (RegisterMappings[*I].first == &WS) + RegisterMappings[*I].first = nullptr; + + if (!ShouldInvalidateSuperRegs) + return; + + for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) + if (RegisterMappings[*I].first == &WS) + RegisterMappings[*I].first = nullptr; +} + +void RegisterFile::collectWrites(SmallVectorImpl &Writes, + unsigned RegID) const { + assert(RegID && RegID < RegisterMappings.size()); + WriteState *WS = RegisterMappings[RegID].first; + if (WS) { + LLVM_DEBUG(dbgs() << "Found a dependent use of RegID=" << RegID << '\n'); + Writes.push_back(WS); + } + + // Handle potential partial register updates. + for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) { + WS = RegisterMappings[*I].first; + if (WS && std::find(Writes.begin(), Writes.end(), WS) == Writes.end()) { + LLVM_DEBUG(dbgs() << "Found a dependent use of subReg " << *I + << " (part of " << RegID << ")\n"); + Writes.push_back(WS); + } + } +} + +unsigned RegisterFile::isAvailable(ArrayRef Regs) const { + SmallVector NumPhysRegs(getNumRegisterFiles()); + + // Find how many new mappings must be created for each register file. + for (const unsigned RegID : Regs) { + const IndexPlusCostPairTy &Entry = RegisterMappings[RegID].second; + if (Entry.first) + NumPhysRegs[Entry.first] += Entry.second; + NumPhysRegs[0] += Entry.second; + } + + unsigned Response = 0; + for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) { + unsigned NumRegs = NumPhysRegs[I]; + if (!NumRegs) + continue; + + const RegisterMappingTracker &RMT = RegisterFiles[I]; + if (!RMT.TotalMappings) { + // The register file has an unbounded number of microarchitectural + // registers. + continue; + } + + if (RMT.TotalMappings < NumRegs) { + // The current register file is too small. This may occur if the number of + // microarchitectural registers in register file #0 was changed by the + // users via flag -reg-file-size. Alternatively, the scheduling model + // specified a too small number of registers for this register file. + report_fatal_error( + "Not enough microarchitectural registers in the register file"); + } + + if (RMT.TotalMappings < (RMT.NumUsedMappings + NumRegs)) + Response |= (1U << I); + } + + return Response; +} + +#ifndef NDEBUG +void RegisterFile::dump() const { + for (unsigned I = 0, E = MRI.getNumRegs(); I < E; ++I) { + const RegisterMapping &RM = RegisterMappings[I]; + dbgs() << MRI.getName(I) << ", " << I << ", Map=" << RM.second.first + << ", "; + if (RM.first) + RM.first->dump(); + else + dbgs() << "(null)\n"; + } + + for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) { + dbgs() << "Register File #" << I; + const RegisterMappingTracker &RMT = RegisterFiles[I]; + dbgs() << "\n TotalMappings: " << RMT.TotalMappings + << "\n NumUsedMappings: " << RMT.NumUsedMappings << '\n'; + } +} +#endif + +} // namespace mca