xref: /freebsd/contrib/llvm-project/llvm/lib/MCA/HardwareUnits/RetireControlUnit.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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