[MCA] Add the ability to compute critical register dependency of an instruction.
authorAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Thu, 23 May 2019 16:32:19 +0000 (16:32 +0000)
committerAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Thu, 23 May 2019 16:32:19 +0000 (16:32 +0000)
This patch adds the methods `getCriticalRegDep()` and `computeCriticalRegDep()` to
class InstructionBase.
The goal is to allow users to obtain information about the critical register
dependency that most affects the latency of an instruction.

These methods are currently unused. However, the long term plan is to use them
in order to allow the computation of a critical-path as part of the bottleneck
analysis. So, this is yet another step towards fixing PR37494.

llvm-svn: 361509

llvm/include/llvm/MCA/Instruction.h
llvm/lib/MCA/Instruction.cpp

index a7a47fd..c4d0f6a 100644 (file)
@@ -80,6 +80,16 @@ struct ReadDescriptor {
 
 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
@@ -123,9 +133,11 @@ class WriteState {
 
   // 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
@@ -140,7 +152,7 @@ public:
       : 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;
@@ -150,7 +162,11 @@ public:
   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
@@ -162,10 +178,6 @@ public:
   // 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)
@@ -189,11 +201,7 @@ public:
   }
 
   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.");
@@ -235,6 +243,8 @@ class ReadState {
   // 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;
@@ -246,13 +256,14 @@ class ReadState {
 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; }
@@ -394,6 +405,9 @@ class InstructionBase {
   // 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) {}
 
@@ -405,6 +419,9 @@ public:
 
   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; });
index 58f0250..5e2fb77 100644 (file)
 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);
@@ -28,7 +36,12 @@ void ReadState::writeStartEvent(unsigned IID, unsigned RegID, unsigned 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;
@@ -121,6 +134,25 @@ void WriteRef::dump() const {
 }
 #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;