[llvm-mca] Use a WriteRef to describe register writes in class RegisterFile.
authorAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Thu, 28 Jun 2018 15:50:26 +0000 (15:50 +0000)
committerAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Thu, 28 Jun 2018 15:50:26 +0000 (15:50 +0000)
This patch introduces a new class named WriteRef. A WriteRef is used by the
RegisterFile to keep track of register definitions. Internally it wraps a
WriteState, as well as the source index of the defining instruction.

This patch allows the tool to propagate additional information to support future
analysis on data dependencies.

llvm-svn: 335867

llvm/tools/llvm-mca/DispatchStage.cpp
llvm/tools/llvm-mca/DispatchStage.h
llvm/tools/llvm-mca/Instruction.cpp
llvm/tools/llvm-mca/Instruction.h
llvm/tools/llvm-mca/RegisterFile.cpp
llvm/tools/llvm-mca/RegisterFile.h

index 70cd28d..1bc292a 100644 (file)
@@ -72,7 +72,7 @@ bool DispatchStage::checkScheduler(const InstRef &IR) {
 
 void DispatchStage::updateRAWDependencies(ReadState &RS,
                                           const MCSubtargetInfo &STI) {
-  SmallVector<WriteState *, 4> DependentWrites;
+  SmallVector<WriteRef, 4> DependentWrites;
 
   collectWrites(DependentWrites, RS.getRegisterID());
   RS.setDependentWrites(DependentWrites.size());
@@ -83,17 +83,18 @@ void DispatchStage::updateRAWDependencies(ReadState &RS,
   // to figure out in how many cycles this read becomes available.
   const ReadDescriptor &RD = RS.getDescriptor();
   if (!RD.HasReadAdvanceEntries) {
-    for (WriteState *WS : DependentWrites)
-      WS->addUser(&RS, /* ReadAdvance */ 0);
+    for (WriteRef &WR : DependentWrites)
+      WR.getWriteState()->addUser(&RS, /* ReadAdvance */ 0);
     return;
   }
 
   const MCSchedModel &SM = STI.getSchedModel();
   const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
-  for (WriteState *WS : DependentWrites) {
-    unsigned WriteResID = WS->getWriteResourceID();
+  for (WriteRef &WR : DependentWrites) {
+    WriteState &WS = *WR.getWriteState();
+    unsigned WriteResID = WS.getWriteResourceID();
     int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.UseIndex, WriteResID);
-    WS->addUser(&RS, ReadAdvance);
+    WS.addUser(&RS, ReadAdvance);
   }
 }
 
@@ -126,7 +127,8 @@ void DispatchStage::dispatch(InstRef IR) {
   // is allocated to the instruction.
   SmallVector<unsigned, 4> RegisterFiles(PRF.getNumRegisterFiles());
   for (std::unique_ptr<WriteState> &WS : IS.getDefs())
-    PRF.addRegisterWrite(*WS, RegisterFiles, !Desc.isZeroLatency());
+    PRF.addRegisterWrite(WriteRef(IR.first, WS.get()), RegisterFiles,
+                         !Desc.isZeroLatency());
 
   // Reserve slots in the RCU, and notify the instruction that it has been
   // dispatched to the schedulers for execution.
index 9695c3e..fff9a2b 100644 (file)
@@ -29,7 +29,6 @@
 
 namespace mca {
 
-class WriteState;
 class Scheduler;
 
 // Implements the hardware dispatch logic.
@@ -78,7 +77,7 @@ class DispatchStage : public Stage {
     return checkRCU(IR) && checkPRF(IR) && checkScheduler(IR);
   }
 
-  void collectWrites(llvm::SmallVectorImpl<WriteState *> &Vec,
+  void collectWrites(llvm::SmallVectorImpl<WriteRef> &Vec,
                      unsigned RegID) const {
     return PRF.collectWrites(Vec, RegID);
   }
index f84c781..c8eb63f 100644 (file)
@@ -96,6 +96,13 @@ void WriteState::dump() const {
   dbgs() << "{ OpIdx=" << WD.OpIndex << ", Lat=" << WD.Latency << ", RegID "
          << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }\n";
 }
+
+void WriteRef::dump() const {
+  if (isValid())
+    getWriteState()->dump();
+  else
+    dbgs() << "(null)";
+}
 #endif
 
 void Instruction::dispatch(unsigned RCUToken) {
@@ -152,4 +159,7 @@ void Instruction::cycleEvent() {
   if (!CyclesLeft)
     Stage = IS_EXECUTED;
 }
+
+const unsigned WriteRef::INVALID_IID = std::numeric_limits<unsigned>::max();
+
 } // namespace mca
index 32246ce..2df6a59 100644 (file)
@@ -381,6 +381,36 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const InstRef &IR) {
 }
 #endif
 
+/// A reference to a register write.
+///
+/// This class is mainly used by the register file to describe register
+/// mappings. It correlates a register write to the source index of the
+/// defining instruction.
+class WriteRef {
+  std::pair<unsigned, WriteState *> Data;
+  static const unsigned INVALID_IID;
+
+public:
+  WriteRef() : Data(INVALID_IID, nullptr) {}
+  WriteRef(unsigned SourceIndex, WriteState *WS) : Data(SourceIndex, WS) {}
+
+  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;
+  }
+  bool operator==(const WriteRef &Other) const {
+    return Data == Other.Data;
+  }
+
+#ifndef NDEBUG
+  void dump() const;
+#endif
+};
+
 } // namespace mca
 
 #endif
index 5da4b5e..427b32a 100644 (file)
@@ -24,6 +24,12 @@ using namespace llvm;
 
 namespace mca {
 
+RegisterFile::RegisterFile(const llvm::MCSchedModel &SM,
+                           const llvm::MCRegisterInfo &mri, unsigned NumRegs)
+    : MRI(mri), RegisterMappings(mri.getNumRegs(), {WriteRef(), {0, 0}}) {
+  initialize(SM, NumRegs);
+}
+
 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
@@ -66,8 +72,7 @@ void RegisterFile::addRegisterFile(ArrayRef<MCRegisterCostEntry> Entries,
   // 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<WriteState *, IndexPlusCostPairTy> &Mapping :
-         RegisterMappings)
+    for (std::pair<WriteRef, IndexPlusCostPairTy> &Mapping : RegisterMappings)
       Mapping.second = std::make_pair(RegisterFileIndex, 1U);
     return;
   }
@@ -120,16 +125,17 @@ void RegisterFile::freePhysRegs(IndexPlusCostPairTy Entry,
   FreedPhysRegs[0] += Cost;
 }
 
-void RegisterFile::addRegisterWrite(WriteState &WS,
+void RegisterFile::addRegisterWrite(WriteRef Write,
                                     MutableArrayRef<unsigned> UsedPhysRegs,
                                     bool ShouldAllocatePhysRegs) {
+  const WriteState &WS = *Write.getWriteState();
   unsigned RegID = WS.getRegisterID();
   assert(RegID && "Adding an invalid register definition?");
 
   RegisterMapping &Mapping = RegisterMappings[RegID];
-  Mapping.first = &WS;
+  Mapping.first = Write;
   for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
-    RegisterMappings[*I].first = &WS;
+    RegisterMappings[*I].first = Write;
 
   // No physical registers are allocated for instructions that are optimized in
   // hardware. For example, zero-latency data-dependency breaking instructions
@@ -142,7 +148,7 @@ void RegisterFile::addRegisterWrite(WriteState &WS,
     return;
 
   for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I)
-    RegisterMappings[*I].first = &WS;
+    RegisterMappings[*I].first = Write;
 }
 
 void RegisterFile::removeRegisterWrite(const WriteState &WS,
@@ -156,50 +162,61 @@ void RegisterFile::removeRegisterWrite(const WriteState &WS,
          "Invalidating a write of unknown cycles!");
   assert(WS.getCyclesLeft() <= 0 && "Invalid cycles left for this write!");
   RegisterMapping &Mapping = RegisterMappings[RegID];
-  if (!Mapping.first)
+  WriteRef &WR = Mapping.first;
+  if (!WR.isValid())
     return;
 
   if (ShouldFreePhysRegs)
     freePhysRegs(Mapping.second, FreedPhysRegs);
 
-  if (Mapping.first == &WS)
-    Mapping.first = nullptr;
+  if (WR.getWriteState() == &WS)
+    WR.invalidate();
 
-  for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
-    if (RegisterMappings[*I].first == &WS)
-      RegisterMappings[*I].first = nullptr;
+  for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) {
+    WR = RegisterMappings[*I].first;
+    if (WR.getWriteState() == &WS)
+      WR.invalidate();
+  }
 
   if (!ShouldInvalidateSuperRegs)
     return;
 
-  for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I)
-    if (RegisterMappings[*I].first == &WS)
-      RegisterMappings[*I].first = nullptr;
+  for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) {
+    WR = RegisterMappings[*I].first;
+    if (WR.getWriteState() == &WS)
+      WR.invalidate();
+  }
 }
 
-void RegisterFile::collectWrites(SmallVectorImpl<WriteState *> &Writes,
+void RegisterFile::collectWrites(SmallVectorImpl<WriteRef> &Writes,
                                  unsigned RegID) const {
   assert(RegID && RegID < RegisterMappings.size());
-  WriteState *WS = RegisterMappings[RegID].first;
-  if (WS)
-    Writes.push_back(WS);
+  const WriteRef &WR = RegisterMappings[RegID].first;
+  if (WR.isValid())
+    Writes.push_back(WR);
 
   // Handle potential partial register updates.
   for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) {
-    WS = RegisterMappings[*I].first;
-    if (WS)
-      Writes.push_back(WS);
+    const WriteRef &WR = RegisterMappings[*I].first;
+    if (WR.isValid())
+      Writes.push_back(WR);
   }
 
   // Remove duplicate entries and resize the input vector.
-  llvm::sort(Writes.begin(), Writes.end());
+  llvm::sort(Writes.begin(), Writes.end(),
+             [](const WriteRef &Lhs, const WriteRef &Rhs) {
+               return Lhs.getWriteState() < Rhs.getWriteState();
+             });
   auto It = std::unique(Writes.begin(), Writes.end());
   Writes.resize(std::distance(Writes.begin(), It));
 
   LLVM_DEBUG({
-    for (const WriteState *WS : Writes)
+    for (const WriteRef &WR : Writes) {
+      const WriteState &WS = *WR.getWriteState();
       dbgs() << "Found a dependent use of Register "
-             << MRI.getName(WS->getRegisterID()) << "\n";
+             << MRI.getName(WS.getRegisterID()) << " (defined by intruction #"
+             << WR.getSourceIndex() << '\n';
+    }
   });
 }
 
@@ -249,10 +266,7 @@ void RegisterFile::dump() const {
     const RegisterMapping &RM = RegisterMappings[I];
     dbgs() << MRI.getName(I) << ", " << I << ", Map=" << RM.second.first
            << ", ";
-    if (RM.first)
-      RM.first->dump();
-    else
-      dbgs() << "(null)\n";
+    RM.first.dump();
   }
 
   for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) {
index 7d5d22b..b93bdeb 100644 (file)
@@ -25,15 +25,16 @@ namespace mca {
 
 class ReadState;
 class WriteState;
+class WriteRef;
 
 /// Manages hardware register files, and tracks register definitions for
 /// register renaming purposes.
 class RegisterFile {
   const llvm::MCRegisterInfo &MRI;
 
-  // Each register file is associated with an instance of RegisterMappingTracker.
-  // A RegisterMappingTracker keeps track of the number of physical registers
-  // which have been dynamically allocated by the simulator.
+  // Each register file is associated with an instance of
+  // RegisterMappingTracker. A RegisterMappingTracker tracks the number of
+  // physical registers that are dynamically allocated by the simulator.
   struct RegisterMappingTracker {
     // The total number of physical registers that are available in this
     // register file for register renaming purpouses.  A value of zero for this
@@ -53,7 +54,7 @@ class RegisterFile {
   // hardware registers declared by the target (i.e. all the register
   // definitions in the target specific `XYZRegisterInfo.td` - where `XYZ` is
   // the target name).
-  // 
+  //
   // Users can limit the number of physical registers that are available in
   // regsiter file #0 specifying command line flag `-register-file-size=<uint>`.
   llvm::SmallVector<RegisterMappingTracker, 4> RegisterFiles;
@@ -68,14 +69,14 @@ class RegisterFile {
   // 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 WriteState object), as well as a
+  // the last register write (in the form of a WriteRef object), as well as a
   // IndexPlusCostPairTy to quickly identify owning register files.
   //
   // 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. If we exclude register #0, every register is "owned" by
   // at most one register file.
-  using RegisterMapping = std::pair<WriteState *, IndexPlusCostPairTy>;
+  using RegisterMapping = std::pair<WriteRef, IndexPlusCostPairTy>;
 
   // This map contains one entry for each register defined by the target.
   std::vector<RegisterMapping> RegisterMappings;
@@ -117,16 +118,13 @@ class RegisterFile {
 
 public:
   RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri,
-               unsigned NumRegs = 0)
-      : MRI(mri), RegisterMappings(mri.getNumRegs(), {nullptr, {0, 0}}) {
-    initialize(SM, NumRegs);
-  }
+               unsigned NumRegs = 0);
 
   // This method updates the register mappings inserting a new register
   // definition. This method is also responsible for updating the number of
   // allocated physical registers in each register file modified by the write.
   // No physical regiser is allocated when flag ShouldAllocatePhysRegs is set.
-  void addRegisterWrite(WriteState &WS,
+  void addRegisterWrite(WriteRef Write,
                         llvm::MutableArrayRef<unsigned> UsedPhysRegs,
                         bool ShouldAllocatePhysRegs = true);
 
@@ -143,7 +141,7 @@ public:
   // register file was busy.  This sematic allows us classify dispatch dispatch
   // stalls caused by the lack of register file resources.
   unsigned isAvailable(llvm::ArrayRef<unsigned> Regs) const;
-  void collectWrites(llvm::SmallVectorImpl<WriteState *> &Writes,
+  void collectWrites(llvm::SmallVectorImpl<WriteRef> &Writes,
                      unsigned RegID) const;
   void updateOnRead(ReadState &RS, unsigned RegID);