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