From ca3aa719e7322ac1b7cb6d04cdcd999eb652b95e Mon Sep 17 00:00:00 2001 From: andreroesti Date: Fri, 15 Nov 2024 17:24:14 -0800 Subject: [PATCH] add FetchDelay stage --- CMakeLists.txt | 5 +++ CustomStages/MCADFetchDelayStage.cpp | 53 ++++++++++++++++++++++++++++ CustomStages/MCADFetchDelayStage.h | 50 ++++++++++++++++++++++++++ MCAWorker.cpp | 8 +++++ plugins/binja-broker/Broker.cpp | 7 +++- 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 CustomStages/MCADFetchDelayStage.cpp create mode 100644 CustomStages/MCADFetchDelayStage.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d1184a..fcf0503 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,10 @@ set(_CUSTOMHW_SOURCE_FILES CustomHWUnits/MCADLSUnit.cpp ) +set(_CUSTOM_STAGES_SOURCE_FILES + CustomStages/MCADFetchDelayStage.cpp + ) + set(_BROKERS_SOURCE_FILES Brokers/BrokerPlugin.cpp Brokers/RawBytesBroker.cpp @@ -111,6 +115,7 @@ set(_SOURCE_FILES llvm-mcad.cpp ${_MCAVIEWS_SOURCE_FILES} ${_CUSTOMHW_SOURCE_FILES} + ${_CUSTOM_STAGES_SOURCE_FILES} ${_BROKERS_SOURCE_FILES} MCAWorker.cpp PipelinePrinter.cpp diff --git a/CustomStages/MCADFetchDelayStage.cpp b/CustomStages/MCADFetchDelayStage.cpp new file mode 100644 index 0000000..430c25f --- /dev/null +++ b/CustomStages/MCADFetchDelayStage.cpp @@ -0,0 +1,53 @@ +#include +#include "CustomStages/MCADFetchDelayStage.h" + +namespace llvm { +namespace mcad { + +struct MCADInstructionFetchedEvent {}; + +bool MCADFetchDelayStage::hasWorkToComplete() const { + return !instrQueue.empty(); +} + +bool MCADFetchDelayStage::isAvailable(const llvm::mca::InstRef &IR) const { + return checkNextStage(IR); +} + +llvm::Error MCADFetchDelayStage::forwardDueInstrs() { + while(!instrQueue.empty() && instrQueue.front().delayCyclesLeft == 0) { + llvm::mca::InstRef IR = instrQueue.front().IR; + if (llvm::Error Val = moveToTheNextStage(IR)) { + return Val; + } + instrQueue.pop_front(); + } + return llvm::ErrorSuccess(); +} + +llvm::Error MCADFetchDelayStage::execute(llvm::mca::InstRef &IR) { + notifyEvent(llvm::mca::HWInstructionEvent(llvm::mca::HWInstructionEvent::LastGenericEventType, IR)); + const llvm::mca::Instruction *I = IR.getInstruction(); + const llvm::mca::InstrDesc &ID = I->getDesc(); + const llvm::MCInstrDesc &MCID = MCII.get(I->getOpcode()); + bool immediatelyExecute = true; + unsigned delayCyclesLeft = 0; + if(MCID.isBranch()) { + // delayed, will have to wait + delayCyclesLeft = 100; + } + instrQueue.emplace_back(DelayedInstr { delayCyclesLeft, IR }); + // if the instruction is not delayed, execute it immediately (it will + // have a delayCyclesLeft of 0 and be at the top of the queue) + return forwardDueInstrs(); +} + +llvm::Error MCADFetchDelayStage::cycleStart() { + if(!instrQueue.empty()) { + instrQueue.front().delayCyclesLeft--; + } + return forwardDueInstrs(); +} + +} +} diff --git a/CustomStages/MCADFetchDelayStage.h b/CustomStages/MCADFetchDelayStage.h new file mode 100644 index 0000000..4b2d6ad --- /dev/null +++ b/CustomStages/MCADFetchDelayStage.h @@ -0,0 +1,50 @@ +// This class does not model a real hardware stage. It is used to block the +// pipeline for a number of cycles to prevent further instructions from being +// fetched. We use this to model the cost of branch mispredictions. + +#ifndef LLVM_MCAD_FETCH_DELAY_STAGE_H +#define LLVM_MCAD_FETCH_DELAY_STAGE_H + +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MCA/SourceMgr.h" +#include "llvm/MCA/Stages/Stage.h" + +#include +#include + +namespace llvm { +namespace mcad { + +class MCADFetchDelayStage : public llvm::mca::Stage { + + struct DelayedInstr { + unsigned delayCyclesLeft; + llvm::mca::InstRef IR; + }; + + const llvm::MCInstrInfo &MCII; + std::deque instrQueue = {}; + +public: + MCADFetchDelayStage(const llvm::MCInstrInfo &MCII) : MCII(MCII) {} + + bool hasWorkToComplete() const override; + bool isAvailable(const llvm::mca::InstRef &IR) const override; + llvm::Error execute(llvm::mca::InstRef &IR) override; + + //llvm::Error cycleStart() override; + llvm::Error cycleStart() override; + + llvm::Error forwardDueInstrs(); + + ///// Called after the pipeline is resumed from pausing state. + //virtual Error cycleResume() { return ErrorSuccess(); } + + ///// Called once at the end of each cycle. + +}; + +} +} + +#endif \ No newline at end of file diff --git a/MCAWorker.cpp b/MCAWorker.cpp index e07cc3f..40d97d9 100644 --- a/MCAWorker.cpp +++ b/MCAWorker.cpp @@ -37,6 +37,7 @@ #include #include "CustomHWUnits/MCADLSUnit.h" +#include "CustomStages/MCADFetchDelayStage.h" #include "MCAViews/SummaryView.h" #include "MCAViews/TimelineView.h" #include "MCAWorker.h" @@ -183,6 +184,7 @@ std::unique_ptr MCAWorker::createDefaultPipeline() { // Create the pipeline stages. auto Fetch = std::make_unique(SrcMgr); + auto FetchDelay = std::make_unique(MCII); auto Dispatch = std::make_unique(STI, MRI, MCAPO.DispatchWidth, *RCU, *PRF); auto Execute = @@ -198,6 +200,7 @@ std::unique_ptr MCAWorker::createDefaultPipeline() { // Build the pipeline. auto StagePipeline = std::make_unique(); StagePipeline->appendStage(std::move(Fetch)); + StagePipeline->appendStage(std::move(FetchDelay)); if (MCAPO.MicroOpQueueSize) StagePipeline->appendStage(std::make_unique( MCAPO.MicroOpQueueSize, MCAPO.DecodersThroughput)); @@ -224,6 +227,7 @@ std::unique_ptr MCAWorker::createInOrderPipeline() { // Create the pipeline stages. auto Entry = std::make_unique(SrcMgr); + auto FetchDelay = std::make_unique(MCII); auto InOrderIssue = std::make_unique(STI, *PRF, *CB, *LSU); auto StagePipeline = std::make_unique(); @@ -233,6 +237,7 @@ std::unique_ptr MCAWorker::createInOrderPipeline() { // Build the pipeline. StagePipeline->appendStage(std::move(Entry)); + StagePipeline->appendStage(std::move(FetchDelay)); StagePipeline->appendStage(std::move(InOrderIssue)); for (auto *listener : Listeners) { @@ -420,6 +425,9 @@ Error MCAWorker::run() { << " has Token " << MDTok << "\n"); NewInst->setIdentifier(MDTok); } + + // Add this instruction to be processed by the pipeline + // (Entry stage will consume from source manager.) SrcMgr.addInst(std::move(NewInst)); } } diff --git a/plugins/binja-broker/Broker.cpp b/plugins/binja-broker/Broker.cpp index 40e9b60..eb1c624 100644 --- a/plugins/binja-broker/Broker.cpp +++ b/plugins/binja-broker/Broker.cpp @@ -150,7 +150,12 @@ class RawListener : public mca::HWEventListener { } switch (Event.Type) { - case mca::HWInstructionEvent::GenericEventType::Ready: { + //case mca::HWInstructionEvent::GenericEventType::Dispatched: { + // We (ab-)use the LastGenericEventType in the FetchDelay stage to + // notify of an event whenever the instruction is fetch. This way, the + // cycle count in Binja shows the total instruction cycle count + // including the fetch and dispatch cost. + case mca::HWInstructionEvent::GenericEventType::LastGenericEventType : { BridgeRef.CountStore[index].CycleReady = CurrentCycle; } case mca::HWInstructionEvent::GenericEventType::Executed: {