summaryrefslogtreecommitdiffstats
path: root/llvm/tools
diff options
context:
space:
mode:
authorAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>2018-04-13 15:19:07 +0000
committerAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>2018-04-13 15:19:07 +0000
commitc752616f30417e277c372ebb32770f62c54b058e (patch)
tree74dfbe33cefedb04eddf1b503bfdf49b5efe0860 /llvm/tools
parent545a0c2fb0886f1c0140ef6cbd05ca0a1c8f800a (diff)
downloadbcm5719-llvm-c752616f30417e277c372ebb32770f62c54b058e.tar.gz
bcm5719-llvm-c752616f30417e277c372ebb32770f62c54b058e.zip
[llvm-mca] Ensure that instructions with a schedule read-advance are always issued in the right order.
Normally, the Scheduler prioritizes older instructions over younger instructions during the instruction issue stage. In one particular case where a dependent instruction had a schedule read-advance associated to one of the input operands, this rule was not correctly applied. This patch fixes the issue and adds a test to verify that we don't regress that particular case. llvm-svn: 330032
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/llvm-mca/Scheduler.cpp91
-rw-r--r--llvm/tools/llvm-mca/Scheduler.h13
2 files changed, 47 insertions, 57 deletions
diff --git a/llvm/tools/llvm-mca/Scheduler.cpp b/llvm/tools/llvm-mca/Scheduler.cpp
index 8f051380ba3..fa63f1b274e 100644
--- a/llvm/tools/llvm-mca/Scheduler.cpp
+++ b/llvm/tools/llvm-mca/Scheduler.cpp
@@ -277,7 +277,7 @@ void Scheduler::scheduleInstruction(unsigned Idx, Instruction &MCIS) {
if (Resources->mustIssueImmediately(Desc)) {
DEBUG(dbgs() << "[SCHEDULER] Instruction " << Idx
<< " issued immediately\n");
- return issueInstruction(MCIS, Idx);
+ return issueInstruction(Idx, MCIS);
}
DEBUG(dbgs() << "[SCHEDULER] Adding " << Idx << " to the Ready Queue\n");
@@ -293,10 +293,15 @@ void Scheduler::cycleEvent() {
updateIssuedQueue();
updatePendingQueue();
- bool InstructionsWerePromoted = false;
- do {
- InstructionsWerePromoted = issue();
- } while(InstructionsWerePromoted);
+
+ while (issue()) {
+ // Instructions that have been issued during this cycle might have unblocked
+ // other dependent instructions. Dependent instructions may be issued during
+ // this same cycle if operands have ReadAdvance entries. Promote those
+ // instructions to the ReadyQueue and tell to the caller that we need
+ // another round of 'issue()'.
+ promoteToReadyQueue();
+ }
}
#ifndef NDEBUG
@@ -317,7 +322,8 @@ bool Scheduler::canBeDispatched(unsigned Index, const InstrDesc &Desc) const {
Type = HWStallEvent::StoreQueueFull;
else {
switch (Resources->canBeDispatched(Desc.Buffers)) {
- default: return true;
+ default:
+ return true;
case ResourceStateEvent::RS_BUFFER_UNAVAILABLE:
Type = HWStallEvent::SchedulerQueueFull;
break;
@@ -330,7 +336,7 @@ bool Scheduler::canBeDispatched(unsigned Index, const InstrDesc &Desc) const {
return false;
}
-void Scheduler::issueInstruction(Instruction &IS, unsigned InstrIndex) {
+void Scheduler::issueInstruction(unsigned InstrIndex, Instruction &IS) {
const InstrDesc &D = IS.getDesc();
if (!D.Buffers.empty()) {
@@ -362,65 +368,51 @@ void Scheduler::issueInstruction(Instruction &IS, unsigned InstrIndex) {
notifyInstructionExecuted(InstrIndex);
}
-bool Scheduler::promoteToReadyQueue() {
+void Scheduler::promoteToReadyQueue() {
// Scan the set of waiting instructions and promote them to the
// ready queue if operands are all ready.
- bool InstructionsWerePromoted = false;
for (auto I = WaitQueue.begin(), E = WaitQueue.end(); I != E;) {
const QueueEntryTy &Entry = *I;
+ unsigned IID = Entry.first;
+ Instruction &Inst = *Entry.second;
// Check if this instruction is now ready. In case, force
// a transition in state using method 'update()'.
- Entry.second->update();
- bool IsReady = Entry.second->isReady();
+ Inst.update();
- const InstrDesc &Desc = Entry.second->getDesc();
+ const InstrDesc &Desc = Inst.getDesc();
bool IsMemOp = Desc.MayLoad || Desc.MayStore;
- if (IsReady && IsMemOp)
- IsReady &= LSU->isReady(Entry.first);
-
- if (IsReady) {
- notifyInstructionReady(Entry.first);
- ReadyQueue[Entry.first] = Entry.second;
- auto ToRemove = I;
- ++I;
- WaitQueue.erase(ToRemove);
- InstructionsWerePromoted = true;
- } else {
+ if (!Inst.isReady() || (IsMemOp && !LSU->isReady(IID))) {
++I;
+ continue;
}
+
+ notifyInstructionReady(IID);
+ ReadyQueue[IID] = &Inst;
+ auto ToRemove = I;
+ ++I;
+ WaitQueue.erase(ToRemove);
}
-
- return InstructionsWerePromoted;
}
-
bool Scheduler::issue() {
- std::vector<unsigned> ToRemove;
- for (const QueueEntryTy QueueEntry : ReadyQueue) {
- // Give priority to older instructions in ReadyQueue. The ready queue is
- // ordered by key, and therefore older instructions are visited first.
- Instruction &IS = *QueueEntry.second;
- const InstrDesc &D = IS.getDesc();
- if (!Resources->canBeIssued(D))
- continue;
- unsigned InstrIndex = QueueEntry.first;
- issueInstruction(IS, InstrIndex);
- ToRemove.emplace_back(InstrIndex);
- }
-
- if (ToRemove.empty())
+ // Give priority to older instructions in the ReadyQueue. Since the ready
+ // queue is ordered by key, this will always prioritize older instructions.
+ const auto It = std::find_if(ReadyQueue.begin(), ReadyQueue.end(),
+ [&](const QueueEntryTy &Entry) {
+ const Instruction &IS = *Entry.second;
+ const InstrDesc &D = IS.getDesc();
+ return Resources->canBeIssued(D);
+ });
+
+ if (It == ReadyQueue.end())
return false;
- for (const unsigned InstrIndex : ToRemove)
- ReadyQueue.erase(InstrIndex);
-
- // Instructions that have been issued during this cycle might have unblocked
- // other dependent instructions. Dependent instructions
- // may be issued during this same cycle if operands have ReadAdvance entries.
- // Promote those instructions to the ReadyQueue and tell to the caller that
- // we need another round of 'issue()'.
- return promoteToReadyQueue();
+ // We found an instruction. Issue it, and update the ready queue.
+ const QueueEntryTy &Entry = *It;
+ issueInstruction(Entry.first, *Entry.second);
+ ReadyQueue.erase(Entry.first);
+ return true;
}
void Scheduler::updatePendingQueue() {
@@ -428,7 +420,6 @@ void Scheduler::updatePendingQueue() {
// started.
for (QueueEntryTy Entry : WaitQueue)
Entry.second->cycleEvent();
-
promoteToReadyQueue();
}
diff --git a/llvm/tools/llvm-mca/Scheduler.h b/llvm/tools/llvm-mca/Scheduler.h
index f2732203c46..4bc8c23b8a6 100644
--- a/llvm/tools/llvm-mca/Scheduler.h
+++ b/llvm/tools/llvm-mca/Scheduler.h
@@ -430,17 +430,16 @@ class Scheduler {
// Notify the Backend that buffered resources were freed.
void notifyReleasedBuffers(llvm::ArrayRef<uint64_t> Buffers);
- /// Issue instructions from the ReadyQueue by giving priority to older
- /// instructions. This method returns true if at least one instruction has
- /// been promoted in the process from the WaitQueue to the ReadyQueue.
+ /// Issue the next instruction from the ReadyQueue. This method gives priority
+ /// to older instructions.
bool issue();
- /// Scans the WaitQueue in search of instructions that can be moved to
- /// the ReadyQueue.
- bool promoteToReadyQueue();
+ /// Move instructions from the WaitQueue to the ReadyQueue if input operands
+ /// are all available.
+ void promoteToReadyQueue();
/// Issue an instruction without updating the ready queue.
- void issueInstruction(Instruction &IS, unsigned InstrIndex);
+ void issueInstruction(unsigned Index, Instruction &IS);
void updatePendingQueue();
void updateIssuedQueue();
OpenPOWER on IntegriCloud