[llvm] r340176 - [llvm-mca] Make the LSUnit a HardwareUnit, and allow derived classes to implement a different memory consistency model.

Andrea Di Biagio via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 20 07:41:36 PDT 2018


Author: adibiagio
Date: Mon Aug 20 07:41:36 2018
New Revision: 340176

URL: http://llvm.org/viewvc/llvm-project?rev=340176&view=rev
Log:
[llvm-mca] Make the LSUnit a HardwareUnit, and allow derived classes to implement a different memory consistency model.

The LSUnit is now a HardwareUnit, and it is owned by the mca::Context.
Derived classes can now implement a different consistency model by overriding
method `LSUnit::isReady()`.

This patch also slightly refactors the Scheduler interface in the attempt to
simplifying the interaction between ExecuteStage and the underlying Scheduler.

Modified:
    llvm/trunk/tools/llvm-mca/Context.cpp
    llvm/trunk/tools/llvm-mca/ExecuteStage.cpp
    llvm/trunk/tools/llvm-mca/LSUnit.cpp
    llvm/trunk/tools/llvm-mca/LSUnit.h
    llvm/trunk/tools/llvm-mca/Scheduler.cpp
    llvm/trunk/tools/llvm-mca/Scheduler.h

Modified: llvm/trunk/tools/llvm-mca/Context.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Context.cpp?rev=340176&r1=340175&r2=340176&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Context.cpp (original)
+++ llvm/trunk/tools/llvm-mca/Context.cpp Mon Aug 20 07:41:36 2018
@@ -36,8 +36,9 @@ Context::createDefaultPipeline(const Pip
   // Create the hardware units defining the backend.
   auto RCU = llvm::make_unique<RetireControlUnit>(SM);
   auto PRF = llvm::make_unique<RegisterFile>(SM, MRI, Opts.RegisterFileSize);
-  auto HWS = llvm::make_unique<Scheduler>(
-      SM, Opts.LoadQueueSize, Opts.StoreQueueSize, Opts.AssumeNoAlias);
+  auto LSU = llvm::make_unique<LSUnit>(Opts.LoadQueueSize, Opts.StoreQueueSize,
+                                       Opts.AssumeNoAlias);
+  auto HWS = llvm::make_unique<Scheduler>(SM, LSU.get());
 
   // Create the pipeline and its stages.
   auto StagePipeline = llvm::make_unique<Pipeline>();
@@ -47,9 +48,10 @@ Context::createDefaultPipeline(const Pip
   auto Execute = llvm::make_unique<ExecuteStage>(*HWS);
   auto Retire = llvm::make_unique<RetireStage>(*RCU, *PRF);
 
-  // Add the hardware to the context.
+  // Pass the ownership of all the hardware units to this Context.
   addHardwareUnit(std::move(RCU));
   addHardwareUnit(std::move(PRF));
+  addHardwareUnit(std::move(LSU));
   addHardwareUnit(std::move(HWS));
 
   // Build the pipeline.

Modified: llvm/trunk/tools/llvm-mca/ExecuteStage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/ExecuteStage.cpp?rev=340176&r1=340175&r2=340176&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/ExecuteStage.cpp (original)
+++ llvm/trunk/tools/llvm-mca/ExecuteStage.cpp Mon Aug 20 07:41:36 2018
@@ -25,17 +25,17 @@ namespace mca {
 
 using namespace llvm;
 
-HWStallEvent::GenericEventType toHWStallEventType(Scheduler::StallKind Event) {
-  switch (Event) {
-  case Scheduler::LoadQueueFull:
+HWStallEvent::GenericEventType toHWStallEventType(Scheduler::Status Status) {
+  switch (Status) {
+  case Scheduler::SC_LOAD_QUEUE_FULL:
     return HWStallEvent::LoadQueueFull;
-  case Scheduler::StoreQueueFull:
+  case Scheduler::SC_STORE_QUEUE_FULL:
     return HWStallEvent::StoreQueueFull;
-  case Scheduler::SchedulerQueueFull:
+  case Scheduler::SC_BUFFERS_FULL:
     return HWStallEvent::SchedulerQueueFull;
-  case Scheduler::DispatchGroupStall:
+  case Scheduler::SC_DISPATCH_GROUP_STALL:
     return HWStallEvent::DispatchGroupStall;
-  case Scheduler::NoStall:
+  case Scheduler::SC_AVAILABLE:
     return HWStallEvent::Invalid;
   }
 
@@ -43,15 +43,15 @@ HWStallEvent::GenericEventType toHWStall
 }
 
 bool ExecuteStage::isAvailable(const InstRef &IR) const {
-  Scheduler::StallKind Event = Scheduler::NoStall;
-  if (HWS.canBeDispatched(IR, Event))
-    return true;
-  HWStallEvent::GenericEventType ET = toHWStallEventType(Event);
-  notifyEvent<HWStallEvent>(HWStallEvent(ET, IR));
-  return false;
+  if (Scheduler::Status S = HWS.isAvailable(IR)) {
+    HWStallEvent::GenericEventType ET = toHWStallEventType(S);
+    notifyEvent<HWStallEvent>(HWStallEvent(ET, IR));
+    return false;
+  }
+
+  return true;
 }
 
-// Reclaim the simulated resources used by the scheduler.
 void ExecuteStage::reclaimSchedulerResources() {
   SmallVector<ResourceRef, 8> ResourcesFreed;
   HWS.reclaimSimulatedResources(ResourcesFreed);
@@ -59,7 +59,6 @@ void ExecuteStage::reclaimSchedulerResou
     notifyResourceAvailable(RR);
 }
 
-// Update the scheduler's instruction queues.
 Error ExecuteStage::updateSchedulerQueues() {
   SmallVector<InstRef, 4> InstructionIDs;
   HWS.updateIssuedSet(InstructionIDs);
@@ -77,7 +76,6 @@ Error ExecuteStage::updateSchedulerQueue
   return ErrorSuccess();
 }
 
-// Issue instructions that are waiting in the scheduler's ready queue.
 Error ExecuteStage::issueReadyInstructions() {
   SmallVector<InstRef, 4> InstructionIDs;
   InstRef IR = HWS.select();
@@ -145,39 +143,20 @@ Error ExecuteStage::execute(InstRef &IR)
   // be released after MCIS is issued, and all the ResourceCycles for those
   // units have been consumed.
   const InstrDesc &Desc = IR.getInstruction()->getDesc();
-  HWS.reserveBuffers(Desc.Buffers);
+  HWS.dispatch(IR);
   notifyReservedBuffers(Desc.Buffers);
-
-  // Obtain a slot in the LSU.  If we cannot reserve resources, return true, so
-  // that succeeding stages can make progress.
-  if (!HWS.reserveResources(IR))
+  if (!HWS.isReady(IR))
     return ErrorSuccess();
 
   // If we did not return early, then the scheduler is ready for execution.
   notifyInstructionReady(IR);
 
-  // Don't add a zero-latency instruction to the Wait or Ready queue.
-  // A zero-latency instruction doesn't consume any scheduler resources. That is
-  // because it doesn't need to be executed, and it is often removed at register
-  // renaming stage. For example, register-register moves are often optimized at
-  // register renaming stage by simply updating register aliases. On some
-  // targets, zero-idiom instructions (for example: a xor that clears the value
-  // of a register) are treated specially, and are often eliminated at register
-  // renaming stage.
-  //
-  // Instructions that use an in-order dispatch/issue processor resource must be
-  // issued immediately to the pipeline(s). Any other in-order buffered
-  // resources (i.e. BufferSize=1) is consumed.
-  //
   // If we cannot issue immediately, the HWS will add IR to its ready queue for
   // execution later, so we must return early here.
-  if (!HWS.issueImmediately(IR))
+  if (!HWS.mustIssueImmediately(IR))
     return ErrorSuccess();
 
-  LLVM_DEBUG(dbgs() << "[SCHEDULER] Instruction #" << IR
-                    << " issued immediately\n");
-
-  // Issue IR.  The resources for this issuance will be placed in 'Used.'
+  // Issue IR to the underlying pipelines.
   SmallVector<std::pair<ResourceRef, double>, 4> Used;
   HWS.issueInstruction(IR, Used);
 
@@ -193,7 +172,6 @@ Error ExecuteStage::execute(InstRef &IR)
 }
 
 void ExecuteStage::notifyInstructionExecuted(const InstRef &IR) {
-  HWS.onInstructionExecuted(IR);
   LLVM_DEBUG(dbgs() << "[E] Instruction Executed: #" << IR << '\n');
   notifyEvent<HWInstructionEvent>(
       HWInstructionEvent(HWInstructionEvent::Executed, IR));

Modified: llvm/trunk/tools/llvm-mca/LSUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/LSUnit.cpp?rev=340176&r1=340175&r2=340176&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/LSUnit.cpp (original)
+++ llvm/trunk/tools/llvm-mca/LSUnit.cpp Mon Aug 20 07:41:36 2018
@@ -51,33 +51,42 @@ void LSUnit::assignSQSlot(unsigned Index
   StoreQueue.insert(Index);
 }
 
-bool LSUnit::reserve(const InstRef &IR) {
+void LSUnit::dispatch(const InstRef &IR) {
   const InstrDesc &Desc = IR.getInstruction()->getDesc();
-  unsigned MayLoad = Desc.MayLoad;
-  unsigned MayStore = Desc.MayStore;
   unsigned IsMemBarrier = Desc.HasSideEffects;
-  if (!MayLoad && !MayStore)
-    return false;
+  assert((Desc.MayLoad || Desc.MayStore) && "Not a memory operation!");
 
   const unsigned Index = IR.getSourceIndex();
-  if (MayLoad) {
+  if (Desc.MayLoad) {
     if (IsMemBarrier)
       LoadBarriers.insert(Index);
     assignLQSlot(Index);
   }
-  if (MayStore) {
+
+  if (Desc.MayStore) {
     if (IsMemBarrier)
       StoreBarriers.insert(Index);
     assignSQSlot(Index);
   }
-  return true;
+}
+
+LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const {
+  const InstrDesc &Desc = IR.getInstruction()->getDesc();
+  if (Desc.MayLoad && isLQFull())
+    return LSUnit::LSU_LQUEUE_FULL;
+  if (Desc.MayStore && isSQFull())
+    return LSUnit::LSU_SQUEUE_FULL;
+  return LSUnit::LSU_AVAILABLE;
 }
 
 bool LSUnit::isReady(const InstRef &IR) const {
+  const InstrDesc &Desc = IR.getInstruction()->getDesc();
   const unsigned Index = IR.getSourceIndex();
-  bool IsALoad = LoadQueue.count(Index) != 0;
-  bool IsAStore = StoreQueue.count(Index) != 0;
-  assert((IsALoad || IsAStore) && "Instruction is not in queue!");
+  bool IsALoad = Desc.MayLoad;
+  bool IsAStore = Desc.MayStore;
+  assert((IsALoad || IsAStore) && "Not a memory operation!");
+  assert((!IsALoad || LoadQueue.count(Index) == 1) && "Load not in queue!");
+  assert((!IsAStore || StoreQueue.count(Index) == 1) && "Store not in queue!");
 
   if (IsALoad && !LoadBarriers.empty()) {
     unsigned LoadBarrierIndex = *LoadBarriers.begin();

Modified: llvm/trunk/tools/llvm-mca/LSUnit.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/LSUnit.h?rev=340176&r1=340175&r2=340176&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/LSUnit.h (original)
+++ llvm/trunk/tools/llvm-mca/LSUnit.h Mon Aug 20 07:41:36 2018
@@ -16,6 +16,7 @@
 #ifndef LLVM_TOOLS_LLVM_MCA_LSUNIT_H
 #define LLVM_TOOLS_LLVM_MCA_LSUNIT_H
 
+#include "HardwareUnit.h"
 #include <set>
 
 namespace mca {
@@ -86,7 +87,7 @@ struct InstrDesc;
 /// A load/store barrier is "executed" when it becomes the oldest entry in
 /// the load/store queue(s). That also means, all the older loads/stores have
 /// already been executed.
-class LSUnit {
+class LSUnit : public HardwareUnit {
   // Load queue size.
   // LQ_Size == 0 means that there are infinite slots in the load queue.
   unsigned LQ_Size;
@@ -115,6 +116,11 @@ class LSUnit {
   // before newer loads are issued.
   std::set<unsigned> LoadBarriers;
 
+  bool isSQEmpty() const { return StoreQueue.empty(); }
+  bool isLQEmpty() const { return LoadQueue.empty(); }
+  bool isSQFull() const { return SQ_Size != 0 && StoreQueue.size() == SQ_Size; }
+  bool isLQFull() const { return LQ_Size != 0 && LoadQueue.size() == LQ_Size; }
+
 public:
   LSUnit(unsigned LQ = 0, unsigned SQ = 0, bool AssumeNoAlias = false)
       : LQ_Size(LQ), SQ_Size(SQ), NoAlias(AssumeNoAlias) {}
@@ -123,22 +129,30 @@ public:
   void dump() const;
 #endif
 
-  bool isSQEmpty() const { return StoreQueue.empty(); }
-  bool isLQEmpty() const { return LoadQueue.empty(); }
-  bool isSQFull() const { return SQ_Size != 0 && StoreQueue.size() == SQ_Size; }
-  bool isLQFull() const { return LQ_Size != 0 && LoadQueue.size() == LQ_Size; }
-
-  // Returns true if this instruction has been successfully enqueued.
-  bool reserve(const InstRef &IR);
+  enum Status {
+    LSU_AVAILABLE = 0,
+    LSU_LQUEUE_FULL,
+    LSU_SQUEUE_FULL
+  };
+
+  // Returns LSU_AVAILABLE if there are enough load/store queue entries to serve
+  // IR. It also returns LSU_AVAILABLE if IR is not a memory operation.
+  Status isAvailable(const InstRef &IR) const;
+
+  // Allocates load/store queue resources for IR.
+  //
+  // This method assumes that a previous call to `isAvailable(IR)` returned
+  // LSU_AVAILABLE, and that IR is a memory operation.
+  void dispatch(const InstRef &IR);
 
-  // The rules are:
+  // By default, rules are:
   // 1. A store may not pass a previous store.
   // 2. A load may not pass a previous store unless flag 'NoAlias' is set.
   // 3. A load may pass a previous load.
   // 4. A store may not pass a previous load (regardless of flag 'NoAlias').
   // 5. A load has to wait until an older load barrier is fully executed.
   // 6. A store has to wait until an older store barrier is fully executed.
-  bool isReady(const InstRef &IR) const;
+  virtual bool isReady(const InstRef &IR) const;
   void onInstructionExecuted(const InstRef &IR);
 };
 

Modified: llvm/trunk/tools/llvm-mca/Scheduler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Scheduler.cpp?rev=340176&r1=340175&r2=340176&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Scheduler.cpp (original)
+++ llvm/trunk/tools/llvm-mca/Scheduler.cpp Mon Aug 20 07:41:36 2018
@@ -171,7 +171,7 @@ bool ResourceManager::canBeIssued(const
 
 // Returns true if all resources are in-order, and there is at least one
 // resource which is a dispatch hazard (BufferSize = 0).
-bool ResourceManager::mustIssueImmediately(const InstrDesc &Desc) {
+bool ResourceManager::mustIssueImmediately(const InstrDesc &Desc) const {
   if (!canBeIssued(Desc))
     return false;
   bool AllInOrderResources = all_of(Desc.Buffers, [&](uint64_t BufferMask) {
@@ -257,29 +257,29 @@ void Scheduler::dump() const {
 }
 #endif
 
-bool Scheduler::canBeDispatched(const InstRef &IR,
-                                Scheduler::StallKind &Event) const {
-  Event = StallKind::NoStall;
+Scheduler::Status Scheduler::isAvailable(const InstRef &IR) const {
   const InstrDesc &Desc = IR.getInstruction()->getDesc();
-
-  // Give lower priority to these stall events.
-  if (Desc.MayStore && LSU->isSQFull())
-    Event = StallKind::StoreQueueFull;
-  if (Desc.MayLoad && LSU->isLQFull())
-    Event = StallKind::LoadQueueFull;
-    
+   
   switch (Resources->canBeDispatched(Desc.Buffers)) {
   case ResourceStateEvent::RS_BUFFER_UNAVAILABLE:
-    Event = StallKind::SchedulerQueueFull;
-    break;
+    return Scheduler::SC_BUFFERS_FULL;
   case ResourceStateEvent::RS_RESERVED:
-    Event = StallKind::DispatchGroupStall;
-    break;
-  default:
+    return Scheduler::SC_DISPATCH_GROUP_STALL;
+  case ResourceStateEvent::RS_BUFFER_AVAILABLE:
     break;
   }
 
-  return Event == StallKind::NoStall;
+  // Give lower priority to LSUnit stall events.
+  switch (LSU->isAvailable(IR)) {
+  case LSUnit::LSU_LQUEUE_FULL:
+    return Scheduler::SC_LOAD_QUEUE_FULL;
+  case LSUnit::LSU_SQUEUE_FULL:
+    return Scheduler::SC_STORE_QUEUE_FULL;
+  case LSUnit::LSU_AVAILABLE:
+    return Scheduler::SC_AVAILABLE;
+  }
+
+  llvm_unreachable("Don't know how to process this LSU state result!");
 }
 
 void Scheduler::issueInstructionImpl(
@@ -298,6 +298,8 @@ void Scheduler::issueInstructionImpl(
 
   if (IS->isExecuting())
     IssuedSet.emplace_back(IR);
+  else if (IS->isExecuted())
+    LSU->onInstructionExecuted(IR);
 }
 
 // Release the buffered resources and issue the instruction.
@@ -305,7 +307,7 @@ void Scheduler::issueInstruction(
     InstRef &IR,
     SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources) {
   const InstrDesc &Desc = IR.getInstruction()->getDesc();
-  releaseBuffers(Desc.Buffers);
+  Resources->releaseBuffers(Desc.Buffers);
   issueInstructionImpl(IR, UsedResources);
 }
 
@@ -324,9 +326,8 @@ void Scheduler::promoteToReadySet(SmallV
     if (!IS.isReady())
       IS.update();
 
-    const InstrDesc &Desc = IS.getDesc();
-    bool IsMemOp = Desc.MayLoad || Desc.MayStore;
-    if (!IS.isReady() || (IsMemOp && !LSU->isReady(IR))) {
+    // Check f there are still unsolved data dependencies. 
+    if (!isReady(IR)) {
       ++I;
       continue;
     }
@@ -405,6 +406,8 @@ void Scheduler::updateIssuedSet(SmallVec
       continue;
     }
 
+    // Instruction IR has completed execution.
+    LSU->onInstructionExecuted(IR);
     Executed.emplace_back(IR);
     ++RemovedElements;
     IR.invalidate();
@@ -414,33 +417,51 @@ void Scheduler::updateIssuedSet(SmallVec
   IssuedSet.resize(IssuedSet.size() - RemovedElements);
 }
 
-void Scheduler::onInstructionExecuted(const InstRef &IR) {
-  LSU->onInstructionExecuted(IR);
-}
-
 void Scheduler::reclaimSimulatedResources(SmallVectorImpl<ResourceRef> &Freed) {
   Resources->cycleEvent(Freed);
 }
 
-bool Scheduler::reserveResources(InstRef &IR) {
+bool Scheduler::mustIssueImmediately(const InstRef &IR) const {
+  // Instructions that use an in-order dispatch/issue processor resource must be
+  // issued immediately to the pipeline(s). Any other in-order buffered
+  // resources (i.e. BufferSize=1) is consumed.
+  const InstrDesc &Desc = IR.getInstruction()->getDesc();
+  return Desc.isZeroLatency() || Resources->mustIssueImmediately(Desc);
+}
+
+void Scheduler::dispatch(const InstRef &IR) {
+  const InstrDesc &Desc = IR.getInstruction()->getDesc();
+  Resources->reserveBuffers(Desc.Buffers);
+
   // If necessary, reserve queue entries in the load-store unit (LSU).
-  const bool Reserved = LSU->reserve(IR);
-  if (!IR.getInstruction()->isReady() || (Reserved && !LSU->isReady(IR))) {
+  bool IsMemOp = Desc.MayLoad || Desc.MayStore;
+  if (IsMemOp)
+    LSU->dispatch(IR);
+
+  if (!isReady(IR)) {
     LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the WaitSet\n");
     WaitSet.push_back(IR);
-    return false;
+    return;
   }
-  return true;
-}
 
-bool Scheduler::issueImmediately(InstRef &IR) {
-  const InstrDesc &Desc = IR.getInstruction()->getDesc();
-  if (!Desc.isZeroLatency() && !Resources->mustIssueImmediately(Desc)) {
+  // Don't add a zero-latency instruction to the Ready queue.
+  // A zero-latency instruction doesn't consume any scheduler resources. That is
+  // because it doesn't need to be executed, and it is often removed at register
+  // renaming stage. For example, register-register moves are often optimized at
+  // register renaming stage by simply updating register aliases. On some
+  // targets, zero-idiom instructions (for example: a xor that clears the value
+  // of a register) are treated specially, and are often eliminated at register
+  // renaming stage.
+  if (!mustIssueImmediately(IR)) {
     LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the ReadySet\n");
     ReadySet.push_back(IR);
-    return false;
   }
-  return true;
+}
+
+bool Scheduler::isReady(const InstRef &IR) const {
+  const InstrDesc &Desc = IR.getInstruction()->getDesc();
+  bool IsMemOp = Desc.MayLoad || Desc.MayStore;
+  return IR.getInstruction()->isReady() && (!IsMemOp || LSU->isReady(IR));
 }
 
 } // namespace mca

Modified: llvm/trunk/tools/llvm-mca/Scheduler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Scheduler.h?rev=340176&r1=340175&r2=340176&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Scheduler.h (original)
+++ llvm/trunk/tools/llvm-mca/Scheduler.h Mon Aug 20 07:41:36 2018
@@ -321,7 +321,7 @@ public:
 
   // Returns true if all resources are in-order, and there is at least one
   // resource which is a dispatch hazard (BufferSize = 0).
-  bool mustIssueImmediately(const InstrDesc &Desc);
+  bool mustIssueImmediately(const InstrDesc &Desc) const;
 
   bool canBeIssued(const InstrDesc &Desc) const;
 
@@ -364,10 +364,10 @@ public:
 /// leaves the IssuedSet when it reaches the write-back stage.
 class Scheduler : public HardwareUnit {
   const llvm::MCSchedModel &SM;
+  LSUnit *LSU;
 
   // Hardware resources that are managed by this scheduler.
   std::unique_ptr<ResourceManager> Resources;
-  std::unique_ptr<LSUnit> LSU;
 
   std::vector<InstRef> WaitSet;
   std::vector<InstRef> ReadySet;
@@ -379,54 +379,49 @@ class Scheduler : public HardwareUnit {
       llvm::SmallVectorImpl<std::pair<ResourceRef, double>> &Pipes);
 
 public:
-  Scheduler(const llvm::MCSchedModel &Model, unsigned LoadQueueSize,
-            unsigned StoreQueueSize, bool AssumeNoAlias)
-      : SM(Model), Resources(llvm::make_unique<ResourceManager>(SM)),
-        LSU(llvm::make_unique<LSUnit>(LoadQueueSize, StoreQueueSize,
-                                      AssumeNoAlias)) {}
+  Scheduler(const llvm::MCSchedModel &Model, LSUnit *Lsu)
+      : SM(Model), LSU(Lsu), Resources(llvm::make_unique<ResourceManager>(SM)) {
+  }
 
   // Stalls generated by the scheduler.
-  enum StallKind {
-    NoStall,
-    LoadQueueFull,
-    StoreQueueFull,
-    SchedulerQueueFull,
-    DispatchGroupStall
+  enum Status {
+    SC_AVAILABLE,
+    SC_LOAD_QUEUE_FULL,
+    SC_STORE_QUEUE_FULL,
+    SC_BUFFERS_FULL,
+    SC_DISPATCH_GROUP_STALL,
   };
 
-  /// Check if the instruction in 'IR' can be dispatched.
+  /// Check if the instruction in 'IR' can be dispatched and returns an answer
+  /// in the form of a Status value.
   ///
   /// The DispatchStage is responsible for querying the Scheduler before
   /// dispatching new instructions. This routine is used for performing such
   /// a query.  If the instruction 'IR' can be dispatched, then true is
   /// returned, otherwise false is returned with Event set to the stall type.
-  bool canBeDispatched(const InstRef &IR, StallKind &Event) const;
+  /// Internally, it also checks if the load/store unit is available.
+  Status isAvailable(const InstRef &IR) const;
 
-  /// Returns true if there is availibility for IR in the LSU.
-  bool isReady(const InstRef &IR) const { return LSU->isReady(IR); }
+  /// Reserves buffer and LSUnit queue resources that are necessary to issue
+  /// this instruction.
+  ///
+  /// Returns true if instruction IR is ready to be issued to the underlying
+  /// pipelines. Note that this operation cannot fail; it assumes that a
+  /// previous call to method `isAvailable(IR)` returned `SC_AVAILABLE`.
+  void dispatch(const InstRef &IR);
+
+  /// Returns true if IR is ready to be executed by the underlying pipelines.
+  /// This method assumes that IR has been previously dispatched.
+  bool isReady(const InstRef &IR) const;
 
   /// Issue an instruction.  The Used container is populated with
   /// the resource objects consumed on behalf of issuing this instruction.
-  void
-  issueInstruction(InstRef &IR,
+  void issueInstruction(InstRef &IR,
                    llvm::SmallVectorImpl<std::pair<ResourceRef, double>> &Used);
 
-  /// This routine will attempt to issue an instruction immediately (for
-  /// zero-latency instructions).
-  ///
-  /// Returns true if the instruction is issued immediately.  If this does not
-  /// occur, then the instruction will be added to the Scheduler's ReadySet.
-  bool issueImmediately(InstRef &IR);
-
-  /// Reserve one entry in each buffered resource.
-  void reserveBuffers(llvm::ArrayRef<uint64_t> Buffers) {
-    Resources->reserveBuffers(Buffers);
-  }
-
-  /// Release buffer entries previously allocated by method reserveBuffers.
-  void releaseBuffers(llvm::ArrayRef<uint64_t> Buffers) {
-    Resources->releaseBuffers(Buffers);
-  }
+  /// Returns true if IR has to be issued immediately, or if IR is a zero
+  /// latency instruction.
+  bool mustIssueImmediately(const InstRef &IR) const;
 
   /// Update the resources managed by the scheduler.
   /// This routine is to be called at the start of a new cycle, and is
@@ -444,21 +439,12 @@ public:
   /// Update the issued queue.
   void updateIssuedSet(llvm::SmallVectorImpl<InstRef> &Executed);
 
-  /// Updates the Scheduler's resources to reflect that an instruction has just
-  /// been executed.
-  void onInstructionExecuted(const InstRef &IR);
-
   /// Obtain the processor's resource identifier for the given
   /// resource mask.
   unsigned getResourceID(uint64_t Mask) {
     return Resources->resolveResourceMask(Mask);
   }
 
-  /// Reserve resources necessary to issue the instruction.
-  /// Returns true if the resources are ready and the (LSU) can
-  /// execute the given instruction immediately.
-  bool reserveResources(InstRef &IR);
-
   /// Select the next instruction to issue from the ReadySet.
   /// This method gives priority to older instructions.
   InstRef select();




More information about the llvm-commits mailing list