10b57cec5SDimitry Andric //===---------------------- RetireControlUnit.cpp ---------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file simulates the hardware responsible for retiring instructions.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "llvm/MCA/HardwareUnits/RetireControlUnit.h"
150b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric #define DEBUG_TYPE "llvm-mca"
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric namespace llvm {
200b57cec5SDimitry Andric namespace mca {
210b57cec5SDimitry Andric
RetireControlUnit(const MCSchedModel & SM)220b57cec5SDimitry Andric RetireControlUnit::RetireControlUnit(const MCSchedModel &SM)
230b57cec5SDimitry Andric : NextAvailableSlotIdx(0), CurrentInstructionSlotIdx(0),
24*fe6060f1SDimitry Andric AvailableEntries(SM.isOutOfOrder() ? SM.MicroOpBufferSize : 0),
25*fe6060f1SDimitry Andric MaxRetirePerCycle(0) {
26*fe6060f1SDimitry Andric assert(SM.isOutOfOrder() &&
27*fe6060f1SDimitry Andric "RetireControlUnit is not available for in-order processors");
280b57cec5SDimitry Andric // Check if the scheduling model provides extra information about the machine
290b57cec5SDimitry Andric // processor. If so, then use that information to set the reorder buffer size
300b57cec5SDimitry Andric // and the maximum number of instructions retired per cycle.
310b57cec5SDimitry Andric if (SM.hasExtraProcessorInfo()) {
320b57cec5SDimitry Andric const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
330b57cec5SDimitry Andric if (EPI.ReorderBufferSize)
348bcb0991SDimitry Andric AvailableEntries = EPI.ReorderBufferSize;
350b57cec5SDimitry Andric MaxRetirePerCycle = EPI.MaxRetirePerCycle;
360b57cec5SDimitry Andric }
378bcb0991SDimitry Andric NumROBEntries = AvailableEntries;
388bcb0991SDimitry Andric assert(NumROBEntries && "Invalid reorder buffer size!");
398bcb0991SDimitry Andric Queue.resize(2 * NumROBEntries);
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric
420b57cec5SDimitry Andric // Reserves a number of slots, and returns a new token.
dispatch(const InstRef & IR)438bcb0991SDimitry Andric unsigned RetireControlUnit::dispatch(const InstRef &IR) {
448bcb0991SDimitry Andric const Instruction &Inst = *IR.getInstruction();
458bcb0991SDimitry Andric unsigned Entries = normalizeQuantity(Inst.getNumMicroOps());
468bcb0991SDimitry Andric assert((AvailableEntries >= Entries) && "Reorder Buffer unavailable!");
478bcb0991SDimitry Andric
480b57cec5SDimitry Andric unsigned TokenID = NextAvailableSlotIdx;
498bcb0991SDimitry Andric Queue[NextAvailableSlotIdx] = {IR, Entries, false};
508bcb0991SDimitry Andric NextAvailableSlotIdx += std::max(1U, Entries);
510b57cec5SDimitry Andric NextAvailableSlotIdx %= Queue.size();
52*fe6060f1SDimitry Andric assert(TokenID < UnhandledTokenID && "Invalid token ID");
538bcb0991SDimitry Andric
548bcb0991SDimitry Andric AvailableEntries -= Entries;
550b57cec5SDimitry Andric return TokenID;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric
getCurrentToken() const588bcb0991SDimitry Andric const RetireControlUnit::RUToken &RetireControlUnit::getCurrentToken() const {
598bcb0991SDimitry Andric const RetireControlUnit::RUToken &Current = Queue[CurrentInstructionSlotIdx];
608bcb0991SDimitry Andric #ifndef NDEBUG
618bcb0991SDimitry Andric const Instruction *Inst = Current.IR.getInstruction();
628bcb0991SDimitry Andric assert(Inst && "Invalid RUToken in the RCU queue.");
638bcb0991SDimitry Andric #endif
648bcb0991SDimitry Andric return Current;
658bcb0991SDimitry Andric }
668bcb0991SDimitry Andric
computeNextSlotIdx() const678bcb0991SDimitry Andric unsigned RetireControlUnit::computeNextSlotIdx() const {
688bcb0991SDimitry Andric const RetireControlUnit::RUToken &Current = getCurrentToken();
698bcb0991SDimitry Andric unsigned NextSlotIdx = CurrentInstructionSlotIdx + std::max(1U, Current.NumSlots);
708bcb0991SDimitry Andric return NextSlotIdx % Queue.size();
718bcb0991SDimitry Andric }
728bcb0991SDimitry Andric
peekNextToken() const738bcb0991SDimitry Andric const RetireControlUnit::RUToken &RetireControlUnit::peekNextToken() const {
748bcb0991SDimitry Andric return Queue[computeNextSlotIdx()];
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric
consumeCurrentToken()770b57cec5SDimitry Andric void RetireControlUnit::consumeCurrentToken() {
780b57cec5SDimitry Andric RetireControlUnit::RUToken &Current = Queue[CurrentInstructionSlotIdx];
790b57cec5SDimitry Andric Current.IR.getInstruction()->retire();
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric // Update the slot index to be the next item in the circular queue.
828bcb0991SDimitry Andric CurrentInstructionSlotIdx += std::max(1U, Current.NumSlots);
830b57cec5SDimitry Andric CurrentInstructionSlotIdx %= Queue.size();
848bcb0991SDimitry Andric AvailableEntries += Current.NumSlots;
858bcb0991SDimitry Andric Current = { InstRef(), 0U, false };
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric
onInstructionExecuted(unsigned TokenID)880b57cec5SDimitry Andric void RetireControlUnit::onInstructionExecuted(unsigned TokenID) {
890b57cec5SDimitry Andric assert(Queue.size() > TokenID);
908bcb0991SDimitry Andric assert(Queue[TokenID].IR.getInstruction() && "Instruction was not dispatched!");
918bcb0991SDimitry Andric assert(Queue[TokenID].Executed == false && "Instruction already executed!");
920b57cec5SDimitry Andric Queue[TokenID].Executed = true;
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric #ifndef NDEBUG
dump() const960b57cec5SDimitry Andric void RetireControlUnit::dump() const {
978bcb0991SDimitry Andric dbgs() << "Retire Unit: { Total ROB Entries =" << NumROBEntries
988bcb0991SDimitry Andric << ", Available ROB entries=" << AvailableEntries << " }\n";
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric #endif
1010b57cec5SDimitry Andric
1020b57cec5SDimitry Andric } // namespace mca
1030b57cec5SDimitry Andric } // namespace llvm
104