1 //===---------------------- RetireControlUnit.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 /// \file
10 ///
11 /// This file simulates the hardware responsible for retiring instructions.
12 ///
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/MCA/HardwareUnits/RetireControlUnit.h"
16 #include "llvm/Support/Debug.h"
17
18 #define DEBUG_TYPE "llvm-mca"
19
20 namespace llvm {
21 namespace mca {
22
RetireControlUnit(const MCSchedModel & SM)23 RetireControlUnit::RetireControlUnit(const MCSchedModel &SM)
24 : NextAvailableSlotIdx(0), CurrentInstructionSlotIdx(0),
25 AvailableSlots(SM.MicroOpBufferSize), MaxRetirePerCycle(0) {
26 // Check if the scheduling model provides extra information about the machine
27 // processor. If so, then use that information to set the reorder buffer size
28 // and the maximum number of instructions retired per cycle.
29 if (SM.hasExtraProcessorInfo()) {
30 const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
31 if (EPI.ReorderBufferSize)
32 AvailableSlots = EPI.ReorderBufferSize;
33 MaxRetirePerCycle = EPI.MaxRetirePerCycle;
34 }
35
36 assert(AvailableSlots && "Invalid reorder buffer size!");
37 Queue.resize(AvailableSlots);
38 }
39
40 // Reserves a number of slots, and returns a new token.
reserveSlot(const InstRef & IR,unsigned NumMicroOps)41 unsigned RetireControlUnit::reserveSlot(const InstRef &IR,
42 unsigned NumMicroOps) {
43 assert(isAvailable(NumMicroOps) && "Reorder Buffer unavailable!");
44 unsigned NormalizedQuantity =
45 std::min(NumMicroOps, static_cast<unsigned>(Queue.size()));
46 // Zero latency instructions may have zero uOps. Artificially bump this
47 // value to 1. Although zero latency instructions don't consume scheduler
48 // resources, they still consume one slot in the retire queue.
49 NormalizedQuantity = std::max(NormalizedQuantity, 1U);
50 unsigned TokenID = NextAvailableSlotIdx;
51 Queue[NextAvailableSlotIdx] = {IR, NormalizedQuantity, false};
52 NextAvailableSlotIdx += NormalizedQuantity;
53 NextAvailableSlotIdx %= Queue.size();
54 AvailableSlots -= NormalizedQuantity;
55 return TokenID;
56 }
57
peekCurrentToken() const58 const RetireControlUnit::RUToken &RetireControlUnit::peekCurrentToken() const {
59 return Queue[CurrentInstructionSlotIdx];
60 }
61
consumeCurrentToken()62 void RetireControlUnit::consumeCurrentToken() {
63 RetireControlUnit::RUToken &Current = Queue[CurrentInstructionSlotIdx];
64 assert(Current.NumSlots && "Reserved zero slots?");
65 assert(Current.IR && "Invalid RUToken in the RCU queue.");
66 Current.IR.getInstruction()->retire();
67
68 // Update the slot index to be the next item in the circular queue.
69 CurrentInstructionSlotIdx += Current.NumSlots;
70 CurrentInstructionSlotIdx %= Queue.size();
71 AvailableSlots += Current.NumSlots;
72 }
73
onInstructionExecuted(unsigned TokenID)74 void RetireControlUnit::onInstructionExecuted(unsigned TokenID) {
75 assert(Queue.size() > TokenID);
76 assert(Queue[TokenID].Executed == false && Queue[TokenID].IR);
77 Queue[TokenID].Executed = true;
78 }
79
80 #ifndef NDEBUG
dump() const81 void RetireControlUnit::dump() const {
82 dbgs() << "Retire Unit: { Total Slots=" << Queue.size()
83 << ", Available Slots=" << AvailableSlots << " }\n";
84 }
85 #endif
86
87 } // namespace mca
88 } // namespace llvm
89