xref: /freebsd-src/contrib/llvm-project/llvm/lib/MCA/Pipeline.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===--------------------- Pipeline.cpp -------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file implements an ordered container of stages that simulate the
110b57cec5SDimitry Andric /// pipeline of a hardware backend.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "llvm/MCA/Pipeline.h"
160b57cec5SDimitry Andric #include "llvm/MCA/HWEventListener.h"
170b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace llvm {
200b57cec5SDimitry Andric namespace mca {
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #define DEBUG_TYPE "llvm-mca"
230b57cec5SDimitry Andric 
addEventListener(HWEventListener * Listener)240b57cec5SDimitry Andric void Pipeline::addEventListener(HWEventListener *Listener) {
250b57cec5SDimitry Andric   if (Listener)
260b57cec5SDimitry Andric     Listeners.insert(Listener);
270b57cec5SDimitry Andric   for (auto &S : Stages)
280b57cec5SDimitry Andric     S->addListener(Listener);
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
hasWorkToProcess()310b57cec5SDimitry Andric bool Pipeline::hasWorkToProcess() {
320b57cec5SDimitry Andric   return any_of(Stages, [](const std::unique_ptr<Stage> &S) {
330b57cec5SDimitry Andric     return S->hasWorkToComplete();
340b57cec5SDimitry Andric   });
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric 
run()370b57cec5SDimitry Andric Expected<unsigned> Pipeline::run() {
380b57cec5SDimitry Andric   assert(!Stages.empty() && "Unexpected empty pipeline found!");
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   do {
41*81ad6265SDimitry Andric     if (!isPaused())
420b57cec5SDimitry Andric       notifyCycleBegin();
430b57cec5SDimitry Andric     if (Error Err = runCycle())
440b57cec5SDimitry Andric       return std::move(Err);
450b57cec5SDimitry Andric     notifyCycleEnd();
460b57cec5SDimitry Andric     ++Cycles;
470b57cec5SDimitry Andric   } while (hasWorkToProcess());
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   return Cycles;
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
runCycle()520b57cec5SDimitry Andric Error Pipeline::runCycle() {
530b57cec5SDimitry Andric   Error Err = ErrorSuccess();
540b57cec5SDimitry Andric   // Update stages before we start processing new instructions.
550b57cec5SDimitry Andric   for (auto I = Stages.rbegin(), E = Stages.rend(); I != E && !Err; ++I) {
560b57cec5SDimitry Andric     const std::unique_ptr<Stage> &S = *I;
57*81ad6265SDimitry Andric     if (isPaused())
58*81ad6265SDimitry Andric       Err = S->cycleResume();
59*81ad6265SDimitry Andric     else
600b57cec5SDimitry Andric       Err = S->cycleStart();
610b57cec5SDimitry Andric   }
620b57cec5SDimitry Andric 
63*81ad6265SDimitry Andric   CurrentState = State::Started;
64*81ad6265SDimitry Andric 
650b57cec5SDimitry Andric   // Now fetch and execute new instructions.
660b57cec5SDimitry Andric   InstRef IR;
670b57cec5SDimitry Andric   Stage &FirstStage = *Stages[0];
680b57cec5SDimitry Andric   while (!Err && FirstStage.isAvailable(IR))
690b57cec5SDimitry Andric     Err = FirstStage.execute(IR);
700b57cec5SDimitry Andric 
71*81ad6265SDimitry Andric   if (Err.isA<InstStreamPause>()) {
72*81ad6265SDimitry Andric     CurrentState = State::Paused;
73*81ad6265SDimitry Andric     return Err;
74*81ad6265SDimitry Andric   }
75*81ad6265SDimitry Andric 
760b57cec5SDimitry Andric   // Update stages in preparation for a new cycle.
770b57cec5SDimitry Andric   for (const std::unique_ptr<Stage> &S : Stages) {
780b57cec5SDimitry Andric     Err = S->cycleEnd();
790b57cec5SDimitry Andric     if (Err)
800b57cec5SDimitry Andric       break;
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   return Err;
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
appendStage(std::unique_ptr<Stage> S)860b57cec5SDimitry Andric void Pipeline::appendStage(std::unique_ptr<Stage> S) {
870b57cec5SDimitry Andric   assert(S && "Invalid null stage in input!");
880b57cec5SDimitry Andric   if (!Stages.empty()) {
890b57cec5SDimitry Andric     Stage *Last = Stages.back().get();
900b57cec5SDimitry Andric     Last->setNextInSequence(S.get());
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   Stages.push_back(std::move(S));
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
notifyCycleBegin()960b57cec5SDimitry Andric void Pipeline::notifyCycleBegin() {
970b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "\n[E] Cycle begin: " << Cycles << '\n');
980b57cec5SDimitry Andric   for (HWEventListener *Listener : Listeners)
990b57cec5SDimitry Andric     Listener->onCycleBegin();
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
notifyCycleEnd()1020b57cec5SDimitry Andric void Pipeline::notifyCycleEnd() {
1030b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "[E] Cycle end: " << Cycles << "\n");
1040b57cec5SDimitry Andric   for (HWEventListener *Listener : Listeners)
1050b57cec5SDimitry Andric     Listener->onCycleEnd();
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric } // namespace mca.
1080b57cec5SDimitry Andric } // namespace llvm
109