MicroOpQueueStage.h revision 351344
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_MICRO_OP_QUEUE_STAGE_H
17#define LLVM_MCA_MICRO_OP_QUEUE_STAGE_H
18
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/MCA/Stages/Stage.h"
21
22namespace llvm {
23namespace mca {
24
25/// A stage that simulates a queue of instruction opcodes.
26class 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(static_cast<unsigned>(Buffer.size()),
57                 IR.getInstruction()->getDesc().NumMicroOps);
58    return NormalizedOpcodes ? NormalizedOpcodes : 1U;
59  }
60
61  Error moveInstructions();
62
63public:
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_MICRO_OP_QUEUE_STAGE_H
89