1//===---------------------- Stage.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.
11/// A chain of stages compose an instruction pipeline.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_MCA_STAGES_STAGE_H
16#define LLVM_MCA_STAGES_STAGE_H
17
18#include "llvm/MCA/HWEventListener.h"
19#include "llvm/Support/Error.h"
20#include <set>
21
22namespace llvm {
23namespace mca {
24
25class InstRef;
26
27class Stage {
28  Stage *NextInSequence = nullptr;
29  std::set<HWEventListener *> Listeners;
30
31  Stage(const Stage &Other) = delete;
32  Stage &operator=(const Stage &Other) = delete;
33
34protected:
35  const std::set<HWEventListener *> &getListeners() const { return Listeners; }
36
37public:
38  Stage() = default;
39  virtual ~Stage();
40
41  /// Returns true if it can execute IR during this cycle.
42  virtual bool isAvailable(const InstRef &IR) const { return true; }
43
44  /// Returns true if some instructions are still executing this stage.
45  virtual bool hasWorkToComplete() const = 0;
46
47  /// Called once at the start of each cycle.  This can be used as a setup
48  /// phase to prepare for the executions during the cycle.
49  virtual Error cycleStart() { return ErrorSuccess(); }
50
51  /// Called after the pipeline is resumed from pausing state.
52  virtual Error cycleResume() { return ErrorSuccess(); }
53
54  /// Called once at the end of each cycle.
55  virtual Error cycleEnd() { return ErrorSuccess(); }
56
57  /// The primary action that this stage performs on instruction IR.
58  virtual Error execute(InstRef &IR) = 0;
59
60  void setNextInSequence(Stage *NextStage) {
61    assert(!NextInSequence && "This stage already has a NextInSequence!");
62    NextInSequence = NextStage;
63  }
64
65  bool checkNextStage(const InstRef &IR) const {
66    return NextInSequence && NextInSequence->isAvailable(IR);
67  }
68
69  /// Called when an instruction is ready to move the next pipeline stage.
70  ///
71  /// Stages are responsible for moving instructions to their immediate
72  /// successor stages.
73  Error moveToTheNextStage(InstRef &IR) {
74    assert(checkNextStage(IR) && "Next stage is not ready!");
75    return NextInSequence->execute(IR);
76  }
77
78  /// Add a listener to receive callbacks during the execution of this stage.
79  void addListener(HWEventListener *Listener);
80
81  /// Notify listeners of a particular hardware event.
82  template <typename EventT> void notifyEvent(const EventT &Event) const {
83    for (HWEventListener *Listener : Listeners)
84      Listener->onEvent(Event);
85  }
86};
87
88/// This is actually not an error but a marker to indicate that
89/// the instruction stream is paused.
90struct InstStreamPause : public ErrorInfo<InstStreamPause> {
91  static char ID;
92
93  std::error_code convertToErrorCode() const override {
94    return llvm::inconvertibleErrorCode();
95  }
96  void log(raw_ostream &OS) const override { OS << "Stream is paused"; }
97};
98} // namespace mca
99} // namespace llvm
100#endif // LLVM_MCA_STAGES_STAGE_H
101