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