Index: llvm/trunk/tools/llvm-mca/Backend.h =================================================================== --- llvm/trunk/tools/llvm-mca/Backend.h +++ llvm/trunk/tools/llvm-mca/Backend.h @@ -16,9 +16,9 @@ #define LLVM_TOOLS_LLVM_MCA_BACKEND_H #include "Dispatch.h" +#include "FetchStage.h" #include "InstrBuilder.h" #include "Scheduler.h" -#include "SourceMgr.h" namespace mca { @@ -29,61 +29,60 @@ /// An out of order backend for a specific subtarget. /// /// It emulates an out-of-order execution of instructions. Instructions are -/// fetched from a MCInst sequence managed by an object of class SourceMgr. -/// Instructions are firstly dispatched to the schedulers and then executed. +/// fetched from a MCInst sequence managed by an initial 'Fetch' stage. +/// Instructions are firstly fetched, then dispatched to the schedulers, and +/// then executed. +/// /// This class tracks the lifetime of an instruction from the moment where /// it gets dispatched to the schedulers, to the moment where it finishes /// executing and register writes are architecturally committed. /// In particular, it monitors changes in the state of every instruction /// in flight. +/// /// Instructions are executed in a loop of iterations. The number of iterations -/// is defined by the SourceMgr object. -/// The Backend entrypoint is method 'Run()' which execute cycles in a loop +/// is defined by the SourceMgr object, which is managed by the initial stage +/// of the instruction pipeline. +/// +/// The Backend entry point is method 'run()' which executes cycles in a loop /// until there are new instructions to dispatch, and not every instruction /// has been retired. +/// /// Internally, the Backend collects statistical information in the form of /// histograms. For example, it tracks how the dispatch group size changes /// over time. class Backend { const llvm::MCSubtargetInfo &STI; - InstrBuilder &IB; + /// This is the initial stage of the pipeline. + /// TODO: Eventually this will become a list of unique Stage* that this + /// backend pipeline executes. + std::unique_ptr Fetch; + std::unique_ptr HWS; std::unique_ptr DU; - SourceMgr &SM; - unsigned Cycles; - - llvm::DenseMap> Instructions; std::set Listeners; + unsigned Cycles; void runCycle(unsigned Cycle); public: Backend(const llvm::MCSubtargetInfo &Subtarget, - const llvm::MCRegisterInfo &MRI, InstrBuilder &B, SourceMgr &Source, - unsigned DispatchWidth = 0, unsigned RegisterFileSize = 0, - unsigned LoadQueueSize = 0, unsigned StoreQueueSize = 0, - bool AssumeNoAlias = false) - : STI(Subtarget), IB(B), + const llvm::MCRegisterInfo &MRI, + std::unique_ptr InitialStage, unsigned DispatchWidth = 0, + unsigned RegisterFileSize = 0, unsigned LoadQueueSize = 0, + unsigned StoreQueueSize = 0, bool AssumeNoAlias = false) + : STI(Subtarget), Fetch(std::move(InitialStage)), HWS(llvm::make_unique(this, Subtarget.getSchedModel(), LoadQueueSize, StoreQueueSize, AssumeNoAlias)), DU(llvm::make_unique(this, Subtarget.getSchedModel(), MRI, RegisterFileSize, DispatchWidth, HWS.get())), - SM(Source), Cycles(0) { + Cycles(0) { HWS->setDispatchUnit(DU.get()); } - void run() { - while (SM.hasNext() || !DU->isRCUEmpty()) - runCycle(Cycles++); - } - - void eraseInstruction(const InstRef &IR) { - Instructions.erase(IR.getSourceIndex()); - } - + void run(); void addEventListener(HWEventListener *Listener); void notifyCycleBegin(unsigned Cycle); void notifyInstructionEvent(const HWInstructionEvent &Event); Index: llvm/trunk/tools/llvm-mca/Backend.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/Backend.cpp +++ llvm/trunk/tools/llvm-mca/Backend.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "Backend.h" +#include "FetchStage.h" #include "HWEventListener.h" #include "llvm/CodeGen/TargetSchedule.h" #include "llvm/Support/Debug.h" @@ -28,20 +29,21 @@ Listeners.insert(Listener); } +void Backend::run() { + while (Fetch->isReady() || !DU->isRCUEmpty()) + runCycle(Cycles++); +} + void Backend::runCycle(unsigned Cycle) { notifyCycleBegin(Cycle); - while (SM.hasNext()) { - SourceRef SR = SM.peekNext(); - std::unique_ptr NewIS = IB.createInstruction(*SR.second); - const InstrDesc &Desc = NewIS->getDesc(); - Instruction *IS = NewIS.get(); - InstRef IR(SR.first, IS); + InstRef IR; + while (Fetch->execute(IR)) { + const InstrDesc &Desc = IR.getInstruction()->getDesc(); if (!DU->isAvailable(Desc.NumMicroOps) || !DU->canDispatch(IR)) break; - Instructions[SR.first] = std::move(NewIS); DU->dispatch(IR, STI); - SM.updateNext(); + Fetch->postExecute(IR); } notifyCycleEnd(Cycle); Index: llvm/trunk/tools/llvm-mca/CMakeLists.txt =================================================================== --- llvm/trunk/tools/llvm-mca/CMakeLists.txt +++ llvm/trunk/tools/llvm-mca/CMakeLists.txt @@ -15,6 +15,7 @@ CodeRegion.cpp Dispatch.cpp DispatchStatistics.cpp + FetchStage.cpp HWEventListener.cpp InstrBuilder.cpp Instruction.cpp @@ -28,6 +29,7 @@ RetireControlUnitStatistics.cpp Scheduler.cpp SchedulerStatistics.cpp + Stage.cpp Support.cpp SummaryView.cpp TimelineView.cpp Index: llvm/trunk/tools/llvm-mca/Dispatch.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/Dispatch.cpp +++ llvm/trunk/tools/llvm-mca/Dispatch.cpp @@ -146,9 +146,9 @@ RegisterMappings[*I].first = &WS; } -void RegisterFile::removeRegisterWrite( - const WriteState &WS, MutableArrayRef FreedPhysRegs, - bool ShouldFreePhysRegs) { +void RegisterFile::removeRegisterWrite(const WriteState &WS, + MutableArrayRef FreedPhysRegs, + bool ShouldFreePhysRegs) { unsigned RegID = WS.getRegisterID(); bool ShouldInvalidateSuperRegs = WS.fullyUpdatesSuperRegs(); @@ -273,7 +273,6 @@ for (const std::unique_ptr &WS : IR.getInstruction()->getDefs()) RAT->removeRegisterWrite(*WS.get(), FreedRegs, !Desc.isZeroLatency()); Owner->notifyInstructionEvent(HWInstructionRetiredEvent(IR, FreedRegs)); - Owner->eraseInstruction(IR); } bool DispatchUnit::checkRAT(const InstRef &IR) { Index: llvm/trunk/tools/llvm-mca/FetchStage.h =================================================================== --- llvm/trunk/tools/llvm-mca/FetchStage.h +++ llvm/trunk/tools/llvm-mca/FetchStage.h @@ -0,0 +1,47 @@ +//===---------------------- FetchStage.h ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the Fetch stage of an instruction pipeline. Its sole +/// purpose in life is to produce instructions for the rest of the pipeline. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_MCA_FETCH_STAGE_H +#define LLVM_TOOLS_LLVM_MCA_FETCH_STAGE_H + +#include "InstrBuilder.h" +#include "Instruction.h" +#include "SourceMgr.h" +#include "Stage.h" +#include "llvm/ADT/DenseMap.h" + +namespace mca { + +class FetchStage : public Stage { + using InstMap = llvm::DenseMap>; + using InstMapPr = + llvm::detail::DenseMapPair>; + InstMap Instructions; + InstrBuilder &IB; + SourceMgr &SM; + +public: + FetchStage(InstrBuilder &IB, SourceMgr &SM) : IB(IB), SM(SM) {} + FetchStage(const FetchStage &Other) = delete; + FetchStage &operator=(const FetchStage &Other) = delete; + + bool isReady() override final; + bool execute(InstRef &IR) override final; + void postExecute(const InstRef &IR) override final; +}; + +} // namespace mca + +#endif // LLVM_TOOLS_LLVM_MCA_FETCH_STAGE_H Index: llvm/trunk/tools/llvm-mca/FetchStage.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/FetchStage.cpp +++ llvm/trunk/tools/llvm-mca/FetchStage.cpp @@ -0,0 +1,38 @@ +//===---------------------- FetchStage.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the Fetch stage of an instruction pipeline. Its sole +/// purpose in life is to produce instructions for the rest of the pipeline. +/// +//===----------------------------------------------------------------------===// + +#include "FetchStage.h" +#include "Instruction.h" + +using namespace mca; + +bool FetchStage::isReady() { return SM.hasNext(); } + +bool FetchStage::execute(InstRef &IR) { + if (!SM.hasNext()) + return false; + const SourceRef SR = SM.peekNext(); + std::unique_ptr I = IB.createInstruction(*SR.second); + IR = InstRef(SR.first, I.get()); + Instructions[IR.getSourceIndex()] = std::move(I); + return true; +} + +void FetchStage::postExecute(const InstRef &IR) { + // Reclaim instructions that have been retired. + llvm::remove_if(Instructions, + [](InstMapPr &Pr) { return Pr.getSecond()->isRetired(); }); + SM.updateNext(); +} Index: llvm/trunk/tools/llvm-mca/Instruction.h =================================================================== --- llvm/trunk/tools/llvm-mca/Instruction.h +++ llvm/trunk/tools/llvm-mca/Instruction.h @@ -347,6 +347,7 @@ bool isReady() const { return Stage == IS_READY; } bool isExecuting() const { return Stage == IS_EXECUTING; } bool isExecuted() const { return Stage == IS_EXECUTED; } + bool isRetired() const { return Stage == IS_RETIRED; } void retire() { assert(isExecuted() && "Instruction is in an invalid state!"); Index: llvm/trunk/tools/llvm-mca/Stage.h =================================================================== --- llvm/trunk/tools/llvm-mca/Stage.h +++ llvm/trunk/tools/llvm-mca/Stage.h @@ -0,0 +1,55 @@ +//===---------------------- Stage.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines a stage. +/// A chain of stages compose an instruction pipeline. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_MCA_STAGE_H +#define LLVM_TOOLS_LLVM_MCA_STAGE_H + +#include "HWEventListener.h" +#include "Instruction.h" +#include "SourceMgr.h" +#include +#include + +namespace mca { + +class Stage { + std::set Listeners; + Stage(const Stage &Other) = delete; + Stage &operator=(const Stage &Other) = delete; + +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() { return true; } + + /// Called as a setup phase to prepare for the main stage execution. + virtual void preExecute(const InstRef &IR) {} + + /// Called as a cleanup and finalization phase after main stage execution. + virtual void postExecute(const InstRef &IR) {} + + /// The primary action that this stage performs. + virtual bool execute(InstRef &IR) = 0; + + /// Add a listener to receive callbaks during the execution of this stage. + void addListener(HWEventListener *Listener); +}; + +} // namespace mca +#endif // LLVM_TOOLS_LLVM_MCA_STAGE_H Index: llvm/trunk/tools/llvm-mca/Stage.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/Stage.cpp +++ llvm/trunk/tools/llvm-mca/Stage.cpp @@ -0,0 +1,28 @@ +//===---------------------- Stage.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines a stage. +/// A chain of stages compose an instruction pipeline. +/// +//===----------------------------------------------------------------------===// + +#include "Stage.h" +#include "llvm/Support/ErrorHandling.h" + +namespace mca { + +// Pin the vtable here in the implementation file. +Stage::Stage() {} + +void Stage::addListener(HWEventListener *Listener) { + llvm::llvm_unreachable_internal("Stage-based eventing is not implemented."); +} + +} // namespace mca Index: llvm/trunk/tools/llvm-mca/llvm-mca.cpp =================================================================== --- llvm/trunk/tools/llvm-mca/llvm-mca.cpp +++ llvm/trunk/tools/llvm-mca/llvm-mca.cpp @@ -24,6 +24,7 @@ #include "BackendPrinter.h" #include "CodeRegion.h" #include "DispatchStatistics.h" +#include "FetchStage.h" #include "InstructionInfoView.h" #include "InstructionTables.h" #include "RegisterFileStatistics.h" @@ -435,8 +436,13 @@ continue; } - mca::Backend B(*STI, *MRI, IB, S, Width, RegisterFileSize, LoadQueueSize, - StoreQueueSize, AssumeNoAlias); + // 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 Fetch = + llvm::make_unique(IB, S); + mca::Backend B(*STI, *MRI, std::move(Fetch), Width, RegisterFileSize, + LoadQueueSize, StoreQueueSize, AssumeNoAlias); mca::BackendPrinter Printer(B); Printer.addView(llvm::make_unique(S, Width));