[llvm-mca] Register listeners with stages; remove Pipeline dependency from Stage.
Summary:
This patch removes a few callbacks from Pipeline. It comes at the cost of
registering Listeners with all Stages. Not all stages need listeners or issue
callbacks, this registration is a bit redundant. However, as we build-out the
API, this redundancy can disappear.
The main purpose here is to move callback code from the Pipeline and into the
stages that actually issue those callbacks. This removes the back-pointer to
the Pipeline that was put into a few Stage subclasses.
Reviewers: andreadb, courbet, RKSimon
Reviewed By: andreadb, courbet
Subscribers: tschuett, gbedwell, llvm-commits
Differential Revision: https://reviews.llvm.org/D48576
llvm-svn: 335748
diff --git a/llvm/tools/llvm-mca/DispatchStage.cpp b/llvm/tools/llvm-mca/DispatchStage.cpp
index 8090918..70cd28d 100644
--- a/llvm/tools/llvm-mca/DispatchStage.cpp
+++ b/llvm/tools/llvm-mca/DispatchStage.cpp
@@ -18,7 +18,6 @@
#include "DispatchStage.h"
#include "HWEventListener.h"
-#include "Pipeline.h"
#include "Scheduler.h"
#include "llvm/Support/Debug.h"
@@ -31,7 +30,12 @@
void DispatchStage::notifyInstructionDispatched(const InstRef &IR,
ArrayRef<unsigned> UsedRegs) {
LLVM_DEBUG(dbgs() << "[E] Instruction Dispatched: " << IR << '\n');
- Owner->notifyInstructionEvent(HWInstructionDispatchedEvent(IR, UsedRegs));
+ notifyInstructionEvent(HWInstructionDispatchedEvent(IR, UsedRegs));
+}
+
+void DispatchStage::notifyStallEvent(const HWStallEvent &Event) {
+ for (HWEventListener *Listener : getListeners())
+ Listener->onStallEvent(Event);
}
bool DispatchStage::checkPRF(const InstRef &IR) {
@@ -43,7 +47,7 @@
const unsigned RegisterMask = PRF.isAvailable(RegDefs);
// A mask with all zeroes means: register files are available.
if (RegisterMask) {
- Owner->notifyStallEvent(HWStallEvent(HWStallEvent::RegisterFileStall, IR));
+ notifyStallEvent(HWStallEvent(HWStallEvent::RegisterFileStall, IR));
return false;
}
@@ -54,8 +58,7 @@
const unsigned NumMicroOps = IR.getInstruction()->getDesc().NumMicroOps;
if (RCU.isAvailable(NumMicroOps))
return true;
- Owner->notifyStallEvent(
- HWStallEvent(HWStallEvent::RetireControlUnitStall, IR));
+ notifyStallEvent(HWStallEvent(HWStallEvent::RetireControlUnitStall, IR));
return false;
}
@@ -63,7 +66,7 @@
HWStallEvent::GenericEventType Event;
const bool Ready = SC.canBeDispatched(IR, Event);
if (!Ready)
- Owner->notifyStallEvent(HWStallEvent(Event, IR));
+ notifyStallEvent(HWStallEvent(Event, IR));
return Ready;
}
diff --git a/llvm/tools/llvm-mca/DispatchStage.h b/llvm/tools/llvm-mca/DispatchStage.h
index 47e4864..9695c3e 100644
--- a/llvm/tools/llvm-mca/DispatchStage.h
+++ b/llvm/tools/llvm-mca/DispatchStage.h
@@ -19,6 +19,7 @@
#ifndef LLVM_TOOLS_LLVM_MCA_DISPATCH_STAGE_H
#define LLVM_TOOLS_LLVM_MCA_DISPATCH_STAGE_H
+#include "HWEventListener.h"
#include "Instruction.h"
#include "RegisterFile.h"
#include "RetireControlUnit.h"
@@ -30,7 +31,6 @@
class WriteState;
class Scheduler;
-class Pipeline;
// Implements the hardware dispatch logic.
//
@@ -54,7 +54,6 @@
unsigned DispatchWidth;
unsigned AvailableEntries;
unsigned CarryOver;
- Pipeline *Owner;
const llvm::MCSubtargetInfo &STI;
RetireControlUnit &RCU;
RegisterFile &PRF;
@@ -66,6 +65,7 @@
void dispatch(InstRef IR);
void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
+ void notifyStallEvent(const HWStallEvent &Event);
void notifyInstructionDispatched(const InstRef &IR,
llvm::ArrayRef<unsigned> UsedPhysRegs);
@@ -84,12 +84,12 @@
}
public:
- DispatchStage(Pipeline *P, const llvm::MCSubtargetInfo &Subtarget,
+ DispatchStage(const llvm::MCSubtargetInfo &Subtarget,
const llvm::MCRegisterInfo &MRI, unsigned RegisterFileSize,
unsigned MaxDispatchWidth, RetireControlUnit &R,
RegisterFile &F, Scheduler &Sched)
: DispatchWidth(MaxDispatchWidth), AvailableEntries(MaxDispatchWidth),
- CarryOver(0U), Owner(P), STI(Subtarget), RCU(R), PRF(F), SC(Sched) {}
+ CarryOver(0U), STI(Subtarget), RCU(R), PRF(F), SC(Sched) {}
// We can always try to dispatch, so returning false is okay in this case.
// The retire stage, which controls the RCU, might have items to complete but
diff --git a/llvm/tools/llvm-mca/ExecuteStage.cpp b/llvm/tools/llvm-mca/ExecuteStage.cpp
index ebd8715..c446ad6 100644
--- a/llvm/tools/llvm-mca/ExecuteStage.cpp
+++ b/llvm/tools/llvm-mca/ExecuteStage.cpp
@@ -16,7 +16,6 @@
//===----------------------------------------------------------------------===//
#include "ExecuteStage.h"
-#include "Pipeline.h"
#include "Scheduler.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
@@ -155,19 +154,20 @@
void ExecuteStage::notifyInstructionExecuted(const InstRef &IR) {
HWS.onInstructionExecuted(IR);
LLVM_DEBUG(dbgs() << "[E] Instruction Executed: " << IR << '\n');
- Owner->notifyInstructionEvent(
- HWInstructionEvent(HWInstructionEvent::Executed, IR));
+ notifyInstructionEvent(HWInstructionEvent(HWInstructionEvent::Executed, IR));
RCU.onInstructionExecuted(IR.getInstruction()->getRCUTokenID());
}
void ExecuteStage::notifyInstructionReady(const InstRef &IR) {
LLVM_DEBUG(dbgs() << "[E] Instruction Ready: " << IR << '\n');
- Owner->notifyInstructionEvent(
- HWInstructionEvent(HWInstructionEvent::Ready, IR));
+ notifyInstructionEvent(HWInstructionEvent(HWInstructionEvent::Ready, IR));
}
void ExecuteStage::notifyResourceAvailable(const ResourceRef &RR) {
- Owner->notifyResourceAvailable(RR);
+ LLVM_DEBUG(dbgs() << "[E] Resource Available: [" << RR.first << '.'
+ << RR.second << "]\n");
+ for (HWEventListener *Listener : getListeners())
+ Listener->onResourceAvailable(RR);
}
void ExecuteStage::notifyInstructionIssued(
@@ -180,7 +180,7 @@
dbgs() << " cycles: " << Resource.second << '\n';
}
});
- Owner->notifyInstructionEvent(HWInstructionIssuedEvent(IR, Used));
+ notifyInstructionEvent(HWInstructionIssuedEvent(IR, Used));
}
void ExecuteStage::notifyReservedBuffers(ArrayRef<uint64_t> Buffers) {
@@ -190,7 +190,8 @@
SmallVector<unsigned, 4> BufferIDs(Buffers.begin(), Buffers.end());
std::transform(Buffers.begin(), Buffers.end(), BufferIDs.begin(),
[&](uint64_t Op) { return HWS.getResourceID(Op); });
- Owner->notifyReservedBuffers(BufferIDs);
+ for (HWEventListener *Listener : getListeners())
+ Listener->onReservedBuffers(BufferIDs);
}
void ExecuteStage::notifyReleasedBuffers(ArrayRef<uint64_t> Buffers) {
@@ -200,7 +201,8 @@
SmallVector<unsigned, 4> BufferIDs(Buffers.begin(), Buffers.end());
std::transform(Buffers.begin(), Buffers.end(), BufferIDs.begin(),
[&](uint64_t Op) { return HWS.getResourceID(Op); });
- Owner->notifyReleasedBuffers(BufferIDs);
+ for (HWEventListener *Listener : getListeners())
+ Listener->onReleasedBuffers(BufferIDs);
}
} // namespace mca
diff --git a/llvm/tools/llvm-mca/ExecuteStage.h b/llvm/tools/llvm-mca/ExecuteStage.h
index 82b9369..622fa0f 100644
--- a/llvm/tools/llvm-mca/ExecuteStage.h
+++ b/llvm/tools/llvm-mca/ExecuteStage.h
@@ -26,11 +26,8 @@
namespace mca {
-class Pipeline;
-
class ExecuteStage : public Stage {
// Owner will go away when we move listeners/eventing to the stages.
- Pipeline *Owner;
RetireControlUnit &RCU;
Scheduler &HWS;
@@ -40,8 +37,7 @@
void issueReadyInstructions();
public:
- ExecuteStage(Pipeline *P, RetireControlUnit &R, Scheduler &S)
- : Stage(), Owner(P), RCU(R), HWS(S) {}
+ ExecuteStage(RetireControlUnit &R, Scheduler &S) : Stage(), RCU(R), HWS(S) {}
ExecuteStage(const ExecuteStage &Other) = delete;
ExecuteStage &operator=(const ExecuteStage &Other) = delete;
diff --git a/llvm/tools/llvm-mca/Pipeline.cpp b/llvm/tools/llvm-mca/Pipeline.cpp
index 49cf71e..716c43b 100644
--- a/llvm/tools/llvm-mca/Pipeline.cpp
+++ b/llvm/tools/llvm-mca/Pipeline.cpp
@@ -27,6 +27,8 @@
void Pipeline::addEventListener(HWEventListener *Listener) {
if (Listener)
Listeners.insert(Listener);
+ for (auto &S : Stages)
+ S->addListener(Listener);
}
bool Pipeline::hasWorkToProcess() {
@@ -77,33 +79,6 @@
Listener->onCycleBegin();
}
-void Pipeline::notifyInstructionEvent(const HWInstructionEvent &Event) {
- for (HWEventListener *Listener : Listeners)
- Listener->onInstructionEvent(Event);
-}
-
-void Pipeline::notifyStallEvent(const HWStallEvent &Event) {
- for (HWEventListener *Listener : Listeners)
- Listener->onStallEvent(Event);
-}
-
-void Pipeline::notifyResourceAvailable(const ResourceRef &RR) {
- LLVM_DEBUG(dbgs() << "[E] Resource Available: [" << RR.first << '.'
- << RR.second << "]\n");
- for (HWEventListener *Listener : Listeners)
- Listener->onResourceAvailable(RR);
-}
-
-void Pipeline::notifyReservedBuffers(ArrayRef<unsigned> Buffers) {
- for (HWEventListener *Listener : Listeners)
- Listener->onReservedBuffers(Buffers);
-}
-
-void Pipeline::notifyReleasedBuffers(ArrayRef<unsigned> Buffers) {
- for (HWEventListener *Listener : Listeners)
- Listener->onReleasedBuffers(Buffers);
-}
-
void Pipeline::notifyCycleEnd(unsigned Cycle) {
LLVM_DEBUG(dbgs() << "[E] Cycle end: " << Cycle << "\n\n");
for (HWEventListener *Listener : Listeners)
diff --git a/llvm/tools/llvm-mca/Pipeline.h b/llvm/tools/llvm-mca/Pipeline.h
index 3ff4f15..399d89e 100644
--- a/llvm/tools/llvm-mca/Pipeline.h
+++ b/llvm/tools/llvm-mca/Pipeline.h
@@ -70,11 +70,6 @@
void run();
void addEventListener(HWEventListener *Listener);
void notifyCycleBegin(unsigned Cycle);
- void notifyInstructionEvent(const HWInstructionEvent &Event);
- void notifyStallEvent(const HWStallEvent &Event);
- void notifyResourceAvailable(const ResourceRef &RR);
- void notifyReservedBuffers(llvm::ArrayRef<unsigned> Buffers);
- void notifyReleasedBuffers(llvm::ArrayRef<unsigned> Buffers);
void notifyCycleEnd(unsigned Cycle);
};
} // namespace mca
diff --git a/llvm/tools/llvm-mca/RetireStage.cpp b/llvm/tools/llvm-mca/RetireStage.cpp
index cdd0a22..0d1f4e4 100644
--- a/llvm/tools/llvm-mca/RetireStage.cpp
+++ b/llvm/tools/llvm-mca/RetireStage.cpp
@@ -16,7 +16,6 @@
#include "RetireStage.h"
#include "HWEventListener.h"
-#include "Pipeline.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
@@ -50,7 +49,7 @@
for (const std::unique_ptr<WriteState> &WS : IR.getInstruction()->getDefs())
PRF.removeRegisterWrite(*WS.get(), FreedRegs, !Desc.isZeroLatency());
- Owner->notifyInstructionEvent(HWInstructionRetiredEvent(IR, FreedRegs));
+ notifyInstructionEvent(HWInstructionRetiredEvent(IR, FreedRegs));
}
} // namespace mca
diff --git a/llvm/tools/llvm-mca/RetireStage.h b/llvm/tools/llvm-mca/RetireStage.h
index 4466890..c91e7e2 100644
--- a/llvm/tools/llvm-mca/RetireStage.h
+++ b/llvm/tools/llvm-mca/RetireStage.h
@@ -23,21 +23,20 @@
namespace mca {
-class Pipeline;
-
class RetireStage : public Stage {
// Owner will go away when we move listeners/eventing to the stages.
- Pipeline *Owner;
RetireControlUnit &RCU;
RegisterFile &PRF;
public:
- RetireStage(Pipeline *P, RetireControlUnit &R, RegisterFile &F)
- : Stage(), Owner(P), RCU(R), PRF(F) {}
+ RetireStage(RetireControlUnit &R, RegisterFile &F)
+ : Stage(), RCU(R), PRF(F) {}
RetireStage(const RetireStage &Other) = delete;
RetireStage &operator=(const RetireStage &Other) = delete;
- virtual bool hasWorkToComplete() const override final { return !RCU.isEmpty(); }
+ virtual bool hasWorkToComplete() const override final {
+ return !RCU.isEmpty();
+ }
virtual void preExecute(const InstRef &IR) override final;
virtual bool execute(InstRef &IR) override final { return true; }
void notifyInstructionRetired(const InstRef &IR);
diff --git a/llvm/tools/llvm-mca/Stage.cpp b/llvm/tools/llvm-mca/Stage.cpp
index f4eb8db..cfcb3f8 100644
--- a/llvm/tools/llvm-mca/Stage.cpp
+++ b/llvm/tools/llvm-mca/Stage.cpp
@@ -14,7 +14,6 @@
//===----------------------------------------------------------------------===//
#include "Stage.h"
-#include "llvm/Support/ErrorHandling.h"
namespace mca {
@@ -22,7 +21,12 @@
Stage::Stage() {}
void Stage::addListener(HWEventListener *Listener) {
- llvm_unreachable("Stage-based eventing is not implemented.");
+ Listeners.insert(Listener);
+}
+
+void Stage::notifyInstructionEvent(const HWInstructionEvent &Event) {
+ for (HWEventListener *Listener : Listeners)
+ Listener->onInstructionEvent(Event);
}
} // namespace mca
diff --git a/llvm/tools/llvm-mca/Stage.h b/llvm/tools/llvm-mca/Stage.h
index 7e709c8..2719376 100644
--- a/llvm/tools/llvm-mca/Stage.h
+++ b/llvm/tools/llvm-mca/Stage.h
@@ -16,17 +16,20 @@
#ifndef LLVM_TOOLS_LLVM_MCA_STAGE_H
#define LLVM_TOOLS_LLVM_MCA_STAGE_H
+#include "HWEventListener.h"
#include <set>
namespace mca {
-class HWEventListener;
class InstRef;
class Stage {
- std::set<HWEventListener *> Listeners;
Stage(const Stage &Other) = delete;
Stage &operator=(const Stage &Other) = delete;
+ std::set<HWEventListener *> Listeners;
+
+protected:
+ const std::set<HWEventListener *> &getListeners() const { return Listeners; }
public:
Stage();
@@ -51,6 +54,8 @@
/// Add a listener to receive callbacks during the execution of this stage.
void addListener(HWEventListener *Listener);
+
+ virtual void notifyInstructionEvent(const HWInstructionEvent &Event);
};
} // namespace mca
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 380cd3f..a492eb8 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -511,9 +511,9 @@
Width, RegisterFileSize, LoadQueueSize, StoreQueueSize, AssumeNoAlias);
P->appendStage(llvm::make_unique<mca::FetchStage>(IB, S));
P->appendStage(llvm::make_unique<mca::DispatchStage>(
- P.get(), *STI, *MRI, RegisterFileSize, Width, RCU, PRF, HWS));
- P->appendStage(llvm::make_unique<mca::RetireStage>(P.get(), RCU, PRF));
- P->appendStage(llvm::make_unique<mca::ExecuteStage>(P.get(), RCU, HWS));
+ *STI, *MRI, RegisterFileSize, Width, RCU, PRF, HWS));
+ P->appendStage(llvm::make_unique<mca::RetireStage>(RCU, PRF));
+ P->appendStage(llvm::make_unique<mca::ExecuteStage>(RCU, HWS));
mca::PipelinePrinter Printer(*P);
if (PrintSummaryView)