Index: llvm/trunk/tools/llvm-mca/DispatchStage.h =================================================================== --- llvm/trunk/tools/llvm-mca/DispatchStage.h +++ llvm/trunk/tools/llvm-mca/DispatchStage.h @@ -93,7 +93,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() override final; virtual bool execute(InstRef &IR) override final; void notifyDispatchStall(const InstRef &IR, unsigned EventType); Index: llvm/trunk/tools/llvm-mca/DispatchStage.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/DispatchStage.cpp +++ llvm/trunk/tools/llvm-mca/DispatchStage.cpp @@ -129,7 +129,7 @@ notifyInstructionDispatched(IR, RegisterFiles); } -void DispatchStage::preExecute(const InstRef &IR) { +void DispatchStage::cycleStart() { AvailableEntries = CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver; CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U; } Index: llvm/trunk/tools/llvm-mca/ExecuteStage.h =================================================================== --- llvm/trunk/tools/llvm-mca/ExecuteStage.h +++ llvm/trunk/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() override final; virtual bool execute(InstRef &IR) override final; void Index: llvm/trunk/tools/llvm-mca/ExecuteStage.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/ExecuteStage.cpp +++ llvm/trunk/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() { reclaimSchedulerResources(); updateSchedulerQueues(); issueReadyInstructions(); Index: llvm/trunk/tools/llvm-mca/FetchStage.h =================================================================== --- llvm/trunk/tools/llvm-mca/FetchStage.h +++ llvm/trunk/tools/llvm-mca/FetchStage.h @@ -37,6 +37,7 @@ bool hasWorkToComplete() const override final; bool execute(InstRef &IR) override final; void postExecute(const InstRef &IR) override final; + void cycleEnd() override final; }; } // namespace mca Index: llvm/trunk/tools/llvm-mca/FetchStage.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/FetchStage.cpp +++ llvm/trunk/tools/llvm-mca/FetchStage.cpp @@ -29,15 +29,18 @@ return true; } -void FetchStage::postExecute(const InstRef &IR) { +void FetchStage::postExecute(const InstRef &IR) { SM.updateNext(); } + +void FetchStage::cycleEnd() { // Find the first instruction which hasn't been retired. const InstMap::iterator It = llvm::find_if(Instructions, [](const InstMap::value_type &KeyValuePair) { return !KeyValuePair.second->isRetired(); }); + + // Erase instructions up to the first that hasn't been retired. if (It != Instructions.begin()) Instructions.erase(Instructions.begin(), It); - SM.updateNext(); } } // namespace mca Index: llvm/trunk/tools/llvm-mca/Pipeline.h =================================================================== --- llvm/trunk/tools/llvm-mca/Pipeline.h +++ llvm/trunk/tools/llvm-mca/Pipeline.h @@ -59,6 +59,7 @@ std::set Listeners; unsigned Cycles; + void preExecuteStages(const InstRef &IR); bool executeStages(InstRef &IR); void postExecuteStages(const InstRef &IR); bool hasWorkToProcess(); Index: llvm/trunk/tools/llvm-mca/Pipeline.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/Pipeline.cpp +++ llvm/trunk/tools/llvm-mca/Pipeline.cpp @@ -47,6 +47,11 @@ return true; } +void Pipeline::preExecuteStages(const InstRef &IR) { + for (const std::unique_ptr &S : Stages) + S->preExecute(IR); +} + void Pipeline::postExecuteStages(const InstRef &IR) { for (const std::unique_ptr &S : Stages) S->postExecute(IR); @@ -63,12 +68,19 @@ // Update the stages before we do any processing for this cycle. InstRef IR; for (auto &S : Stages) - S->preExecute(IR); + S->cycleStart(); // Continue executing this cycle until any stage claims it cannot make // progress. - while (executeStages(IR)) + while (true) { + preExecuteStages(IR); + if (!executeStages(IR)) + break; postExecuteStages(IR); + } + + for (auto &S : Stages) + S->cycleEnd(); notifyCycleEnd(Cycle); } Index: llvm/trunk/tools/llvm-mca/RetireStage.h =================================================================== --- llvm/trunk/tools/llvm-mca/RetireStage.h +++ llvm/trunk/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() override final; virtual bool execute(InstRef &IR) override final { return true; } void notifyInstructionRetired(const InstRef &IR); void onInstructionExecuted(unsigned TokenID); Index: llvm/trunk/tools/llvm-mca/RetireStage.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/RetireStage.cpp +++ llvm/trunk/tools/llvm-mca/RetireStage.cpp @@ -24,7 +24,7 @@ namespace mca { -void RetireStage::preExecute(const InstRef &IR) { +void RetireStage::cycleStart() { if (RCU.isEmpty()) return; Index: llvm/trunk/tools/llvm-mca/Stage.h =================================================================== --- llvm/trunk/tools/llvm-mca/Stage.h +++ llvm/trunk/tools/llvm-mca/Stage.h @@ -41,15 +41,25 @@ /// retire. virtual bool hasWorkToComplete() const = 0; - /// Called as a setup phase to prepare for the main stage execution. + /// 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() {} + + /// Called once at the end of each cycle. + virtual void cycleEnd() {} + + /// Called prior to executing the list of stages. + /// This can be called multiple times per cycle. virtual void preExecute(const InstRef &IR) {} - /// Called as a cleanup and finalization phase after main stage execution. + /// Called as a cleanup and finalization phase after each execution. + /// This will only be called if all stages return a success from their + /// execute callback. This can be called multiple times per cycle. virtual void postExecute(const InstRef &IR) {} /// 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.