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