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