1 | //===---------------------- MicroOpQueueStage.h -----------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// \file |
9 | /// |
10 | /// This file defines a stage that implements a queue of micro opcodes. |
11 | /// It can be used to simulate a hardware micro-op queue that serves opcodes to |
12 | /// the out of order backend. |
13 | /// |
14 | //===----------------------------------------------------------------------===// |
15 | |
16 | #ifndef LLVM_MCA_STAGES_MICROOPQUEUESTAGE_H |
17 | #define LLVM_MCA_STAGES_MICROOPQUEUESTAGE_H |
18 | |
19 | #include "llvm/ADT/SmallVector.h" |
20 | #include "llvm/MCA/Stages/Stage.h" |
21 | |
22 | namespace llvm { |
23 | namespace mca { |
24 | |
25 | /// A stage that simulates a queue of instruction opcodes. |
26 | class MicroOpQueueStage : public Stage { |
27 | SmallVector<InstRef, 8> Buffer; |
28 | unsigned NextAvailableSlotIdx; |
29 | unsigned CurrentInstructionSlotIdx; |
30 | |
31 | // Limits the number of instructions that can be written to this buffer every |
32 | // cycle. A value of zero means that there is no limit to the instruction |
33 | // throughput in input. |
34 | const unsigned MaxIPC; |
35 | unsigned CurrentIPC; |
36 | |
37 | // Number of entries that are available during this cycle. |
38 | unsigned AvailableEntries; |
39 | |
40 | // True if instructions dispatched to this stage don't need to wait for the |
41 | // next cycle before moving to the next stage. |
42 | // False if this buffer acts as a one cycle delay in the execution pipeline. |
43 | bool IsZeroLatencyStage; |
44 | |
45 | MicroOpQueueStage(const MicroOpQueueStage &Other) = delete; |
46 | MicroOpQueueStage &operator=(const MicroOpQueueStage &Other) = delete; |
47 | |
48 | // By default, an instruction consumes a number of buffer entries equal to its |
49 | // number of micro opcodes (see field `InstrDesc::NumMicroOpcodes`). The |
50 | // number of entries consumed by an instruction is normalized to the |
51 | // minimum value between NumMicroOpcodes and the buffer size. This is to avoid |
52 | // problems with (microcoded) instructions that generate a number of micro |
53 | // opcodes than doesn't fit in the buffer. |
54 | unsigned getNormalizedOpcodes(const InstRef &IR) const { |
55 | unsigned NormalizedOpcodes = |
56 | std::min(a: static_cast<unsigned>(Buffer.size()), |
57 | b: IR.getInstruction()->getDesc().NumMicroOps); |
58 | return NormalizedOpcodes ? NormalizedOpcodes : 1U; |
59 | } |
60 | |
61 | Error moveInstructions(); |
62 | |
63 | public: |
64 | MicroOpQueueStage(unsigned Size, unsigned IPC = 0, |
65 | bool ZeroLatencyStage = true); |
66 | |
67 | bool isAvailable(const InstRef &IR) const override { |
68 | if (MaxIPC && CurrentIPC == MaxIPC) |
69 | return false; |
70 | unsigned NormalizedOpcodes = getNormalizedOpcodes(IR); |
71 | if (NormalizedOpcodes > AvailableEntries) |
72 | return false; |
73 | return true; |
74 | } |
75 | |
76 | bool hasWorkToComplete() const override { |
77 | return AvailableEntries != Buffer.size(); |
78 | } |
79 | |
80 | Error execute(InstRef &IR) override; |
81 | Error cycleStart() override; |
82 | Error cycleEnd() override; |
83 | }; |
84 | |
85 | } // namespace mca |
86 | } // namespace llvm |
87 | |
88 | #endif // LLVM_MCA_STAGES_MICROOPQUEUESTAGE_H |
89 | |