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