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 Andricvoid 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 Andricbool 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 AndricExpected<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 AndricError 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 Andricvoid 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 Andricvoid 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 Andricvoid 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