summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-mca
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-mca')
-rw-r--r--llvm/tools/llvm-mca/Backend.cpp42
-rw-r--r--llvm/tools/llvm-mca/Backend.h47
-rw-r--r--llvm/tools/llvm-mca/DispatchStage.h6
-rw-r--r--llvm/tools/llvm-mca/ExecuteStage.cpp5
-rw-r--r--llvm/tools/llvm-mca/ExecuteStage.h4
-rw-r--r--llvm/tools/llvm-mca/FetchStage.cpp2
-rw-r--r--llvm/tools/llvm-mca/FetchStage.h2
-rw-r--r--llvm/tools/llvm-mca/RetireStage.h1
-rw-r--r--llvm/tools/llvm-mca/Stage.h9
-rw-r--r--llvm/tools/llvm-mca/llvm-mca.cpp42
10 files changed, 86 insertions, 74 deletions
diff --git a/llvm/tools/llvm-mca/Backend.cpp b/llvm/tools/llvm-mca/Backend.cpp
index 3e7a3650e9d..c3e8d2f44c3 100644
--- a/llvm/tools/llvm-mca/Backend.cpp
+++ b/llvm/tools/llvm-mca/Backend.cpp
@@ -13,7 +13,6 @@
//===----------------------------------------------------------------------===//
#include "Backend.h"
-#include "FetchStage.h"
#include "HWEventListener.h"
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/Support/Debug.h"
@@ -29,8 +28,29 @@ void Backend::addEventListener(HWEventListener *Listener) {
Listeners.insert(Listener);
}
+bool Backend::hasWorkToProcess() {
+ const auto It = llvm::find_if(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
+// called on it.
+bool Backend::executeStages(InstRef &IR) {
+ for (const std::unique_ptr<Stage> &S : Stages)
+ if (!S->execute(IR))
+ return false;
+ return true;
+}
+
+void Backend::postExecuteStages(const InstRef &IR) {
+ for (const std::unique_ptr<Stage> &S : Stages)
+ S->postExecute(IR);
+}
+
void Backend::run() {
- while (Fetch->isReady() || !Dispatch->isReady())
+ while (hasWorkToProcess())
runCycle(Cycles++);
}
@@ -39,17 +59,13 @@ void Backend::runCycle(unsigned Cycle) {
// Update the stages before we do any processing for this cycle.
InstRef IR;
- Retire->preExecute(IR);
- Dispatch->preExecute(IR);
- Execute->preExecute(IR);
-
- // Fetch instructions and dispatch them to the hardware.
- while (Fetch->execute(IR)) {
- if (!Dispatch->execute(IR))
- break;
- Execute->execute(IR);
- Fetch->postExecute(IR);
- }
+ for (auto &S : Stages)
+ S->preExecute(IR);
+
+ // Continue executing this cycle until any stage claims it cannot make
+ // progress.
+ while (executeStages(IR))
+ postExecuteStages(IR);
notifyCycleEnd(Cycle);
}
diff --git a/llvm/tools/llvm-mca/Backend.h b/llvm/tools/llvm-mca/Backend.h
index 79e5bba7f8d..87969ae61c5 100644
--- a/llvm/tools/llvm-mca/Backend.h
+++ b/llvm/tools/llvm-mca/Backend.h
@@ -15,14 +15,9 @@
#ifndef LLVM_TOOLS_LLVM_MCA_BACKEND_H
#define LLVM_TOOLS_LLVM_MCA_BACKEND_H
-#include "DispatchStage.h"
-#include "ExecuteStage.h"
-#include "FetchStage.h"
-#include "InstrBuilder.h"
-#include "RegisterFile.h"
-#include "RetireControlUnit.h"
-#include "RetireStage.h"
#include "Scheduler.h"
+#include "Stage.h"
+#include "llvm/ADT/SmallVector.h"
namespace mca {
@@ -55,40 +50,22 @@ class HWStallEvent;
/// histograms. For example, it tracks how the dispatch group size changes
/// over time.
class Backend {
- // The following are the simulated hardware components of the backend.
- RetireControlUnit RCU;
- RegisterFile PRF;
- Scheduler HWS;
-
- /// TODO: Eventually this will become a list of unique Stage* that this
- /// backend pipeline executes.
- std::unique_ptr<FetchStage> Fetch;
- std::unique_ptr<DispatchStage> Dispatch;
- std::unique_ptr<ExecuteStage> Execute;
- std::unique_ptr<RetireStage> Retire;
-
+ /// An ordered list of stages that define this backend's instruction pipeline.
+ llvm::SmallVector<std::unique_ptr<Stage>, 8> Stages;
std::set<HWEventListener *> Listeners;
unsigned Cycles;
+ bool executeStages(InstRef &IR);
+ void postExecuteStages(const InstRef &IR);
+ bool hasWorkToProcess();
void runCycle(unsigned Cycle);
public:
- Backend(const llvm::MCSubtargetInfo &Subtarget,
- const llvm::MCRegisterInfo &MRI,
- std::unique_ptr<FetchStage> InitialStage, unsigned DispatchWidth = 0,
- unsigned RegisterFileSize = 0, unsigned LoadQueueSize = 0,
- unsigned StoreQueueSize = 0, bool AssumeNoAlias = false)
- : RCU(Subtarget.getSchedModel()),
- PRF(Subtarget.getSchedModel(), MRI, RegisterFileSize),
- HWS(Subtarget.getSchedModel(), LoadQueueSize, StoreQueueSize,
- AssumeNoAlias),
- Fetch(std::move(InitialStage)),
- Dispatch(llvm::make_unique<DispatchStage>(
- this, Subtarget, MRI, RegisterFileSize, DispatchWidth, RCU, PRF,
- HWS)),
- Execute(llvm::make_unique<ExecuteStage>(this, RCU, HWS)),
- Retire(llvm::make_unique<RetireStage>(this, RCU, PRF)), Cycles(0) {}
-
+ Backend(unsigned DispatchWidth = 0, unsigned RegisterFileSize = 0,
+ unsigned LoadQueueSize = 0, unsigned StoreQueueSize = 0,
+ bool AssumeNoAlias = false)
+ : Cycles(0) {}
+ void appendStage(std::unique_ptr<Stage> S) { Stages.push_back(std::move(S)); }
void run();
void addEventListener(HWEventListener *Listener);
void notifyCycleBegin(unsigned Cycle);
diff --git a/llvm/tools/llvm-mca/DispatchStage.h b/llvm/tools/llvm-mca/DispatchStage.h
index 9317f88192e..60b33324ba0 100644
--- a/llvm/tools/llvm-mca/DispatchStage.h
+++ b/llvm/tools/llvm-mca/DispatchStage.h
@@ -64,7 +64,6 @@ class DispatchStage : public Stage {
bool checkPRF(const InstRef &IR);
bool checkScheduler(const InstRef &IR);
void dispatch(InstRef IR);
- bool isRCUEmpty() const { return RCU.isEmpty(); }
void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
void notifyInstructionDispatched(const InstRef &IR,
@@ -92,7 +91,10 @@ public:
: DispatchWidth(MaxDispatchWidth), AvailableEntries(MaxDispatchWidth),
CarryOver(0U), Owner(B), STI(Subtarget), RCU(R), PRF(F), SC(Sched) {}
- virtual bool isReady() const override final { return isRCUEmpty(); }
+ // 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
+ // RetireStage::hasWorkToComplete will check for that case.
+ virtual bool hasWorkToComplete() const override final { return false; }
virtual void preExecute(const InstRef &IR) override final;
virtual bool execute(InstRef &IR) override final;
void notifyDispatchStall(const InstRef &IR, unsigned EventType);
diff --git a/llvm/tools/llvm-mca/ExecuteStage.cpp b/llvm/tools/llvm-mca/ExecuteStage.cpp
index 1c222f0f1eb..6a0fefdadcc 100644
--- a/llvm/tools/llvm-mca/ExecuteStage.cpp
+++ b/llvm/tools/llvm-mca/ExecuteStage.cpp
@@ -110,9 +110,10 @@ bool ExecuteStage::execute(InstRef &IR) {
HWS.reserveBuffers(Desc.Buffers);
notifyReservedBuffers(Desc.Buffers);
- // Obtain a slot in the LSU.
+ // Obtain a slot in the LSU. If we cannot reserve resources, return true, so
+ // that succeeding stages can make progress.
if (!HWS.reserveResources(IR))
- return false;
+ return true;
// If we did not return early, then the scheduler is ready for execution.
notifyInstructionReady(IR);
diff --git a/llvm/tools/llvm-mca/ExecuteStage.h b/llvm/tools/llvm-mca/ExecuteStage.h
index c7399182316..a71aa45b3fd 100644
--- a/llvm/tools/llvm-mca/ExecuteStage.h
+++ b/llvm/tools/llvm-mca/ExecuteStage.h
@@ -45,6 +45,10 @@ public:
ExecuteStage(const ExecuteStage &Other) = delete;
ExecuteStage &operator=(const ExecuteStage &Other) = delete;
+ // The ExecuteStage will always complete all of its work per call to
+ // execute(), so it is never left in a 'to-be-processed' state.
+ virtual bool hasWorkToComplete() const override final { return false; }
+
virtual void preExecute(const InstRef &IR) override final;
virtual bool execute(InstRef &IR) override final;
diff --git a/llvm/tools/llvm-mca/FetchStage.cpp b/llvm/tools/llvm-mca/FetchStage.cpp
index d73585869e1..4ea1c6b0fe3 100644
--- a/llvm/tools/llvm-mca/FetchStage.cpp
+++ b/llvm/tools/llvm-mca/FetchStage.cpp
@@ -17,7 +17,7 @@
namespace mca {
-bool FetchStage::isReady() const { return SM.hasNext(); }
+bool FetchStage::hasWorkToComplete() const { return SM.hasNext(); }
bool FetchStage::execute(InstRef &IR) {
if (!SM.hasNext())
diff --git a/llvm/tools/llvm-mca/FetchStage.h b/llvm/tools/llvm-mca/FetchStage.h
index b288d7aae99..4c70b7f2bc6 100644
--- a/llvm/tools/llvm-mca/FetchStage.h
+++ b/llvm/tools/llvm-mca/FetchStage.h
@@ -34,7 +34,7 @@ public:
FetchStage(const FetchStage &Other) = delete;
FetchStage &operator=(const FetchStage &Other) = delete;
- bool isReady() const override final;
+ bool hasWorkToComplete() const override final;
bool execute(InstRef &IR) override final;
void postExecute(const InstRef &IR) override final;
};
diff --git a/llvm/tools/llvm-mca/RetireStage.h b/llvm/tools/llvm-mca/RetireStage.h
index a40e4033b1f..3041f26fd6e 100644
--- a/llvm/tools/llvm-mca/RetireStage.h
+++ b/llvm/tools/llvm-mca/RetireStage.h
@@ -37,6 +37,7 @@ public:
RetireStage(const RetireStage &Other) = delete;
RetireStage &operator=(const RetireStage &Other) = delete;
+ 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.h b/llvm/tools/llvm-mca/Stage.h
index ffaf371921a..426c0227cb7 100644
--- a/llvm/tools/llvm-mca/Stage.h
+++ b/llvm/tools/llvm-mca/Stage.h
@@ -32,10 +32,11 @@ public:
Stage();
virtual ~Stage() = default;
- /// Called prior to preExecute to ensure that the stage can operate.
- /// TODO: Remove this logic once backend::run and backend::runCycle become
- /// one routine.
- virtual bool isReady() const { return true; }
+ /// Called prior to preExecute to ensure that the stage has items that it
+ /// is to process. For example, a FetchStage might have more instructions
+ /// that need to be processed, or a RCU might have items that have yet to
+ /// retire.
+ virtual bool hasWorkToComplete() const = 0;
/// Called as a setup phase to prepare for the main stage execution.
virtual void preExecute(const InstRef &IR) {}
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 372be3e0d6d..fb019f12580 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -23,13 +23,19 @@
#include "BackendPrinter.h"
#include "CodeRegion.h"
+#include "DispatchStage.h"
#include "DispatchStatistics.h"
+#include "ExecuteStage.h"
#include "FetchStage.h"
#include "InstructionInfoView.h"
#include "InstructionTables.h"
+#include "RegisterFile.h"
#include "RegisterFileStatistics.h"
#include "ResourcePressureView.h"
+#include "RetireControlUnit.h"
#include "RetireControlUnitStatistics.h"
+#include "RetireStage.h"
+#include "Scheduler.h"
#include "SchedulerStatistics.h"
#include "SummaryView.h"
#include "TimelineView.h"
@@ -65,15 +71,13 @@ static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
cl::value_desc("filename"));
static cl::opt<std::string>
- ArchName("march",
- cl::desc("Target arch to assemble for, "
- "see -version for available targets"),
+ ArchName("march", cl::desc("Target arch to assemble for, "
+ "see -version for available targets"),
cl::cat(ToolOptions));
static cl::opt<std::string>
- TripleName("mtriple",
- cl::desc("Target triple to assemble for, "
- "see -version for available targets"),
+ TripleName("mtriple", cl::desc("Target triple to assemble for, "
+ "see -version for available targets"),
cl::cat(ToolOptions));
static cl::opt<std::string>
@@ -483,7 +487,7 @@ int main(int argc, char **argv) {
PrintInstructionTables ? 1 : Iterations);
if (PrintInstructionTables) {
- mca::InstructionTables IT(STI->getSchedModel(), IB, S);
+ mca::InstructionTables IT(SM, IB, S);
if (PrintInstructionInfoView) {
IT.addView(
@@ -496,14 +500,20 @@ int main(int argc, char **argv) {
continue;
}
- // Ideally, I'd like to expose the pipeline building here,
- // by registering all of the Stage instances.
- // But for now, it's just this single puppy.
- std::unique_ptr<mca::FetchStage> Fetch =
- llvm::make_unique<mca::FetchStage>(IB, S);
- mca::Backend B(*STI, *MRI, std::move(Fetch), Width, RegisterFileSize,
- LoadQueueSize, StoreQueueSize, AssumeNoAlias);
- mca::BackendPrinter Printer(B);
+ // Create the hardware components required for the pipeline.
+ mca::RetireControlUnit RCU(SM);
+ mca::RegisterFile PRF(SM, *MRI, RegisterFileSize);
+ mca::Scheduler HWS(SM, LoadQueueSize, StoreQueueSize, AssumeNoAlias);
+
+ // Create the pipeline and add stages to it.
+ auto B = llvm::make_unique<mca::Backend>(
+ Width, RegisterFileSize, LoadQueueSize, StoreQueueSize, AssumeNoAlias);
+ B->appendStage(llvm::make_unique<mca::FetchStage>(IB, S));
+ B->appendStage(llvm::make_unique<mca::DispatchStage>(
+ B.get(), *STI, *MRI, RegisterFileSize, Width, RCU, PRF, HWS));
+ B->appendStage(llvm::make_unique<mca::RetireStage>(B.get(), RCU, PRF));
+ B->appendStage(llvm::make_unique<mca::ExecuteStage>(B.get(), RCU, HWS));
+ mca::BackendPrinter Printer(*B);
if (PrintSummaryView)
Printer.addView(llvm::make_unique<mca::SummaryView>(SM, S, Width));
@@ -533,7 +543,7 @@ int main(int argc, char **argv) {
*STI, *IP, S, TimelineMaxIterations, TimelineMaxCycles));
}
- B.run();
+ B->run();
Printer.printReport(TOF->os());
}
OpenPOWER on IntegriCloud