// Each bit of the mask represents an unavailable resource.
uint64_t BusyResourceUnits;
+ // Counts the number of instructions dispatched during this cycle that are
+ // added to the pending set. This information is used by the bottleneck
+ // analysis when analyzing instructions in the pending set.
+ unsigned NumDispatchedToThePendingSet;
+
/// Verify the given selection strategy and set the Strategy member
/// accordingly. If no strategy is provided, the DefaultSchedulerStrategy is
/// used.
/// Returns true if instruction IR is ready to be issued to the underlying
/// pipelines. Note that this operation cannot fail; it assumes that a
/// previous call to method `isAvailable(IR)` returned `SC_AVAILABLE`.
- void dispatch(const InstRef &IR);
-
- /// Returns true if IR is ready to be executed by the underlying pipelines.
- /// This method assumes that IR has been previously dispatched.
- bool isReady(const InstRef &IR) const;
+ bool dispatch(const InstRef &IR);
/// Issue an instruction and populates a vector of used pipeline resources,
/// and a vector of instructions that transitioned to the ready state as a
// Returns true if this instruction is a candidate for move elimination.
bool isOptimizableMove() const { return IsOptimizableMove; }
void setOptimizableMove() { IsOptimizableMove = true; }
+ bool isMemOp() const { return Desc.MayLoad || Desc.MayStore; }
};
/// An instruction propagated through the simulated instruction pipeline.
// Retire Unit token ID for this instruction.
unsigned RCUTokenID;
+ uint64_t CriticalResourceMask;
+ unsigned CriticalMemDep;
+
public:
Instruction(const InstrDesc &D)
: InstructionBase(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES),
- RCUTokenID(0) {}
+ RCUTokenID(0), CriticalResourceMask(0), CriticalMemDep(0) {}
unsigned getRCUTokenID() const { return RCUTokenID; }
int getCyclesLeft() const { return CyclesLeft; }
Stage = IS_RETIRED;
}
+ void updateCriticalResourceMask(uint64_t BusyResourceUnits) {
+ CriticalResourceMask |= BusyResourceUnits;
+ }
+ uint64_t getCriticalResourceMask() const { return CriticalResourceMask; }
+ void setCriticalMemDep(unsigned IID) { CriticalMemDep = IID; }
+ unsigned getCriticalMemDep() const { return CriticalMemDep; }
+
void cycleEvent();
};
if (!IR)
break;
- // Check if this instruction is now ready. In case, force
- // a transition in state using method 'update()'.
+ // Check if there are still unsolved memory dependencies.
Instruction &IS = *IR.getInstruction();
- if (!IS.isReady())
- IS.updatePending();
+ if (IS.isMemOp()) {
+ unsigned CriticalMemDep = LSU.isReady(IR);
+ if (CriticalMemDep != IR.getSourceIndex()) {
+ IS.setCriticalMemDep(CriticalMemDep);
+ ++I;
+ continue;
+ }
+ }
- // Check if there are still unsolved data dependencies.
- if (!isReady(IR)) {
+ // Check if this instruction is now ready. In case, force
+ // a transition in state using method 'update()'.
+ if (!IS.isReady() && !IS.updatePending()) {
++I;
continue;
}
-
LLVM_DEBUG(dbgs() << "[SCHEDULER]: Instruction #" << IR
<< " promoted to the READY set.\n");
InstRef Scheduler::select() {
unsigned QueueIndex = ReadySet.size();
for (unsigned I = 0, E = ReadySet.size(); I != E; ++I) {
- const InstRef &IR = ReadySet[I];
+ InstRef &IR = ReadySet[I];
if (QueueIndex == ReadySet.size() ||
Strategy->compare(IR, ReadySet[QueueIndex])) {
const InstrDesc &D = IR.getInstruction()->getDesc();
uint64_t BusyResourceMask = Resources->checkAvailability(D);
+ IR.getInstruction()->updateCriticalResourceMask(BusyResourceMask);
BusyResourceUnits |= BusyResourceMask;
if (!BusyResourceMask)
QueueIndex = I;
// Release consumed resources.
Resources->cycleEvent(Freed);
- // Propagate the cycle event to the 'Issued' and 'Wait' sets.
for (InstRef &IR : IssuedSet)
IR.getInstruction()->cycleEvent();
-
updateIssuedSet(Executed);
for (InstRef &IR : PendingSet)
promoteToPendingSet();
promoteToReadySet(Ready);
+ NumDispatchedToThePendingSet = 0;
BusyResourceUnits = 0;
}
return Desc.MustIssueImmediately;
}
-void Scheduler::dispatch(const InstRef &IR) {
- const InstrDesc &Desc = IR.getInstruction()->getDesc();
+bool Scheduler::dispatch(const InstRef &IR) {
+ const Instruction &IS = *IR.getInstruction();
+ const InstrDesc &Desc = IS.getDesc();
Resources->reserveBuffers(Desc.Buffers);
// If necessary, reserve queue entries in the load-store unit (LSU).
- bool IsMemOp = Desc.MayLoad || Desc.MayStore;
- if (IsMemOp)
+ if (IS.isMemOp())
LSU.dispatch(IR);
- if (IR.getInstruction()->isPending()) {
+ if (IS.isPending()) {
LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR
<< " to the PendingSet\n");
PendingSet.push_back(IR);
- return;
+ ++NumDispatchedToThePendingSet;
+ return false;
}
- if (!isReady(IR)) {
+ if (!IS.isReady() ||
+ (IS.isMemOp() && LSU.isReady(IR) != IR.getSourceIndex())) {
LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the WaitSet\n");
WaitSet.push_back(IR);
- return;
+ return false;
}
// Don't add a zero-latency instruction to the Ready queue.
LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the ReadySet\n");
ReadySet.push_back(IR);
}
-}
-bool Scheduler::isReady(const InstRef &IR) const {
- const InstrDesc &Desc = IR.getInstruction()->getDesc();
- bool IsMemOp = Desc.MayLoad || Desc.MayStore;
- return IR.getInstruction()->isReady() &&
- (!IsMemOp || LSU.isReady(IR) == IR.getSourceIndex());
+ return true;
}
} // namespace mca