[llvm] r342483 - [llvm-mca] Add the ability to mark register reads/writes associated with dep-breaking instructions. NFCI

Andrea Di Biagio via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 18 08:00:07 PDT 2018


Author: adibiagio
Date: Tue Sep 18 08:00:06 2018
New Revision: 342483

URL: http://llvm.org/viewvc/llvm-project?rev=342483&view=rev
Log:
[llvm-mca] Add the ability to mark register reads/writes associated with dep-breaking instructions. NFCI

This patch adds two new boolean fields:
  - Field `ReadState::IndependentFromDef`.
  - Field `WriteState::WritesZero`.

Field `IndependentFromDef` is set for ReadState objects associated with
dependency-breaking instructions. It is used by the simulator when updating data
dependencies between registers.

Field `WritesZero` is set by WriteState objects associated with dependency
breaking zero-idiom instructions. It helps the PRF identify which writes don't
consume any physical registers.

Modified:
    llvm/trunk/tools/llvm-mca/include/HardwareUnits/RegisterFile.h
    llvm/trunk/tools/llvm-mca/include/Instruction.h
    llvm/trunk/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp
    llvm/trunk/tools/llvm-mca/lib/InstrBuilder.cpp
    llvm/trunk/tools/llvm-mca/lib/Stages/DispatchStage.cpp
    llvm/trunk/tools/llvm-mca/lib/Stages/RetireStage.cpp

Modified: llvm/trunk/tools/llvm-mca/include/HardwareUnits/RegisterFile.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/include/HardwareUnits/RegisterFile.h?rev=342483&r1=342482&r2=342483&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/include/HardwareUnits/RegisterFile.h (original)
+++ llvm/trunk/tools/llvm-mca/include/HardwareUnits/RegisterFile.h Tue Sep 18 08:00:06 2018
@@ -136,16 +136,15 @@ public:
   // 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.
+  // No physical regiser is allocated if this write is from a zero-idiom.
   void addRegisterWrite(WriteRef Write,
-                        llvm::MutableArrayRef<unsigned> UsedPhysRegs,
-                        bool ShouldAllocatePhysRegs = true);
+                        llvm::MutableArrayRef<unsigned> UsedPhysRegs);
 
   // Removes write \param WS from the register mappings.
   // Physical registers may be released to reflect this update.
+  // No registers are released if this write is from a zero-idiom.
   void removeRegisterWrite(const WriteState &WS,
-                           llvm::MutableArrayRef<unsigned> FreedPhysRegs,
-                           bool ShouldFreePhysRegs = true);
+                           llvm::MutableArrayRef<unsigned> FreedPhysRegs);
 
   // Checks if there are enough physical registers in the register files.
   // Returns a "response mask" where each bit represents the response from a

Modified: llvm/trunk/tools/llvm-mca/include/Instruction.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/include/Instruction.h?rev=342483&r1=342482&r2=342483&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/include/Instruction.h (original)
+++ llvm/trunk/tools/llvm-mca/include/Instruction.h Tue Sep 18 08:00:06 2018
@@ -102,6 +102,9 @@ class WriteState {
   // super-registers.
   bool ClearsSuperRegs;
 
+  // True if this write is from a dependency breaking zero-idiom instruction.
+  bool WritesZero;
+
   // This field is set if this is a partial register write, and it has a false
   // dependency on any previous write of the same register (or a portion of it).
   // DependentWrite must be able to complete before this write completes, so
@@ -121,10 +124,10 @@ class WriteState {
 
 public:
   WriteState(const WriteDescriptor &Desc, unsigned RegID,
-             bool clearsSuperRegs = false)
+             bool clearsSuperRegs = false, bool writesZero = false)
       : WD(Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID),
-        ClearsSuperRegs(clearsSuperRegs), DependentWrite(nullptr),
-        NumWriteUsers(0U) {}
+        ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
+        DependentWrite(nullptr), NumWriteUsers(0U) {}
   WriteState(const WriteState &Other) = delete;
   WriteState &operator=(const WriteState &Other) = delete;
 
@@ -137,6 +140,7 @@ public:
 
   unsigned getNumUsers() const { return Users.size() + NumWriteUsers; }
   bool clearsSuperRegisters() const { return ClearsSuperRegs; }
+  bool isWriteZero() const { return WritesZero; }
 
   const WriteState *getDependentWrite() const { return DependentWrite; }
   void setDependentWrite(WriteState *Other) {
@@ -177,11 +181,14 @@ class ReadState {
   // This field is set to true only if there are no dependent writes, and
   // there are no `CyclesLeft' to wait.
   bool IsReady;
+  // True if this register read is from a dependency-breaking instruction.
+  bool IndependentFromDef;
 
 public:
   ReadState(const ReadDescriptor &Desc, unsigned RegID)
       : RD(Desc), RegisterID(RegID), DependentWrites(0),
-        CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), IsReady(true) {}
+        CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), IsReady(true),
+        IndependentFromDef(false) {}
   ReadState(const ReadState &Other) = delete;
   ReadState &operator=(const ReadState &Other) = delete;
 
@@ -192,6 +199,9 @@ public:
   bool isReady() const { return IsReady; }
   bool isImplicitRead() const { return RD.isImplicitRead(); }
 
+  bool isIndependentFromDef() const { return IndependentFromDef; }
+  void setIndependentFromDef() { IndependentFromDef = true; }
+
   void cycleEvent();
   void writeStartEvent(unsigned Cycles);
   void setDependentWrites(unsigned Writes) {
@@ -281,6 +291,10 @@ struct InstrDesc {
 
   // A zero latency instruction doesn't consume any scheduler resources.
   bool isZeroLatency() const { return !MaxLatency && Resources.empty(); }
+
+  InstrDesc() = default;
+  InstrDesc(const InstrDesc &Other) = delete;
+  InstrDesc &operator=(const InstrDesc &Other) = delete;
 };
 
 /// An instruction propagated through the simulated instruction pipeline.
@@ -309,8 +323,6 @@ class Instruction {
   // Retire Unit token ID for this instruction.
   unsigned RCUTokenID;
 
-  bool IsDepBreaking;
-
   using UniqueDef = std::unique_ptr<WriteState>;
   using UniqueUse = std::unique_ptr<ReadState>;
   using VecDefs = std::vector<UniqueDef>;
@@ -326,8 +338,7 @@ class Instruction {
 
 public:
   Instruction(const InstrDesc &D)
-      : Desc(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES), RCUTokenID(0),
-        IsDepBreaking(false) {}
+      : Desc(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES), RCUTokenID(0) {}
   Instruction(const Instruction &Other) = delete;
   Instruction &operator=(const Instruction &Other) = delete;
 
@@ -345,9 +356,6 @@ public:
     });
   }
 
-  bool isDependencyBreaking() const { return IsDepBreaking; }
-  void setDependencyBreaking() { IsDepBreaking = true; }
-
   unsigned getNumUsers() const {
     unsigned NumUsers = 0;
     for (const UniqueDef &Def : Defs)

Modified: llvm/trunk/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp?rev=342483&r1=342482&r2=342483&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp (original)
+++ llvm/trunk/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp Tue Sep 18 08:00:06 2018
@@ -139,8 +139,7 @@ void RegisterFile::freePhysRegs(const Re
 }
 
 void RegisterFile::addRegisterWrite(WriteRef Write,
-                                    MutableArrayRef<unsigned> UsedPhysRegs,
-                                    bool ShouldAllocatePhysRegs) {
+                                    MutableArrayRef<unsigned> UsedPhysRegs) {
   WriteState &WS = *Write.getWriteState();
   unsigned RegID = WS.getRegisterID();
   assert(RegID && "Adding an invalid register definition?");
@@ -163,6 +162,7 @@ void RegisterFile::addRegisterWrite(Writ
   // 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();
   const RegisterRenamingInfo &RRI = RegisterMappings[RegID].second;
   if (RRI.RenameAs && RRI.RenameAs != RegID) {
     RegID = RRI.RenameAs;
@@ -200,9 +200,8 @@ void RegisterFile::addRegisterWrite(Writ
     RegisterMappings[*I].first = Write;
 }
 
-void RegisterFile::removeRegisterWrite(const WriteState &WS,
-                                       MutableArrayRef<unsigned> FreedPhysRegs,
-                                       bool ShouldFreePhysRegs) {
+void RegisterFile::removeRegisterWrite(
+    const WriteState &WS, MutableArrayRef<unsigned> FreedPhysRegs) {
   unsigned RegID = WS.getRegisterID();
 
   assert(RegID != 0 && "Invalidating an already invalid register?");
@@ -210,6 +209,7 @@ void RegisterFile::removeRegisterWrite(c
          "Invalidating a write of unknown cycles!");
   assert(WS.getCyclesLeft() <= 0 && "Invalid cycles left for this write!");
 
+  bool ShouldFreePhysRegs = !WS.isWriteZero();
   unsigned RenameAs = RegisterMappings[RegID].second.RenameAs;
   if (RenameAs && RenameAs != RegID) {
     RegID = RenameAs;

Modified: llvm/trunk/tools/llvm-mca/lib/InstrBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/lib/InstrBuilder.cpp?rev=342483&r1=342482&r2=342483&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/lib/InstrBuilder.cpp (original)
+++ llvm/trunk/tools/llvm-mca/lib/InstrBuilder.cpp Tue Sep 18 08:00:06 2018
@@ -423,6 +423,11 @@ InstrBuilder::createInstruction(const MC
   const InstrDesc &D = *DescOrErr;
   std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D);
 
+  // Check if this is a dependency breaking instruction.
+  bool IsDepBreaking = MCIA.isDependencyBreaking(STI, MCI);
+  // FIXME: this is a temporary hack to identify zero-idioms.
+  bool IsZeroIdiom = D.isZeroLatency() && IsDepBreaking;
+
   // Initialize Reads first.
   for (const ReadDescriptor &RD : D.Reads) {
     int RegID = -1;
@@ -444,7 +449,11 @@ InstrBuilder::createInstruction(const MC
 
     // Okay, this is a register operand. Create a ReadState for it.
     assert(RegID > 0 && "Invalid register ID found!");
-    NewIS->getUses().emplace_back(llvm::make_unique<ReadState>(RD, RegID));
+    auto RS = llvm::make_unique<ReadState>(RD, RegID);
+
+    if (IsDepBreaking && !RD.isImplicitRead())
+      RS->setIndependentFromDef();
+    NewIS->getUses().emplace_back(std::move(RS));
   }
 
   // Early exit if there are no writes.
@@ -459,10 +468,6 @@ InstrBuilder::createInstruction(const MC
   // register writes implicitly clear the upper portion of a super-register.
   MCIA.clearsSuperRegisters(MRI, MCI, WriteMask);
 
-  // Check if this is a dependency breaking instruction.
-  if (MCIA.isDependencyBreaking(STI, MCI))
-    NewIS->setDependencyBreaking();
-
   // Initialize writes.
   unsigned WriteIndex = 0;
   for (const WriteDescriptor &WD : D.Writes) {
@@ -476,7 +481,8 @@ InstrBuilder::createInstruction(const MC
 
     assert(RegID && "Expected a valid register ID!");
     NewIS->getDefs().emplace_back(llvm::make_unique<WriteState>(
-        WD, RegID, /* ClearsSuperRegs */ WriteMask[WriteIndex]));
+        WD, RegID, /* ClearsSuperRegs */ WriteMask[WriteIndex],
+        /* WritesZero */ IsZeroIdiom));
     ++WriteIndex;
   }
 

Modified: llvm/trunk/tools/llvm-mca/lib/Stages/DispatchStage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/lib/Stages/DispatchStage.cpp?rev=342483&r1=342482&r2=342483&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/lib/Stages/DispatchStage.cpp (original)
+++ llvm/trunk/tools/llvm-mca/lib/Stages/DispatchStage.cpp Tue Sep 18 08:00:06 2018
@@ -106,21 +106,16 @@ llvm::Error DispatchStage::dispatch(Inst
   // instruction. A dependency-breaking instruction is a zero-latency
   // instruction that doesn't consume hardware resources.
   // An example of dependency-breaking instruction on X86 is a zero-idiom XOR.
-  bool IsDependencyBreaking = IS.isDependencyBreaking();
   for (std::unique_ptr<ReadState> &RS : IS.getUses())
-    if (RS->isImplicitRead() || !IsDependencyBreaking)
+    if (!RS->isIndependentFromDef())
       updateRAWDependencies(*RS, STI);
 
-  // By default, a dependency-breaking zero-latency instruction is expected to
-  // be optimized at register renaming stage. That means, no physical register
-  // is allocated to the instruction.
-  bool ShouldAllocateRegisters =
-      !(Desc.isZeroLatency() && IsDependencyBreaking);
+  // By default, a dependency-breaking zero-idiom is expected to be optimized
+  // at register renaming stage. That means, no physical register is allocated
+  // to the instruction.
   SmallVector<unsigned, 4> RegisterFiles(PRF.getNumRegisterFiles());
-  for (std::unique_ptr<WriteState> &WS : IS.getDefs()) {
-    PRF.addRegisterWrite(WriteRef(IR.getSourceIndex(), WS.get()), RegisterFiles,
-                         ShouldAllocateRegisters);
-  }
+  for (std::unique_ptr<WriteState> &WS : IS.getDefs())
+    PRF.addRegisterWrite(WriteRef(IR.getSourceIndex(), WS.get()), RegisterFiles);
 
   // Reserve slots in the RCU, and notify the instruction that it has been
   // dispatched to the schedulers for execution.

Modified: llvm/trunk/tools/llvm-mca/lib/Stages/RetireStage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/lib/Stages/RetireStage.cpp?rev=342483&r1=342482&r2=342483&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/lib/Stages/RetireStage.cpp (original)
+++ llvm/trunk/tools/llvm-mca/lib/Stages/RetireStage.cpp Tue Sep 18 08:00:06 2018
@@ -51,11 +51,9 @@ void RetireStage::notifyInstructionRetir
   LLVM_DEBUG(llvm::dbgs() << "[E] Instruction Retired: #" << IR << '\n');
   llvm::SmallVector<unsigned, 4> FreedRegs(PRF.getNumRegisterFiles());
   const Instruction &Inst = *IR.getInstruction();
-  const InstrDesc &Desc = Inst.getDesc();
 
-  bool ShouldFreeRegs = !(Desc.isZeroLatency() && Inst.isDependencyBreaking());
   for (const std::unique_ptr<WriteState> &WS : Inst.getDefs())
-    PRF.removeRegisterWrite(*WS.get(), FreedRegs, ShouldFreeRegs);
+    PRF.removeRegisterWrite(*WS.get(), FreedRegs);
   notifyEvent<HWInstructionEvent>(HWInstructionRetiredEvent(IR, FreedRegs));
 }
 




More information about the llvm-commits mailing list