mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-20 19:42:54 +02:00
[llvm-mca] Small refactoring in preparation for another patch that will improve the modularity of the Pipeline. NFCI
The main difference is that now `cycleStart()` and `cycleEnd()` return an llvm::Error. This patch implements a few minor style changes, and adds missing 'const' to some methods. llvm-svn: 339885
This commit is contained in:
parent
64e945b7fb
commit
da0d5626a8
@ -33,7 +33,7 @@ void DispatchStage::notifyInstructionDispatched(const InstRef &IR,
|
|||||||
notifyEvent<HWInstructionEvent>(HWInstructionDispatchedEvent(IR, UsedRegs));
|
notifyEvent<HWInstructionEvent>(HWInstructionDispatchedEvent(IR, UsedRegs));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DispatchStage::checkPRF(const InstRef &IR) {
|
bool DispatchStage::checkPRF(const InstRef &IR) const {
|
||||||
SmallVector<unsigned, 4> RegDefs;
|
SmallVector<unsigned, 4> RegDefs;
|
||||||
for (const std::unique_ptr<WriteState> &RegDef :
|
for (const std::unique_ptr<WriteState> &RegDef :
|
||||||
IR.getInstruction()->getDefs())
|
IR.getInstruction()->getDefs())
|
||||||
@ -50,7 +50,7 @@ bool DispatchStage::checkPRF(const InstRef &IR) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DispatchStage::checkRCU(const InstRef &IR) {
|
bool DispatchStage::checkRCU(const InstRef &IR) const {
|
||||||
const unsigned NumMicroOps = IR.getInstruction()->getDesc().NumMicroOps;
|
const unsigned NumMicroOps = IR.getInstruction()->getDesc().NumMicroOps;
|
||||||
if (RCU.isAvailable(NumMicroOps))
|
if (RCU.isAvailable(NumMicroOps))
|
||||||
return true;
|
return true;
|
||||||
@ -59,7 +59,7 @@ bool DispatchStage::checkRCU(const InstRef &IR) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DispatchStage::checkScheduler(const InstRef &IR) {
|
bool DispatchStage::checkScheduler(const InstRef &IR) const {
|
||||||
HWStallEvent::GenericEventType Event;
|
HWStallEvent::GenericEventType Event;
|
||||||
const bool Ready = SC.canBeDispatched(IR, Event);
|
const bool Ready = SC.canBeDispatched(IR, Event);
|
||||||
if (!Ready)
|
if (!Ready)
|
||||||
@ -131,9 +131,10 @@ void DispatchStage::dispatch(InstRef IR) {
|
|||||||
notifyInstructionDispatched(IR, RegisterFiles);
|
notifyInstructionDispatched(IR, RegisterFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispatchStage::cycleStart() {
|
llvm::Error DispatchStage::cycleStart() {
|
||||||
AvailableEntries = CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver;
|
AvailableEntries = CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver;
|
||||||
CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U;
|
CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U;
|
||||||
|
return llvm::ErrorSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stage::Status DispatchStage::execute(InstRef &IR) {
|
Stage::Status DispatchStage::execute(InstRef &IR) {
|
||||||
|
@ -58,9 +58,9 @@ class DispatchStage final : public Stage {
|
|||||||
RegisterFile &PRF;
|
RegisterFile &PRF;
|
||||||
Scheduler &SC;
|
Scheduler &SC;
|
||||||
|
|
||||||
bool checkRCU(const InstRef &IR);
|
bool checkRCU(const InstRef &IR) const;
|
||||||
bool checkPRF(const InstRef &IR);
|
bool checkPRF(const InstRef &IR) const;
|
||||||
bool checkScheduler(const InstRef &IR);
|
bool checkScheduler(const InstRef &IR) const;
|
||||||
void dispatch(InstRef IR);
|
void dispatch(InstRef IR);
|
||||||
void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
|
void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ public:
|
|||||||
// The retire stage, which controls the RCU, might have items to complete but
|
// The retire stage, which controls the RCU, might have items to complete but
|
||||||
// RetireStage::hasWorkToComplete will check for that case.
|
// RetireStage::hasWorkToComplete will check for that case.
|
||||||
bool hasWorkToComplete() const override { return false; }
|
bool hasWorkToComplete() const override { return false; }
|
||||||
void cycleStart() override;
|
llvm::Error cycleStart() override;
|
||||||
Status execute(InstRef &IR) override;
|
Status execute(InstRef &IR) override;
|
||||||
void notifyDispatchStall(const InstRef &IR, unsigned EventType);
|
void notifyDispatchStall(const InstRef &IR, unsigned EventType);
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ void ExecuteStage::reclaimSchedulerResources() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the scheduler's instruction queues.
|
// Update the scheduler's instruction queues.
|
||||||
void ExecuteStage::updateSchedulerQueues() {
|
Error ExecuteStage::updateSchedulerQueues() {
|
||||||
SmallVector<InstRef, 4> InstructionIDs;
|
SmallVector<InstRef, 4> InstructionIDs;
|
||||||
HWS.updateIssuedSet(InstructionIDs);
|
HWS.updateIssuedSet(InstructionIDs);
|
||||||
for (const InstRef &IR : InstructionIDs)
|
for (const InstRef &IR : InstructionIDs)
|
||||||
@ -45,10 +45,11 @@ void ExecuteStage::updateSchedulerQueues() {
|
|||||||
HWS.updatePendingQueue(InstructionIDs);
|
HWS.updatePendingQueue(InstructionIDs);
|
||||||
for (const InstRef &IR : InstructionIDs)
|
for (const InstRef &IR : InstructionIDs)
|
||||||
notifyInstructionReady(IR);
|
notifyInstructionReady(IR);
|
||||||
|
return ErrorSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue instructions that are waiting in the scheduler's ready queue.
|
// Issue instructions that are waiting in the scheduler's ready queue.
|
||||||
void ExecuteStage::issueReadyInstructions() {
|
Error ExecuteStage::issueReadyInstructions() {
|
||||||
SmallVector<InstRef, 4> InstructionIDs;
|
SmallVector<InstRef, 4> InstructionIDs;
|
||||||
InstRef IR = HWS.select();
|
InstRef IR = HWS.select();
|
||||||
while (IR.isValid()) {
|
while (IR.isValid()) {
|
||||||
@ -75,6 +76,8 @@ void ExecuteStage::issueReadyInstructions() {
|
|||||||
// Select the next instruction to issue.
|
// Select the next instruction to issue.
|
||||||
IR = HWS.select();
|
IR = HWS.select();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ErrorSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following routine is the maintenance routine of the ExecuteStage.
|
// The following routine is the maintenance routine of the ExecuteStage.
|
||||||
@ -89,10 +92,11 @@ void ExecuteStage::issueReadyInstructions() {
|
|||||||
// Notifications are issued to this stage's listeners when instructions are
|
// Notifications are issued to this stage's listeners when instructions are
|
||||||
// moved between the HWS's queues. In particular, when an instruction becomes
|
// moved between the HWS's queues. In particular, when an instruction becomes
|
||||||
// ready or executed.
|
// ready or executed.
|
||||||
void ExecuteStage::cycleStart() {
|
Error ExecuteStage::cycleStart() {
|
||||||
reclaimSchedulerResources();
|
reclaimSchedulerResources();
|
||||||
updateSchedulerQueues();
|
if (Error S = updateSchedulerQueues())
|
||||||
issueReadyInstructions();
|
return S;
|
||||||
|
return issueReadyInstructions();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule the instruction for execution on the hardware.
|
// Schedule the instruction for execution on the hardware.
|
||||||
|
@ -33,8 +33,8 @@ class ExecuteStage final : public Stage {
|
|||||||
|
|
||||||
// The following routines are used to maintain the HWS.
|
// The following routines are used to maintain the HWS.
|
||||||
void reclaimSchedulerResources();
|
void reclaimSchedulerResources();
|
||||||
void updateSchedulerQueues();
|
llvm::Error updateSchedulerQueues();
|
||||||
void issueReadyInstructions();
|
llvm::Error issueReadyInstructions();
|
||||||
|
|
||||||
ExecuteStage(const ExecuteStage &Other) = delete;
|
ExecuteStage(const ExecuteStage &Other) = delete;
|
||||||
ExecuteStage &operator=(const ExecuteStage &Other) = delete;
|
ExecuteStage &operator=(const ExecuteStage &Other) = delete;
|
||||||
@ -42,11 +42,15 @@ class ExecuteStage final : public Stage {
|
|||||||
public:
|
public:
|
||||||
ExecuteStage(RetireControlUnit &R, Scheduler &S) : Stage(), RCU(R), HWS(S) {}
|
ExecuteStage(RetireControlUnit &R, Scheduler &S) : Stage(), RCU(R), HWS(S) {}
|
||||||
|
|
||||||
// The ExecuteStage will always complete all of its work per call to
|
// This stage works under the assumption that the Pipeline will eventually
|
||||||
// execute(), so it is never left in a 'to-be-processed' state.
|
// execute a retire stage. We don't need to check if pipelines and/or
|
||||||
|
// schedulers have instructions to process, because those instructions are
|
||||||
|
// also tracked by the retire control unit. That means,
|
||||||
|
// RetireControlUnit::hasWorkToComplete() is responsible for checking if there
|
||||||
|
// are still instructions in-flight in the out-of-order backend.
|
||||||
bool hasWorkToComplete() const override { return false; }
|
bool hasWorkToComplete() const override { return false; }
|
||||||
|
|
||||||
void cycleStart() override;
|
llvm::Error cycleStart() override;
|
||||||
Status execute(InstRef &IR) override;
|
Status execute(InstRef &IR) override;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -35,7 +35,7 @@ Stage::Status FetchStage::execute(InstRef &IR) {
|
|||||||
|
|
||||||
void FetchStage::postExecute() { SM.updateNext(); }
|
void FetchStage::postExecute() { SM.updateNext(); }
|
||||||
|
|
||||||
void FetchStage::cycleEnd() {
|
llvm::Error FetchStage::cycleEnd() {
|
||||||
// Find the first instruction which hasn't been retired.
|
// Find the first instruction which hasn't been retired.
|
||||||
const InstMap::iterator It =
|
const InstMap::iterator It =
|
||||||
llvm::find_if(Instructions, [](const InstMap::value_type &KeyValuePair) {
|
llvm::find_if(Instructions, [](const InstMap::value_type &KeyValuePair) {
|
||||||
@ -45,6 +45,8 @@ void FetchStage::cycleEnd() {
|
|||||||
// Erase instructions up to the first that hasn't been retired.
|
// Erase instructions up to the first that hasn't been retired.
|
||||||
if (It != Instructions.begin())
|
if (It != Instructions.begin())
|
||||||
Instructions.erase(Instructions.begin(), It);
|
Instructions.erase(Instructions.begin(), It);
|
||||||
|
|
||||||
|
return llvm::ErrorSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mca
|
} // namespace mca
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
bool hasWorkToComplete() const override;
|
bool hasWorkToComplete() const override;
|
||||||
Status execute(InstRef &IR) override;
|
Status execute(InstRef &IR) override;
|
||||||
void postExecute() override;
|
void postExecute() override;
|
||||||
void cycleEnd() override;
|
llvm::Error cycleEnd() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mca
|
} // namespace mca
|
||||||
|
@ -32,10 +32,9 @@ void Pipeline::addEventListener(HWEventListener *Listener) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Pipeline::hasWorkToProcess() {
|
bool Pipeline::hasWorkToProcess() {
|
||||||
const auto It = llvm::find_if(Stages, [](const std::unique_ptr<Stage> &S) {
|
return llvm::any_of(Stages, [](const std::unique_ptr<Stage> &S) {
|
||||||
return S->hasWorkToComplete();
|
return S->hasWorkToComplete();
|
||||||
});
|
});
|
||||||
return It != Stages.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This routine returns early if any stage returns 'false' after execute() is
|
// This routine returns early if any stage returns 'false' after execute() is
|
||||||
@ -62,6 +61,8 @@ void Pipeline::postExecuteStages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
llvm::Error Pipeline::run() {
|
llvm::Error Pipeline::run() {
|
||||||
|
assert(!Stages.empty() && "Unexpected empty pipeline found!");
|
||||||
|
|
||||||
while (hasWorkToProcess()) {
|
while (hasWorkToProcess()) {
|
||||||
notifyCycleBegin();
|
notifyCycleBegin();
|
||||||
if (llvm::Error Err = runCycle())
|
if (llvm::Error Err = runCycle())
|
||||||
@ -73,13 +74,18 @@ llvm::Error Pipeline::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
llvm::Error Pipeline::runCycle() {
|
llvm::Error Pipeline::runCycle() {
|
||||||
// Update the stages before we do any processing for this cycle.
|
// Update stages before we start processing new instructions.
|
||||||
InstRef IR;
|
llvm::Error Err = llvm::ErrorSuccess();
|
||||||
for (auto &S : Stages)
|
for (auto I = Stages.begin(), E = Stages.end(); I != E && !Err; ++I) {
|
||||||
S->cycleStart();
|
const std::unique_ptr<Stage> &S = *I;
|
||||||
|
Err = S->cycleStart();
|
||||||
|
}
|
||||||
|
|
||||||
// Continue executing this cycle until any stage claims it cannot make
|
if (Err)
|
||||||
// progress.
|
return Err;
|
||||||
|
|
||||||
|
// Now fetch and execute new instructions.
|
||||||
|
InstRef IR;
|
||||||
while (true) {
|
while (true) {
|
||||||
preExecuteStages();
|
preExecuteStages();
|
||||||
Stage::Status Val = executeStages(IR);
|
Stage::Status Val = executeStages(IR);
|
||||||
@ -90,9 +96,12 @@ llvm::Error Pipeline::runCycle() {
|
|||||||
postExecuteStages();
|
postExecuteStages();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &S : Stages)
|
// Update stages in preparation for a new cycle.
|
||||||
S->cycleEnd();
|
for (auto I = Stages.begin(), E = Stages.end(); I != E && !Err; ++I) {
|
||||||
return llvm::ErrorSuccess();
|
const std::unique_ptr<Stage> &S = *I;
|
||||||
|
Err = S->cycleEnd();
|
||||||
|
}
|
||||||
|
return Err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pipeline::notifyCycleBegin() {
|
void Pipeline::notifyCycleBegin() {
|
||||||
|
@ -18,15 +18,13 @@
|
|||||||
#include "HWEventListener.h"
|
#include "HWEventListener.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
#define DEBUG_TYPE "llvm-mca"
|
#define DEBUG_TYPE "llvm-mca"
|
||||||
|
|
||||||
namespace mca {
|
namespace mca {
|
||||||
|
|
||||||
void RetireStage::cycleStart() {
|
llvm::Error RetireStage::cycleStart() {
|
||||||
if (RCU.isEmpty())
|
if (RCU.isEmpty())
|
||||||
return;
|
return llvm::ErrorSuccess();
|
||||||
|
|
||||||
const unsigned MaxRetirePerCycle = RCU.getMaxRetirePerCycle();
|
const unsigned MaxRetirePerCycle = RCU.getMaxRetirePerCycle();
|
||||||
unsigned NumRetired = 0;
|
unsigned NumRetired = 0;
|
||||||
@ -40,11 +38,13 @@ void RetireStage::cycleStart() {
|
|||||||
notifyInstructionRetired(Current.IR);
|
notifyInstructionRetired(Current.IR);
|
||||||
NumRetired++;
|
NumRetired++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return llvm::ErrorSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RetireStage::notifyInstructionRetired(const InstRef &IR) {
|
void RetireStage::notifyInstructionRetired(const InstRef &IR) {
|
||||||
LLVM_DEBUG(dbgs() << "[E] Instruction Retired: #" << IR << '\n');
|
LLVM_DEBUG(llvm::dbgs() << "[E] Instruction Retired: #" << IR << '\n');
|
||||||
SmallVector<unsigned, 4> FreedRegs(PRF.getNumRegisterFiles());
|
llvm::SmallVector<unsigned, 4> FreedRegs(PRF.getNumRegisterFiles());
|
||||||
const Instruction &Inst = *IR.getInstruction();
|
const Instruction &Inst = *IR.getInstruction();
|
||||||
const InstrDesc &Desc = Inst.getDesc();
|
const InstrDesc &Desc = Inst.getDesc();
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ public:
|
|||||||
: Stage(), RCU(R), PRF(F) {}
|
: Stage(), RCU(R), PRF(F) {}
|
||||||
|
|
||||||
bool hasWorkToComplete() const override { return !RCU.isEmpty(); }
|
bool hasWorkToComplete() const override { return !RCU.isEmpty(); }
|
||||||
void cycleStart() override;
|
llvm::Error cycleStart() override;
|
||||||
Status execute(InstRef &IR) override { return Stage::Continue; }
|
Status execute(InstRef &IR) override { return Stage::Continue; }
|
||||||
void notifyInstructionRetired(const InstRef &IR);
|
void notifyInstructionRetired(const InstRef &IR);
|
||||||
void onInstructionExecuted(unsigned TokenID);
|
void onInstructionExecuted(unsigned TokenID);
|
||||||
|
@ -44,6 +44,7 @@ public:
|
|||||||
void updateNext() { Current++; }
|
void updateNext() { Current++; }
|
||||||
|
|
||||||
const SourceRef peekNext() const {
|
const SourceRef peekNext() const {
|
||||||
|
assert(hasNext() && "Already at end of sequence!");
|
||||||
unsigned Index = getCurrentInstructionIndex();
|
unsigned Index = getCurrentInstructionIndex();
|
||||||
return SourceRef(Current, Sequence[Index].get());
|
return SourceRef(Current, Sequence[Index].get());
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
namespace mca {
|
namespace mca {
|
||||||
|
|
||||||
// Pin the vtable here in the implementation file.
|
// Pin the vtable here in the implementation file.
|
||||||
Stage::Stage() {}
|
Stage::~Stage() = default;
|
||||||
|
|
||||||
void Stage::addListener(HWEventListener *Listener) {
|
void Stage::addListener(HWEventListener *Listener) {
|
||||||
Listeners.insert(Listener);
|
Listeners.insert(Listener);
|
||||||
|
@ -25,9 +25,10 @@ namespace mca {
|
|||||||
class InstRef;
|
class InstRef;
|
||||||
|
|
||||||
class Stage {
|
class Stage {
|
||||||
|
std::set<HWEventListener *> Listeners;
|
||||||
|
|
||||||
Stage(const Stage &Other) = delete;
|
Stage(const Stage &Other) = delete;
|
||||||
Stage &operator=(const Stage &Other) = delete;
|
Stage &operator=(const Stage &Other) = delete;
|
||||||
std::set<HWEventListener *> Listeners;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// A Stage's execute() returns Continue, Stop, or an error. Returning
|
/// A Stage's execute() returns Continue, Stop, or an error. Returning
|
||||||
@ -46,8 +47,8 @@ protected:
|
|||||||
const std::set<HWEventListener *> &getListeners() const { return Listeners; }
|
const std::set<HWEventListener *> &getListeners() const { return Listeners; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Stage();
|
Stage() {}
|
||||||
virtual ~Stage() = default;
|
virtual ~Stage();
|
||||||
|
|
||||||
/// Called prior to preExecute to ensure that the stage has items that it
|
/// Called prior to preExecute to ensure that the stage has items that it
|
||||||
/// is to process. For example, a FetchStage might have more instructions
|
/// is to process. For example, a FetchStage might have more instructions
|
||||||
@ -57,10 +58,10 @@ public:
|
|||||||
|
|
||||||
/// Called once at the start of each cycle. This can be used as a setup
|
/// Called once at the start of each cycle. This can be used as a setup
|
||||||
/// phase to prepare for the executions during the cycle.
|
/// phase to prepare for the executions during the cycle.
|
||||||
virtual void cycleStart() {}
|
virtual llvm::Error cycleStart() { return llvm::ErrorSuccess(); }
|
||||||
|
|
||||||
/// Called once at the end of each cycle.
|
/// Called once at the end of each cycle.
|
||||||
virtual void cycleEnd() {}
|
virtual llvm::Error cycleEnd() { return llvm::ErrorSuccess(); }
|
||||||
|
|
||||||
/// Called prior to executing the list of stages.
|
/// Called prior to executing the list of stages.
|
||||||
/// This can be called multiple times per cycle.
|
/// This can be called multiple times per cycle.
|
||||||
@ -80,7 +81,7 @@ public:
|
|||||||
void addListener(HWEventListener *Listener);
|
void addListener(HWEventListener *Listener);
|
||||||
|
|
||||||
/// Notify listeners of a particular hardware event.
|
/// Notify listeners of a particular hardware event.
|
||||||
template <typename EventT> void notifyEvent(const EventT &Event) {
|
template <typename EventT> void notifyEvent(const EventT &Event) const {
|
||||||
for (HWEventListener *Listener : Listeners)
|
for (HWEventListener *Listener : Listeners)
|
||||||
Listener->onEvent(Event);
|
Listener->onEvent(Event);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user