diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2024-07-27 23:34:35 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-10-23 18:26:01 +0000 |
commit | 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch) | |
tree | 6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp | |
parent | 6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff) | |
parent | ac9a064cb179f3425b310fa2847f8764ac970a4d (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp | 344 |
1 files changed, 276 insertions, 68 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp b/contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp index f40e91819a48..a8a17101b9c9 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp @@ -32,7 +32,6 @@ #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachinePassRegistry.h" #include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/MachineValueType.h" #include "llvm/CodeGen/RegisterClassInfo.h" #include "llvm/CodeGen/RegisterPressure.h" #include "llvm/CodeGen/ScheduleDAG.h" @@ -48,6 +47,7 @@ #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSchedule.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/CodeGenTypes/MachineValueType.h" #include "llvm/Config/llvm-config.h" #include "llvm/InitializePasses.h" #include "llvm/MC/LaneBitmask.h" @@ -81,6 +81,26 @@ cl::opt<bool> ForceTopDown("misched-topdown", cl::Hidden, cl::desc("Force top-down list scheduling")); cl::opt<bool> ForceBottomUp("misched-bottomup", cl::Hidden, cl::desc("Force bottom-up list scheduling")); +namespace MISchedPostRASched { +enum Direction { + TopDown, + BottomUp, + Bidirectional, +}; +} // end namespace MISchedPostRASched +cl::opt<MISchedPostRASched::Direction> PostRADirection( + "misched-postra-direction", cl::Hidden, + cl::desc("Post reg-alloc list scheduling direction"), + // Default to top-down because it was implemented first and existing targets + // expect that behavior by default. + cl::init(MISchedPostRASched::TopDown), + cl::values( + clEnumValN(MISchedPostRASched::TopDown, "topdown", + "Force top-down post reg-alloc list scheduling"), + clEnumValN(MISchedPostRASched::BottomUp, "bottomup", + "Force bottom-up post reg-alloc list scheduling"), + clEnumValN(MISchedPostRASched::Bidirectional, "bidirectional", + "Force bidirectional post reg-alloc list scheduling"))); cl::opt<bool> DumpCriticalPathLength("misched-dcpl", cl::Hidden, cl::desc("Print critical path length to stdout")); @@ -246,10 +266,10 @@ char &llvm::MachineSchedulerID = MachineScheduler::ID; INITIALIZE_PASS_BEGIN(MachineScheduler, DEBUG_TYPE, "Machine Instruction Scheduler", false, false) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) -INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) -INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) -INITIALIZE_PASS_DEPENDENCY(SlotIndexes) -INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass) +INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass) INITIALIZE_PASS_END(MachineScheduler, DEBUG_TYPE, "Machine Instruction Scheduler", false, false) @@ -259,14 +279,14 @@ MachineScheduler::MachineScheduler() : MachineSchedulerBase(ID) { void MachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); - AU.addRequired<MachineDominatorTree>(); - AU.addRequired<MachineLoopInfo>(); + AU.addRequired<MachineDominatorTreeWrapperPass>(); + AU.addRequired<MachineLoopInfoWrapperPass>(); AU.addRequired<AAResultsWrapperPass>(); AU.addRequired<TargetPassConfig>(); - AU.addRequired<SlotIndexes>(); - AU.addPreserved<SlotIndexes>(); - AU.addRequired<LiveIntervals>(); - AU.addPreserved<LiveIntervals>(); + AU.addRequired<SlotIndexesWrapperPass>(); + AU.addPreserved<SlotIndexesWrapperPass>(); + AU.addRequired<LiveIntervalsWrapperPass>(); + AU.addPreserved<LiveIntervalsWrapperPass>(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -276,8 +296,8 @@ char &llvm::PostMachineSchedulerID = PostMachineScheduler::ID; INITIALIZE_PASS_BEGIN(PostMachineScheduler, "postmisched", "PostRA Machine Instruction Scheduler", false, false) -INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) -INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_END(PostMachineScheduler, "postmisched", "PostRA Machine Instruction Scheduler", false, false) @@ -288,8 +308,8 @@ PostMachineScheduler::PostMachineScheduler() : MachineSchedulerBase(ID) { void PostMachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); - AU.addRequired<MachineDominatorTree>(); - AU.addRequired<MachineLoopInfo>(); + AU.addRequired<MachineDominatorTreeWrapperPass>(); + AU.addRequired<MachineLoopInfoWrapperPass>(); AU.addRequired<AAResultsWrapperPass>(); AU.addRequired<TargetPassConfig>(); MachineFunctionPass::getAnalysisUsage(AU); @@ -424,12 +444,12 @@ bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) { // Initialize the context of the pass. MF = &mf; - MLI = &getAnalysis<MachineLoopInfo>(); - MDT = &getAnalysis<MachineDominatorTree>(); + MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI(); + MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); PassConfig = &getAnalysis<TargetPassConfig>(); AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); - LIS = &getAnalysis<LiveIntervals>(); + LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS(); if (VerifyScheduling) { LLVM_DEBUG(LIS->dump()); @@ -440,6 +460,14 @@ bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) { // Instantiate the selected scheduler for this target, function, and // optimization level. std::unique_ptr<ScheduleDAGInstrs> Scheduler(createMachineScheduler()); + ScheduleDAGMI::DumpDirection D; + if (ForceTopDown) + D = ScheduleDAGMI::DumpDirection::TopDown; + else if (ForceBottomUp) + D = ScheduleDAGMI::DumpDirection::BottomUp; + else + D = ScheduleDAGMI::DumpDirection::Bidirectional; + Scheduler->setDumpDirection(D); scheduleRegions(*Scheduler, false); LLVM_DEBUG(LIS->dump()); @@ -463,7 +491,7 @@ bool PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) { // Initialize the context of the pass. MF = &mf; - MLI = &getAnalysis<MachineLoopInfo>(); + MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI(); PassConfig = &getAnalysis<TargetPassConfig>(); AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); @@ -473,6 +501,14 @@ bool PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) { // Instantiate the selected scheduler for this target, function, and // optimization level. std::unique_ptr<ScheduleDAGInstrs> Scheduler(createPostMachineScheduler()); + ScheduleDAGMI::DumpDirection D; + if (PostRADirection == MISchedPostRASched::TopDown) + D = ScheduleDAGMI::DumpDirection::TopDown; + else if (PostRADirection == MISchedPostRASched::BottomUp) + D = ScheduleDAGMI::DumpDirection::BottomUp; + else + D = ScheduleDAGMI::DumpDirection::Bidirectional; + Scheduler->setDumpDirection(D); scheduleRegions(*Scheduler, true); if (VerifyScheduling) @@ -1125,12 +1161,14 @@ LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceBottomUp() const { #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void ScheduleDAGMI::dumpSchedule() const { if (MISchedDumpScheduleTrace) { - if (ForceTopDown) + if (DumpDir == DumpDirection::TopDown) dumpScheduleTraceTopDown(); - else if (ForceBottomUp) + else if (DumpDir == DumpDirection::BottomUp) dumpScheduleTraceBottomUp(); - else { + else if (DumpDir == DumpDirection::Bidirectional) { dbgs() << "* Schedule table (Bidirectional): not implemented\n"; + } else { + dbgs() << "* Schedule table: DumpDirection not set.\n"; } } @@ -1626,7 +1664,8 @@ void ScheduleDAGMILive::scheduleMI(SUnit *SU, bool IsTopNode) { if (ShouldTrackPressure) { // Update top scheduled pressure. RegisterOperands RegOpers; - RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, false); + RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, + /*IgnoreDead=*/false); if (ShouldTrackLaneMasks) { // Adjust liveness and add missing dead+read-undef flags. SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot(); @@ -1660,7 +1699,8 @@ void ScheduleDAGMILive::scheduleMI(SUnit *SU, bool IsTopNode) { } if (ShouldTrackPressure) { RegisterOperands RegOpers; - RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, false); + RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, + /*IgnoreDead=*/false); if (ShouldTrackLaneMasks) { // Adjust liveness and add missing dead+read-undef flags. SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot(); @@ -1697,11 +1737,11 @@ class BaseMemOpClusterMutation : public ScheduleDAGMutation { SUnit *SU; SmallVector<const MachineOperand *, 4> BaseOps; int64_t Offset; - unsigned Width; + LocationSize Width; bool OffsetIsScalable; MemOpInfo(SUnit *SU, ArrayRef<const MachineOperand *> BaseOps, - int64_t Offset, bool OffsetIsScalable, unsigned Width) + int64_t Offset, bool OffsetIsScalable, LocationSize Width) : SU(SU), BaseOps(BaseOps.begin(), BaseOps.end()), Offset(Offset), Width(Width), OffsetIsScalable(OffsetIsScalable) {} @@ -1834,11 +1874,12 @@ void BaseMemOpClusterMutation::clusterNeighboringMemOps( auto MemOpb = MemOpRecords[NextIdx]; unsigned ClusterLength = 2; - unsigned CurrentClusterBytes = MemOpa.Width + MemOpb.Width; + unsigned CurrentClusterBytes = MemOpa.Width.getValue().getKnownMinValue() + + MemOpb.Width.getValue().getKnownMinValue(); if (SUnit2ClusterInfo.count(MemOpa.SU->NodeNum)) { ClusterLength = SUnit2ClusterInfo[MemOpa.SU->NodeNum].first + 1; - CurrentClusterBytes = - SUnit2ClusterInfo[MemOpa.SU->NodeNum].second + MemOpb.Width; + CurrentClusterBytes = SUnit2ClusterInfo[MemOpa.SU->NodeNum].second + + MemOpb.Width.getValue().getKnownMinValue(); } if (!TII->shouldClusterMemOps(MemOpa.BaseOps, MemOpa.Offset, @@ -1908,7 +1949,7 @@ void BaseMemOpClusterMutation::collectMemOpRecords( SmallVector<const MachineOperand *, 4> BaseOps; int64_t Offset; bool OffsetIsScalable; - unsigned Width; + LocationSize Width = 0; if (TII->getMemOperandsWithOffsetWidth(MI, BaseOps, Offset, OffsetIsScalable, Width, TRI)) { MemOpRecords.push_back( @@ -3224,14 +3265,10 @@ void GenericScheduler::initialize(ScheduleDAGMI *dag) { // are disabled, then these HazardRecs will be disabled. const InstrItineraryData *Itin = SchedModel->getInstrItineraries(); if (!Top.HazardRec) { - Top.HazardRec = - DAG->MF.getSubtarget().getInstrInfo()->CreateTargetMIHazardRecognizer( - Itin, DAG); + Top.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG); } if (!Bot.HazardRec) { - Bot.HazardRec = - DAG->MF.getSubtarget().getInstrInfo()->CreateTargetMIHazardRecognizer( - Itin, DAG); + Bot.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG); } TopCand.SU = nullptr; BotCand.SU = nullptr; @@ -3246,14 +3283,16 @@ void GenericScheduler::initPolicy(MachineBasicBlock::iterator Begin, // Avoid setting up the register pressure tracker for small regions to save // compile time. As a rough heuristic, only track pressure when the number of - // schedulable instructions exceeds half the integer register file. + // schedulable instructions exceeds half the allocatable integer register file + // that is the largest legal integer regiser type. RegionPolicy.ShouldTrackPressure = true; - for (unsigned VT = MVT::i32; VT > (unsigned)MVT::i1; --VT) { + for (unsigned VT = MVT::i64; VT > (unsigned)MVT::i1; --VT) { MVT::SimpleValueType LegalIntVT = (MVT::SimpleValueType)VT; if (TLI->isTypeLegal(LegalIntVT)) { unsigned NIntRegs = Context->RegClassInfo->getNumAllocatableRegs( TLI->getRegClassFor(LegalIntVT)); RegionPolicy.ShouldTrackPressure = NumRegionInstrs > (NIntRegs / 2); + break; } } @@ -3682,7 +3721,7 @@ SUnit *GenericScheduler::pickNodeBidirectional(bool &IsTopNode) { TCand.reset(CandPolicy()); pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand); assert(TCand.SU == TopCand.SU && - "Last pick result should correspond to re-picking right now"); + "Last pick result should correspond to re-picking right now"); } #endif } @@ -3738,6 +3777,21 @@ SUnit *GenericScheduler::pickNode(bool &IsTopNode) { } } while (SU->isScheduled); + // If IsTopNode, then SU is in Top.Available and must be removed. Otherwise, + // if isTopReady(), then SU is in either Top.Available or Top.Pending. + // If !IsTopNode, then SU is in Bot.Available and must be removed. Otherwise, + // if isBottomReady(), then SU is in either Bot.Available or Bot.Pending. + // + // It is coincidental when !IsTopNode && isTopReady or when IsTopNode && + // isBottomReady. That is, it didn't factor into the decision to choose SU + // because it isTopReady or isBottomReady, respectively. In fact, if the + // RegionPolicy is OnlyTopDown or OnlyBottomUp, then the Bot queues and Top + // queues respectivley contain the original roots and don't get updated when + // picking a node. So if SU isTopReady on a OnlyBottomUp pick, then it was + // because we schduled everything but the top roots. Conversley, if SU + // isBottomReady on OnlyTopDown, then it was because we scheduled everything + // but the bottom roots. If its in a queue even coincidentally, it should be + // removed so it does not get re-picked in a subsequent pickNode call. if (SU->isTopReady()) Top.removeReady(SU); if (SU->isBottomReady()) @@ -3804,6 +3858,12 @@ ScheduleDAGMILive *llvm::createGenericSchedLive(MachineSchedContext *C) { // data and pass it to later mutations. Have a single mutation that gathers // the interesting nodes in one pass. DAG->addMutation(createCopyConstrainDAGMutation(DAG->TII, DAG->TRI)); + + const TargetSubtargetInfo &STI = C->MF->getSubtarget(); + // Add MacroFusion mutation if fusions are not empty. + const auto &MacroFusions = STI.getMacroFusions(); + if (!MacroFusions.empty()) + DAG->addMutation(createMacroFusionDAGMutation(MacroFusions)); return DAG; } @@ -3826,15 +3886,31 @@ void PostGenericScheduler::initialize(ScheduleDAGMI *Dag) { Rem.init(DAG, SchedModel); Top.init(DAG, SchedModel, &Rem); - BotRoots.clear(); + Bot.init(DAG, SchedModel, &Rem); // Initialize the HazardRecognizers. If itineraries don't exist, are empty, // or are disabled, then these HazardRecs will be disabled. const InstrItineraryData *Itin = SchedModel->getInstrItineraries(); if (!Top.HazardRec) { - Top.HazardRec = - DAG->MF.getSubtarget().getInstrInfo()->CreateTargetMIHazardRecognizer( - Itin, DAG); + Top.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG); + } + if (!Bot.HazardRec) { + Bot.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG); + } +} + +void PostGenericScheduler::initPolicy(MachineBasicBlock::iterator Begin, + MachineBasicBlock::iterator End, + unsigned NumRegionInstrs) { + if (PostRADirection == MISchedPostRASched::TopDown) { + RegionPolicy.OnlyTopDown = true; + RegionPolicy.OnlyBottomUp = false; + } else if (PostRADirection == MISchedPostRASched::BottomUp) { + RegionPolicy.OnlyTopDown = false; + RegionPolicy.OnlyBottomUp = true; + } else if (PostRADirection == MISchedPostRASched::Bidirectional) { + RegionPolicy.OnlyBottomUp = false; + RegionPolicy.OnlyTopDown = false; } } @@ -3842,7 +3918,7 @@ void PostGenericScheduler::registerRoots() { Rem.CriticalPath = DAG->ExitSU.getDepth(); // Some roots may not feed into ExitSU. Check all of them in case. - for (const SUnit *SU : BotRoots) { + for (const SUnit *SU : Bot.Available) { if (SU->getDepth() > Rem.CriticalPath) Rem.CriticalPath = SU->getDepth(); } @@ -3899,12 +3975,13 @@ bool PostGenericScheduler::tryCandidate(SchedCandidate &Cand, return false; } -void PostGenericScheduler::pickNodeFromQueue(SchedCandidate &Cand) { - ReadyQueue &Q = Top.Available; +void PostGenericScheduler::pickNodeFromQueue(SchedBoundary &Zone, + SchedCandidate &Cand) { + ReadyQueue &Q = Zone.Available; for (SUnit *SU : Q) { SchedCandidate TryCand(Cand.Policy); TryCand.SU = SU; - TryCand.AtTop = true; + TryCand.AtTop = Zone.isTop(); TryCand.initResourceDelta(DAG, SchedModel); if (tryCandidate(Cand, TryCand)) { Cand.setBest(TryCand); @@ -3913,32 +3990,137 @@ void PostGenericScheduler::pickNodeFromQueue(SchedCandidate &Cand) { } } +/// Pick the best candidate node from either the top or bottom queue. +SUnit *PostGenericScheduler::pickNodeBidirectional(bool &IsTopNode) { + // FIXME: This is similiar to GenericScheduler::pickNodeBidirectional. Factor + // out common parts. + + // Schedule as far as possible in the direction of no choice. This is most + // efficient, but also provides the best heuristics for CriticalPSets. + if (SUnit *SU = Bot.pickOnlyChoice()) { + IsTopNode = false; + tracePick(Only1, false); + return SU; + } + if (SUnit *SU = Top.pickOnlyChoice()) { + IsTopNode = true; + tracePick(Only1, true); + return SU; + } + // Set the bottom-up policy based on the state of the current bottom zone and + // the instructions outside the zone, including the top zone. + CandPolicy BotPolicy; + setPolicy(BotPolicy, /*IsPostRA=*/true, Bot, &Top); + // Set the top-down policy based on the state of the current top zone and + // the instructions outside the zone, including the bottom zone. + CandPolicy TopPolicy; + setPolicy(TopPolicy, /*IsPostRA=*/true, Top, &Bot); + + // See if BotCand is still valid (because we previously scheduled from Top). + LLVM_DEBUG(dbgs() << "Picking from Bot:\n"); + if (!BotCand.isValid() || BotCand.SU->isScheduled || + BotCand.Policy != BotPolicy) { + BotCand.reset(CandPolicy()); + pickNodeFromQueue(Bot, BotCand); + assert(BotCand.Reason != NoCand && "failed to find the first candidate"); + } else { + LLVM_DEBUG(traceCandidate(BotCand)); +#ifndef NDEBUG + if (VerifyScheduling) { + SchedCandidate TCand; + TCand.reset(CandPolicy()); + pickNodeFromQueue(Bot, BotCand); + assert(TCand.SU == BotCand.SU && + "Last pick result should correspond to re-picking right now"); + } +#endif + } + + // Check if the top Q has a better candidate. + LLVM_DEBUG(dbgs() << "Picking from Top:\n"); + if (!TopCand.isValid() || TopCand.SU->isScheduled || + TopCand.Policy != TopPolicy) { + TopCand.reset(CandPolicy()); + pickNodeFromQueue(Top, TopCand); + assert(TopCand.Reason != NoCand && "failed to find the first candidate"); + } else { + LLVM_DEBUG(traceCandidate(TopCand)); +#ifndef NDEBUG + if (VerifyScheduling) { + SchedCandidate TCand; + TCand.reset(CandPolicy()); + pickNodeFromQueue(Top, TopCand); + assert(TCand.SU == TopCand.SU && + "Last pick result should correspond to re-picking right now"); + } +#endif + } + + // Pick best from BotCand and TopCand. + assert(BotCand.isValid()); + assert(TopCand.isValid()); + SchedCandidate Cand = BotCand; + TopCand.Reason = NoCand; + if (tryCandidate(Cand, TopCand)) { + Cand.setBest(TopCand); + LLVM_DEBUG(traceCandidate(Cand)); + } + + IsTopNode = Cand.AtTop; + tracePick(Cand); + return Cand.SU; +} + /// Pick the next node to schedule. SUnit *PostGenericScheduler::pickNode(bool &IsTopNode) { if (DAG->top() == DAG->bottom()) { - assert(Top.Available.empty() && Top.Pending.empty() && "ReadyQ garbage"); + assert(Top.Available.empty() && Top.Pending.empty() && + Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage"); return nullptr; } SUnit *SU; do { - SU = Top.pickOnlyChoice(); - if (SU) { - tracePick(Only1, true); + if (RegionPolicy.OnlyBottomUp) { + SU = Bot.pickOnlyChoice(); + if (SU) { + tracePick(Only1, true); + } else { + CandPolicy NoPolicy; + BotCand.reset(NoPolicy); + // Set the bottom-up policy based on the state of the current bottom + // zone and the instructions outside the zone, including the top zone. + setPolicy(BotCand.Policy, /*IsPostRA=*/true, Bot, nullptr); + pickNodeFromQueue(Bot, BotCand); + assert(BotCand.Reason != NoCand && "failed to find a candidate"); + tracePick(BotCand); + SU = BotCand.SU; + } + IsTopNode = false; + } else if (RegionPolicy.OnlyTopDown) { + SU = Top.pickOnlyChoice(); + if (SU) { + tracePick(Only1, true); + } else { + CandPolicy NoPolicy; + TopCand.reset(NoPolicy); + // Set the top-down policy based on the state of the current top zone + // and the instructions outside the zone, including the bottom zone. + setPolicy(TopCand.Policy, /*IsPostRA=*/true, Top, nullptr); + pickNodeFromQueue(Top, TopCand); + assert(TopCand.Reason != NoCand && "failed to find a candidate"); + tracePick(TopCand); + SU = TopCand.SU; + } + IsTopNode = true; } else { - CandPolicy NoPolicy; - SchedCandidate TopCand(NoPolicy); - // Set the top-down policy based on the state of the current top zone and - // the instructions outside the zone, including the bottom zone. - setPolicy(TopCand.Policy, /*IsPostRA=*/true, Top, nullptr); - pickNodeFromQueue(TopCand); - assert(TopCand.Reason != NoCand && "failed to find a candidate"); - tracePick(TopCand); - SU = TopCand.SU; + SU = pickNodeBidirectional(IsTopNode); } } while (SU->isScheduled); - IsTopNode = true; - Top.removeReady(SU); + if (SU->isTopReady()) + Top.removeReady(SU); + if (SU->isBottomReady()) + Bot.removeReady(SU); LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " << *SU->getInstr()); @@ -3948,13 +4130,25 @@ SUnit *PostGenericScheduler::pickNode(bool &IsTopNode) { /// Called after ScheduleDAGMI has scheduled an instruction and updated /// scheduled/remaining flags in the DAG nodes. void PostGenericScheduler::schedNode(SUnit *SU, bool IsTopNode) { - SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle()); - Top.bumpNode(SU); + if (IsTopNode) { + SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle()); + Top.bumpNode(SU); + } else { + SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle()); + Bot.bumpNode(SU); + } } ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) { - return new ScheduleDAGMI(C, std::make_unique<PostGenericScheduler>(C), - /*RemoveKillFlags=*/true); + ScheduleDAGMI *DAG = + new ScheduleDAGMI(C, std::make_unique<PostGenericScheduler>(C), + /*RemoveKillFlags=*/true); + const TargetSubtargetInfo &STI = C->MF->getSubtarget(); + // Add MacroFusion mutation if fusions are not empty. + const auto &MacroFusions = STI.getMacroFusions(); + if (!MacroFusions.empty()) + DAG->addMutation(createMacroFusionDAGMutation(MacroFusions)); + return DAG; } //===----------------------------------------------------------------------===// @@ -4219,7 +4413,7 @@ struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits { SS << "SU:" << SU->NodeNum; if (DFS) SS << " I:" << DFS->getNumInstrs(SU); - return SS.str(); + return Str; } static std::string getNodeDescription(const SUnit *SU, const ScheduleDAG *G) { @@ -4275,6 +4469,12 @@ unsigned ResourceSegments::getFirstAvailableAt( assert(std::is_sorted(std::begin(_Intervals), std::end(_Intervals), sortIntervals) && "Cannot execute on an un-sorted set of intervals."); + + // Zero resource usage is allowed by TargetSchedule.td but we do not construct + // a ResourceSegment interval for that situation. + if (AcquireAtCycle == ReleaseAtCycle) + return CurrCycle; + unsigned RetCycle = CurrCycle; ResourceSegments::IntervalTy NewInterval = IntervalBuilder(RetCycle, AcquireAtCycle, ReleaseAtCycle); @@ -4294,8 +4494,16 @@ unsigned ResourceSegments::getFirstAvailableAt( void ResourceSegments::add(ResourceSegments::IntervalTy A, const unsigned CutOff) { - assert(A.first < A.second && "Cannot add empty resource usage"); + assert(A.first <= A.second && "Cannot add negative resource usage"); assert(CutOff > 0 && "0-size interval history has no use."); + // Zero resource usage is allowed by TargetSchedule.td, in the case that the + // instruction needed the resource to be available but does not use it. + // However, ResourceSegment represents an interval that is closed on the left + // and open on the right. It is impossible to represent an empty interval when + // the left is closed. Do not add it to Intervals. + if (A.first == A.second) + return; + assert(all_of(_Intervals, [&A](const ResourceSegments::IntervalTy &Interval) -> bool { return !intersects(A, Interval); |