[llvm] r369010 - [MCA] Slightly refactor class RetireControlUnit, and add the ability to override the mask of used buffered resources in class mca::Instruction. NFCI
Andrea Di Biagio via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 15 08:27:40 PDT 2019
Author: adibiagio
Date: Thu Aug 15 08:27:40 2019
New Revision: 369010
URL: http://llvm.org/viewvc/llvm-project?rev=369010&view=rev
Log:
[MCA] Slightly refactor class RetireControlUnit, and add the ability to override the mask of used buffered resources in class mca::Instruction. NFCI
This patch teaches the RCU how to peek 'next' RCUTokens. A new method has been
added to the RetireControlUnit class with the goal of minimizing the complexity
of follow-up patches that will enable macro-fusion support in mca.
This patch also adds method Instruction::getNumMicroOpcodes() to simplify common
interactions with the instruction descriptor (a pattern quite common in some
pipeline stages).
Added the ability to override the default set of consumed scheduler resources
(this -again- is to simplify future patches that add support for macro-op fusion).
No functional change intended.
Modified:
llvm/trunk/include/llvm/MCA/HardwareUnits/RetireControlUnit.h
llvm/trunk/include/llvm/MCA/Instruction.h
llvm/trunk/lib/MCA/HardwareUnits/RetireControlUnit.cpp
llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp
llvm/trunk/lib/MCA/Stages/DispatchStage.cpp
llvm/trunk/lib/MCA/Stages/ExecuteStage.cpp
llvm/trunk/lib/MCA/Stages/RetireStage.cpp
Modified: llvm/trunk/include/llvm/MCA/HardwareUnits/RetireControlUnit.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MCA/HardwareUnits/RetireControlUnit.h?rev=369010&r1=369009&r2=369010&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MCA/HardwareUnits/RetireControlUnit.h (original)
+++ llvm/trunk/include/llvm/MCA/HardwareUnits/RetireControlUnit.h Thu Aug 15 08:27:40 2019
@@ -57,34 +57,43 @@ struct RetireControlUnit : public Hardwa
private:
unsigned NextAvailableSlotIdx;
unsigned CurrentInstructionSlotIdx;
- unsigned AvailableSlots;
+ unsigned NumROBEntries;
+ unsigned AvailableEntries;
unsigned MaxRetirePerCycle; // 0 means no limit.
std::vector<RUToken> Queue;
-public:
- RetireControlUnit(const MCSchedModel &SM);
-
- bool isEmpty() const { return AvailableSlots == Queue.size(); }
- bool isAvailable(unsigned Quantity = 1) const {
+ unsigned normalizeQuantity(unsigned Quantity) const {
// Some instructions may declare a number of uOps which exceeds the size
// of the reorder buffer. To avoid problems, cap the amount of slots to
// the size of the reorder buffer.
- Quantity = std::min(Quantity, static_cast<unsigned>(Queue.size()));
+ Quantity = std::min(Quantity, NumROBEntries);
// Further normalize the number of micro opcodes for instructions that
// declare zero opcodes. This should match the behavior of method
// reserveSlot().
- Quantity = std::max(Quantity, 1U);
- return AvailableSlots >= Quantity;
+ return std::max(Quantity, 1U);
+ }
+
+ unsigned computeNextSlotIdx() const;
+
+public:
+ RetireControlUnit(const MCSchedModel &SM);
+
+ bool isEmpty() const { return AvailableEntries == NumROBEntries; }
+
+ bool isAvailable(unsigned Quantity = 1) const {
+ return AvailableEntries >= normalizeQuantity(Quantity);
}
unsigned getMaxRetirePerCycle() const { return MaxRetirePerCycle; }
- // Reserves a number of slots, and returns a new token.
- unsigned reserveSlot(const InstRef &IS, unsigned NumMicroOps);
+ // Reserves a number of slots, and returns a new token reference.
+ unsigned dispatch(const InstRef &IS);
// Return the current token from the RCU's circular token queue.
- const RUToken &peekCurrentToken() const;
+ const RUToken &getCurrentToken() const;
+
+ const RUToken &peekNextToken() const;
// Advance the pointer to the next token in the circular token queue.
void consumeCurrentToken();
Modified: llvm/trunk/include/llvm/MCA/Instruction.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MCA/Instruction.h?rev=369010&r1=369009&r2=369010&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MCA/Instruction.h (original)
+++ llvm/trunk/include/llvm/MCA/Instruction.h Thu Aug 15 08:27:40 2019
@@ -417,6 +417,7 @@ public:
const InstrDesc &getDesc() const { return Desc; }
unsigned getLatency() const { return Desc.MaxLatency; }
+ unsigned getNumMicroOps() const { return Desc.NumMicroOps; }
bool hasDependentUsers() const {
return any_of(Defs,
@@ -466,6 +467,12 @@ class Instruction : public InstructionBa
// operation.
unsigned LSUTokenID;
+ // A resource mask which identifies buffered resources consumed by this
+ // instruction at dispatch stage. In the absence of macro-fusion, this value
+ // should always match the value of field `UsedBuffers` from the instruction
+ // descriptor (see field InstrBase::Desc).
+ uint64_t UsedBuffers;
+
// Critical register dependency.
CriticalDependency CriticalRegDep;
@@ -483,12 +490,18 @@ class Instruction : public InstructionBa
public:
Instruction(const InstrDesc &D)
: InstructionBase(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES),
- RCUTokenID(0), LSUTokenID(0), CriticalRegDep(), CriticalMemDep(),
- CriticalResourceMask(0), IsEliminated(false) {}
+ RCUTokenID(0), LSUTokenID(0), UsedBuffers(D.UsedBuffers),
+ CriticalRegDep(), CriticalMemDep(), CriticalResourceMask(0),
+ IsEliminated(false) {}
unsigned getRCUTokenID() const { return RCUTokenID; }
unsigned getLSUTokenID() const { return LSUTokenID; }
void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; }
+
+ uint64_t getUsedBuffers() const { return UsedBuffers; }
+ void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; }
+ void clearUsedBuffers() { UsedBuffers = 0ULL; }
+
int getCyclesLeft() const { return CyclesLeft; }
// Transition to the dispatch stage, and assign a RCUToken to this
Modified: llvm/trunk/lib/MCA/HardwareUnits/RetireControlUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MCA/HardwareUnits/RetireControlUnit.cpp?rev=369010&r1=369009&r2=369010&view=diff
==============================================================================
--- llvm/trunk/lib/MCA/HardwareUnits/RetireControlUnit.cpp (original)
+++ llvm/trunk/lib/MCA/HardwareUnits/RetireControlUnit.cpp Thu Aug 15 08:27:40 2019
@@ -21,65 +21,78 @@ namespace mca {
RetireControlUnit::RetireControlUnit(const MCSchedModel &SM)
: NextAvailableSlotIdx(0), CurrentInstructionSlotIdx(0),
- AvailableSlots(SM.MicroOpBufferSize), MaxRetirePerCycle(0) {
+ NumROBEntries(SM.MicroOpBufferSize),
+ AvailableEntries(SM.MicroOpBufferSize), MaxRetirePerCycle(0) {
// Check if the scheduling model provides extra information about the machine
// processor. If so, then use that information to set the reorder buffer size
// and the maximum number of instructions retired per cycle.
if (SM.hasExtraProcessorInfo()) {
const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
if (EPI.ReorderBufferSize)
- AvailableSlots = EPI.ReorderBufferSize;
+ AvailableEntries = EPI.ReorderBufferSize;
MaxRetirePerCycle = EPI.MaxRetirePerCycle;
}
-
- assert(AvailableSlots && "Invalid reorder buffer size!");
- Queue.resize(AvailableSlots);
+ NumROBEntries = AvailableEntries;
+ assert(NumROBEntries && "Invalid reorder buffer size!");
+ Queue.resize(2 * NumROBEntries);
}
// Reserves a number of slots, and returns a new token.
-unsigned RetireControlUnit::reserveSlot(const InstRef &IR,
- unsigned NumMicroOps) {
- assert(isAvailable(NumMicroOps) && "Reorder Buffer unavailable!");
- unsigned NormalizedQuantity =
- std::min(NumMicroOps, static_cast<unsigned>(Queue.size()));
- // Zero latency instructions may have zero uOps. Artificially bump this
- // value to 1. Although zero latency instructions don't consume scheduler
- // resources, they still consume one slot in the retire queue.
- NormalizedQuantity = std::max(NormalizedQuantity, 1U);
+unsigned RetireControlUnit::dispatch(const InstRef &IR) {
+ const Instruction &Inst = *IR.getInstruction();
+ unsigned Entries = normalizeQuantity(Inst.getNumMicroOps());
+ assert((AvailableEntries >= Entries) && "Reorder Buffer unavailable!");
+
unsigned TokenID = NextAvailableSlotIdx;
- Queue[NextAvailableSlotIdx] = {IR, NormalizedQuantity, false};
- NextAvailableSlotIdx += NormalizedQuantity;
+ Queue[NextAvailableSlotIdx] = {IR, Entries, false};
+ NextAvailableSlotIdx += std::max(1U, Entries);
NextAvailableSlotIdx %= Queue.size();
- AvailableSlots -= NormalizedQuantity;
+
+ AvailableEntries -= Entries;
return TokenID;
}
-const RetireControlUnit::RUToken &RetireControlUnit::peekCurrentToken() const {
- return Queue[CurrentInstructionSlotIdx];
+const RetireControlUnit::RUToken &RetireControlUnit::getCurrentToken() const {
+ const RetireControlUnit::RUToken &Current = Queue[CurrentInstructionSlotIdx];
+#ifndef NDEBUG
+ const Instruction *Inst = Current.IR.getInstruction();
+ assert(Inst && "Invalid RUToken in the RCU queue.");
+#endif
+ return Current;
+}
+
+unsigned RetireControlUnit::computeNextSlotIdx() const {
+ const RetireControlUnit::RUToken &Current = getCurrentToken();
+ unsigned NextSlotIdx = CurrentInstructionSlotIdx + std::max(1U, Current.NumSlots);
+ return NextSlotIdx % Queue.size();
+}
+
+const RetireControlUnit::RUToken &RetireControlUnit::peekNextToken() const {
+ return Queue[computeNextSlotIdx()];
}
void RetireControlUnit::consumeCurrentToken() {
RetireControlUnit::RUToken &Current = Queue[CurrentInstructionSlotIdx];
- assert(Current.NumSlots && "Reserved zero slots?");
- assert(Current.IR && "Invalid RUToken in the RCU queue.");
Current.IR.getInstruction()->retire();
// Update the slot index to be the next item in the circular queue.
- CurrentInstructionSlotIdx += Current.NumSlots;
+ CurrentInstructionSlotIdx += std::max(1U, Current.NumSlots);
CurrentInstructionSlotIdx %= Queue.size();
- AvailableSlots += Current.NumSlots;
+ AvailableEntries += Current.NumSlots;
+ Current = { InstRef(), 0U, false };
}
void RetireControlUnit::onInstructionExecuted(unsigned TokenID) {
assert(Queue.size() > TokenID);
- assert(Queue[TokenID].Executed == false && Queue[TokenID].IR);
+ assert(Queue[TokenID].IR.getInstruction() && "Instruction was not dispatched!");
+ assert(Queue[TokenID].Executed == false && "Instruction already executed!");
Queue[TokenID].Executed = true;
}
#ifndef NDEBUG
void RetireControlUnit::dump() const {
- dbgs() << "Retire Unit: { Total Slots=" << Queue.size()
- << ", Available Slots=" << AvailableSlots << " }\n";
+ dbgs() << "Retire Unit: { Total ROB Entries =" << NumROBEntries
+ << ", Available ROB entries=" << AvailableEntries << " }\n";
}
#endif
Modified: llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp?rev=369010&r1=369009&r2=369010&view=diff
==============================================================================
--- llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp (original)
+++ llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp Thu Aug 15 08:27:40 2019
@@ -38,9 +38,8 @@ void Scheduler::dump() const {
#endif
Scheduler::Status Scheduler::isAvailable(const InstRef &IR) {
- const InstrDesc &Desc = IR.getInstruction()->getDesc();
-
- ResourceStateEvent RSE = Resources->canBeDispatched(Desc.UsedBuffers);
+ ResourceStateEvent RSE =
+ Resources->canBeDispatched(IR.getInstruction()->getUsedBuffers());
HadTokenStall = RSE != RS_BUFFER_AVAILABLE;
switch (RSE) {
@@ -106,7 +105,7 @@ void Scheduler::issueInstruction(
bool HasDependentUsers = Inst.hasDependentUsers();
HasDependentUsers |= Inst.isMemOp() && LSU.hasDependentUsers(IR);
- Resources->releaseBuffers(Inst.getDesc().UsedBuffers);
+ Resources->releaseBuffers(Inst.getUsedBuffers());
issueInstructionImpl(IR, UsedResources);
// Instructions that have been issued during this cycle might have unblocked
// other dependent instructions. Dependent instructions may be issued during
@@ -300,8 +299,7 @@ bool Scheduler::mustIssueImmediately(con
bool Scheduler::dispatch(InstRef &IR) {
Instruction &IS = *IR.getInstruction();
- const InstrDesc &Desc = IS.getDesc();
- Resources->reserveBuffers(Desc.UsedBuffers);
+ Resources->reserveBuffers(IS.getUsedBuffers());
// If necessary, reserve queue entries in the load-store unit (LSU).
if (IS.isMemOp())
Modified: llvm/trunk/lib/MCA/Stages/DispatchStage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MCA/Stages/DispatchStage.cpp?rev=369010&r1=369009&r2=369010&view=diff
==============================================================================
--- llvm/trunk/lib/MCA/Stages/DispatchStage.cpp (original)
+++ llvm/trunk/lib/MCA/Stages/DispatchStage.cpp Thu Aug 15 08:27:40 2019
@@ -60,7 +60,7 @@ bool DispatchStage::checkPRF(const InstR
}
bool DispatchStage::checkRCU(const InstRef &IR) const {
- const unsigned NumMicroOps = IR.getInstruction()->getDesc().NumMicroOps;
+ const unsigned NumMicroOps = IR.getInstruction()->getNumMicroOps();
if (RCU.isAvailable(NumMicroOps))
return true;
notifyEvent<HWStallEvent>(
@@ -79,7 +79,7 @@ Error DispatchStage::dispatch(InstRef IR
assert(!CarryOver && "Cannot dispatch another instruction!");
Instruction &IS = *IR.getInstruction();
const InstrDesc &Desc = IS.getDesc();
- const unsigned NumMicroOps = Desc.NumMicroOps;
+ const unsigned NumMicroOps = IS.getNumMicroOps();
if (NumMicroOps > DispatchWidth) {
assert(AvailableEntries == DispatchWidth);
AvailableEntries = 0;
@@ -123,9 +123,10 @@ Error DispatchStage::dispatch(InstRef IR
for (WriteState &WS : IS.getDefs())
PRF.addRegisterWrite(WriteRef(IR.getSourceIndex(), &WS), RegisterFiles);
- // Reserve slots in the RCU, and notify the instruction that it has been
- // dispatched to the schedulers for execution.
- IS.dispatch(RCU.reserveSlot(IR, NumMicroOps));
+ // Reserve entries in the reorder buffer.
+ unsigned RCUTokenID = RCU.dispatch(IR);
+ // Notify the instruction that it has been dispatched.
+ IS.dispatch(RCUTokenID);
// Notify listeners of the "instruction dispatched" event,
// and move IR to the next stage.
@@ -155,8 +156,10 @@ Error DispatchStage::cycleStart() {
}
bool DispatchStage::isAvailable(const InstRef &IR) const {
- const InstrDesc &Desc = IR.getInstruction()->getDesc();
- unsigned Required = std::min(Desc.NumMicroOps, DispatchWidth);
+ const Instruction &Inst = *IR.getInstruction();
+ unsigned NumMicroOps = Inst.getNumMicroOps();
+ const InstrDesc &Desc = Inst.getDesc();
+ unsigned Required = std::min(NumMicroOps, DispatchWidth);
if (Required > AvailableEntries)
return false;
Modified: llvm/trunk/lib/MCA/Stages/ExecuteStage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MCA/Stages/ExecuteStage.cpp?rev=369010&r1=369009&r2=369010&view=diff
==============================================================================
--- llvm/trunk/lib/MCA/Stages/ExecuteStage.cpp (original)
+++ llvm/trunk/lib/MCA/Stages/ExecuteStage.cpp Thu Aug 15 08:27:40 2019
@@ -56,12 +56,13 @@ Error ExecuteStage::issueInstruction(Ins
SmallVector<InstRef, 4> Ready;
HWS.issueInstruction(IR, Used, Pending, Ready);
- NumIssuedOpcodes += IR.getInstruction()->getDesc().NumMicroOps;
+ Instruction &IS = *IR.getInstruction();
+ NumIssuedOpcodes += IS.getNumMicroOps();
notifyReservedOrReleasedBuffers(IR, /* Reserved */ false);
notifyInstructionIssued(IR, Used);
- if (IR.getInstruction()->isExecuted()) {
+ if (IS.isExecuted()) {
notifyInstructionExecuted(IR);
// FIXME: add a buffer of executed instructions.
if (Error S = moveToTheNextStage(IR))
@@ -199,7 +200,8 @@ Error ExecuteStage::execute(InstRef &IR)
// units have been consumed.
bool IsReadyInstruction = HWS.dispatch(IR);
const Instruction &Inst = *IR.getInstruction();
- NumDispatchedOpcodes += Inst.getDesc().NumMicroOps;
+ unsigned NumMicroOps = Inst.getNumMicroOps();
+ NumDispatchedOpcodes += NumMicroOps;
notifyReservedOrReleasedBuffers(IR, /* Reserved */ true);
if (!IsReadyInstruction) {
Modified: llvm/trunk/lib/MCA/Stages/RetireStage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MCA/Stages/RetireStage.cpp?rev=369010&r1=369009&r2=369010&view=diff
==============================================================================
--- llvm/trunk/lib/MCA/Stages/RetireStage.cpp (original)
+++ llvm/trunk/lib/MCA/Stages/RetireStage.cpp Thu Aug 15 08:27:40 2019
@@ -31,11 +31,11 @@ llvm::Error RetireStage::cycleStart() {
while (!RCU.isEmpty()) {
if (MaxRetirePerCycle != 0 && NumRetired == MaxRetirePerCycle)
break;
- const RetireControlUnit::RUToken &Current = RCU.peekCurrentToken();
+ const RetireControlUnit::RUToken &Current = RCU.getCurrentToken();
if (!Current.Executed)
break;
- RCU.consumeCurrentToken();
notifyInstructionRetired(Current.IR);
+ RCU.consumeCurrentToken();
NumRetired++;
}
More information about the llvm-commits
mailing list