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