Index: tools/llvm-mca/DispatchStage.h =================================================================== --- tools/llvm-mca/DispatchStage.h +++ tools/llvm-mca/DispatchStage.h @@ -94,7 +94,7 @@ // 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 void cycleStart(unsigned Cycle) override final; virtual bool execute(InstRef &IR) override final; void notifyDispatchStall(const InstRef &IR, unsigned EventType); Index: tools/llvm-mca/DispatchStage.cpp =================================================================== --- tools/llvm-mca/DispatchStage.cpp +++ tools/llvm-mca/DispatchStage.cpp @@ -132,7 +132,7 @@ notifyInstructionDispatched(IR, RegisterFiles); } -void DispatchStage::preExecute(const InstRef &IR) { +void DispatchStage::cycleStart(unsigned Cycle) { AvailableEntries = CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver; CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U; } Index: tools/llvm-mca/ExecuteStage.h =================================================================== --- tools/llvm-mca/ExecuteStage.h +++ tools/llvm-mca/ExecuteStage.h @@ -45,7 +45,7 @@ // 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 void cycleStart(unsigned Cycle) override final; virtual bool execute(InstRef &IR) override final; void Index: tools/llvm-mca/ExecuteStage.cpp =================================================================== --- tools/llvm-mca/ExecuteStage.cpp +++ tools/llvm-mca/ExecuteStage.cpp @@ -89,7 +89,7 @@ // 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::preExecute(const InstRef &Unused) { +void ExecuteStage::cycleStart(unsigned Cycle) { reclaimSchedulerResources(); updateSchedulerQueues(); issueReadyInstructions(); Index: tools/llvm-mca/FetchStage.h =================================================================== --- tools/llvm-mca/FetchStage.h +++ tools/llvm-mca/FetchStage.h @@ -29,14 +29,21 @@ InstrBuilder &IB; SourceMgr &SM; + // The number of times Fetch::execute has been called for this cycle. + // Multiple fetches can occur during a single cycle, and this is used to know + // when to retrieve the next instruction from the SourceManager. + unsigned CurrentCycleCounter; + public: - FetchStage(InstrBuilder &IB, SourceMgr &SM) : IB(IB), SM(SM) {} + FetchStage(InstrBuilder &IB, SourceMgr &SM) + : IB(IB), SM(SM), CurrentCycleCounter(~0U) {} FetchStage(const FetchStage &Other) = delete; FetchStage &operator=(const FetchStage &Other) = delete; bool hasWorkToComplete() const override final; bool execute(InstRef &IR) override final; - void postExecute(const InstRef &IR) override final; + void cycleStart(unsigned Cycle) override final; + void cycleEnd(unsigned Cycle) override final; }; } // namespace mca Index: tools/llvm-mca/FetchStage.cpp =================================================================== --- tools/llvm-mca/FetchStage.cpp +++ tools/llvm-mca/FetchStage.cpp @@ -19,7 +19,12 @@ bool FetchStage::hasWorkToComplete() const { return SM.hasNext(); } +void FetchStage::cycleStart(unsigned Cycle) { CurrentCycleCounter = 0; } + bool FetchStage::execute(InstRef &IR) { + if (CurrentCycleCounter > 0) + SM.updateNext(); + ++CurrentCycleCounter; if (!SM.hasNext()) return false; const SourceRef SR = SM.peekNext(); @@ -29,7 +34,7 @@ return true; } -void FetchStage::postExecute(const InstRef &IR) { +void FetchStage::cycleEnd(unsigned Cycle) { // Find the first instruction which hasn't been retired. const InstMap::iterator It = llvm::find_if(Instructions, [](const InstMap::value_type &KeyValuePair) { @@ -37,7 +42,6 @@ }); if (It != Instructions.begin()) Instructions.erase(Instructions.begin(), It); - SM.updateNext(); } } // namespace mca Index: tools/llvm-mca/Pipeline.h =================================================================== --- tools/llvm-mca/Pipeline.h +++ tools/llvm-mca/Pipeline.h @@ -60,7 +60,6 @@ unsigned Cycles; bool executeStages(InstRef &IR); - void postExecuteStages(const InstRef &IR); bool hasWorkToProcess(); void runCycle(unsigned Cycle); Index: tools/llvm-mca/Pipeline.cpp =================================================================== --- tools/llvm-mca/Pipeline.cpp +++ tools/llvm-mca/Pipeline.cpp @@ -47,11 +47,6 @@ return true; } -void Pipeline::postExecuteStages(const InstRef &IR) { - for (const std::unique_ptr &S : Stages) - S->postExecute(IR); -} - void Pipeline::run() { while (hasWorkToProcess()) runCycle(Cycles++); @@ -63,12 +58,16 @@ // Update the stages before we do any processing for this cycle. InstRef IR; for (auto &S : Stages) - S->preExecute(IR); + S->cycleStart(Cycle); // Continue executing this cycle until any stage claims it cannot make // progress. - while (executeStages(IR)) - postExecuteStages(IR); + while (true) + if (!executeStages(IR)) + break; + + for (auto &S : Stages) + S->cycleEnd(Cycle); notifyCycleEnd(Cycle); } Index: tools/llvm-mca/RetireStage.h =================================================================== --- tools/llvm-mca/RetireStage.h +++ tools/llvm-mca/RetireStage.h @@ -37,7 +37,7 @@ virtual bool hasWorkToComplete() const override final { return !RCU.isEmpty(); } - virtual void preExecute(const InstRef &IR) override final; + virtual void cycleStart(unsigned Cycle) override final; virtual bool execute(InstRef &IR) override final { return true; } void notifyInstructionRetired(const InstRef &IR); void onInstructionExecuted(unsigned TokenID); Index: tools/llvm-mca/RetireStage.cpp =================================================================== --- tools/llvm-mca/RetireStage.cpp +++ tools/llvm-mca/RetireStage.cpp @@ -24,7 +24,7 @@ namespace mca { -void RetireStage::preExecute(const InstRef &IR) { +void RetireStage::cycleStart(unsigned Cycle) { if (RCU.isEmpty()) return; Index: tools/llvm-mca/Stage.h =================================================================== --- tools/llvm-mca/Stage.h +++ tools/llvm-mca/Stage.h @@ -41,15 +41,16 @@ /// retire. virtual bool hasWorkToComplete() const = 0; - /// Called as a setup phase to prepare for the main stage execution. - virtual void preExecute(const InstRef &IR) {} + /// 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(unsigned Cycle) {} - /// Called as a cleanup and finalization phase after main stage execution. - virtual void postExecute(const InstRef &IR) {} + /// Called once at the end of each cycle. + virtual void cycleEnd(unsigned Cycle) {} /// The primary action that this stage performs. /// Returning false prevents successor stages from having their 'execute' - /// routine called. + /// routine called. This can be called multiple times during a single cycle. virtual bool execute(InstRef &IR) = 0; /// Add a listener to receive callbacks during the execution of this stage.