blob: da93c2c11c1f8c2f17ee2a6a92c2a8e8e7fb5b71 [file] [log] [blame]
Matt Davis6aa5dcd2018-05-01 23:04:01 +00001#include "Dispatch.h"
2#include "RetireControlUnit.h"
3#include "llvm/MC/MCSchedule.h"
4#include "llvm/Support/Debug.h"
5
6using namespace llvm;
7
8#define DEBUG_TYPE "llvm-mca"
9
10namespace mca {
11
12RetireControlUnit::RetireControlUnit(const llvm::MCSchedModel &SM,
13 DispatchUnit *DU)
14 : NextAvailableSlotIdx(0), CurrentInstructionSlotIdx(0),
15 AvailableSlots(SM.MicroOpBufferSize), MaxRetirePerCycle(0), Owner(DU) {
16 // Check if the scheduling model provides extra information about the machine
17 // processor. If so, then use that information to set the reorder buffer size
18 // and the maximum number of instructions retired per cycle.
19 if (SM.hasExtraProcessorInfo()) {
20 const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
21 if (EPI.ReorderBufferSize)
22 AvailableSlots = EPI.ReorderBufferSize;
23 MaxRetirePerCycle = EPI.MaxRetirePerCycle;
24 }
25
26 assert(AvailableSlots && "Invalid reorder buffer size!");
27 Queue.resize(AvailableSlots);
28}
29
30// Reserves a number of slots, and returns a new token.
Matt Davis21a8d322018-05-07 18:29:15 +000031unsigned RetireControlUnit::reserveSlot(const InstRef &IR, unsigned NumMicroOps) {
Matt Davis6aa5dcd2018-05-01 23:04:01 +000032 assert(isAvailable(NumMicroOps));
33 unsigned NormalizedQuantity =
34 std::min(NumMicroOps, static_cast<unsigned>(Queue.size()));
35 // Zero latency instructions may have zero mOps. Artificially bump this
36 // value to 1. Although zero latency instructions don't consume scheduler
37 // resources, they still consume one slot in the retire queue.
38 NormalizedQuantity = std::max(NormalizedQuantity, 1U);
39 unsigned TokenID = NextAvailableSlotIdx;
Matt Davis21a8d322018-05-07 18:29:15 +000040 Queue[NextAvailableSlotIdx] = {IR, NormalizedQuantity, false};
Matt Davis6aa5dcd2018-05-01 23:04:01 +000041 NextAvailableSlotIdx += NormalizedQuantity;
42 NextAvailableSlotIdx %= Queue.size();
43 AvailableSlots -= NormalizedQuantity;
44 return TokenID;
45}
46
47void RetireControlUnit::cycleEvent() {
48 if (isEmpty())
49 return;
50
51 unsigned NumRetired = 0;
52 while (!isEmpty()) {
53 if (MaxRetirePerCycle != 0 && NumRetired == MaxRetirePerCycle)
54 break;
55 RUToken &Current = Queue[CurrentInstructionSlotIdx];
56 assert(Current.NumSlots && "Reserved zero slots?");
Matt Davis21a8d322018-05-07 18:29:15 +000057 assert(Current.IR.isValid() && "Invalid RUToken in the RCU queue.");
Matt Davis6aa5dcd2018-05-01 23:04:01 +000058 if (!Current.Executed)
59 break;
Matt Davis21a8d322018-05-07 18:29:15 +000060 Owner->notifyInstructionRetired(Current.IR);
Matt Davis6aa5dcd2018-05-01 23:04:01 +000061 CurrentInstructionSlotIdx += Current.NumSlots;
62 CurrentInstructionSlotIdx %= Queue.size();
63 AvailableSlots += Current.NumSlots;
64 NumRetired++;
65 }
66}
67
68void RetireControlUnit::onInstructionExecuted(unsigned TokenID) {
69 assert(Queue.size() > TokenID);
Matt Davis21a8d322018-05-07 18:29:15 +000070 assert(Queue[TokenID].Executed == false && Queue[TokenID].IR.isValid());
Matt Davis6aa5dcd2018-05-01 23:04:01 +000071 Queue[TokenID].Executed = true;
72}
73
74#ifndef NDEBUG
75void RetireControlUnit::dump() const {
76 dbgs() << "Retire Unit: { Total Slots=" << Queue.size()
77 << ", Available Slots=" << AvailableSlots << " }\n";
78}
79#endif
80
81} // namespace mca