class ReadState;
+/// Longest register dependency.
+///
+/// Used internally by WriteState/ReadState/InstructionBase to help with the
+/// computation of the longest register dependency for an instruction.
+struct CriticalRegDep {
+ unsigned IID;
+ unsigned RegID;
+ unsigned Cycles;
+};
+
/// Tracks uses of a register definition (e.g. register write).
///
/// Each implicit/explicit register write is associated with an instance of
// A partial write that is in a false dependency with this write.
WriteState *PartialWrite;
-
unsigned DependentWriteCyclesLeft;
+ // Critical register dependency for this write.
+ CriticalRegDep CRD;
+
// A list of dependent reads. Users is a set of dependent
// reads. A dependent read is added to the set only if CyclesLeft
// is "unknown". As soon as CyclesLeft is 'known', each user in the set
: WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
- DependentWriteCyclesLeft(0) {}
+ DependentWriteCyclesLeft(0), CRD() {}
WriteState(const WriteState &Other) = default;
WriteState &operator=(const WriteState &Other) = default;
unsigned getRegisterID() const { return RegisterID; }
unsigned getRegisterFileID() const { return PRFID; }
unsigned getLatency() const { return WD->Latency; }
+ unsigned getDependentWriteCyclesLeft() const {
+ return DependentWriteCyclesLeft;
+ }
const WriteState *getDependentWrite() const { return DependentWrite; }
+ const CriticalRegDep &getCriticalRegDep() const { return CRD; }
// This method adds Use to the set of data dependent reads. IID is the
// instruction identifier associated with this write. ReadAdvance is the
// write. IID is the instruction identifier associated with this write.
void addUser(unsigned IID, WriteState *Use);
- unsigned getDependentWriteCyclesLeft() const {
- return DependentWriteCyclesLeft;
- }
-
unsigned getNumUsers() const {
unsigned NumUsers = Users.size();
if (PartialWrite)
}
void setDependentWrite(const WriteState *Other) { DependentWrite = Other; }
- void writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles) {
- DependentWriteCyclesLeft = Cycles;
- DependentWrite = nullptr;
- }
-
+ void writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles);
void setWriteZero() { WritesZero = true; }
void setEliminated() {
assert(Users.empty() && "Write is in an inconsistent state.");
// dependent writes (i.e. field DependentWrite) is zero, this value is
// propagated to field CyclesLeft.
unsigned TotalCycles;
+ // Longest register dependency.
+ CriticalRegDep CRD;
// This field is set to true only if there are no dependent writes, and
// there are no `CyclesLeft' to wait.
bool IsReady;
public:
ReadState(const ReadDescriptor &Desc, unsigned RegID)
: RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0),
- CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), IsReady(true),
- IsZero(false), IndependentFromDef(false) {}
+ CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), CRD(),
+ IsReady(true), IsZero(false), IndependentFromDef(false) {}
const ReadDescriptor &getDescriptor() const { return *RD; }
unsigned getSchedClass() const { return RD->SchedClassID; }
unsigned getRegisterID() const { return RegisterID; }
unsigned getRegisterFileID() const { return PRFID; }
+ const CriticalRegDep &getCriticalRegDep() const { return CRD; }
bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
bool isReady() const { return IsReady; }
// One entry per each implicit and explicit register use.
SmallVector<ReadState, 4> Uses;
+ // Critical register dependency.
+ CriticalRegDep CRD;
+
public:
InstructionBase(const InstrDesc &D) : Desc(D), IsOptimizableMove(false) {}
unsigned getLatency() const { return Desc.MaxLatency; }
+ const CriticalRegDep &getCriticalRegDep() const { return CRD; }
+ const CriticalRegDep &computeCriticalRegDep();
+
bool hasDependentUsers() const {
return any_of(Defs,
[](const WriteState &Def) { return Def.getNumUsers() > 0; });
namespace llvm {
namespace mca {
+void WriteState::writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles) {
+ CRD.IID = IID;
+ CRD.RegID = RegID;
+ CRD.Cycles = Cycles;
+ DependentWriteCyclesLeft = Cycles;
+ DependentWrite = nullptr;
+}
+
void ReadState::writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles) {
assert(DependentWrites);
assert(CyclesLeft == UNKNOWN_CYCLES);
// The HW is forced to do some extra bookkeeping to track of all the
// dependent writes, and implement a merging scheme for the partial writes.
--DependentWrites;
- TotalCycles = std::max(TotalCycles, Cycles);
+ if (TotalCycles < Cycles) {
+ CRD.IID = IID;
+ CRD.RegID = RegID;
+ CRD.Cycles = Cycles;
+ TotalCycles = Cycles;
+ }
if (!DependentWrites) {
CyclesLeft = TotalCycles;
}
#endif
+const CriticalRegDep &InstructionBase::computeCriticalRegDep() {
+ if (CRD.Cycles || (Defs.empty() && Uses.empty()))
+ return CRD;
+ unsigned MaxLatency = 0;
+ for (const WriteState &WS : Defs) {
+ const CriticalRegDep &WriteCRD = WS.getCriticalRegDep();
+ if (WriteCRD.Cycles > MaxLatency)
+ CRD = WriteCRD;
+ }
+
+ for (const ReadState &RS : Uses) {
+ const CriticalRegDep &ReadCRD = RS.getCriticalRegDep();
+ if (ReadCRD.Cycles > MaxLatency)
+ CRD = ReadCRD;
+ }
+
+ return CRD;
+}
+
void Instruction::dispatch(unsigned RCUToken) {
assert(Stage == IS_INVALID);
Stage = IS_DISPATCHED;