| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 1 | //===--------------------- Scheduler.cpp ------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // A scheduler for processor resource units and processor resource groups. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| Andrea Di Biagio | 51dba7d | 2018-03-23 17:36:07 +0000 | [diff] [blame] | 14 | #include "Scheduler.h" |
| Andrea Di Biagio | eec6b81 | 2018-06-26 10:44:12 +0000 | [diff] [blame] | 15 | #include "llvm/Support/Debug.h" |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 16 | #include "llvm/Support/raw_ostream.h" |
| 17 | |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 18 | namespace mca { |
| 19 | |
| 20 | using namespace llvm; |
| 21 | |
| Andrea Di Biagio | eec6b81 | 2018-06-26 10:44:12 +0000 | [diff] [blame] | 22 | #define DEBUG_TYPE "llvm-mca" |
| 23 | |
| Matt Davis | 0f70bc0 | 2018-08-23 18:42:37 +0000 | [diff] [blame] | 24 | void Scheduler::initializeStrategy(std::unique_ptr<SchedulerStrategy> S) { |
| 25 | // Ensure we have a valid (non-null) strategy object. |
| 26 | Strategy = S ? std::move(S) : llvm::make_unique<DefaultSchedulerStrategy>(); |
| 27 | } |
| 28 | |
| Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 29 | // Anchor the vtable of SchedulerStrategy and DefaultSchedulerStrategy. |
| 30 | SchedulerStrategy::~SchedulerStrategy() = default; |
| 31 | DefaultSchedulerStrategy::~DefaultSchedulerStrategy() = default; |
| 32 | |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 33 | #ifndef NDEBUG |
| 34 | void Scheduler::dump() const { |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 35 | dbgs() << "[SCHEDULER]: WaitSet size is: " << WaitSet.size() << '\n'; |
| 36 | dbgs() << "[SCHEDULER]: ReadySet size is: " << ReadySet.size() << '\n'; |
| 37 | dbgs() << "[SCHEDULER]: IssuedSet size is: " << IssuedSet.size() << '\n'; |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 38 | Resources->dump(); |
| 39 | } |
| 40 | #endif |
| 41 | |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 42 | Scheduler::Status Scheduler::isAvailable(const InstRef &IR) const { |
| Matt Davis | 21a8d32 | 2018-05-07 18:29:15 +0000 | [diff] [blame] | 43 | const InstrDesc &Desc = IR.getInstruction()->getDesc(); |
| Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 44 | |
| Andrea Di Biagio | 163419f | 2018-08-17 15:01:37 +0000 | [diff] [blame] | 45 | switch (Resources->canBeDispatched(Desc.Buffers)) { |
| 46 | case ResourceStateEvent::RS_BUFFER_UNAVAILABLE: |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 47 | return Scheduler::SC_BUFFERS_FULL; |
| Andrea Di Biagio | 163419f | 2018-08-17 15:01:37 +0000 | [diff] [blame] | 48 | case ResourceStateEvent::RS_RESERVED: |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 49 | return Scheduler::SC_DISPATCH_GROUP_STALL; |
| 50 | case ResourceStateEvent::RS_BUFFER_AVAILABLE: |
| Andrea Di Biagio | 163419f | 2018-08-17 15:01:37 +0000 | [diff] [blame] | 51 | break; |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 52 | } |
| Andrea Di Biagio | b24953b | 2018-04-11 18:05:23 +0000 | [diff] [blame] | 53 | |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 54 | // Give lower priority to LSUnit stall events. |
| 55 | switch (LSU->isAvailable(IR)) { |
| 56 | case LSUnit::LSU_LQUEUE_FULL: |
| 57 | return Scheduler::SC_LOAD_QUEUE_FULL; |
| 58 | case LSUnit::LSU_SQUEUE_FULL: |
| 59 | return Scheduler::SC_STORE_QUEUE_FULL; |
| 60 | case LSUnit::LSU_AVAILABLE: |
| 61 | return Scheduler::SC_AVAILABLE; |
| 62 | } |
| 63 | |
| 64 | llvm_unreachable("Don't know how to process this LSU state result!"); |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 65 | } |
| 66 | |
| Andrea Di Biagio | 27c4b09 | 2018-04-24 14:53:16 +0000 | [diff] [blame] | 67 | void Scheduler::issueInstructionImpl( |
| Matt Davis | 21a8d32 | 2018-05-07 18:29:15 +0000 | [diff] [blame] | 68 | InstRef &IR, |
| Andrea Di Biagio | 27c4b09 | 2018-04-24 14:53:16 +0000 | [diff] [blame] | 69 | SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources) { |
| Matt Davis | 21a8d32 | 2018-05-07 18:29:15 +0000 | [diff] [blame] | 70 | Instruction *IS = IR.getInstruction(); |
| 71 | const InstrDesc &D = IS->getDesc(); |
| Andrea Di Biagio | a3f2e48 | 2018-03-20 18:20:39 +0000 | [diff] [blame] | 72 | |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 73 | // Issue the instruction and collect all the consumed resources |
| 74 | // into a vector. That vector is then used to notify the listener. |
| Matt Davis | ad78e66 | 2018-04-26 22:30:40 +0000 | [diff] [blame] | 75 | Resources->issueInstruction(D, UsedResources); |
| Andrea Di Biagio | 27c4b09 | 2018-04-24 14:53:16 +0000 | [diff] [blame] | 76 | |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 77 | // Notify the instruction that it started executing. |
| 78 | // This updates the internal state of each write. |
| Matt Davis | 21a8d32 | 2018-05-07 18:29:15 +0000 | [diff] [blame] | 79 | IS->execute(); |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 80 | |
| Matt Davis | 21a8d32 | 2018-05-07 18:29:15 +0000 | [diff] [blame] | 81 | if (IS->isExecuting()) |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 82 | IssuedSet.emplace_back(IR); |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 83 | else if (IS->isExecuted()) |
| 84 | LSU->onInstructionExecuted(IR); |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 85 | } |
| 86 | |
| Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 87 | // Release the buffered resources and issue the instruction. |
| 88 | void Scheduler::issueInstruction( |
| Andrea Di Biagio | 4660fd2 | 2018-08-22 10:23:28 +0000 | [diff] [blame] | 89 | InstRef &IR, SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources, |
| Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 90 | SmallVectorImpl<InstRef> &ReadyInstructions) { |
| 91 | const Instruction &Inst = *IR.getInstruction(); |
| 92 | bool HasDependentUsers = Inst.hasDependentUsers(); |
| 93 | |
| 94 | Resources->releaseBuffers(Inst.getDesc().Buffers); |
| Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 95 | issueInstructionImpl(IR, UsedResources); |
| Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 96 | // Instructions that have been issued during this cycle might have unblocked |
| 97 | // other dependent instructions. Dependent instructions may be issued during |
| 98 | // this same cycle if operands have ReadAdvance entries. Promote those |
| 99 | // instructions to the ReadySet and notify the caller that those are ready. |
| 100 | if (HasDependentUsers) |
| 101 | promoteToReadySet(ReadyInstructions); |
| Andrea Di Biagio | 27c4b09 | 2018-04-24 14:53:16 +0000 | [diff] [blame] | 102 | } |
| 103 | |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 104 | void Scheduler::promoteToReadySet(SmallVectorImpl<InstRef> &Ready) { |
| Andrea Di Biagio | 0a837ef | 2018-03-29 14:26:56 +0000 | [diff] [blame] | 105 | // Scan the set of waiting instructions and promote them to the |
| 106 | // ready queue if operands are all ready. |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 107 | unsigned RemovedElements = 0; |
| Matt Davis | 06ac6af | 2018-08-17 18:06:01 +0000 | [diff] [blame] | 108 | for (auto I = WaitSet.begin(), E = WaitSet.end(); I != E;) { |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 109 | InstRef &IR = *I; |
| 110 | if (!IR.isValid()) |
| 111 | break; |
| Andrea Di Biagio | 0a837ef | 2018-03-29 14:26:56 +0000 | [diff] [blame] | 112 | |
| 113 | // Check if this instruction is now ready. In case, force |
| 114 | // a transition in state using method 'update()'. |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 115 | Instruction &IS = *IR.getInstruction(); |
| 116 | if (!IS.isReady()) |
| 117 | IS.update(); |
| Andrea Di Biagio | 0a837ef | 2018-03-29 14:26:56 +0000 | [diff] [blame] | 118 | |
| Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 119 | // Check if there are still unsolved data dependencies. |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 120 | if (!isReady(IR)) { |
| Andrea Di Biagio | 0a837ef | 2018-03-29 14:26:56 +0000 | [diff] [blame] | 121 | ++I; |
| Andrea Di Biagio | c752616 | 2018-04-13 15:19:07 +0000 | [diff] [blame] | 122 | continue; |
| Andrea Di Biagio | 0a837ef | 2018-03-29 14:26:56 +0000 | [diff] [blame] | 123 | } |
| Andrea Di Biagio | c752616 | 2018-04-13 15:19:07 +0000 | [diff] [blame] | 124 | |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 125 | Ready.emplace_back(IR); |
| 126 | ReadySet.emplace_back(IR); |
| 127 | |
| 128 | IR.invalidate(); |
| 129 | ++RemovedElements; |
| 130 | std::iter_swap(I, E - RemovedElements); |
| Andrea Di Biagio | 0a837ef | 2018-03-29 14:26:56 +0000 | [diff] [blame] | 131 | } |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 132 | |
| 133 | WaitSet.resize(WaitSet.size() - RemovedElements); |
| Andrea Di Biagio | 0a837ef | 2018-03-29 14:26:56 +0000 | [diff] [blame] | 134 | } |
| 135 | |
| Matt Davis | 21a8d32 | 2018-05-07 18:29:15 +0000 | [diff] [blame] | 136 | InstRef Scheduler::select() { |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 137 | unsigned QueueIndex = ReadySet.size(); |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 138 | for (unsigned I = 0, E = ReadySet.size(); I != E; ++I) { |
| 139 | const InstRef &IR = ReadySet[I]; |
| Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 140 | if (QueueIndex == ReadySet.size() || |
| 141 | Strategy->compare(IR, ReadySet[QueueIndex])) { |
| 142 | const InstrDesc &D = IR.getInstruction()->getDesc(); |
| 143 | if (Resources->canBeIssued(D)) |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 144 | QueueIndex = I; |
| Andrea Di Biagio | 61c52af | 2018-07-06 08:08:30 +0000 | [diff] [blame] | 145 | } |
| 146 | } |
| 147 | |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 148 | if (QueueIndex == ReadySet.size()) |
| 149 | return InstRef(); |
| 150 | |
| Andrea Di Biagio | 27c4b09 | 2018-04-24 14:53:16 +0000 | [diff] [blame] | 151 | // We found an instruction to issue. |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 152 | InstRef IR = ReadySet[QueueIndex]; |
| 153 | std::swap(ReadySet[QueueIndex], ReadySet[ReadySet.size() - 1]); |
| 154 | ReadySet.pop_back(); |
| Matt Davis | 21a8d32 | 2018-05-07 18:29:15 +0000 | [diff] [blame] | 155 | return IR; |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 156 | } |
| 157 | |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 158 | void Scheduler::updateIssuedSet(SmallVectorImpl<InstRef> &Executed) { |
| 159 | unsigned RemovedElements = 0; |
| Matt Davis | 06ac6af | 2018-08-17 18:06:01 +0000 | [diff] [blame] | 160 | for (auto I = IssuedSet.begin(), E = IssuedSet.end(); I != E;) { |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 161 | InstRef &IR = *I; |
| 162 | if (!IR.isValid()) |
| 163 | break; |
| 164 | Instruction &IS = *IR.getInstruction(); |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 165 | if (!IS.isExecuted()) { |
| 166 | LLVM_DEBUG(dbgs() << "[SCHEDULER]: Instruction #" << IR |
| Nicola Zaghen | d34e60c | 2018-05-14 12:53:11 +0000 | [diff] [blame] | 167 | << " is still executing.\n"); |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 168 | ++I; |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 169 | continue; |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 170 | } |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 171 | |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 172 | // Instruction IR has completed execution. |
| 173 | LSU->onInstructionExecuted(IR); |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 174 | Executed.emplace_back(IR); |
| 175 | ++RemovedElements; |
| 176 | IR.invalidate(); |
| 177 | std::iter_swap(I, E - RemovedElements); |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 178 | } |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 179 | |
| 180 | IssuedSet.resize(IssuedSet.size() - RemovedElements); |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 181 | } |
| 182 | |
| Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 183 | void Scheduler::cycleEvent(SmallVectorImpl<ResourceRef> &Freed, |
| 184 | SmallVectorImpl<InstRef> &Executed, |
| 185 | SmallVectorImpl<InstRef> &Ready) { |
| 186 | // Release consumed resources. |
| Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 187 | Resources->cycleEvent(Freed); |
| Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 188 | |
| 189 | // Propagate the cycle event to the 'Issued' and 'Wait' sets. |
| 190 | for (InstRef &IR : IssuedSet) |
| 191 | IR.getInstruction()->cycleEvent(); |
| 192 | |
| 193 | updateIssuedSet(Executed); |
| 194 | |
| 195 | for (InstRef &IR : WaitSet) |
| 196 | IR.getInstruction()->cycleEvent(); |
| Andrea Di Biagio | f3374f0 | 2018-08-21 18:20:16 +0000 | [diff] [blame] | 197 | |
| Andrea Di Biagio | 5184995 | 2018-08-21 12:40:15 +0000 | [diff] [blame] | 198 | promoteToReadySet(Ready); |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 199 | } |
| 200 | |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 201 | bool Scheduler::mustIssueImmediately(const InstRef &IR) const { |
| 202 | // Instructions that use an in-order dispatch/issue processor resource must be |
| 203 | // issued immediately to the pipeline(s). Any other in-order buffered |
| 204 | // resources (i.e. BufferSize=1) is consumed. |
| 205 | const InstrDesc &Desc = IR.getInstruction()->getDesc(); |
| 206 | return Desc.isZeroLatency() || Resources->mustIssueImmediately(Desc); |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 207 | } |
| Andrea Di Biagio | a3f2e48 | 2018-03-20 18:20:39 +0000 | [diff] [blame] | 208 | |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 209 | void Scheduler::dispatch(const InstRef &IR) { |
| Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 210 | const InstrDesc &Desc = IR.getInstruction()->getDesc(); |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 211 | Resources->reserveBuffers(Desc.Buffers); |
| 212 | |
| 213 | // If necessary, reserve queue entries in the load-store unit (LSU). |
| 214 | bool IsMemOp = Desc.MayLoad || Desc.MayStore; |
| 215 | if (IsMemOp) |
| 216 | LSU->dispatch(IR); |
| 217 | |
| 218 | if (!isReady(IR)) { |
| 219 | LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the WaitSet\n"); |
| 220 | WaitSet.push_back(IR); |
| 221 | return; |
| 222 | } |
| 223 | |
| 224 | // Don't add a zero-latency instruction to the Ready queue. |
| 225 | // A zero-latency instruction doesn't consume any scheduler resources. That is |
| 226 | // because it doesn't need to be executed, and it is often removed at register |
| 227 | // renaming stage. For example, register-register moves are often optimized at |
| 228 | // register renaming stage by simply updating register aliases. On some |
| 229 | // targets, zero-idiom instructions (for example: a xor that clears the value |
| 230 | // of a register) are treated specially, and are often eliminated at register |
| 231 | // renaming stage. |
| 232 | if (!mustIssueImmediately(IR)) { |
| Andrea Di Biagio | 1c3bcc6 | 2018-08-03 12:55:28 +0000 | [diff] [blame] | 233 | LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the ReadySet\n"); |
| 234 | ReadySet.push_back(IR); |
| Matt Davis | 488ac4c | 2018-06-14 01:20:18 +0000 | [diff] [blame] | 235 | } |
| Andrea Di Biagio | 0875e75 | 2018-08-20 14:41:36 +0000 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | bool Scheduler::isReady(const InstRef &IR) const { |
| 239 | const InstrDesc &Desc = IR.getInstruction()->getDesc(); |
| 240 | bool IsMemOp = Desc.MayLoad || Desc.MayStore; |
| 241 | return IR.getInstruction()->isReady() && (!IsMemOp || LSU->isReady(IR)); |
| Andrea Di Biagio | a3f2e48 | 2018-03-20 18:20:39 +0000 | [diff] [blame] | 242 | } |
| 243 | |
| Andrea Di Biagio | 3a6b092 | 2018-03-08 13:05:02 +0000 | [diff] [blame] | 244 | } // namespace mca |