1 | //===--------------------- Pipeline.cpp -------------------------*- 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 implements an ordered container of stages that simulate the |
11 | /// pipeline of a hardware backend. |
12 | /// |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "llvm/MCA/Pipeline.h" |
16 | #include "llvm/MCA/HWEventListener.h" |
17 | #include "llvm/Support/Debug.h" |
18 | |
19 | namespace llvm { |
20 | namespace mca { |
21 | |
22 | #define DEBUG_TYPE "llvm-mca" |
23 | |
24 | void Pipeline::addEventListener(HWEventListener *Listener) { |
25 | if (Listener) |
26 | Listeners.insert(x: Listener); |
27 | for (auto &S : Stages) |
28 | S->addListener(Listener); |
29 | } |
30 | |
31 | bool Pipeline::hasWorkToProcess() { |
32 | return any_of(Range&: Stages, P: [](const std::unique_ptr<Stage> &S) { |
33 | return S->hasWorkToComplete(); |
34 | }); |
35 | } |
36 | |
37 | Expected<unsigned> Pipeline::run() { |
38 | assert(!Stages.empty() && "Unexpected empty pipeline found!"); |
39 | |
40 | do { |
41 | if (!isPaused()) |
42 | notifyCycleBegin(); |
43 | if (Error Err = runCycle()) |
44 | return std::move(Err); |
45 | notifyCycleEnd(); |
46 | ++Cycles; |
47 | } while (hasWorkToProcess()); |
48 | |
49 | return Cycles; |
50 | } |
51 | |
52 | Error Pipeline::runCycle() { |
53 | Error Err = ErrorSuccess(); |
54 | // Update stages before we start processing new instructions. |
55 | for (auto I = Stages.rbegin(), E = Stages.rend(); I != E && !Err; ++I) { |
56 | const std::unique_ptr<Stage> &S = *I; |
57 | if (isPaused()) |
58 | Err = S->cycleResume(); |
59 | else |
60 | Err = S->cycleStart(); |
61 | } |
62 | |
63 | CurrentState = State::Started; |
64 | |
65 | // Now fetch and execute new instructions. |
66 | InstRef IR; |
67 | Stage &FirstStage = *Stages[0]; |
68 | while (!Err && FirstStage.isAvailable(IR)) |
69 | Err = FirstStage.execute(IR); |
70 | |
71 | if (Err.isA<InstStreamPause>()) { |
72 | CurrentState = State::Paused; |
73 | return Err; |
74 | } |
75 | |
76 | // Update stages in preparation for a new cycle. |
77 | for (const std::unique_ptr<Stage> &S : Stages) { |
78 | Err = S->cycleEnd(); |
79 | if (Err) |
80 | break; |
81 | } |
82 | |
83 | return Err; |
84 | } |
85 | |
86 | void Pipeline::appendStage(std::unique_ptr<Stage> S) { |
87 | assert(S && "Invalid null stage in input!"); |
88 | if (!Stages.empty()) { |
89 | Stage *Last = Stages.back().get(); |
90 | Last->setNextInSequence(S.get()); |
91 | } |
92 | |
93 | Stages.push_back(Elt: std::move(S)); |
94 | } |
95 | |
96 | void Pipeline::notifyCycleBegin() { |
97 | LLVM_DEBUG(dbgs() << "\n[E] Cycle begin: "<< Cycles << '\n'); |
98 | for (HWEventListener *Listener : Listeners) |
99 | Listener->onCycleBegin(); |
100 | } |
101 | |
102 | void Pipeline::notifyCycleEnd() { |
103 | LLVM_DEBUG(dbgs() << "[E] Cycle end: "<< Cycles << "\n"); |
104 | for (HWEventListener *Listener : Listeners) |
105 | Listener->onCycleEnd(); |
106 | } |
107 | } // namespace mca. |
108 | } // namespace llvm |
109 |