1343171Sdim//===---------------------- RetireControlUnit.h -----------------*- C++ -*-===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===----------------------------------------------------------------------===// 8343171Sdim/// \file 9343171Sdim/// 10343171Sdim/// This file simulates the hardware responsible for retiring instructions. 11343171Sdim/// 12343171Sdim//===----------------------------------------------------------------------===// 13343171Sdim 14343171Sdim#ifndef LLVM_MCA_RETIRE_CONTROL_UNIT_H 15343171Sdim#define LLVM_MCA_RETIRE_CONTROL_UNIT_H 16343171Sdim 17343171Sdim#include "llvm/MC/MCSchedule.h" 18343171Sdim#include "llvm/MCA/HardwareUnits/HardwareUnit.h" 19343171Sdim#include "llvm/MCA/Instruction.h" 20343171Sdim#include <vector> 21343171Sdim 22343171Sdimnamespace llvm { 23343171Sdimnamespace mca { 24343171Sdim 25343171Sdim/// This class tracks which instructions are in-flight (i.e., dispatched but not 26343171Sdim/// retired) in the OoO backend. 27343171Sdim// 28343171Sdim/// This class checks on every cycle if/which instructions can be retired. 29343171Sdim/// Instructions are retired in program order. 30343171Sdim/// In the event of an instruction being retired, the pipeline that owns 31343171Sdim/// this RetireControlUnit (RCU) gets notified. 32343171Sdim/// 33343171Sdim/// On instruction retired, register updates are all architecturally 34343171Sdim/// committed, and any physicall registers previously allocated for the 35343171Sdim/// retired instruction are freed. 36343171Sdimstruct RetireControlUnit : public HardwareUnit { 37343171Sdim // A RUToken is created by the RCU for every instruction dispatched to the 38343171Sdim // schedulers. These "tokens" are managed by the RCU in its token Queue. 39343171Sdim // 40343171Sdim // On every cycle ('cycleEvent'), the RCU iterates through the token queue 41343171Sdim // looking for any token with its 'Executed' flag set. If a token has that 42343171Sdim // flag set, then the instruction has reached the write-back stage and will 43343171Sdim // be retired by the RCU. 44343171Sdim // 45343171Sdim // 'NumSlots' represents the number of entries consumed by the instruction in 46343171Sdim // the reorder buffer. Those entries will become available again once the 47343171Sdim // instruction is retired. 48343171Sdim // 49343171Sdim // Note that the size of the reorder buffer is defined by the scheduling 50343171Sdim // model via field 'NumMicroOpBufferSize'. 51343171Sdim struct RUToken { 52343171Sdim InstRef IR; 53343171Sdim unsigned NumSlots; // Slots reserved to this instruction. 54343171Sdim bool Executed; // True if the instruction is past the WB stage. 55343171Sdim }; 56343171Sdim 57343171Sdimprivate: 58343171Sdim unsigned NextAvailableSlotIdx; 59343171Sdim unsigned CurrentInstructionSlotIdx; 60360784Sdim unsigned NumROBEntries; 61360784Sdim unsigned AvailableEntries; 62343171Sdim unsigned MaxRetirePerCycle; // 0 means no limit. 63343171Sdim std::vector<RUToken> Queue; 64343171Sdim 65360784Sdim unsigned normalizeQuantity(unsigned Quantity) const { 66343171Sdim // Some instructions may declare a number of uOps which exceeds the size 67343171Sdim // of the reorder buffer. To avoid problems, cap the amount of slots to 68343171Sdim // the size of the reorder buffer. 69360784Sdim Quantity = std::min(Quantity, NumROBEntries); 70343171Sdim 71343171Sdim // Further normalize the number of micro opcodes for instructions that 72343171Sdim // declare zero opcodes. This should match the behavior of method 73343171Sdim // reserveSlot(). 74360784Sdim return std::max(Quantity, 1U); 75343171Sdim } 76343171Sdim 77360784Sdim unsigned computeNextSlotIdx() const; 78360784Sdim 79360784Sdimpublic: 80360784Sdim RetireControlUnit(const MCSchedModel &SM); 81360784Sdim 82360784Sdim bool isEmpty() const { return AvailableEntries == NumROBEntries; } 83360784Sdim 84360784Sdim bool isAvailable(unsigned Quantity = 1) const { 85360784Sdim return AvailableEntries >= normalizeQuantity(Quantity); 86360784Sdim } 87360784Sdim 88343171Sdim unsigned getMaxRetirePerCycle() const { return MaxRetirePerCycle; } 89343171Sdim 90360784Sdim // Reserves a number of slots, and returns a new token reference. 91360784Sdim unsigned dispatch(const InstRef &IS); 92343171Sdim 93343171Sdim // Return the current token from the RCU's circular token queue. 94360784Sdim const RUToken &getCurrentToken() const; 95343171Sdim 96360784Sdim const RUToken &peekNextToken() const; 97360784Sdim 98343171Sdim // Advance the pointer to the next token in the circular token queue. 99343171Sdim void consumeCurrentToken(); 100343171Sdim 101343171Sdim // Update the RCU token to represent the executed state. 102343171Sdim void onInstructionExecuted(unsigned TokenID); 103343171Sdim 104343171Sdim#ifndef NDEBUG 105343171Sdim void dump() const; 106343171Sdim#endif 107343171Sdim}; 108343171Sdim 109343171Sdim} // namespace mca 110343171Sdim} // namespace llvm 111343171Sdim 112343171Sdim#endif // LLVM_MCA_RETIRE_CONTROL_UNIT_H 113