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. getNormalizedOpcodes(const InstRef & IR)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 63 public: 64 MicroOpQueueStage(unsigned Size, unsigned IPC = 0, 65 bool ZeroLatencyStage = true); 66 isAvailable(const InstRef & IR)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 hasWorkToComplete()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