xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/MCA/HardwareUnits/RetireControlUnit.h (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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