| //===---------------------- RetireControlUnit.cpp ---------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| /// \file |
| /// |
| /// This file simulates the hardware responsible for retiring instructions. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "RetireControlUnit.h" |
| #include "llvm/Support/Debug.h" |
| |
| using namespace llvm; |
| |
| #define DEBUG_TYPE "llvm-mca" |
| |
| namespace mca { |
| |
| RetireControlUnit::RetireControlUnit(const llvm::MCSchedModel &SM) |
| : NextAvailableSlotIdx(0), CurrentInstructionSlotIdx(0), |
| AvailableSlots(SM.MicroOpBufferSize), MaxRetirePerCycle(0) { |
| // Check if the scheduling model provides extra information about the machine |
| // processor. If so, then use that information to set the reorder buffer size |
| // and the maximum number of instructions retired per cycle. |
| if (SM.hasExtraProcessorInfo()) { |
| const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo(); |
| if (EPI.ReorderBufferSize) |
| AvailableSlots = EPI.ReorderBufferSize; |
| MaxRetirePerCycle = EPI.MaxRetirePerCycle; |
| } |
| |
| assert(AvailableSlots && "Invalid reorder buffer size!"); |
| Queue.resize(AvailableSlots); |
| } |
| |
| // Reserves a number of slots, and returns a new token. |
| unsigned RetireControlUnit::reserveSlot(const InstRef &IR, |
| unsigned NumMicroOps) { |
| assert(isAvailable(NumMicroOps)); |
| unsigned NormalizedQuantity = |
| std::min(NumMicroOps, static_cast<unsigned>(Queue.size())); |
| // Zero latency instructions may have zero mOps. Artificially bump this |
| // value to 1. Although zero latency instructions don't consume scheduler |
| // resources, they still consume one slot in the retire queue. |
| NormalizedQuantity = std::max(NormalizedQuantity, 1U); |
| unsigned TokenID = NextAvailableSlotIdx; |
| Queue[NextAvailableSlotIdx] = {IR, NormalizedQuantity, false}; |
| NextAvailableSlotIdx += NormalizedQuantity; |
| NextAvailableSlotIdx %= Queue.size(); |
| AvailableSlots -= NormalizedQuantity; |
| return TokenID; |
| } |
| |
| const RetireControlUnit::RUToken &RetireControlUnit::peekCurrentToken() const { |
| return Queue[CurrentInstructionSlotIdx]; |
| } |
| |
| void RetireControlUnit::consumeCurrentToken() { |
| const RetireControlUnit::RUToken &Current = peekCurrentToken(); |
| assert(Current.NumSlots && "Reserved zero slots?"); |
| assert(Current.IR.isValid() && "Invalid RUToken in the RCU queue."); |
| |
| // Update the slot index to be the next item in the circular queue. |
| CurrentInstructionSlotIdx += Current.NumSlots; |
| CurrentInstructionSlotIdx %= Queue.size(); |
| AvailableSlots += Current.NumSlots; |
| } |
| |
| void RetireControlUnit::onInstructionExecuted(unsigned TokenID) { |
| assert(Queue.size() > TokenID); |
| assert(Queue[TokenID].Executed == false && Queue[TokenID].IR.isValid()); |
| Queue[TokenID].Executed = true; |
| } |
| |
| #ifndef NDEBUG |
| void RetireControlUnit::dump() const { |
| dbgs() << "Retire Unit: { Total Slots=" << Queue.size() |
| << ", Available Slots=" << AvailableSlots << " }\n"; |
| } |
| #endif |
| |
| } // namespace mca |