10b57cec5SDimitry Andric //===---------------------- RetireControlUnit.h -----------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// 100b57cec5SDimitry Andric /// This file simulates the hardware responsible for retiring instructions. 110b57cec5SDimitry Andric /// 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 14*fe6060f1SDimitry Andric #ifndef LLVM_MCA_HARDWAREUNITS_RETIRECONTROLUNIT_H 15*fe6060f1SDimitry Andric #define LLVM_MCA_HARDWAREUNITS_RETIRECONTROLUNIT_H 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "llvm/MC/MCSchedule.h" 180b57cec5SDimitry Andric #include "llvm/MCA/HardwareUnits/HardwareUnit.h" 190b57cec5SDimitry Andric #include "llvm/MCA/Instruction.h" 200b57cec5SDimitry Andric #include <vector> 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric namespace llvm { 230b57cec5SDimitry Andric namespace mca { 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric /// This class tracks which instructions are in-flight (i.e., dispatched but not 260b57cec5SDimitry Andric /// retired) in the OoO backend. 270b57cec5SDimitry Andric // 280b57cec5SDimitry Andric /// This class checks on every cycle if/which instructions can be retired. 290b57cec5SDimitry Andric /// Instructions are retired in program order. 300b57cec5SDimitry Andric /// In the event of an instruction being retired, the pipeline that owns 310b57cec5SDimitry Andric /// this RetireControlUnit (RCU) gets notified. 320b57cec5SDimitry Andric /// 330b57cec5SDimitry Andric /// On instruction retired, register updates are all architecturally 340b57cec5SDimitry Andric /// committed, and any physicall registers previously allocated for the 350b57cec5SDimitry Andric /// retired instruction are freed. 360b57cec5SDimitry Andric struct RetireControlUnit : public HardwareUnit { 370b57cec5SDimitry Andric // A RUToken is created by the RCU for every instruction dispatched to the 380b57cec5SDimitry Andric // schedulers. These "tokens" are managed by the RCU in its token Queue. 390b57cec5SDimitry Andric // 400b57cec5SDimitry Andric // On every cycle ('cycleEvent'), the RCU iterates through the token queue 410b57cec5SDimitry Andric // looking for any token with its 'Executed' flag set. If a token has that 420b57cec5SDimitry Andric // flag set, then the instruction has reached the write-back stage and will 430b57cec5SDimitry Andric // be retired by the RCU. 440b57cec5SDimitry Andric // 450b57cec5SDimitry Andric // 'NumSlots' represents the number of entries consumed by the instruction in 460b57cec5SDimitry Andric // the reorder buffer. Those entries will become available again once the 470b57cec5SDimitry Andric // instruction is retired. 480b57cec5SDimitry Andric // 490b57cec5SDimitry Andric // Note that the size of the reorder buffer is defined by the scheduling 500b57cec5SDimitry Andric // model via field 'NumMicroOpBufferSize'. 510b57cec5SDimitry Andric struct RUToken { 520b57cec5SDimitry Andric InstRef IR; 530b57cec5SDimitry Andric unsigned NumSlots; // Slots reserved to this instruction. 540b57cec5SDimitry Andric bool Executed; // True if the instruction is past the WB stage. 550b57cec5SDimitry Andric }; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric private: 580b57cec5SDimitry Andric unsigned NextAvailableSlotIdx; 590b57cec5SDimitry Andric unsigned CurrentInstructionSlotIdx; 608bcb0991SDimitry Andric unsigned NumROBEntries; 618bcb0991SDimitry Andric unsigned AvailableEntries; 620b57cec5SDimitry Andric unsigned MaxRetirePerCycle; // 0 means no limit. 630b57cec5SDimitry Andric std::vector<RUToken> Queue; 640b57cec5SDimitry Andric normalizeQuantityRetireControlUnit658bcb0991SDimitry Andric unsigned normalizeQuantity(unsigned Quantity) const { 660b57cec5SDimitry Andric // Some instructions may declare a number of uOps which exceeds the size 670b57cec5SDimitry Andric // of the reorder buffer. To avoid problems, cap the amount of slots to 680b57cec5SDimitry Andric // the size of the reorder buffer. 698bcb0991SDimitry Andric Quantity = std::min(Quantity, NumROBEntries); 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // Further normalize the number of micro opcodes for instructions that 720b57cec5SDimitry Andric // declare zero opcodes. This should match the behavior of method 730b57cec5SDimitry Andric // reserveSlot(). 748bcb0991SDimitry Andric return std::max(Quantity, 1U); 758bcb0991SDimitry Andric } 768bcb0991SDimitry Andric 778bcb0991SDimitry Andric unsigned computeNextSlotIdx() const; 788bcb0991SDimitry Andric 798bcb0991SDimitry Andric public: 808bcb0991SDimitry Andric RetireControlUnit(const MCSchedModel &SM); 818bcb0991SDimitry Andric isEmptyRetireControlUnit828bcb0991SDimitry Andric bool isEmpty() const { return AvailableEntries == NumROBEntries; } 838bcb0991SDimitry Andric 848bcb0991SDimitry Andric bool isAvailable(unsigned Quantity = 1) const { 858bcb0991SDimitry Andric return AvailableEntries >= normalizeQuantity(Quantity); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric getMaxRetirePerCycleRetireControlUnit880b57cec5SDimitry Andric unsigned getMaxRetirePerCycle() const { return MaxRetirePerCycle; } 890b57cec5SDimitry Andric 908bcb0991SDimitry Andric // Reserves a number of slots, and returns a new token reference. 918bcb0991SDimitry Andric unsigned dispatch(const InstRef &IS); 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric // Return the current token from the RCU's circular token queue. 948bcb0991SDimitry Andric const RUToken &getCurrentToken() const; 958bcb0991SDimitry Andric 968bcb0991SDimitry Andric const RUToken &peekNextToken() const; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric // Advance the pointer to the next token in the circular token queue. 990b57cec5SDimitry Andric void consumeCurrentToken(); 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric // Update the RCU token to represent the executed state. 1020b57cec5SDimitry Andric void onInstructionExecuted(unsigned TokenID); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric #ifndef NDEBUG 1050b57cec5SDimitry Andric void dump() const; 1060b57cec5SDimitry Andric #endif 107*fe6060f1SDimitry Andric 108*fe6060f1SDimitry Andric // Assigned to instructions that are not handled by the RCU. 109*fe6060f1SDimitry Andric static const unsigned UnhandledTokenID = ~0U; 1100b57cec5SDimitry Andric }; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric } // namespace mca 1130b57cec5SDimitry Andric } // namespace llvm 1140b57cec5SDimitry Andric 115*fe6060f1SDimitry Andric #endif // LLVM_MCA_HARDWAREUNITS_RETIRECONTROLUNIT_H 116