[llvm-mca] Small refactoring in preparation for another patch that will improve the...
authorAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Thu, 16 Aug 2018 15:43:09 +0000 (15:43 +0000)
committerAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Thu, 16 Aug 2018 15:43:09 +0000 (15:43 +0000)
The main difference is that now `cycleStart()` and `cycleEnd()` return an
llvm::Error.

This patch implements a few minor style changes, and adds missing 'const' to
some methods.

llvm-svn: 339885

12 files changed:
llvm/tools/llvm-mca/DispatchStage.cpp
llvm/tools/llvm-mca/DispatchStage.h
llvm/tools/llvm-mca/ExecuteStage.cpp
llvm/tools/llvm-mca/ExecuteStage.h
llvm/tools/llvm-mca/FetchStage.cpp
llvm/tools/llvm-mca/FetchStage.h
llvm/tools/llvm-mca/Pipeline.cpp
llvm/tools/llvm-mca/RetireStage.cpp
llvm/tools/llvm-mca/RetireStage.h
llvm/tools/llvm-mca/SourceMgr.h
llvm/tools/llvm-mca/Stage.cpp
llvm/tools/llvm-mca/Stage.h

index d397f72..4f2dbee 100644 (file)
@@ -33,7 +33,7 @@ void DispatchStage::notifyInstructionDispatched(const InstRef &IR,
   notifyEvent<HWInstructionEvent>(HWInstructionDispatchedEvent(IR, UsedRegs));
 }
 
-bool DispatchStage::checkPRF(const InstRef &IR) {
+bool DispatchStage::checkPRF(const InstRef &IR) const {
   SmallVector<unsigned, 4> RegDefs;
   for (const std::unique_ptr<WriteState> &RegDef :
        IR.getInstruction()->getDefs())
@@ -50,7 +50,7 @@ bool DispatchStage::checkPRF(const InstRef &IR) {
   return true;
 }
 
-bool DispatchStage::checkRCU(const InstRef &IR) {
+bool DispatchStage::checkRCU(const InstRef &IR) const {
   const unsigned NumMicroOps = IR.getInstruction()->getDesc().NumMicroOps;
   if (RCU.isAvailable(NumMicroOps))
     return true;
@@ -59,7 +59,7 @@ bool DispatchStage::checkRCU(const InstRef &IR) {
   return false;
 }
 
-bool DispatchStage::checkScheduler(const InstRef &IR) {
+bool DispatchStage::checkScheduler(const InstRef &IR) const {
   HWStallEvent::GenericEventType Event;
   const bool Ready = SC.canBeDispatched(IR, Event);
   if (!Ready)
@@ -131,9 +131,10 @@ void DispatchStage::dispatch(InstRef IR) {
   notifyInstructionDispatched(IR, RegisterFiles);
 }
 
-void DispatchStage::cycleStart() {
+llvm::Error DispatchStage::cycleStart() {
   AvailableEntries = CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver;
   CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U;
+  return llvm::ErrorSuccess();
 }
 
 Stage::Status DispatchStage::execute(InstRef &IR) {
index 06619a8..2312f86 100644 (file)
@@ -58,9 +58,9 @@ class DispatchStage final : public Stage {
   RegisterFile &PRF;
   Scheduler &SC;
 
-  bool checkRCU(const InstRef &IR);
-  bool checkPRF(const InstRef &IR);
-  bool checkScheduler(const InstRef &IR);
+  bool checkRCU(const InstRef &IR) const;
+  bool checkPRF(const InstRef &IR) const;
+  bool checkScheduler(const InstRef &IR) const;
   void dispatch(InstRef IR);
   void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
 
@@ -93,7 +93,7 @@ public:
   // The retire stage, which controls the RCU, might have items to complete but
   // RetireStage::hasWorkToComplete will check for that case.
   bool hasWorkToComplete() const override { return false; }
-  void cycleStart() override;
+  llvm::Error cycleStart() override;
   Status execute(InstRef &IR) override;
   void notifyDispatchStall(const InstRef &IR, unsigned EventType);
 
index 25f90b4..f9abf9f 100644 (file)
@@ -35,7 +35,7 @@ void ExecuteStage::reclaimSchedulerResources() {
 }
 
 // Update the scheduler's instruction queues.
-void ExecuteStage::updateSchedulerQueues() {
+Error ExecuteStage::updateSchedulerQueues() {
   SmallVector<InstRef, 4> InstructionIDs;
   HWS.updateIssuedSet(InstructionIDs);
   for (const InstRef &IR : InstructionIDs)
@@ -45,10 +45,11 @@ void ExecuteStage::updateSchedulerQueues() {
   HWS.updatePendingQueue(InstructionIDs);
   for (const InstRef &IR : InstructionIDs)
     notifyInstructionReady(IR);
+  return ErrorSuccess();
 }
 
 // Issue instructions that are waiting in the scheduler's ready queue.
-void ExecuteStage::issueReadyInstructions() {
+Error ExecuteStage::issueReadyInstructions() {
   SmallVector<InstRef, 4> InstructionIDs;
   InstRef IR = HWS.select();
   while (IR.isValid()) {
@@ -75,6 +76,8 @@ void ExecuteStage::issueReadyInstructions() {
     // Select the next instruction to issue.
     IR = HWS.select();
   }
+
+  return ErrorSuccess();
 }
 
 // The following routine is the maintenance routine of the ExecuteStage.
@@ -89,10 +92,11 @@ void ExecuteStage::issueReadyInstructions() {
 // Notifications are issued to this stage's listeners when instructions are
 // moved between the HWS's queues.  In particular, when an instruction becomes
 // ready or executed.
-void ExecuteStage::cycleStart() {
+Error ExecuteStage::cycleStart() {
   reclaimSchedulerResources();
-  updateSchedulerQueues();
-  issueReadyInstructions();
+  if (Error S = updateSchedulerQueues())
+    return S;
+  return issueReadyInstructions();
 }
 
 // Schedule the instruction for execution on the hardware.
index d40057a..d22cca0 100644 (file)
@@ -33,8 +33,8 @@ class ExecuteStage final : public Stage {
 
   // The following routines are used to maintain the HWS.
   void reclaimSchedulerResources();
-  void updateSchedulerQueues();
-  void issueReadyInstructions();
+  llvm::Error updateSchedulerQueues();
+  llvm::Error issueReadyInstructions();
 
   ExecuteStage(const ExecuteStage &Other) = delete;
   ExecuteStage &operator=(const ExecuteStage &Other) = delete;
@@ -42,11 +42,15 @@ class ExecuteStage final : public Stage {
 public:
   ExecuteStage(RetireControlUnit &R, Scheduler &S) : Stage(), RCU(R), HWS(S) {}
 
-  // The ExecuteStage will always complete all of its work per call to
-  // execute(), so it is never left in a 'to-be-processed' state.
+  // This stage works under the assumption that the Pipeline will eventually
+  // execute a retire stage. We don't need to check if pipelines and/or
+  // schedulers have instructions to process, because those instructions are
+  // also tracked by the retire control unit. That means,
+  // RetireControlUnit::hasWorkToComplete() is responsible for checking if there
+  // are still instructions in-flight in the out-of-order backend.
   bool hasWorkToComplete() const override { return false; }
 
-  void cycleStart() override;
+  llvm::Error cycleStart() override;
   Status execute(InstRef &IR) override;
 
   void
index acb5b05..1a6b939 100644 (file)
@@ -35,7 +35,7 @@ Stage::Status FetchStage::execute(InstRef &IR) {
 
 void FetchStage::postExecute() { SM.updateNext(); }
 
-void FetchStage::cycleEnd() {
+llvm::Error FetchStage::cycleEnd() {
   // Find the first instruction which hasn't been retired.
   const InstMap::iterator It =
       llvm::find_if(Instructions, [](const InstMap::value_type &KeyValuePair) {
@@ -45,6 +45,8 @@ void FetchStage::cycleEnd() {
   // Erase instructions up to the first that hasn't been retired.
   if (It != Instructions.begin())
     Instructions.erase(Instructions.begin(), It);
+
+  return llvm::ErrorSuccess();
 }
 
 } // namespace mca
index 447ec3b..e028cd0 100644 (file)
@@ -38,7 +38,7 @@ public:
   bool hasWorkToComplete() const override;
   Status execute(InstRef &IR) override;
   void postExecute() override;
-  void cycleEnd() override;
+  llvm::Error cycleEnd() override;
 };
 
 } // namespace mca
index f099ec6..91c7a5d 100644 (file)
@@ -32,10 +32,9 @@ void Pipeline::addEventListener(HWEventListener *Listener) {
 }
 
 bool Pipeline::hasWorkToProcess() {
-  const auto It = llvm::find_if(Stages, [](const std::unique_ptr<Stage> &S) {
+  return llvm::any_of(Stages, [](const std::unique_ptr<Stage> &S) {
     return S->hasWorkToComplete();
   });
-  return It != Stages.end();
 }
 
 // This routine returns early if any stage returns 'false' after execute() is
@@ -62,6 +61,8 @@ void Pipeline::postExecuteStages() {
 }
 
 llvm::Error Pipeline::run() {
+  assert(!Stages.empty() && "Unexpected empty pipeline found!");
+
   while (hasWorkToProcess()) {
     notifyCycleBegin();
     if (llvm::Error Err = runCycle())
@@ -73,13 +74,18 @@ llvm::Error Pipeline::run() {
 }
 
 llvm::Error Pipeline::runCycle() {
-  // Update the stages before we do any processing for this cycle.
-  InstRef IR;
-  for (auto &S : Stages)
-    S->cycleStart();
+  // Update stages before we start processing new instructions.
+  llvm::Error Err = llvm::ErrorSuccess();
+  for (auto I = Stages.begin(), E = Stages.end(); I != E && !Err; ++I) {
+    const std::unique_ptr<Stage> &S = *I;
+    Err = S->cycleStart();
+  }
+
+  if (Err)
+    return Err;
 
-  // Continue executing this cycle until any stage claims it cannot make
-  // progress.
+  // Now fetch and execute new instructions.
+  InstRef IR;
   while (true) {
     preExecuteStages();
     Stage::Status Val = executeStages(IR);
@@ -90,9 +96,12 @@ llvm::Error Pipeline::runCycle() {
     postExecuteStages();
   }
 
-  for (auto &S : Stages)
-    S->cycleEnd();
-  return llvm::ErrorSuccess();
+  // Update stages in preparation for a new cycle.
+  for (auto I = Stages.begin(), E = Stages.end(); I != E && !Err; ++I) {
+    const std::unique_ptr<Stage> &S = *I;
+    Err = S->cycleEnd();
+  }
+  return Err;
 }
 
 void Pipeline::notifyCycleBegin() {
index 55c3b88..43e3364 100644 (file)
 #include "HWEventListener.h"
 #include "llvm/Support/Debug.h"
 
-using namespace llvm;
-
 #define DEBUG_TYPE "llvm-mca"
 
 namespace mca {
 
-void RetireStage::cycleStart() {
+llvm::Error RetireStage::cycleStart() {
   if (RCU.isEmpty())
-    return;
+    return llvm::ErrorSuccess();
 
   const unsigned MaxRetirePerCycle = RCU.getMaxRetirePerCycle();
   unsigned NumRetired = 0;
@@ -40,11 +38,13 @@ void RetireStage::cycleStart() {
     notifyInstructionRetired(Current.IR);
     NumRetired++;
   }
+
+  return llvm::ErrorSuccess();
 }
 
 void RetireStage::notifyInstructionRetired(const InstRef &IR) {
-  LLVM_DEBUG(dbgs() << "[E] Instruction Retired: #" << IR << '\n');
-  SmallVector<unsigned, 4> FreedRegs(PRF.getNumRegisterFiles());
+  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();
 
index f10188d..36af447 100644 (file)
@@ -36,7 +36,7 @@ public:
       : Stage(), RCU(R), PRF(F) {}
 
   bool hasWorkToComplete() const override { return !RCU.isEmpty(); }
-  void cycleStart() override;
+  llvm::Error cycleStart() override;
   Status execute(InstRef &IR) override { return Stage::Continue; }
   void notifyInstructionRetired(const InstRef &IR);
   void onInstructionExecuted(unsigned TokenID);
index 15a85a6..573ca7a 100644 (file)
@@ -44,6 +44,7 @@ public:
   void updateNext() { Current++; }
 
   const SourceRef peekNext() const {
+    assert(hasNext() && "Already at end of sequence!");
     unsigned Index = getCurrentInstructionIndex();
     return SourceRef(Current, Sequence[Index].get());
   }
index 7ead940..5cf76ab 100644 (file)
@@ -18,7 +18,7 @@
 namespace mca {
 
 // Pin the vtable here in the implementation file.
-Stage::Stage() {}
+Stage::~Stage() = default;
 
 void Stage::addListener(HWEventListener *Listener) {
   Listeners.insert(Listener);
index 1516712..c9ca1b2 100644 (file)
@@ -25,9 +25,10 @@ namespace mca {
 class InstRef;
 
 class Stage {
+  std::set<HWEventListener *> Listeners;
+
   Stage(const Stage &Other) = delete;
   Stage &operator=(const Stage &Other) = delete;
-  std::set<HWEventListener *> Listeners;
 
 public:
   /// A Stage's execute() returns Continue, Stop, or an error.  Returning
@@ -46,8 +47,8 @@ protected:
   const std::set<HWEventListener *> &getListeners() const { return Listeners; }
 
 public:
-  Stage();
-  virtual ~Stage() = default;
+  Stage() {}
+  virtual ~Stage();
 
   /// Called prior to preExecute to ensure that the stage has items that it
   /// is to process.  For example, a FetchStage might have more instructions
@@ -57,10 +58,10 @@ public:
 
   /// Called once at the start of each cycle.  This can be used as a setup
   /// phase to prepare for the executions during the cycle.
-  virtual void cycleStart() {}
+  virtual llvm::Error cycleStart() { return llvm::ErrorSuccess(); }
 
   /// Called once at the end of each cycle.
-  virtual void cycleEnd() {}
+  virtual llvm::Error cycleEnd() { return llvm::ErrorSuccess(); }
 
   /// Called prior to executing the list of stages.
   /// This can be called multiple times per cycle.
@@ -80,7 +81,7 @@ public:
   void addListener(HWEventListener *Listener);
 
   /// Notify listeners of a particular hardware event.
-  template <typename EventT> void notifyEvent(const EventT &Event) {
+  template <typename EventT> void notifyEvent(const EventT &Event) const {
     for (HWEventListener *Listener : Listeners)
       Listener->onEvent(Event);
   }