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 
22 namespace llvm {
23 namespace mca {
24 
25 class InstRef;
26 
27 class Stage {
28   Stage *NextInSequence;
29   std::set<HWEventListener *> Listeners;
30 
31   Stage(const Stage &Other) = delete;
32   Stage &operator=(const Stage &Other) = delete;
33 
34 protected:
35   const std::set<HWEventListener *> &getListeners() const { return Listeners; }
36 
37 public:
38   Stage() : NextInSequence(nullptr) {}
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.
90 struct 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