1 //===---------------------- RetireControlUnit.cpp ---------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file simulates the hardware responsible for retiring instructions.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/MCA/HardwareUnits/RetireControlUnit.h"
15 #include "llvm/Support/Debug.h"
17 #define DEBUG_TYPE "llvm-mca"
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
;
35 assert(AvailableSlots
&& "Invalid reorder buffer size!");
36 Queue
.resize(AvailableSlots
);
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
;
57 const RetireControlUnit::RUToken
&RetireControlUnit::peekCurrentToken() const {
58 return Queue
[CurrentInstructionSlotIdx
];
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();
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
;
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;
80 void RetireControlUnit::dump() const {
81 dbgs() << "Retire Unit: { Total Slots=" << Queue
.size()
82 << ", Available Slots=" << AvailableSlots
<< " }\n";