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 "RetireControlUnit.h" 16 #include "llvm/Support/Debug.h" 17 18 using namespace llvm; 19 20 #define DEBUG_TYPE "llvm-mca" 21 22 namespace mca { 23 24 RetireControlUnit::RetireControlUnit(const llvm::MCSchedModel &SM) 25 : NextAvailableSlotIdx(0), CurrentInstructionSlotIdx(0), 26 AvailableSlots(SM.MicroOpBufferSize), MaxRetirePerCycle(0) { 27 // Check if the scheduling model provides extra information about the machine 28 // processor. If so, then use that information to set the reorder buffer size 29 // and the maximum number of instructions retired per cycle. 30 if (SM.hasExtraProcessorInfo()) { 31 const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo(); 32 if (EPI.ReorderBufferSize) 33 AvailableSlots = EPI.ReorderBufferSize; 34 MaxRetirePerCycle = EPI.MaxRetirePerCycle; 35 } 36 37 assert(AvailableSlots && "Invalid reorder buffer size!"); 38 Queue.resize(AvailableSlots); 39 } 40 41 // Reserves a number of slots, and returns a new token. 42 unsigned RetireControlUnit::reserveSlot(const InstRef &IR, 43 unsigned NumMicroOps) { 44 assert(isAvailable(NumMicroOps)); 45 unsigned NormalizedQuantity = 46 std::min(NumMicroOps, static_cast<unsigned>(Queue.size())); 47 // Zero latency instructions may have zero mOps. Artificially bump this 48 // value to 1. Although zero latency instructions don't consume scheduler 49 // resources, they still consume one slot in the retire queue. 50 NormalizedQuantity = std::max(NormalizedQuantity, 1U); 51 unsigned TokenID = NextAvailableSlotIdx; 52 Queue[NextAvailableSlotIdx] = {IR, NormalizedQuantity, false}; 53 NextAvailableSlotIdx += NormalizedQuantity; 54 NextAvailableSlotIdx %= Queue.size(); 55 AvailableSlots -= NormalizedQuantity; 56 return TokenID; 57 } 58 59 const RetireControlUnit::RUToken &RetireControlUnit::peekCurrentToken() const { 60 return Queue[CurrentInstructionSlotIdx]; 61 } 62 63 void RetireControlUnit::consumeCurrentToken() { 64 const RetireControlUnit::RUToken &Current = peekCurrentToken(); 65 assert(Current.NumSlots && "Reserved zero slots?"); 66 assert(Current.IR.isValid() && "Invalid RUToken in the RCU queue."); 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.isValid()); 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