Home | History | Annotate | Download | only in llvm-mca
      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