1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 19:23:23 +01:00

[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.

llvm-svn: 343307
This commit is contained in:
Andrea Di Biagio 2018-09-28 09:42:06 +00:00
parent f7ab544ae0
commit 5d291cb05b
3 changed files with 79 additions and 27 deletions

View File

@ -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.

View File

@ -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); }
bool isValid() const {
return Data.first != INVALID_IID && Data.second != nullptr;
void invalidate() { Data.second = nullptr; }
bool isWriteZero() const {
assert(isValid() && "Invalid null WriteState found!");
return getWriteState()->isWriteZero();
}
/// 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

View File

@ -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,15 +348,17 @@ 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
if (ZeroRegisters[I]) {
dbgs() << MRI.getName(I) << ", " << I
<< ", PRF=" << RRI.IndexPlusCost.first
<< ", Cost=" << RRI.IndexPlusCost.second
<< ", RenameAs=" << RRI.RenameAs << ", ";
<< ", RenameAs=" << RRI.RenameAs << ", IsZero=" << ZeroRegisters[I]
<< ",";
RM.first.dump();
dbgs() << '\n';
}
}
for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) {
dbgs() << "Register File #" << I;