diff options
author | Andrea Di Biagio <Andrea_DiBiagio@sn.scee.net> | 2018-09-28 09:42:06 +0000 |
---|---|---|
committer | Andrea Di Biagio <Andrea_DiBiagio@sn.scee.net> | 2018-09-28 09:42:06 +0000 |
commit | 28ed7674e36a654bd6ed2be47e5504bcfc82e38a (patch) | |
tree | e711fab61f2957702aad8e33ce3723b55f9fbe79 | |
parent | 2d3fd448c5cf5df520ad19479f2616ed2abcbb0d (diff) |
[llvm-mca] Teach how to track zero registers in class RegisterFile.
This change is in preparation for a future work on improving support for
optimizable register moves. We already know if a write is from a zero-idiom, so
we can propagate that bit of information to the PRF. We use an APInt mask to
identify registers that are set to zero.
-rw-r--r-- | llvm/tools/llvm-mca/include/HardwareUnits/RegisterFile.h | 34 | ||||
-rw-r--r-- | llvm/tools/llvm-mca/include/Instruction.h | 25 | ||||
-rw-r--r-- | llvm/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp | 45 |
3 files changed, 78 insertions, 26 deletions
diff --git a/llvm/tools/llvm-mca/include/HardwareUnits/RegisterFile.h b/llvm/tools/llvm-mca/include/HardwareUnits/RegisterFile.h index bae8840438f..7829b42c307 100644 --- a/llvm/tools/llvm-mca/include/HardwareUnits/RegisterFile.h +++ b/llvm/tools/llvm-mca/include/HardwareUnits/RegisterFile.h @@ -19,6 +19,7 @@ #include "HardwareUnits/HardwareUnit.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/APInt.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSchedule.h" #include "llvm/Support/Error.h" @@ -71,20 +72,31 @@ class RegisterFile : public HardwareUnit { // 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 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 llvm::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. struct RegisterRenamingInfo { IndexPlusCostPairTy IndexPlusCost; llvm::MCPhysReg RenameAs; + RegisterRenamingInfo() + : IndexPlusCost(std::make_pair(0U, 1U)), RenameAs(0U) {} }; // 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. + // 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 @@ -92,9 +104,13 @@ class RegisterFile : public HardwareUnit { // at most one register file. using RegisterMapping = std::pair<WriteRef, RegisterRenamingInfo>; - // This map contains one entry for each register defined by the target. + // 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. + llvm::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. diff --git a/llvm/tools/llvm-mca/include/Instruction.h b/llvm/tools/llvm-mca/include/Instruction.h index b6c0f9b8637..cd9a0d69c02 100644 --- a/llvm/tools/llvm-mca/include/Instruction.h +++ b/llvm/tools/llvm-mca/include/Instruction.h @@ -141,6 +141,9 @@ public: unsigned getNumUsers() const { return Users.size() + NumWriteUsers; } bool clearsSuperRegisters() const { return ClearsSuperRegs; } bool isWriteZero() const { return WritesZero; } + bool isExecuted() const { + return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0; + } const WriteState *getDependentWrite() const { return DependentWrite; } void setDependentWrite(WriteState *Other) { @@ -351,9 +354,8 @@ public: int getCyclesLeft() const { return CyclesLeft; } bool hasDependentUsers() const { - return llvm::any_of(Defs, [](const UniqueDef &Def) { - return Def->getNumUsers() > 0; - }); + return llvm::any_of( + Defs, [](const UniqueDef &Def) { return Def->getNumUsers() > 0; }); } unsigned getNumUsers() const { @@ -444,11 +446,22 @@ public: unsigned getSourceIndex() const { return Data.first; } const WriteState *getWriteState() const { return Data.second; } WriteState *getWriteState() { return Data.second; } - void invalidate() { Data = std::make_pair(INVALID_IID, nullptr); } + void invalidate() { Data.second = nullptr; } + bool isWriteZero() const { + assert(isValid() && "Invalid null WriteState found!"); + return getWriteState()->isWriteZero(); + } - bool isValid() const { - return Data.first != INVALID_IID && Data.second != nullptr; + /// Returns true if this register write has been executed, and the new + /// register value is therefore available to users. + bool isAvailable() const { + if (getSourceIndex() == INVALID_IID) + return false; + const WriteState *WS = getWriteState(); + return !WS || WS->isExecuted(); } + + bool isValid() const { return Data.first != INVALID_IID && Data.second; } bool operator==(const WriteRef &Other) const { return Data == Other.Data; } #ifndef NDEBUG diff --git a/llvm/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp b/llvm/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp index 47b5153b966..20db2b83036 100644 --- a/llvm/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp +++ b/llvm/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp @@ -26,8 +26,9 @@ namespace mca { RegisterFile::RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri, unsigned NumRegs) - : MRI(mri), RegisterMappings(mri.getNumRegs(), - {WriteRef(), {IndexPlusCostPairTy(0, 1), 0}}) { + : MRI(mri), + RegisterMappings(mri.getNumRegs(), {WriteRef(), RegisterRenamingInfo()}), + ZeroRegisters(mri.getNumRegs(), false) { initialize(SM, NumRegs); } @@ -162,8 +163,10 @@ void RegisterFile::addRegisterWrite(WriteRef Write, // a false dependency on RenameAs. The only exception is for when the write // implicitly clears the upper portion of the underlying register. // If a write clears its super-registers, then it is renamed as `RenameAs`. - bool ShouldAllocatePhysRegs = !WS.isWriteZero(); + bool IsWriteZero = WS.isWriteZero(); + bool ShouldAllocatePhysRegs = !IsWriteZero; const RegisterRenamingInfo &RRI = RegisterMappings[RegID].second; + if (RRI.RenameAs && RRI.RenameAs != RegID) { RegID = RRI.RenameAs; WriteRef &OtherWrite = RegisterMappings[RegID].first; @@ -182,6 +185,19 @@ void RegisterFile::addRegisterWrite(WriteRef Write, } } + // Update zero registers. + unsigned ZeroRegisterID = + WS.clearsSuperRegisters() ? RegID : WS.getRegisterID(); + if (IsWriteZero) { + ZeroRegisters.setBit(ZeroRegisterID); + for (MCSubRegIterator I(ZeroRegisterID, &MRI); I.isValid(); ++I) + ZeroRegisters.setBit(*I); + } else { + ZeroRegisters.clearBit(ZeroRegisterID); + for (MCSubRegIterator I(ZeroRegisterID, &MRI); I.isValid(); ++I) + ZeroRegisters.clearBit(*I); + } + // Update the mapping for register RegID including its sub-registers. RegisterMappings[RegID].first = Write; for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) @@ -196,8 +212,13 @@ void RegisterFile::addRegisterWrite(WriteRef Write, if (!WS.clearsSuperRegisters()) return; - for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) + for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) { RegisterMappings[*I].first = Write; + if (IsWriteZero) + ZeroRegisters.setBit(*I); + else + ZeroRegisters.clearBit(*I); + } } void RegisterFile::removeRegisterWrite( @@ -327,14 +348,16 @@ unsigned RegisterFile::isAvailable(ArrayRef<unsigned> Regs) const { void RegisterFile::dump() const { for (unsigned I = 0, E = MRI.getNumRegs(); I < E; ++I) { const RegisterMapping &RM = RegisterMappings[I]; - if (!RM.first.getWriteState()) - continue; const RegisterRenamingInfo &RRI = RM.second; - dbgs() << MRI.getName(I) << ", " << I << ", PRF=" << RRI.IndexPlusCost.first - << ", Cost=" << RRI.IndexPlusCost.second - << ", RenameAs=" << RRI.RenameAs << ", "; - RM.first.dump(); - dbgs() << '\n'; + if (ZeroRegisters[I]) { + dbgs() << MRI.getName(I) << ", " << I + << ", PRF=" << RRI.IndexPlusCost.first + << ", Cost=" << RRI.IndexPlusCost.second + << ", RenameAs=" << RRI.RenameAs << ", IsZero=" << ZeroRegisters[I] + << ","; + RM.first.dump(); + dbgs() << '\n'; + } } for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) { |