| 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 |