Path: blob/main/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp
35266 views
//-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// -------------------------- Post RA scheduling ---------------------------- //9// SystemZPostRASchedStrategy is a scheduling strategy which is plugged into10// the MachineScheduler. It has a sorted Available set of SUs and a pickNode()11// implementation that looks to optimize decoder grouping and balance the12// usage of processor resources. Scheduler states are saved for the end13// region of each MBB, so that a successor block can learn from it.14//===----------------------------------------------------------------------===//1516#include "SystemZMachineScheduler.h"17#include "llvm/CodeGen/MachineLoopInfo.h"1819using namespace llvm;2021#define DEBUG_TYPE "machine-scheduler"2223#ifndef NDEBUG24// Print the set of SUs25void SystemZPostRASchedStrategy::SUSet::26dump(SystemZHazardRecognizer &HazardRec) const {27dbgs() << "{";28for (auto &SU : *this) {29HazardRec.dumpSU(SU, dbgs());30if (SU != *rbegin())31dbgs() << ", ";32}33dbgs() << "}\n";34}35#endif3637// Try to find a single predecessor that would be interesting for the38// scheduler in the top-most region of MBB.39static MachineBasicBlock *getSingleSchedPred(MachineBasicBlock *MBB,40const MachineLoop *Loop) {41MachineBasicBlock *PredMBB = nullptr;42if (MBB->pred_size() == 1)43PredMBB = *MBB->pred_begin();4445// The loop header has two predecessors, return the latch, but not for a46// single block loop.47if (MBB->pred_size() == 2 && Loop != nullptr && Loop->getHeader() == MBB) {48for (MachineBasicBlock *Pred : MBB->predecessors())49if (Loop->contains(Pred))50PredMBB = (Pred == MBB ? nullptr : Pred);51}5253assert ((PredMBB == nullptr || !Loop || Loop->contains(PredMBB))54&& "Loop MBB should not consider predecessor outside of loop.");5556return PredMBB;57}5859void SystemZPostRASchedStrategy::60advanceTo(MachineBasicBlock::iterator NextBegin) {61MachineBasicBlock::iterator LastEmittedMI = HazardRec->getLastEmittedMI();62MachineBasicBlock::iterator I =63((LastEmittedMI != nullptr && LastEmittedMI->getParent() == MBB) ?64std::next(LastEmittedMI) : MBB->begin());6566for (; I != NextBegin; ++I) {67if (I->isPosition() || I->isDebugInstr())68continue;69HazardRec->emitInstruction(&*I);70}71}7273void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) {74Available.clear(); // -misched-cutoff.75LLVM_DEBUG(HazardRec->dumpState(););76}7778void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {79assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&80"Entering MBB twice?");81LLVM_DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB));8283MBB = NextMBB;8485/// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to86/// point to it.87HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);88LLVM_DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB);89if (Loop && Loop->getHeader() == MBB) dbgs() << " (Loop header)";90dbgs() << ":\n";);9192// Try to take over the state from a single predecessor, if it has been93// scheduled. If this is not possible, we are done.94MachineBasicBlock *SinglePredMBB =95getSingleSchedPred(MBB, MLI->getLoopFor(MBB));96if (SinglePredMBB == nullptr ||97SchedStates.find(SinglePredMBB) == SchedStates.end())98return;99100LLVM_DEBUG(dbgs() << "** Continued scheduling from "101<< printMBBReference(*SinglePredMBB) << "\n";);102103HazardRec->copyState(SchedStates[SinglePredMBB]);104LLVM_DEBUG(HazardRec->dumpState(););105106// Emit incoming terminator(s). Be optimistic and assume that branch107// prediction will generally do "the right thing".108for (MachineInstr &MI : SinglePredMBB->terminators()) {109LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; MI.dump(););110bool TakenBranch = (MI.isBranch() &&111(TII->getBranchInfo(MI).isIndirect() ||112TII->getBranchInfo(MI).getMBBTarget() == MBB));113HazardRec->emitInstruction(&MI, TakenBranch);114if (TakenBranch)115break;116}117}118119void SystemZPostRASchedStrategy::leaveMBB() {120LLVM_DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";);121122// Advance to first terminator. The successor block will handle terminators123// dependent on CFG layout (T/NT branch etc).124advanceTo(MBB->getFirstTerminator());125}126127SystemZPostRASchedStrategy::128SystemZPostRASchedStrategy(const MachineSchedContext *C)129: MLI(C->MLI),130TII(static_cast<const SystemZInstrInfo *>131(C->MF->getSubtarget().getInstrInfo())),132MBB(nullptr), HazardRec(nullptr) {133const TargetSubtargetInfo *ST = &C->MF->getSubtarget();134SchedModel.init(ST);135}136137SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {138// Delete hazard recognizers kept around for each MBB.139for (auto I : SchedStates) {140SystemZHazardRecognizer *hazrec = I.second;141delete hazrec;142}143}144145void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,146MachineBasicBlock::iterator End,147unsigned NumRegionInstrs) {148// Don't emit the terminators.149if (Begin->isTerminator())150return;151152// Emit any instructions before start of region.153advanceTo(Begin);154}155156// Pick the next node to schedule.157SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {158// Only scheduling top-down.159IsTopNode = true;160161if (Available.empty())162return nullptr;163164// If only one choice, return it.165if (Available.size() == 1) {166LLVM_DEBUG(dbgs() << "** Only one: ";167HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);168return *Available.begin();169}170171// All nodes that are possible to schedule are stored in the Available set.172LLVM_DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec););173174Candidate Best;175for (auto *SU : Available) {176177// SU is the next candidate to be compared against current Best.178Candidate c(SU, *HazardRec);179180// Remeber which SU is the best candidate.181if (Best.SU == nullptr || c < Best) {182Best = c;183LLVM_DEBUG(dbgs() << "** Best so far: ";);184} else185LLVM_DEBUG(dbgs() << "** Tried : ";);186LLVM_DEBUG(HazardRec->dumpSU(c.SU, dbgs()); c.dumpCosts();187dbgs() << " Height:" << c.SU->getHeight(); dbgs() << "\n";);188189// Once we know we have seen all SUs that affect grouping or use unbuffered190// resources, we can stop iterating if Best looks good.191if (!SU->isScheduleHigh && Best.noCost())192break;193}194195assert (Best.SU != nullptr);196return Best.SU;197}198199SystemZPostRASchedStrategy::Candidate::200Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {201SU = SU_;202203// Check the grouping cost. For a node that must begin / end a204// group, it is positive if it would do so prematurely, or negative205// if it would fit naturally into the schedule.206GroupingCost = HazardRec.groupingCost(SU);207208// Check the resources cost for this SU.209ResourcesCost = HazardRec.resourcesCost(SU);210}211212bool SystemZPostRASchedStrategy::Candidate::213operator<(const Candidate &other) {214215// Check decoder grouping.216if (GroupingCost < other.GroupingCost)217return true;218if (GroupingCost > other.GroupingCost)219return false;220221// Compare the use of resources.222if (ResourcesCost < other.ResourcesCost)223return true;224if (ResourcesCost > other.ResourcesCost)225return false;226227// Higher SU is otherwise generally better.228if (SU->getHeight() > other.SU->getHeight())229return true;230if (SU->getHeight() < other.SU->getHeight())231return false;232233// If all same, fall back to original order.234if (SU->NodeNum < other.SU->NodeNum)235return true;236237return false;238}239240void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {241LLVM_DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") ";242if (Available.size() == 1) dbgs() << "(only one) ";243Candidate c(SU, *HazardRec); c.dumpCosts(); dbgs() << "\n";);244245// Remove SU from Available set and update HazardRec.246Available.erase(SU);247HazardRec->EmitInstruction(SU);248}249250void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {251// Set isScheduleHigh flag on all SUs that we want to consider first in252// pickNode().253const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);254bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));255SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);256257// Put all released SUs in the Available set.258Available.insert(SU);259}260261262