10b57cec5SDimitry Andric //===- MachineScheduler.cpp - Machine Instruction Scheduler ---------------===// 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 // 90b57cec5SDimitry Andric // MachineScheduler schedules machine instructions after phi elimination. It 100b57cec5SDimitry Andric // preserves LiveIntervals so it can be invoked before register allocation. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h" 150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 160b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 170b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 180b57cec5SDimitry Andric #include "llvm/ADT/PriorityQueue.h" 190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 21e8d8bef9SDimitry Andric #include "llvm/ADT/Statistic.h" 220b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h" 230b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/LiveInterval.h" 250b57cec5SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 330b57cec5SDimitry Andric #include "llvm/CodeGen/MachinePassRegistry.h" 340b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 350b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h" 360b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h" 370b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h" 380b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAGInstrs.h" 390b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAGMutation.h" 400b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDFS.h" 410b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h" 420b57cec5SDimitry Andric #include "llvm/CodeGen/SlotIndexes.h" 430b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h" 440b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 450b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 460b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 470b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 480b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSchedule.h" 490b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 50*0fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/MachineValueType.h" 510b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h" 52480093f4SDimitry Andric #include "llvm/InitializePasses.h" 530b57cec5SDimitry Andric #include "llvm/MC/LaneBitmask.h" 540b57cec5SDimitry Andric #include "llvm/Pass.h" 550b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 560b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 570b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 580b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 590b57cec5SDimitry Andric #include "llvm/Support/GraphWriter.h" 600b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 610b57cec5SDimitry Andric #include <algorithm> 620b57cec5SDimitry Andric #include <cassert> 630b57cec5SDimitry Andric #include <cstdint> 640b57cec5SDimitry Andric #include <iterator> 650b57cec5SDimitry Andric #include <limits> 660b57cec5SDimitry Andric #include <memory> 670b57cec5SDimitry Andric #include <string> 680b57cec5SDimitry Andric #include <tuple> 690b57cec5SDimitry Andric #include <utility> 700b57cec5SDimitry Andric #include <vector> 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric using namespace llvm; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler" 750b57cec5SDimitry Andric 76e8d8bef9SDimitry Andric STATISTIC(NumClustered, "Number of load/store pairs clustered"); 77e8d8bef9SDimitry Andric 780b57cec5SDimitry Andric namespace llvm { 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric cl::opt<bool> ForceTopDown("misched-topdown", cl::Hidden, 810b57cec5SDimitry Andric cl::desc("Force top-down list scheduling")); 820b57cec5SDimitry Andric cl::opt<bool> ForceBottomUp("misched-bottomup", cl::Hidden, 830b57cec5SDimitry Andric cl::desc("Force bottom-up list scheduling")); 84*0fca6ea1SDimitry Andric namespace MISchedPostRASched { 85*0fca6ea1SDimitry Andric enum Direction { 86*0fca6ea1SDimitry Andric TopDown, 87*0fca6ea1SDimitry Andric BottomUp, 88*0fca6ea1SDimitry Andric Bidirectional, 89*0fca6ea1SDimitry Andric }; 90*0fca6ea1SDimitry Andric } // end namespace MISchedPostRASched 91*0fca6ea1SDimitry Andric cl::opt<MISchedPostRASched::Direction> PostRADirection( 92*0fca6ea1SDimitry Andric "misched-postra-direction", cl::Hidden, 93*0fca6ea1SDimitry Andric cl::desc("Post reg-alloc list scheduling direction"), 94*0fca6ea1SDimitry Andric // Default to top-down because it was implemented first and existing targets 95*0fca6ea1SDimitry Andric // expect that behavior by default. 96*0fca6ea1SDimitry Andric cl::init(MISchedPostRASched::TopDown), 97*0fca6ea1SDimitry Andric cl::values( 98*0fca6ea1SDimitry Andric clEnumValN(MISchedPostRASched::TopDown, "topdown", 99*0fca6ea1SDimitry Andric "Force top-down post reg-alloc list scheduling"), 100*0fca6ea1SDimitry Andric clEnumValN(MISchedPostRASched::BottomUp, "bottomup", 101*0fca6ea1SDimitry Andric "Force bottom-up post reg-alloc list scheduling"), 102*0fca6ea1SDimitry Andric clEnumValN(MISchedPostRASched::Bidirectional, "bidirectional", 103*0fca6ea1SDimitry Andric "Force bidirectional post reg-alloc list scheduling"))); 1040b57cec5SDimitry Andric cl::opt<bool> 1050b57cec5SDimitry Andric DumpCriticalPathLength("misched-dcpl", cl::Hidden, 1060b57cec5SDimitry Andric cl::desc("Print critical path length to stdout")); 1070b57cec5SDimitry Andric 1088bcb0991SDimitry Andric cl::opt<bool> VerifyScheduling( 1098bcb0991SDimitry Andric "verify-misched", cl::Hidden, 1108bcb0991SDimitry Andric cl::desc("Verify machine instrs before and after machine scheduling")); 1118bcb0991SDimitry Andric 1120eae32dcSDimitry Andric #ifndef NDEBUG 1130eae32dcSDimitry Andric cl::opt<bool> ViewMISchedDAGs( 1140eae32dcSDimitry Andric "view-misched-dags", cl::Hidden, 1150eae32dcSDimitry Andric cl::desc("Pop up a window to show MISched dags after they are processed")); 116753f127fSDimitry Andric cl::opt<bool> PrintDAGs("misched-print-dags", cl::Hidden, 117753f127fSDimitry Andric cl::desc("Print schedule DAGs")); 118bdd1243dSDimitry Andric cl::opt<bool> MISchedDumpReservedCycles( 119bdd1243dSDimitry Andric "misched-dump-reserved-cycles", cl::Hidden, cl::init(false), 120bdd1243dSDimitry Andric cl::desc("Dump resource usage at schedule boundary.")); 12106c3fb27SDimitry Andric cl::opt<bool> MischedDetailResourceBooking( 12206c3fb27SDimitry Andric "misched-detail-resource-booking", cl::Hidden, cl::init(false), 12306c3fb27SDimitry Andric cl::desc("Show details of invoking getNextResoufceCycle.")); 1240eae32dcSDimitry Andric #else 1250eae32dcSDimitry Andric const bool ViewMISchedDAGs = false; 126753f127fSDimitry Andric const bool PrintDAGs = false; 12706c3fb27SDimitry Andric const bool MischedDetailResourceBooking = false; 128bdd1243dSDimitry Andric #ifdef LLVM_ENABLE_DUMP 129bdd1243dSDimitry Andric const bool MISchedDumpReservedCycles = false; 130bdd1243dSDimitry Andric #endif // LLVM_ENABLE_DUMP 1310eae32dcSDimitry Andric #endif // NDEBUG 1320eae32dcSDimitry Andric 1330b57cec5SDimitry Andric } // end namespace llvm 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric #ifndef NDEBUG 1360b57cec5SDimitry Andric /// In some situations a few uninteresting nodes depend on nearly all other 1370b57cec5SDimitry Andric /// nodes in the graph, provide a cutoff to hide them. 1380b57cec5SDimitry Andric static cl::opt<unsigned> ViewMISchedCutoff("view-misched-cutoff", cl::Hidden, 1390b57cec5SDimitry Andric cl::desc("Hide nodes with more predecessor/successor than cutoff")); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric static cl::opt<unsigned> MISchedCutoff("misched-cutoff", cl::Hidden, 1420b57cec5SDimitry Andric cl::desc("Stop scheduling after N instructions"), cl::init(~0U)); 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric static cl::opt<std::string> SchedOnlyFunc("misched-only-func", cl::Hidden, 1450b57cec5SDimitry Andric cl::desc("Only schedule this function")); 1460b57cec5SDimitry Andric static cl::opt<unsigned> SchedOnlyBlock("misched-only-block", cl::Hidden, 1470b57cec5SDimitry Andric cl::desc("Only schedule this MBB#")); 1480b57cec5SDimitry Andric #endif // NDEBUG 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric /// Avoid quadratic complexity in unusually large basic blocks by limiting the 1510b57cec5SDimitry Andric /// size of the ready lists. 1520b57cec5SDimitry Andric static cl::opt<unsigned> ReadyListLimit("misched-limit", cl::Hidden, 1530b57cec5SDimitry Andric cl::desc("Limit ready list to N instructions"), cl::init(256)); 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric static cl::opt<bool> EnableRegPressure("misched-regpressure", cl::Hidden, 1560b57cec5SDimitry Andric cl::desc("Enable register pressure scheduling."), cl::init(true)); 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric static cl::opt<bool> EnableCyclicPath("misched-cyclicpath", cl::Hidden, 1590b57cec5SDimitry Andric cl::desc("Enable cyclic critical path analysis."), cl::init(true)); 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric static cl::opt<bool> EnableMemOpCluster("misched-cluster", cl::Hidden, 1620b57cec5SDimitry Andric cl::desc("Enable memop clustering."), 1630b57cec5SDimitry Andric cl::init(true)); 164e8d8bef9SDimitry Andric static cl::opt<bool> 165e8d8bef9SDimitry Andric ForceFastCluster("force-fast-cluster", cl::Hidden, 166e8d8bef9SDimitry Andric cl::desc("Switch to fast cluster algorithm with the lost " 167e8d8bef9SDimitry Andric "of some fusion opportunities"), 168e8d8bef9SDimitry Andric cl::init(false)); 169e8d8bef9SDimitry Andric static cl::opt<unsigned> 170e8d8bef9SDimitry Andric FastClusterThreshold("fast-cluster-threshold", cl::Hidden, 171e8d8bef9SDimitry Andric cl::desc("The threshold for fast cluster"), 172e8d8bef9SDimitry Andric cl::init(1000)); 1730b57cec5SDimitry Andric 17406c3fb27SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 17506c3fb27SDimitry Andric static cl::opt<bool> MISchedDumpScheduleTrace( 17606c3fb27SDimitry Andric "misched-dump-schedule-trace", cl::Hidden, cl::init(false), 17706c3fb27SDimitry Andric cl::desc("Dump resource usage at schedule boundary.")); 17806c3fb27SDimitry Andric static cl::opt<unsigned> 17906c3fb27SDimitry Andric HeaderColWidth("misched-dump-schedule-trace-col-header-width", cl::Hidden, 18006c3fb27SDimitry Andric cl::desc("Set width of the columns with " 18106c3fb27SDimitry Andric "the resources and schedule units"), 18206c3fb27SDimitry Andric cl::init(19)); 18306c3fb27SDimitry Andric static cl::opt<unsigned> 18406c3fb27SDimitry Andric ColWidth("misched-dump-schedule-trace-col-width", cl::Hidden, 18506c3fb27SDimitry Andric cl::desc("Set width of the columns showing resource booking."), 18606c3fb27SDimitry Andric cl::init(5)); 18706c3fb27SDimitry Andric static cl::opt<bool> MISchedSortResourcesInTrace( 18806c3fb27SDimitry Andric "misched-sort-resources-in-trace", cl::Hidden, cl::init(true), 18906c3fb27SDimitry Andric cl::desc("Sort the resources printed in the dump trace")); 19006c3fb27SDimitry Andric #endif 19106c3fb27SDimitry Andric 19206c3fb27SDimitry Andric static cl::opt<unsigned> 19306c3fb27SDimitry Andric MIResourceCutOff("misched-resource-cutoff", cl::Hidden, 19406c3fb27SDimitry Andric cl::desc("Number of intervals to track"), cl::init(10)); 19506c3fb27SDimitry Andric 1960b57cec5SDimitry Andric // DAG subtrees must have at least this many nodes. 1970b57cec5SDimitry Andric static const unsigned MinSubtreeSize = 8; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric // Pin the vtables to this file. 2000b57cec5SDimitry Andric void MachineSchedStrategy::anchor() {} 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric void ScheduleDAGMutation::anchor() {} 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2050b57cec5SDimitry Andric // Machine Instruction Scheduling Pass and Registry 2060b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric MachineSchedContext::MachineSchedContext() { 2090b57cec5SDimitry Andric RegClassInfo = new RegisterClassInfo(); 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric MachineSchedContext::~MachineSchedContext() { 2130b57cec5SDimitry Andric delete RegClassInfo; 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric namespace { 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric /// Base class for a machine scheduler class that can run at any point. 2190b57cec5SDimitry Andric class MachineSchedulerBase : public MachineSchedContext, 2200b57cec5SDimitry Andric public MachineFunctionPass { 2210b57cec5SDimitry Andric public: 2220b57cec5SDimitry Andric MachineSchedulerBase(char &ID): MachineFunctionPass(ID) {} 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric void print(raw_ostream &O, const Module* = nullptr) const override; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric protected: 2270b57cec5SDimitry Andric void scheduleRegions(ScheduleDAGInstrs &Scheduler, bool FixKillFlags); 2280b57cec5SDimitry Andric }; 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric /// MachineScheduler runs after coalescing and before register allocation. 2310b57cec5SDimitry Andric class MachineScheduler : public MachineSchedulerBase { 2320b57cec5SDimitry Andric public: 2330b57cec5SDimitry Andric MachineScheduler(); 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction&) override; 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric static char ID; // Class identification, replacement for typeinfo 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric protected: 2420b57cec5SDimitry Andric ScheduleDAGInstrs *createMachineScheduler(); 2430b57cec5SDimitry Andric }; 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric /// PostMachineScheduler runs after shortly before code emission. 2460b57cec5SDimitry Andric class PostMachineScheduler : public MachineSchedulerBase { 2470b57cec5SDimitry Andric public: 2480b57cec5SDimitry Andric PostMachineScheduler(); 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction&) override; 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric static char ID; // Class identification, replacement for typeinfo 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric protected: 2570b57cec5SDimitry Andric ScheduleDAGInstrs *createPostMachineScheduler(); 2580b57cec5SDimitry Andric }; 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric } // end anonymous namespace 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric char MachineScheduler::ID = 0; 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric char &llvm::MachineSchedulerID = MachineScheduler::ID; 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(MachineScheduler, DEBUG_TYPE, 2670b57cec5SDimitry Andric "Machine Instruction Scheduler", false, false) 2680b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) 269*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) 270*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass) 271*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass) 272*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass) 2730b57cec5SDimitry Andric INITIALIZE_PASS_END(MachineScheduler, DEBUG_TYPE, 2740b57cec5SDimitry Andric "Machine Instruction Scheduler", false, false) 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric MachineScheduler::MachineScheduler() : MachineSchedulerBase(ID) { 2770b57cec5SDimitry Andric initializeMachineSchedulerPass(*PassRegistry::getPassRegistry()); 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric void MachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const { 2810b57cec5SDimitry Andric AU.setPreservesCFG(); 282*0fca6ea1SDimitry Andric AU.addRequired<MachineDominatorTreeWrapperPass>(); 283*0fca6ea1SDimitry Andric AU.addRequired<MachineLoopInfoWrapperPass>(); 2840b57cec5SDimitry Andric AU.addRequired<AAResultsWrapperPass>(); 2850b57cec5SDimitry Andric AU.addRequired<TargetPassConfig>(); 286*0fca6ea1SDimitry Andric AU.addRequired<SlotIndexesWrapperPass>(); 287*0fca6ea1SDimitry Andric AU.addPreserved<SlotIndexesWrapperPass>(); 288*0fca6ea1SDimitry Andric AU.addRequired<LiveIntervalsWrapperPass>(); 289*0fca6ea1SDimitry Andric AU.addPreserved<LiveIntervalsWrapperPass>(); 2900b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric char PostMachineScheduler::ID = 0; 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric char &llvm::PostMachineSchedulerID = PostMachineScheduler::ID; 2960b57cec5SDimitry Andric 297e8d8bef9SDimitry Andric INITIALIZE_PASS_BEGIN(PostMachineScheduler, "postmisched", 298e8d8bef9SDimitry Andric "PostRA Machine Instruction Scheduler", false, false) 299*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) 300*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass) 301e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) 302e8d8bef9SDimitry Andric INITIALIZE_PASS_END(PostMachineScheduler, "postmisched", 3030b57cec5SDimitry Andric "PostRA Machine Instruction Scheduler", false, false) 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric PostMachineScheduler::PostMachineScheduler() : MachineSchedulerBase(ID) { 3060b57cec5SDimitry Andric initializePostMachineSchedulerPass(*PassRegistry::getPassRegistry()); 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric void PostMachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const { 3100b57cec5SDimitry Andric AU.setPreservesCFG(); 311*0fca6ea1SDimitry Andric AU.addRequired<MachineDominatorTreeWrapperPass>(); 312*0fca6ea1SDimitry Andric AU.addRequired<MachineLoopInfoWrapperPass>(); 313480093f4SDimitry Andric AU.addRequired<AAResultsWrapperPass>(); 3140b57cec5SDimitry Andric AU.addRequired<TargetPassConfig>(); 3150b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric MachinePassRegistry<MachineSchedRegistry::ScheduleDAGCtor> 3190b57cec5SDimitry Andric MachineSchedRegistry::Registry; 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric /// A dummy default scheduler factory indicates whether the scheduler 3220b57cec5SDimitry Andric /// is overridden on the command line. 3230b57cec5SDimitry Andric static ScheduleDAGInstrs *useDefaultMachineSched(MachineSchedContext *C) { 3240b57cec5SDimitry Andric return nullptr; 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric /// MachineSchedOpt allows command line selection of the scheduler. 3280b57cec5SDimitry Andric static cl::opt<MachineSchedRegistry::ScheduleDAGCtor, false, 3290b57cec5SDimitry Andric RegisterPassParser<MachineSchedRegistry>> 3300b57cec5SDimitry Andric MachineSchedOpt("misched", 3310b57cec5SDimitry Andric cl::init(&useDefaultMachineSched), cl::Hidden, 3320b57cec5SDimitry Andric cl::desc("Machine instruction scheduler to use")); 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric static MachineSchedRegistry 3350b57cec5SDimitry Andric DefaultSchedRegistry("default", "Use the target's default scheduler choice.", 3360b57cec5SDimitry Andric useDefaultMachineSched); 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric static cl::opt<bool> EnableMachineSched( 3390b57cec5SDimitry Andric "enable-misched", 3400b57cec5SDimitry Andric cl::desc("Enable the machine instruction scheduling pass."), cl::init(true), 3410b57cec5SDimitry Andric cl::Hidden); 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric static cl::opt<bool> EnablePostRAMachineSched( 3440b57cec5SDimitry Andric "enable-post-misched", 3450b57cec5SDimitry Andric cl::desc("Enable the post-ra machine instruction scheduling pass."), 3460b57cec5SDimitry Andric cl::init(true), cl::Hidden); 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric /// Decrement this iterator until reaching the top or a non-debug instr. 3490b57cec5SDimitry Andric static MachineBasicBlock::const_iterator 3500b57cec5SDimitry Andric priorNonDebug(MachineBasicBlock::const_iterator I, 3510b57cec5SDimitry Andric MachineBasicBlock::const_iterator Beg) { 3520b57cec5SDimitry Andric assert(I != Beg && "reached the top of the region, cannot decrement"); 3530b57cec5SDimitry Andric while (--I != Beg) { 354fe6060f1SDimitry Andric if (!I->isDebugOrPseudoInstr()) 3550b57cec5SDimitry Andric break; 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric return I; 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric /// Non-const version. 3610b57cec5SDimitry Andric static MachineBasicBlock::iterator 3620b57cec5SDimitry Andric priorNonDebug(MachineBasicBlock::iterator I, 3630b57cec5SDimitry Andric MachineBasicBlock::const_iterator Beg) { 3640b57cec5SDimitry Andric return priorNonDebug(MachineBasicBlock::const_iterator(I), Beg) 3650b57cec5SDimitry Andric .getNonConstIterator(); 3660b57cec5SDimitry Andric } 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric /// If this iterator is a debug value, increment until reaching the End or a 3690b57cec5SDimitry Andric /// non-debug instruction. 3700b57cec5SDimitry Andric static MachineBasicBlock::const_iterator 3710b57cec5SDimitry Andric nextIfDebug(MachineBasicBlock::const_iterator I, 3720b57cec5SDimitry Andric MachineBasicBlock::const_iterator End) { 3730b57cec5SDimitry Andric for(; I != End; ++I) { 374fe6060f1SDimitry Andric if (!I->isDebugOrPseudoInstr()) 3750b57cec5SDimitry Andric break; 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric return I; 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric /// Non-const version. 3810b57cec5SDimitry Andric static MachineBasicBlock::iterator 3820b57cec5SDimitry Andric nextIfDebug(MachineBasicBlock::iterator I, 3830b57cec5SDimitry Andric MachineBasicBlock::const_iterator End) { 3840b57cec5SDimitry Andric return nextIfDebug(MachineBasicBlock::const_iterator(I), End) 3850b57cec5SDimitry Andric .getNonConstIterator(); 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric /// Instantiate a ScheduleDAGInstrs that will be owned by the caller. 3890b57cec5SDimitry Andric ScheduleDAGInstrs *MachineScheduler::createMachineScheduler() { 3900b57cec5SDimitry Andric // Select the scheduler, or set the default. 3910b57cec5SDimitry Andric MachineSchedRegistry::ScheduleDAGCtor Ctor = MachineSchedOpt; 3920b57cec5SDimitry Andric if (Ctor != useDefaultMachineSched) 3930b57cec5SDimitry Andric return Ctor(this); 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric // Get the default scheduler set by the target for this function. 3960b57cec5SDimitry Andric ScheduleDAGInstrs *Scheduler = PassConfig->createMachineScheduler(this); 3970b57cec5SDimitry Andric if (Scheduler) 3980b57cec5SDimitry Andric return Scheduler; 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric // Default to GenericScheduler. 4010b57cec5SDimitry Andric return createGenericSchedLive(this); 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric /// Instantiate a ScheduleDAGInstrs for PostRA scheduling that will be owned by 4050b57cec5SDimitry Andric /// the caller. We don't have a command line option to override the postRA 4060b57cec5SDimitry Andric /// scheduler. The Target must configure it. 4070b57cec5SDimitry Andric ScheduleDAGInstrs *PostMachineScheduler::createPostMachineScheduler() { 4080b57cec5SDimitry Andric // Get the postRA scheduler set by the target for this function. 4090b57cec5SDimitry Andric ScheduleDAGInstrs *Scheduler = PassConfig->createPostMachineScheduler(this); 4100b57cec5SDimitry Andric if (Scheduler) 4110b57cec5SDimitry Andric return Scheduler; 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric // Default to GenericScheduler. 4140b57cec5SDimitry Andric return createGenericSchedPostRA(this); 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric /// Top-level MachineScheduler pass driver. 4180b57cec5SDimitry Andric /// 4190b57cec5SDimitry Andric /// Visit blocks in function order. Divide each block into scheduling regions 4200b57cec5SDimitry Andric /// and visit them bottom-up. Visiting regions bottom-up is not required, but is 4210b57cec5SDimitry Andric /// consistent with the DAG builder, which traverses the interior of the 4220b57cec5SDimitry Andric /// scheduling regions bottom-up. 4230b57cec5SDimitry Andric /// 4240b57cec5SDimitry Andric /// This design avoids exposing scheduling boundaries to the DAG builder, 4250b57cec5SDimitry Andric /// simplifying the DAG builder's support for "special" target instructions. 4260b57cec5SDimitry Andric /// At the same time the design allows target schedulers to operate across 4270b57cec5SDimitry Andric /// scheduling boundaries, for example to bundle the boundary instructions 4280b57cec5SDimitry Andric /// without reordering them. This creates complexity, because the target 4290b57cec5SDimitry Andric /// scheduler must update the RegionBegin and RegionEnd positions cached by 4300b57cec5SDimitry Andric /// ScheduleDAGInstrs whenever adding or removing instructions. A much simpler 4310b57cec5SDimitry Andric /// design would be to split blocks at scheduling boundaries, but LLVM has a 4320b57cec5SDimitry Andric /// general bias against block splitting purely for implementation simplicity. 4330b57cec5SDimitry Andric bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) { 4340b57cec5SDimitry Andric if (skipFunction(mf.getFunction())) 4350b57cec5SDimitry Andric return false; 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric if (EnableMachineSched.getNumOccurrences()) { 4380b57cec5SDimitry Andric if (!EnableMachineSched) 4390b57cec5SDimitry Andric return false; 4400b57cec5SDimitry Andric } else if (!mf.getSubtarget().enableMachineScheduler()) 4410b57cec5SDimitry Andric return false; 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Before MISched:\n"; mf.print(dbgs())); 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric // Initialize the context of the pass. 4460b57cec5SDimitry Andric MF = &mf; 447*0fca6ea1SDimitry Andric MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI(); 448*0fca6ea1SDimitry Andric MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 4490b57cec5SDimitry Andric PassConfig = &getAnalysis<TargetPassConfig>(); 4500b57cec5SDimitry Andric AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); 4510b57cec5SDimitry Andric 452*0fca6ea1SDimitry Andric LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS(); 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric if (VerifyScheduling) { 4550b57cec5SDimitry Andric LLVM_DEBUG(LIS->dump()); 4560b57cec5SDimitry Andric MF->verify(this, "Before machine scheduling."); 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric RegClassInfo->runOnMachineFunction(*MF); 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric // Instantiate the selected scheduler for this target, function, and 4610b57cec5SDimitry Andric // optimization level. 4620b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGInstrs> Scheduler(createMachineScheduler()); 463*0fca6ea1SDimitry Andric ScheduleDAGMI::DumpDirection D; 464*0fca6ea1SDimitry Andric if (ForceTopDown) 465*0fca6ea1SDimitry Andric D = ScheduleDAGMI::DumpDirection::TopDown; 466*0fca6ea1SDimitry Andric else if (ForceBottomUp) 467*0fca6ea1SDimitry Andric D = ScheduleDAGMI::DumpDirection::BottomUp; 468*0fca6ea1SDimitry Andric else 469*0fca6ea1SDimitry Andric D = ScheduleDAGMI::DumpDirection::Bidirectional; 470*0fca6ea1SDimitry Andric Scheduler->setDumpDirection(D); 4710b57cec5SDimitry Andric scheduleRegions(*Scheduler, false); 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric LLVM_DEBUG(LIS->dump()); 4740b57cec5SDimitry Andric if (VerifyScheduling) 4750b57cec5SDimitry Andric MF->verify(this, "After machine scheduling."); 4760b57cec5SDimitry Andric return true; 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric bool PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) { 4800b57cec5SDimitry Andric if (skipFunction(mf.getFunction())) 4810b57cec5SDimitry Andric return false; 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric if (EnablePostRAMachineSched.getNumOccurrences()) { 4840b57cec5SDimitry Andric if (!EnablePostRAMachineSched) 4850b57cec5SDimitry Andric return false; 486480093f4SDimitry Andric } else if (!mf.getSubtarget().enablePostRAMachineScheduler()) { 4870b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Subtarget disables post-MI-sched.\n"); 4880b57cec5SDimitry Andric return false; 4890b57cec5SDimitry Andric } 4900b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Before post-MI-sched:\n"; mf.print(dbgs())); 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric // Initialize the context of the pass. 4930b57cec5SDimitry Andric MF = &mf; 494*0fca6ea1SDimitry Andric MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI(); 4950b57cec5SDimitry Andric PassConfig = &getAnalysis<TargetPassConfig>(); 496480093f4SDimitry Andric AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric if (VerifyScheduling) 4990b57cec5SDimitry Andric MF->verify(this, "Before post machine scheduling."); 5000b57cec5SDimitry Andric 5010b57cec5SDimitry Andric // Instantiate the selected scheduler for this target, function, and 5020b57cec5SDimitry Andric // optimization level. 5030b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGInstrs> Scheduler(createPostMachineScheduler()); 504*0fca6ea1SDimitry Andric ScheduleDAGMI::DumpDirection D; 505*0fca6ea1SDimitry Andric if (PostRADirection == MISchedPostRASched::TopDown) 506*0fca6ea1SDimitry Andric D = ScheduleDAGMI::DumpDirection::TopDown; 507*0fca6ea1SDimitry Andric else if (PostRADirection == MISchedPostRASched::BottomUp) 508*0fca6ea1SDimitry Andric D = ScheduleDAGMI::DumpDirection::BottomUp; 509*0fca6ea1SDimitry Andric else 510*0fca6ea1SDimitry Andric D = ScheduleDAGMI::DumpDirection::Bidirectional; 511*0fca6ea1SDimitry Andric Scheduler->setDumpDirection(D); 5120b57cec5SDimitry Andric scheduleRegions(*Scheduler, true); 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric if (VerifyScheduling) 5150b57cec5SDimitry Andric MF->verify(this, "After post machine scheduling."); 5160b57cec5SDimitry Andric return true; 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric /// Return true of the given instruction should not be included in a scheduling 5200b57cec5SDimitry Andric /// region. 5210b57cec5SDimitry Andric /// 5220b57cec5SDimitry Andric /// MachineScheduler does not currently support scheduling across calls. To 5230b57cec5SDimitry Andric /// handle calls, the DAG builder needs to be modified to create register 5240b57cec5SDimitry Andric /// anti/output dependencies on the registers clobbered by the call's regmask 5250b57cec5SDimitry Andric /// operand. In PreRA scheduling, the stack pointer adjustment already prevents 5260b57cec5SDimitry Andric /// scheduling across calls. In PostRA scheduling, we need the isCall to enforce 5270b57cec5SDimitry Andric /// the boundary, but there would be no benefit to postRA scheduling across 5280b57cec5SDimitry Andric /// calls this late anyway. 5290b57cec5SDimitry Andric static bool isSchedBoundary(MachineBasicBlock::iterator MI, 5300b57cec5SDimitry Andric MachineBasicBlock *MBB, 5310b57cec5SDimitry Andric MachineFunction *MF, 5320b57cec5SDimitry Andric const TargetInstrInfo *TII) { 5330b57cec5SDimitry Andric return MI->isCall() || TII->isSchedulingBoundary(*MI, MBB, *MF); 5340b57cec5SDimitry Andric } 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric /// A region of an MBB for scheduling. 5370b57cec5SDimitry Andric namespace { 5380b57cec5SDimitry Andric struct SchedRegion { 5390b57cec5SDimitry Andric /// RegionBegin is the first instruction in the scheduling region, and 5400b57cec5SDimitry Andric /// RegionEnd is either MBB->end() or the scheduling boundary after the 5410b57cec5SDimitry Andric /// last instruction in the scheduling region. These iterators cannot refer 5420b57cec5SDimitry Andric /// to instructions outside of the identified scheduling region because 5430b57cec5SDimitry Andric /// those may be reordered before scheduling this region. 5440b57cec5SDimitry Andric MachineBasicBlock::iterator RegionBegin; 5450b57cec5SDimitry Andric MachineBasicBlock::iterator RegionEnd; 5460b57cec5SDimitry Andric unsigned NumRegionInstrs; 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric SchedRegion(MachineBasicBlock::iterator B, MachineBasicBlock::iterator E, 5490b57cec5SDimitry Andric unsigned N) : 5500b57cec5SDimitry Andric RegionBegin(B), RegionEnd(E), NumRegionInstrs(N) {} 5510b57cec5SDimitry Andric }; 5520b57cec5SDimitry Andric } // end anonymous namespace 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric using MBBRegionsVector = SmallVector<SchedRegion, 16>; 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric static void 5570b57cec5SDimitry Andric getSchedRegions(MachineBasicBlock *MBB, 5580b57cec5SDimitry Andric MBBRegionsVector &Regions, 5590b57cec5SDimitry Andric bool RegionsTopDown) { 5600b57cec5SDimitry Andric MachineFunction *MF = MBB->getParent(); 5610b57cec5SDimitry Andric const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric MachineBasicBlock::iterator I = nullptr; 5640b57cec5SDimitry Andric for(MachineBasicBlock::iterator RegionEnd = MBB->end(); 5650b57cec5SDimitry Andric RegionEnd != MBB->begin(); RegionEnd = I) { 5660b57cec5SDimitry Andric 5670b57cec5SDimitry Andric // Avoid decrementing RegionEnd for blocks with no terminator. 5680b57cec5SDimitry Andric if (RegionEnd != MBB->end() || 5690b57cec5SDimitry Andric isSchedBoundary(&*std::prev(RegionEnd), &*MBB, MF, TII)) { 5700b57cec5SDimitry Andric --RegionEnd; 5710b57cec5SDimitry Andric } 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric // The next region starts above the previous region. Look backward in the 5740b57cec5SDimitry Andric // instruction stream until we find the nearest boundary. 5750b57cec5SDimitry Andric unsigned NumRegionInstrs = 0; 5760b57cec5SDimitry Andric I = RegionEnd; 5770b57cec5SDimitry Andric for (;I != MBB->begin(); --I) { 5780b57cec5SDimitry Andric MachineInstr &MI = *std::prev(I); 5790b57cec5SDimitry Andric if (isSchedBoundary(&MI, &*MBB, MF, TII)) 5800b57cec5SDimitry Andric break; 581fe6060f1SDimitry Andric if (!MI.isDebugOrPseudoInstr()) { 5820b57cec5SDimitry Andric // MBB::size() uses instr_iterator to count. Here we need a bundle to 5830b57cec5SDimitry Andric // count as a single instruction. 5840b57cec5SDimitry Andric ++NumRegionInstrs; 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric // It's possible we found a scheduling region that only has debug 5890b57cec5SDimitry Andric // instructions. Don't bother scheduling these. 5900b57cec5SDimitry Andric if (NumRegionInstrs != 0) 5910b57cec5SDimitry Andric Regions.push_back(SchedRegion(I, RegionEnd, NumRegionInstrs)); 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric if (RegionsTopDown) 5950b57cec5SDimitry Andric std::reverse(Regions.begin(), Regions.end()); 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric /// Main driver for both MachineScheduler and PostMachineScheduler. 5990b57cec5SDimitry Andric void MachineSchedulerBase::scheduleRegions(ScheduleDAGInstrs &Scheduler, 6000b57cec5SDimitry Andric bool FixKillFlags) { 6010b57cec5SDimitry Andric // Visit all machine basic blocks. 6020b57cec5SDimitry Andric // 6030b57cec5SDimitry Andric // TODO: Visit blocks in global postorder or postorder within the bottom-up 6040b57cec5SDimitry Andric // loop tree. Then we can optionally compute global RegPressure. 6050b57cec5SDimitry Andric for (MachineFunction::iterator MBB = MF->begin(), MBBEnd = MF->end(); 6060b57cec5SDimitry Andric MBB != MBBEnd; ++MBB) { 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric Scheduler.startBlock(&*MBB); 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric #ifndef NDEBUG 6110b57cec5SDimitry Andric if (SchedOnlyFunc.getNumOccurrences() && SchedOnlyFunc != MF->getName()) 6120b57cec5SDimitry Andric continue; 6130b57cec5SDimitry Andric if (SchedOnlyBlock.getNumOccurrences() 6140b57cec5SDimitry Andric && (int)SchedOnlyBlock != MBB->getNumber()) 6150b57cec5SDimitry Andric continue; 6160b57cec5SDimitry Andric #endif 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric // Break the block into scheduling regions [I, RegionEnd). RegionEnd 6190b57cec5SDimitry Andric // points to the scheduling boundary at the bottom of the region. The DAG 6200b57cec5SDimitry Andric // does not include RegionEnd, but the region does (i.e. the next 6210b57cec5SDimitry Andric // RegionEnd is above the previous RegionBegin). If the current block has 6220b57cec5SDimitry Andric // no terminator then RegionEnd == MBB->end() for the bottom region. 6230b57cec5SDimitry Andric // 6240b57cec5SDimitry Andric // All the regions of MBB are first found and stored in MBBRegions, which 6250b57cec5SDimitry Andric // will be processed (MBB) top-down if initialized with true. 6260b57cec5SDimitry Andric // 6270b57cec5SDimitry Andric // The Scheduler may insert instructions during either schedule() or 6280b57cec5SDimitry Andric // exitRegion(), even for empty regions. So the local iterators 'I' and 6290b57cec5SDimitry Andric // 'RegionEnd' are invalid across these calls. Instructions must not be 6300b57cec5SDimitry Andric // added to other regions than the current one without updating MBBRegions. 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric MBBRegionsVector MBBRegions; 6330b57cec5SDimitry Andric getSchedRegions(&*MBB, MBBRegions, Scheduler.doMBBSchedRegionsTopDown()); 6340eae32dcSDimitry Andric for (const SchedRegion &R : MBBRegions) { 6350eae32dcSDimitry Andric MachineBasicBlock::iterator I = R.RegionBegin; 6360eae32dcSDimitry Andric MachineBasicBlock::iterator RegionEnd = R.RegionEnd; 6370eae32dcSDimitry Andric unsigned NumRegionInstrs = R.NumRegionInstrs; 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric // Notify the scheduler of the region, even if we may skip scheduling 6400b57cec5SDimitry Andric // it. Perhaps it still needs to be bundled. 6410b57cec5SDimitry Andric Scheduler.enterRegion(&*MBB, I, RegionEnd, NumRegionInstrs); 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric // Skip empty scheduling regions (0 or 1 schedulable instructions). 6440b57cec5SDimitry Andric if (I == RegionEnd || I == std::prev(RegionEnd)) { 6450b57cec5SDimitry Andric // Close the current region. Bundle the terminator if needed. 6460b57cec5SDimitry Andric // This invalidates 'RegionEnd' and 'I'. 6470b57cec5SDimitry Andric Scheduler.exitRegion(); 6480b57cec5SDimitry Andric continue; 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n"); 6510b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << MF->getName() << ":" << printMBBReference(*MBB) 6520b57cec5SDimitry Andric << " " << MBB->getName() << "\n From: " << *I 6530b57cec5SDimitry Andric << " To: "; 6540b57cec5SDimitry Andric if (RegionEnd != MBB->end()) dbgs() << *RegionEnd; 655349cc55cSDimitry Andric else dbgs() << "End\n"; 6560b57cec5SDimitry Andric dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n'); 6570b57cec5SDimitry Andric if (DumpCriticalPathLength) { 6580b57cec5SDimitry Andric errs() << MF->getName(); 6590b57cec5SDimitry Andric errs() << ":%bb. " << MBB->getNumber(); 6600b57cec5SDimitry Andric errs() << " " << MBB->getName() << " \n"; 6610b57cec5SDimitry Andric } 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric // Schedule a region: possibly reorder instructions. 6640b57cec5SDimitry Andric // This invalidates the original region iterators. 6650b57cec5SDimitry Andric Scheduler.schedule(); 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric // Close the current region. 6680b57cec5SDimitry Andric Scheduler.exitRegion(); 6690b57cec5SDimitry Andric } 6700b57cec5SDimitry Andric Scheduler.finishBlock(); 6710b57cec5SDimitry Andric // FIXME: Ideally, no further passes should rely on kill flags. However, 6720b57cec5SDimitry Andric // thumb2 size reduction is currently an exception, so the PostMIScheduler 6730b57cec5SDimitry Andric // needs to do this. 6740b57cec5SDimitry Andric if (FixKillFlags) 6750b57cec5SDimitry Andric Scheduler.fixupKills(*MBB); 6760b57cec5SDimitry Andric } 6770b57cec5SDimitry Andric Scheduler.finalizeSchedule(); 6780b57cec5SDimitry Andric } 6790b57cec5SDimitry Andric 6800b57cec5SDimitry Andric void MachineSchedulerBase::print(raw_ostream &O, const Module* m) const { 6810b57cec5SDimitry Andric // unimplemented 6820b57cec5SDimitry Andric } 6830b57cec5SDimitry Andric 6840b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 6850b57cec5SDimitry Andric LLVM_DUMP_METHOD void ReadyQueue::dump() const { 6860b57cec5SDimitry Andric dbgs() << "Queue " << Name << ": "; 6870b57cec5SDimitry Andric for (const SUnit *SU : Queue) 6880b57cec5SDimitry Andric dbgs() << SU->NodeNum << " "; 6890b57cec5SDimitry Andric dbgs() << "\n"; 6900b57cec5SDimitry Andric } 6910b57cec5SDimitry Andric #endif 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 6940b57cec5SDimitry Andric // ScheduleDAGMI - Basic machine instruction scheduling. This is 6950b57cec5SDimitry Andric // independent of PreRA/PostRA scheduling and involves no extra book-keeping for 6960b57cec5SDimitry Andric // virtual registers. 6970b57cec5SDimitry Andric // ===----------------------------------------------------------------------===/ 6980b57cec5SDimitry Andric 6990b57cec5SDimitry Andric // Provide a vtable anchor. 7000b57cec5SDimitry Andric ScheduleDAGMI::~ScheduleDAGMI() = default; 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric /// ReleaseSucc - Decrement the NumPredsLeft count of a successor. When 7030b57cec5SDimitry Andric /// NumPredsLeft reaches zero, release the successor node. 7040b57cec5SDimitry Andric /// 7050b57cec5SDimitry Andric /// FIXME: Adjust SuccSU height based on MinLatency. 7060b57cec5SDimitry Andric void ScheduleDAGMI::releaseSucc(SUnit *SU, SDep *SuccEdge) { 7070b57cec5SDimitry Andric SUnit *SuccSU = SuccEdge->getSUnit(); 7080b57cec5SDimitry Andric 7090b57cec5SDimitry Andric if (SuccEdge->isWeak()) { 7100b57cec5SDimitry Andric --SuccSU->WeakPredsLeft; 7110b57cec5SDimitry Andric if (SuccEdge->isCluster()) 7120b57cec5SDimitry Andric NextClusterSucc = SuccSU; 7130b57cec5SDimitry Andric return; 7140b57cec5SDimitry Andric } 7150b57cec5SDimitry Andric #ifndef NDEBUG 7160b57cec5SDimitry Andric if (SuccSU->NumPredsLeft == 0) { 7170b57cec5SDimitry Andric dbgs() << "*** Scheduling failed! ***\n"; 7180b57cec5SDimitry Andric dumpNode(*SuccSU); 7190b57cec5SDimitry Andric dbgs() << " has been released too many times!\n"; 7200b57cec5SDimitry Andric llvm_unreachable(nullptr); 7210b57cec5SDimitry Andric } 7220b57cec5SDimitry Andric #endif 7230b57cec5SDimitry Andric // SU->TopReadyCycle was set to CurrCycle when it was scheduled. However, 7240b57cec5SDimitry Andric // CurrCycle may have advanced since then. 7250b57cec5SDimitry Andric if (SuccSU->TopReadyCycle < SU->TopReadyCycle + SuccEdge->getLatency()) 7260b57cec5SDimitry Andric SuccSU->TopReadyCycle = SU->TopReadyCycle + SuccEdge->getLatency(); 7270b57cec5SDimitry Andric 7280b57cec5SDimitry Andric --SuccSU->NumPredsLeft; 7290b57cec5SDimitry Andric if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU) 7300b57cec5SDimitry Andric SchedImpl->releaseTopNode(SuccSU); 7310b57cec5SDimitry Andric } 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric /// releaseSuccessors - Call releaseSucc on each of SU's successors. 7340b57cec5SDimitry Andric void ScheduleDAGMI::releaseSuccessors(SUnit *SU) { 7350b57cec5SDimitry Andric for (SDep &Succ : SU->Succs) 7360b57cec5SDimitry Andric releaseSucc(SU, &Succ); 7370b57cec5SDimitry Andric } 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric /// ReleasePred - Decrement the NumSuccsLeft count of a predecessor. When 7400b57cec5SDimitry Andric /// NumSuccsLeft reaches zero, release the predecessor node. 7410b57cec5SDimitry Andric /// 7420b57cec5SDimitry Andric /// FIXME: Adjust PredSU height based on MinLatency. 7430b57cec5SDimitry Andric void ScheduleDAGMI::releasePred(SUnit *SU, SDep *PredEdge) { 7440b57cec5SDimitry Andric SUnit *PredSU = PredEdge->getSUnit(); 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric if (PredEdge->isWeak()) { 7470b57cec5SDimitry Andric --PredSU->WeakSuccsLeft; 7480b57cec5SDimitry Andric if (PredEdge->isCluster()) 7490b57cec5SDimitry Andric NextClusterPred = PredSU; 7500b57cec5SDimitry Andric return; 7510b57cec5SDimitry Andric } 7520b57cec5SDimitry Andric #ifndef NDEBUG 7530b57cec5SDimitry Andric if (PredSU->NumSuccsLeft == 0) { 7540b57cec5SDimitry Andric dbgs() << "*** Scheduling failed! ***\n"; 7550b57cec5SDimitry Andric dumpNode(*PredSU); 7560b57cec5SDimitry Andric dbgs() << " has been released too many times!\n"; 7570b57cec5SDimitry Andric llvm_unreachable(nullptr); 7580b57cec5SDimitry Andric } 7590b57cec5SDimitry Andric #endif 7600b57cec5SDimitry Andric // SU->BotReadyCycle was set to CurrCycle when it was scheduled. However, 7610b57cec5SDimitry Andric // CurrCycle may have advanced since then. 7620b57cec5SDimitry Andric if (PredSU->BotReadyCycle < SU->BotReadyCycle + PredEdge->getLatency()) 7630b57cec5SDimitry Andric PredSU->BotReadyCycle = SU->BotReadyCycle + PredEdge->getLatency(); 7640b57cec5SDimitry Andric 7650b57cec5SDimitry Andric --PredSU->NumSuccsLeft; 7660b57cec5SDimitry Andric if (PredSU->NumSuccsLeft == 0 && PredSU != &EntrySU) 7670b57cec5SDimitry Andric SchedImpl->releaseBottomNode(PredSU); 7680b57cec5SDimitry Andric } 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric /// releasePredecessors - Call releasePred on each of SU's predecessors. 7710b57cec5SDimitry Andric void ScheduleDAGMI::releasePredecessors(SUnit *SU) { 7720b57cec5SDimitry Andric for (SDep &Pred : SU->Preds) 7730b57cec5SDimitry Andric releasePred(SU, &Pred); 7740b57cec5SDimitry Andric } 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric void ScheduleDAGMI::startBlock(MachineBasicBlock *bb) { 7770b57cec5SDimitry Andric ScheduleDAGInstrs::startBlock(bb); 7780b57cec5SDimitry Andric SchedImpl->enterMBB(bb); 7790b57cec5SDimitry Andric } 7800b57cec5SDimitry Andric 7810b57cec5SDimitry Andric void ScheduleDAGMI::finishBlock() { 7820b57cec5SDimitry Andric SchedImpl->leaveMBB(); 7830b57cec5SDimitry Andric ScheduleDAGInstrs::finishBlock(); 7840b57cec5SDimitry Andric } 7850b57cec5SDimitry Andric 7865f757f3fSDimitry Andric /// enterRegion - Called back from PostMachineScheduler::runOnMachineFunction 7875f757f3fSDimitry Andric /// after crossing a scheduling boundary. [begin, end) includes all instructions 7885f757f3fSDimitry Andric /// in the region, including the boundary itself and single-instruction regions 7890b57cec5SDimitry Andric /// that don't get scheduled. 7900b57cec5SDimitry Andric void ScheduleDAGMI::enterRegion(MachineBasicBlock *bb, 7910b57cec5SDimitry Andric MachineBasicBlock::iterator begin, 7920b57cec5SDimitry Andric MachineBasicBlock::iterator end, 7930b57cec5SDimitry Andric unsigned regioninstrs) 7940b57cec5SDimitry Andric { 7950b57cec5SDimitry Andric ScheduleDAGInstrs::enterRegion(bb, begin, end, regioninstrs); 7960b57cec5SDimitry Andric 7970b57cec5SDimitry Andric SchedImpl->initPolicy(begin, end, regioninstrs); 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric 8000b57cec5SDimitry Andric /// This is normally called from the main scheduler loop but may also be invoked 8010b57cec5SDimitry Andric /// by the scheduling strategy to perform additional code motion. 8020b57cec5SDimitry Andric void ScheduleDAGMI::moveInstruction( 8030b57cec5SDimitry Andric MachineInstr *MI, MachineBasicBlock::iterator InsertPos) { 8040b57cec5SDimitry Andric // Advance RegionBegin if the first instruction moves down. 8050b57cec5SDimitry Andric if (&*RegionBegin == MI) 8060b57cec5SDimitry Andric ++RegionBegin; 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric // Update the instruction stream. 8090b57cec5SDimitry Andric BB->splice(InsertPos, BB, MI); 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric // Update LiveIntervals 8120b57cec5SDimitry Andric if (LIS) 8130b57cec5SDimitry Andric LIS->handleMove(*MI, /*UpdateFlags=*/true); 8140b57cec5SDimitry Andric 8150b57cec5SDimitry Andric // Recede RegionBegin if an instruction moves above the first. 8160b57cec5SDimitry Andric if (RegionBegin == InsertPos) 8170b57cec5SDimitry Andric RegionBegin = MI; 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric bool ScheduleDAGMI::checkSchedLimit() { 82161cfbce3SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG) 8220b57cec5SDimitry Andric if (NumInstrsScheduled == MISchedCutoff && MISchedCutoff != ~0U) { 8230b57cec5SDimitry Andric CurrentTop = CurrentBottom; 8240b57cec5SDimitry Andric return false; 8250b57cec5SDimitry Andric } 8260b57cec5SDimitry Andric ++NumInstrsScheduled; 8270b57cec5SDimitry Andric #endif 8280b57cec5SDimitry Andric return true; 8290b57cec5SDimitry Andric } 8300b57cec5SDimitry Andric 8310b57cec5SDimitry Andric /// Per-region scheduling driver, called back from 8325f757f3fSDimitry Andric /// PostMachineScheduler::runOnMachineFunction. This is a simplified driver 8335f757f3fSDimitry Andric /// that does not consider liveness or register pressure. It is useful for 8345f757f3fSDimitry Andric /// PostRA scheduling and potentially other custom schedulers. 8350b57cec5SDimitry Andric void ScheduleDAGMI::schedule() { 8360b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "ScheduleDAGMI::schedule starting\n"); 8370b57cec5SDimitry Andric LLVM_DEBUG(SchedImpl->dumpPolicy()); 8380b57cec5SDimitry Andric 8390b57cec5SDimitry Andric // Build the DAG. 8400b57cec5SDimitry Andric buildSchedGraph(AA); 8410b57cec5SDimitry Andric 84206c3fb27SDimitry Andric postProcessDAG(); 8430b57cec5SDimitry Andric 8440b57cec5SDimitry Andric SmallVector<SUnit*, 8> TopRoots, BotRoots; 8450b57cec5SDimitry Andric findRootsAndBiasEdges(TopRoots, BotRoots); 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric LLVM_DEBUG(dump()); 8480b57cec5SDimitry Andric if (PrintDAGs) dump(); 8490b57cec5SDimitry Andric if (ViewMISchedDAGs) viewGraph(); 8500b57cec5SDimitry Andric 8510b57cec5SDimitry Andric // Initialize the strategy before modifying the DAG. 8520b57cec5SDimitry Andric // This may initialize a DFSResult to be used for queue priority. 8530b57cec5SDimitry Andric SchedImpl->initialize(this); 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric // Initialize ready queues now that the DAG and priority data are finalized. 8560b57cec5SDimitry Andric initQueues(TopRoots, BotRoots); 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric bool IsTopNode = false; 8590b57cec5SDimitry Andric while (true) { 8600b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** ScheduleDAGMI::schedule picking next node\n"); 8610b57cec5SDimitry Andric SUnit *SU = SchedImpl->pickNode(IsTopNode); 8620b57cec5SDimitry Andric if (!SU) break; 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric assert(!SU->isScheduled && "Node already scheduled"); 8650b57cec5SDimitry Andric if (!checkSchedLimit()) 8660b57cec5SDimitry Andric break; 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric MachineInstr *MI = SU->getInstr(); 8690b57cec5SDimitry Andric if (IsTopNode) { 8700b57cec5SDimitry Andric assert(SU->isTopReady() && "node still has unscheduled dependencies"); 8710b57cec5SDimitry Andric if (&*CurrentTop == MI) 8720b57cec5SDimitry Andric CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom); 8730b57cec5SDimitry Andric else 8740b57cec5SDimitry Andric moveInstruction(MI, CurrentTop); 8750b57cec5SDimitry Andric } else { 8760b57cec5SDimitry Andric assert(SU->isBottomReady() && "node still has unscheduled dependencies"); 8770b57cec5SDimitry Andric MachineBasicBlock::iterator priorII = 8780b57cec5SDimitry Andric priorNonDebug(CurrentBottom, CurrentTop); 8790b57cec5SDimitry Andric if (&*priorII == MI) 8800b57cec5SDimitry Andric CurrentBottom = priorII; 8810b57cec5SDimitry Andric else { 8820b57cec5SDimitry Andric if (&*CurrentTop == MI) 8830b57cec5SDimitry Andric CurrentTop = nextIfDebug(++CurrentTop, priorII); 8840b57cec5SDimitry Andric moveInstruction(MI, CurrentBottom); 8850b57cec5SDimitry Andric CurrentBottom = MI; 8860b57cec5SDimitry Andric } 8870b57cec5SDimitry Andric } 8880b57cec5SDimitry Andric // Notify the scheduling strategy before updating the DAG. 8890b57cec5SDimitry Andric // This sets the scheduled node's ReadyCycle to CurrCycle. When updateQueues 8900b57cec5SDimitry Andric // runs, it can then use the accurate ReadyCycle time to determine whether 8910b57cec5SDimitry Andric // newly released nodes can move to the readyQ. 8920b57cec5SDimitry Andric SchedImpl->schedNode(SU, IsTopNode); 8930b57cec5SDimitry Andric 8940b57cec5SDimitry Andric updateQueues(SU, IsTopNode); 8950b57cec5SDimitry Andric } 8960b57cec5SDimitry Andric assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric placeDebugValues(); 8990b57cec5SDimitry Andric 9000b57cec5SDimitry Andric LLVM_DEBUG({ 9010b57cec5SDimitry Andric dbgs() << "*** Final schedule for " 9020b57cec5SDimitry Andric << printMBBReference(*begin()->getParent()) << " ***\n"; 9030b57cec5SDimitry Andric dumpSchedule(); 9040b57cec5SDimitry Andric dbgs() << '\n'; 9050b57cec5SDimitry Andric }); 9060b57cec5SDimitry Andric } 9070b57cec5SDimitry Andric 9080b57cec5SDimitry Andric /// Apply each ScheduleDAGMutation step in order. 90906c3fb27SDimitry Andric void ScheduleDAGMI::postProcessDAG() { 9100b57cec5SDimitry Andric for (auto &m : Mutations) 9110b57cec5SDimitry Andric m->apply(this); 9120b57cec5SDimitry Andric } 9130b57cec5SDimitry Andric 9140b57cec5SDimitry Andric void ScheduleDAGMI:: 9150b57cec5SDimitry Andric findRootsAndBiasEdges(SmallVectorImpl<SUnit*> &TopRoots, 9160b57cec5SDimitry Andric SmallVectorImpl<SUnit*> &BotRoots) { 9170b57cec5SDimitry Andric for (SUnit &SU : SUnits) { 9180b57cec5SDimitry Andric assert(!SU.isBoundaryNode() && "Boundary node should not be in SUnits"); 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric // Order predecessors so DFSResult follows the critical path. 9210b57cec5SDimitry Andric SU.biasCriticalPath(); 9220b57cec5SDimitry Andric 9230b57cec5SDimitry Andric // A SUnit is ready to top schedule if it has no predecessors. 9240b57cec5SDimitry Andric if (!SU.NumPredsLeft) 9250b57cec5SDimitry Andric TopRoots.push_back(&SU); 9260b57cec5SDimitry Andric // A SUnit is ready to bottom schedule if it has no successors. 9270b57cec5SDimitry Andric if (!SU.NumSuccsLeft) 9280b57cec5SDimitry Andric BotRoots.push_back(&SU); 9290b57cec5SDimitry Andric } 9300b57cec5SDimitry Andric ExitSU.biasCriticalPath(); 9310b57cec5SDimitry Andric } 9320b57cec5SDimitry Andric 9330b57cec5SDimitry Andric /// Identify DAG roots and setup scheduler queues. 9340b57cec5SDimitry Andric void ScheduleDAGMI::initQueues(ArrayRef<SUnit*> TopRoots, 9350b57cec5SDimitry Andric ArrayRef<SUnit*> BotRoots) { 9360b57cec5SDimitry Andric NextClusterSucc = nullptr; 9370b57cec5SDimitry Andric NextClusterPred = nullptr; 9380b57cec5SDimitry Andric 9390b57cec5SDimitry Andric // Release all DAG roots for scheduling, not including EntrySU/ExitSU. 9400b57cec5SDimitry Andric // 9410b57cec5SDimitry Andric // Nodes with unreleased weak edges can still be roots. 9420b57cec5SDimitry Andric // Release top roots in forward order. 9430b57cec5SDimitry Andric for (SUnit *SU : TopRoots) 9440b57cec5SDimitry Andric SchedImpl->releaseTopNode(SU); 9450b57cec5SDimitry Andric 9460b57cec5SDimitry Andric // Release bottom roots in reverse order so the higher priority nodes appear 9470b57cec5SDimitry Andric // first. This is more natural and slightly more efficient. 9480b57cec5SDimitry Andric for (SmallVectorImpl<SUnit*>::const_reverse_iterator 9490b57cec5SDimitry Andric I = BotRoots.rbegin(), E = BotRoots.rend(); I != E; ++I) { 9500b57cec5SDimitry Andric SchedImpl->releaseBottomNode(*I); 9510b57cec5SDimitry Andric } 9520b57cec5SDimitry Andric 9530b57cec5SDimitry Andric releaseSuccessors(&EntrySU); 9540b57cec5SDimitry Andric releasePredecessors(&ExitSU); 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric SchedImpl->registerRoots(); 9570b57cec5SDimitry Andric 9580b57cec5SDimitry Andric // Advance past initial DebugValues. 9590b57cec5SDimitry Andric CurrentTop = nextIfDebug(RegionBegin, RegionEnd); 9600b57cec5SDimitry Andric CurrentBottom = RegionEnd; 9610b57cec5SDimitry Andric } 9620b57cec5SDimitry Andric 9630b57cec5SDimitry Andric /// Update scheduler queues after scheduling an instruction. 9640b57cec5SDimitry Andric void ScheduleDAGMI::updateQueues(SUnit *SU, bool IsTopNode) { 9650b57cec5SDimitry Andric // Release dependent instructions for scheduling. 9660b57cec5SDimitry Andric if (IsTopNode) 9670b57cec5SDimitry Andric releaseSuccessors(SU); 9680b57cec5SDimitry Andric else 9690b57cec5SDimitry Andric releasePredecessors(SU); 9700b57cec5SDimitry Andric 9710b57cec5SDimitry Andric SU->isScheduled = true; 9720b57cec5SDimitry Andric } 9730b57cec5SDimitry Andric 9740b57cec5SDimitry Andric /// Reinsert any remaining debug_values, just like the PostRA scheduler. 9750b57cec5SDimitry Andric void ScheduleDAGMI::placeDebugValues() { 9760b57cec5SDimitry Andric // If first instruction was a DBG_VALUE then put it back. 9770b57cec5SDimitry Andric if (FirstDbgValue) { 9780b57cec5SDimitry Andric BB->splice(RegionBegin, BB, FirstDbgValue); 9790b57cec5SDimitry Andric RegionBegin = FirstDbgValue; 9800b57cec5SDimitry Andric } 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric for (std::vector<std::pair<MachineInstr *, MachineInstr *>>::iterator 9830b57cec5SDimitry Andric DI = DbgValues.end(), DE = DbgValues.begin(); DI != DE; --DI) { 9840b57cec5SDimitry Andric std::pair<MachineInstr *, MachineInstr *> P = *std::prev(DI); 9850b57cec5SDimitry Andric MachineInstr *DbgValue = P.first; 9860b57cec5SDimitry Andric MachineBasicBlock::iterator OrigPrevMI = P.second; 9870b57cec5SDimitry Andric if (&*RegionBegin == DbgValue) 9880b57cec5SDimitry Andric ++RegionBegin; 98981ad6265SDimitry Andric BB->splice(std::next(OrigPrevMI), BB, DbgValue); 99081ad6265SDimitry Andric if (RegionEnd != BB->end() && OrigPrevMI == &*RegionEnd) 9910b57cec5SDimitry Andric RegionEnd = DbgValue; 9920b57cec5SDimitry Andric } 9930b57cec5SDimitry Andric } 9940b57cec5SDimitry Andric 9950b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 99606c3fb27SDimitry Andric static const char *scheduleTableLegend = " i: issue\n x: resource booked"; 99706c3fb27SDimitry Andric 99806c3fb27SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceTopDown() const { 99906c3fb27SDimitry Andric // Bail off when there is no schedule model to query. 100006c3fb27SDimitry Andric if (!SchedModel.hasInstrSchedModel()) 100106c3fb27SDimitry Andric return; 100206c3fb27SDimitry Andric 100306c3fb27SDimitry Andric // Nothing to show if there is no or just one instruction. 100406c3fb27SDimitry Andric if (BB->size() < 2) 100506c3fb27SDimitry Andric return; 100606c3fb27SDimitry Andric 100706c3fb27SDimitry Andric dbgs() << " * Schedule table (TopDown):\n"; 100806c3fb27SDimitry Andric dbgs() << scheduleTableLegend << "\n"; 100906c3fb27SDimitry Andric const unsigned FirstCycle = getSUnit(&*(std::begin(*this)))->TopReadyCycle; 101006c3fb27SDimitry Andric unsigned LastCycle = getSUnit(&*(std::prev(std::end(*this))))->TopReadyCycle; 101106c3fb27SDimitry Andric for (MachineInstr &MI : *this) { 101206c3fb27SDimitry Andric SUnit *SU = getSUnit(&MI); 101306c3fb27SDimitry Andric if (!SU) 101406c3fb27SDimitry Andric continue; 101506c3fb27SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 101606c3fb27SDimitry Andric for (TargetSchedModel::ProcResIter PI = SchedModel.getWriteProcResBegin(SC), 101706c3fb27SDimitry Andric PE = SchedModel.getWriteProcResEnd(SC); 101806c3fb27SDimitry Andric PI != PE; ++PI) { 10195f757f3fSDimitry Andric if (SU->TopReadyCycle + PI->ReleaseAtCycle - 1 > LastCycle) 10205f757f3fSDimitry Andric LastCycle = SU->TopReadyCycle + PI->ReleaseAtCycle - 1; 102106c3fb27SDimitry Andric } 102206c3fb27SDimitry Andric } 102306c3fb27SDimitry Andric // Print the header with the cycles 102406c3fb27SDimitry Andric dbgs() << llvm::left_justify("Cycle", HeaderColWidth); 102506c3fb27SDimitry Andric for (unsigned C = FirstCycle; C <= LastCycle; ++C) 102606c3fb27SDimitry Andric dbgs() << llvm::left_justify("| " + std::to_string(C), ColWidth); 102706c3fb27SDimitry Andric dbgs() << "|\n"; 102806c3fb27SDimitry Andric 102906c3fb27SDimitry Andric for (MachineInstr &MI : *this) { 103006c3fb27SDimitry Andric SUnit *SU = getSUnit(&MI); 103106c3fb27SDimitry Andric if (!SU) { 103206c3fb27SDimitry Andric dbgs() << "Missing SUnit\n"; 103306c3fb27SDimitry Andric continue; 103406c3fb27SDimitry Andric } 103506c3fb27SDimitry Andric std::string NodeName("SU("); 103606c3fb27SDimitry Andric NodeName += std::to_string(SU->NodeNum) + ")"; 103706c3fb27SDimitry Andric dbgs() << llvm::left_justify(NodeName, HeaderColWidth); 103806c3fb27SDimitry Andric unsigned C = FirstCycle; 103906c3fb27SDimitry Andric for (; C <= LastCycle; ++C) { 104006c3fb27SDimitry Andric if (C == SU->TopReadyCycle) 104106c3fb27SDimitry Andric dbgs() << llvm::left_justify("| i", ColWidth); 104206c3fb27SDimitry Andric else 104306c3fb27SDimitry Andric dbgs() << llvm::left_justify("|", ColWidth); 104406c3fb27SDimitry Andric } 104506c3fb27SDimitry Andric dbgs() << "|\n"; 104606c3fb27SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 104706c3fb27SDimitry Andric 104806c3fb27SDimitry Andric SmallVector<MCWriteProcResEntry, 4> ResourcesIt( 104906c3fb27SDimitry Andric make_range(SchedModel.getWriteProcResBegin(SC), 105006c3fb27SDimitry Andric SchedModel.getWriteProcResEnd(SC))); 105106c3fb27SDimitry Andric 105206c3fb27SDimitry Andric if (MISchedSortResourcesInTrace) 105306c3fb27SDimitry Andric llvm::stable_sort(ResourcesIt, 105406c3fb27SDimitry Andric [](const MCWriteProcResEntry &LHS, 105506c3fb27SDimitry Andric const MCWriteProcResEntry &RHS) -> bool { 10565f757f3fSDimitry Andric return LHS.AcquireAtCycle < RHS.AcquireAtCycle || 10575f757f3fSDimitry Andric (LHS.AcquireAtCycle == RHS.AcquireAtCycle && 10585f757f3fSDimitry Andric LHS.ReleaseAtCycle < RHS.ReleaseAtCycle); 105906c3fb27SDimitry Andric }); 106006c3fb27SDimitry Andric for (const MCWriteProcResEntry &PI : ResourcesIt) { 106106c3fb27SDimitry Andric C = FirstCycle; 106206c3fb27SDimitry Andric const std::string ResName = 106306c3fb27SDimitry Andric SchedModel.getResourceName(PI.ProcResourceIdx); 106406c3fb27SDimitry Andric dbgs() << llvm::right_justify(ResName + " ", HeaderColWidth); 10655f757f3fSDimitry Andric for (; C < SU->TopReadyCycle + PI.AcquireAtCycle; ++C) { 106606c3fb27SDimitry Andric dbgs() << llvm::left_justify("|", ColWidth); 106706c3fb27SDimitry Andric } 10685f757f3fSDimitry Andric for (unsigned I = 0, E = PI.ReleaseAtCycle - PI.AcquireAtCycle; I != E; 10695f757f3fSDimitry Andric ++I, ++C) 107006c3fb27SDimitry Andric dbgs() << llvm::left_justify("| x", ColWidth); 107106c3fb27SDimitry Andric while (C++ <= LastCycle) 107206c3fb27SDimitry Andric dbgs() << llvm::left_justify("|", ColWidth); 107306c3fb27SDimitry Andric // Place end char 107406c3fb27SDimitry Andric dbgs() << "| \n"; 107506c3fb27SDimitry Andric } 107606c3fb27SDimitry Andric } 107706c3fb27SDimitry Andric } 107806c3fb27SDimitry Andric 107906c3fb27SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceBottomUp() const { 108006c3fb27SDimitry Andric // Bail off when there is no schedule model to query. 108106c3fb27SDimitry Andric if (!SchedModel.hasInstrSchedModel()) 108206c3fb27SDimitry Andric return; 108306c3fb27SDimitry Andric 108406c3fb27SDimitry Andric // Nothing to show if there is no or just one instruction. 108506c3fb27SDimitry Andric if (BB->size() < 2) 108606c3fb27SDimitry Andric return; 108706c3fb27SDimitry Andric 108806c3fb27SDimitry Andric dbgs() << " * Schedule table (BottomUp):\n"; 108906c3fb27SDimitry Andric dbgs() << scheduleTableLegend << "\n"; 109006c3fb27SDimitry Andric 109106c3fb27SDimitry Andric const int FirstCycle = getSUnit(&*(std::begin(*this)))->BotReadyCycle; 109206c3fb27SDimitry Andric int LastCycle = getSUnit(&*(std::prev(std::end(*this))))->BotReadyCycle; 109306c3fb27SDimitry Andric for (MachineInstr &MI : *this) { 109406c3fb27SDimitry Andric SUnit *SU = getSUnit(&MI); 109506c3fb27SDimitry Andric if (!SU) 109606c3fb27SDimitry Andric continue; 109706c3fb27SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 109806c3fb27SDimitry Andric for (TargetSchedModel::ProcResIter PI = SchedModel.getWriteProcResBegin(SC), 109906c3fb27SDimitry Andric PE = SchedModel.getWriteProcResEnd(SC); 110006c3fb27SDimitry Andric PI != PE; ++PI) { 11015f757f3fSDimitry Andric if ((int)SU->BotReadyCycle - PI->ReleaseAtCycle + 1 < LastCycle) 11025f757f3fSDimitry Andric LastCycle = (int)SU->BotReadyCycle - PI->ReleaseAtCycle + 1; 110306c3fb27SDimitry Andric } 110406c3fb27SDimitry Andric } 110506c3fb27SDimitry Andric // Print the header with the cycles 110606c3fb27SDimitry Andric dbgs() << llvm::left_justify("Cycle", HeaderColWidth); 110706c3fb27SDimitry Andric for (int C = FirstCycle; C >= LastCycle; --C) 110806c3fb27SDimitry Andric dbgs() << llvm::left_justify("| " + std::to_string(C), ColWidth); 110906c3fb27SDimitry Andric dbgs() << "|\n"; 111006c3fb27SDimitry Andric 111106c3fb27SDimitry Andric for (MachineInstr &MI : *this) { 111206c3fb27SDimitry Andric SUnit *SU = getSUnit(&MI); 111306c3fb27SDimitry Andric if (!SU) { 111406c3fb27SDimitry Andric dbgs() << "Missing SUnit\n"; 111506c3fb27SDimitry Andric continue; 111606c3fb27SDimitry Andric } 111706c3fb27SDimitry Andric std::string NodeName("SU("); 111806c3fb27SDimitry Andric NodeName += std::to_string(SU->NodeNum) + ")"; 111906c3fb27SDimitry Andric dbgs() << llvm::left_justify(NodeName, HeaderColWidth); 112006c3fb27SDimitry Andric int C = FirstCycle; 112106c3fb27SDimitry Andric for (; C >= LastCycle; --C) { 112206c3fb27SDimitry Andric if (C == (int)SU->BotReadyCycle) 112306c3fb27SDimitry Andric dbgs() << llvm::left_justify("| i", ColWidth); 112406c3fb27SDimitry Andric else 112506c3fb27SDimitry Andric dbgs() << llvm::left_justify("|", ColWidth); 112606c3fb27SDimitry Andric } 112706c3fb27SDimitry Andric dbgs() << "|\n"; 112806c3fb27SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 112906c3fb27SDimitry Andric SmallVector<MCWriteProcResEntry, 4> ResourcesIt( 113006c3fb27SDimitry Andric make_range(SchedModel.getWriteProcResBegin(SC), 113106c3fb27SDimitry Andric SchedModel.getWriteProcResEnd(SC))); 113206c3fb27SDimitry Andric 113306c3fb27SDimitry Andric if (MISchedSortResourcesInTrace) 113406c3fb27SDimitry Andric llvm::stable_sort(ResourcesIt, 113506c3fb27SDimitry Andric [](const MCWriteProcResEntry &LHS, 113606c3fb27SDimitry Andric const MCWriteProcResEntry &RHS) -> bool { 11375f757f3fSDimitry Andric return LHS.AcquireAtCycle < RHS.AcquireAtCycle || 11385f757f3fSDimitry Andric (LHS.AcquireAtCycle == RHS.AcquireAtCycle && 11395f757f3fSDimitry Andric LHS.ReleaseAtCycle < RHS.ReleaseAtCycle); 114006c3fb27SDimitry Andric }); 114106c3fb27SDimitry Andric for (const MCWriteProcResEntry &PI : ResourcesIt) { 114206c3fb27SDimitry Andric C = FirstCycle; 114306c3fb27SDimitry Andric const std::string ResName = 114406c3fb27SDimitry Andric SchedModel.getResourceName(PI.ProcResourceIdx); 114506c3fb27SDimitry Andric dbgs() << llvm::right_justify(ResName + " ", HeaderColWidth); 11465f757f3fSDimitry Andric for (; C > ((int)SU->BotReadyCycle - (int)PI.AcquireAtCycle); --C) { 114706c3fb27SDimitry Andric dbgs() << llvm::left_justify("|", ColWidth); 114806c3fb27SDimitry Andric } 11495f757f3fSDimitry Andric for (unsigned I = 0, E = PI.ReleaseAtCycle - PI.AcquireAtCycle; I != E; 11505f757f3fSDimitry Andric ++I, --C) 115106c3fb27SDimitry Andric dbgs() << llvm::left_justify("| x", ColWidth); 115206c3fb27SDimitry Andric while (C-- >= LastCycle) 115306c3fb27SDimitry Andric dbgs() << llvm::left_justify("|", ColWidth); 115406c3fb27SDimitry Andric // Place end char 115506c3fb27SDimitry Andric dbgs() << "| \n"; 115606c3fb27SDimitry Andric } 115706c3fb27SDimitry Andric } 115806c3fb27SDimitry Andric } 115906c3fb27SDimitry Andric #endif 116006c3fb27SDimitry Andric 116106c3fb27SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 11620b57cec5SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpSchedule() const { 116306c3fb27SDimitry Andric if (MISchedDumpScheduleTrace) { 1164*0fca6ea1SDimitry Andric if (DumpDir == DumpDirection::TopDown) 116506c3fb27SDimitry Andric dumpScheduleTraceTopDown(); 1166*0fca6ea1SDimitry Andric else if (DumpDir == DumpDirection::BottomUp) 116706c3fb27SDimitry Andric dumpScheduleTraceBottomUp(); 1168*0fca6ea1SDimitry Andric else if (DumpDir == DumpDirection::Bidirectional) { 116906c3fb27SDimitry Andric dbgs() << "* Schedule table (Bidirectional): not implemented\n"; 1170*0fca6ea1SDimitry Andric } else { 1171*0fca6ea1SDimitry Andric dbgs() << "* Schedule table: DumpDirection not set.\n"; 117206c3fb27SDimitry Andric } 117306c3fb27SDimitry Andric } 117406c3fb27SDimitry Andric 1175fe6060f1SDimitry Andric for (MachineInstr &MI : *this) { 1176fe6060f1SDimitry Andric if (SUnit *SU = getSUnit(&MI)) 11770b57cec5SDimitry Andric dumpNode(*SU); 11780b57cec5SDimitry Andric else 11790b57cec5SDimitry Andric dbgs() << "Missing SUnit\n"; 11800b57cec5SDimitry Andric } 11810b57cec5SDimitry Andric } 11820b57cec5SDimitry Andric #endif 11830b57cec5SDimitry Andric 11840b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11850b57cec5SDimitry Andric // ScheduleDAGMILive - Base class for MachineInstr scheduling with LiveIntervals 11860b57cec5SDimitry Andric // preservation. 11870b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11880b57cec5SDimitry Andric 11890b57cec5SDimitry Andric ScheduleDAGMILive::~ScheduleDAGMILive() { 11900b57cec5SDimitry Andric delete DFSResult; 11910b57cec5SDimitry Andric } 11920b57cec5SDimitry Andric 11930b57cec5SDimitry Andric void ScheduleDAGMILive::collectVRegUses(SUnit &SU) { 11940b57cec5SDimitry Andric const MachineInstr &MI = *SU.getInstr(); 11950b57cec5SDimitry Andric for (const MachineOperand &MO : MI.operands()) { 11960b57cec5SDimitry Andric if (!MO.isReg()) 11970b57cec5SDimitry Andric continue; 11980b57cec5SDimitry Andric if (!MO.readsReg()) 11990b57cec5SDimitry Andric continue; 12000b57cec5SDimitry Andric if (TrackLaneMasks && !MO.isUse()) 12010b57cec5SDimitry Andric continue; 12020b57cec5SDimitry Andric 12038bcb0991SDimitry Andric Register Reg = MO.getReg(); 1204bdd1243dSDimitry Andric if (!Reg.isVirtual()) 12050b57cec5SDimitry Andric continue; 12060b57cec5SDimitry Andric 12070b57cec5SDimitry Andric // Ignore re-defs. 12080b57cec5SDimitry Andric if (TrackLaneMasks) { 12090b57cec5SDimitry Andric bool FoundDef = false; 121006c3fb27SDimitry Andric for (const MachineOperand &MO2 : MI.all_defs()) { 121106c3fb27SDimitry Andric if (MO2.getReg() == Reg && !MO2.isDead()) { 12120b57cec5SDimitry Andric FoundDef = true; 12130b57cec5SDimitry Andric break; 12140b57cec5SDimitry Andric } 12150b57cec5SDimitry Andric } 12160b57cec5SDimitry Andric if (FoundDef) 12170b57cec5SDimitry Andric continue; 12180b57cec5SDimitry Andric } 12190b57cec5SDimitry Andric 12200b57cec5SDimitry Andric // Record this local VReg use. 12210b57cec5SDimitry Andric VReg2SUnitMultiMap::iterator UI = VRegUses.find(Reg); 12220b57cec5SDimitry Andric for (; UI != VRegUses.end(); ++UI) { 12230b57cec5SDimitry Andric if (UI->SU == &SU) 12240b57cec5SDimitry Andric break; 12250b57cec5SDimitry Andric } 12260b57cec5SDimitry Andric if (UI == VRegUses.end()) 12270b57cec5SDimitry Andric VRegUses.insert(VReg2SUnit(Reg, LaneBitmask::getNone(), &SU)); 12280b57cec5SDimitry Andric } 12290b57cec5SDimitry Andric } 12300b57cec5SDimitry Andric 12310b57cec5SDimitry Andric /// enterRegion - Called back from MachineScheduler::runOnMachineFunction after 12320b57cec5SDimitry Andric /// crossing a scheduling boundary. [begin, end) includes all instructions in 12330b57cec5SDimitry Andric /// the region, including the boundary itself and single-instruction regions 12340b57cec5SDimitry Andric /// that don't get scheduled. 12350b57cec5SDimitry Andric void ScheduleDAGMILive::enterRegion(MachineBasicBlock *bb, 12360b57cec5SDimitry Andric MachineBasicBlock::iterator begin, 12370b57cec5SDimitry Andric MachineBasicBlock::iterator end, 12380b57cec5SDimitry Andric unsigned regioninstrs) 12390b57cec5SDimitry Andric { 12400b57cec5SDimitry Andric // ScheduleDAGMI initializes SchedImpl's per-region policy. 12410b57cec5SDimitry Andric ScheduleDAGMI::enterRegion(bb, begin, end, regioninstrs); 12420b57cec5SDimitry Andric 12430b57cec5SDimitry Andric // For convenience remember the end of the liveness region. 12440b57cec5SDimitry Andric LiveRegionEnd = (RegionEnd == bb->end()) ? RegionEnd : std::next(RegionEnd); 12450b57cec5SDimitry Andric 12460b57cec5SDimitry Andric SUPressureDiffs.clear(); 12470b57cec5SDimitry Andric 12480b57cec5SDimitry Andric ShouldTrackPressure = SchedImpl->shouldTrackPressure(); 12490b57cec5SDimitry Andric ShouldTrackLaneMasks = SchedImpl->shouldTrackLaneMasks(); 12500b57cec5SDimitry Andric 12510b57cec5SDimitry Andric assert((!ShouldTrackLaneMasks || ShouldTrackPressure) && 12520b57cec5SDimitry Andric "ShouldTrackLaneMasks requires ShouldTrackPressure"); 12530b57cec5SDimitry Andric } 12540b57cec5SDimitry Andric 12558bcb0991SDimitry Andric // Setup the register pressure trackers for the top scheduled and bottom 12560b57cec5SDimitry Andric // scheduled regions. 12570b57cec5SDimitry Andric void ScheduleDAGMILive::initRegPressure() { 12580b57cec5SDimitry Andric VRegUses.clear(); 12590b57cec5SDimitry Andric VRegUses.setUniverse(MRI.getNumVirtRegs()); 12600b57cec5SDimitry Andric for (SUnit &SU : SUnits) 12610b57cec5SDimitry Andric collectVRegUses(SU); 12620b57cec5SDimitry Andric 12630b57cec5SDimitry Andric TopRPTracker.init(&MF, RegClassInfo, LIS, BB, RegionBegin, 12640b57cec5SDimitry Andric ShouldTrackLaneMasks, false); 12650b57cec5SDimitry Andric BotRPTracker.init(&MF, RegClassInfo, LIS, BB, LiveRegionEnd, 12660b57cec5SDimitry Andric ShouldTrackLaneMasks, false); 12670b57cec5SDimitry Andric 12680b57cec5SDimitry Andric // Close the RPTracker to finalize live ins. 12690b57cec5SDimitry Andric RPTracker.closeRegion(); 12700b57cec5SDimitry Andric 12710b57cec5SDimitry Andric LLVM_DEBUG(RPTracker.dump()); 12720b57cec5SDimitry Andric 12730b57cec5SDimitry Andric // Initialize the live ins and live outs. 12740b57cec5SDimitry Andric TopRPTracker.addLiveRegs(RPTracker.getPressure().LiveInRegs); 12750b57cec5SDimitry Andric BotRPTracker.addLiveRegs(RPTracker.getPressure().LiveOutRegs); 12760b57cec5SDimitry Andric 12770b57cec5SDimitry Andric // Close one end of the tracker so we can call 12780b57cec5SDimitry Andric // getMaxUpward/DownwardPressureDelta before advancing across any 12790b57cec5SDimitry Andric // instructions. This converts currently live regs into live ins/outs. 12800b57cec5SDimitry Andric TopRPTracker.closeTop(); 12810b57cec5SDimitry Andric BotRPTracker.closeBottom(); 12820b57cec5SDimitry Andric 12830b57cec5SDimitry Andric BotRPTracker.initLiveThru(RPTracker); 12840b57cec5SDimitry Andric if (!BotRPTracker.getLiveThru().empty()) { 12850b57cec5SDimitry Andric TopRPTracker.initLiveThru(BotRPTracker.getLiveThru()); 12860b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Live Thru: "; 12870b57cec5SDimitry Andric dumpRegSetPressure(BotRPTracker.getLiveThru(), TRI)); 12880b57cec5SDimitry Andric }; 12890b57cec5SDimitry Andric 12900b57cec5SDimitry Andric // For each live out vreg reduce the pressure change associated with other 12910b57cec5SDimitry Andric // uses of the same vreg below the live-out reaching def. 12920b57cec5SDimitry Andric updatePressureDiffs(RPTracker.getPressure().LiveOutRegs); 12930b57cec5SDimitry Andric 12940b57cec5SDimitry Andric // Account for liveness generated by the region boundary. 12950b57cec5SDimitry Andric if (LiveRegionEnd != RegionEnd) { 12960b57cec5SDimitry Andric SmallVector<RegisterMaskPair, 8> LiveUses; 12970b57cec5SDimitry Andric BotRPTracker.recede(&LiveUses); 12980b57cec5SDimitry Andric updatePressureDiffs(LiveUses); 12990b57cec5SDimitry Andric } 13000b57cec5SDimitry Andric 13010b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Top Pressure:\n"; 13020b57cec5SDimitry Andric dumpRegSetPressure(TopRPTracker.getRegSetPressureAtPos(), TRI); 13030b57cec5SDimitry Andric dbgs() << "Bottom Pressure:\n"; 13040b57cec5SDimitry Andric dumpRegSetPressure(BotRPTracker.getRegSetPressureAtPos(), TRI);); 13050b57cec5SDimitry Andric 13060b57cec5SDimitry Andric assert((BotRPTracker.getPos() == RegionEnd || 13070b57cec5SDimitry Andric (RegionEnd->isDebugInstr() && 13080b57cec5SDimitry Andric BotRPTracker.getPos() == priorNonDebug(RegionEnd, RegionBegin))) && 13090b57cec5SDimitry Andric "Can't find the region bottom"); 13100b57cec5SDimitry Andric 13110b57cec5SDimitry Andric // Cache the list of excess pressure sets in this region. This will also track 13120b57cec5SDimitry Andric // the max pressure in the scheduled code for these sets. 13130b57cec5SDimitry Andric RegionCriticalPSets.clear(); 13140b57cec5SDimitry Andric const std::vector<unsigned> &RegionPressure = 13150b57cec5SDimitry Andric RPTracker.getPressure().MaxSetPressure; 13160b57cec5SDimitry Andric for (unsigned i = 0, e = RegionPressure.size(); i < e; ++i) { 13170b57cec5SDimitry Andric unsigned Limit = RegClassInfo->getRegPressureSetLimit(i); 13180b57cec5SDimitry Andric if (RegionPressure[i] > Limit) { 13190b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << TRI->getRegPressureSetName(i) << " Limit " << Limit 13200b57cec5SDimitry Andric << " Actual " << RegionPressure[i] << "\n"); 13210b57cec5SDimitry Andric RegionCriticalPSets.push_back(PressureChange(i)); 13220b57cec5SDimitry Andric } 13230b57cec5SDimitry Andric } 13240b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Excess PSets: "; 13250b57cec5SDimitry Andric for (const PressureChange &RCPS 13260b57cec5SDimitry Andric : RegionCriticalPSets) dbgs() 13270b57cec5SDimitry Andric << TRI->getRegPressureSetName(RCPS.getPSet()) << " "; 13280b57cec5SDimitry Andric dbgs() << "\n"); 13290b57cec5SDimitry Andric } 13300b57cec5SDimitry Andric 13310b57cec5SDimitry Andric void ScheduleDAGMILive:: 13320b57cec5SDimitry Andric updateScheduledPressure(const SUnit *SU, 13330b57cec5SDimitry Andric const std::vector<unsigned> &NewMaxPressure) { 13340b57cec5SDimitry Andric const PressureDiff &PDiff = getPressureDiff(SU); 13350b57cec5SDimitry Andric unsigned CritIdx = 0, CritEnd = RegionCriticalPSets.size(); 13360b57cec5SDimitry Andric for (const PressureChange &PC : PDiff) { 13370b57cec5SDimitry Andric if (!PC.isValid()) 13380b57cec5SDimitry Andric break; 13390b57cec5SDimitry Andric unsigned ID = PC.getPSet(); 13400b57cec5SDimitry Andric while (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() < ID) 13410b57cec5SDimitry Andric ++CritIdx; 13420b57cec5SDimitry Andric if (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() == ID) { 13430b57cec5SDimitry Andric if ((int)NewMaxPressure[ID] > RegionCriticalPSets[CritIdx].getUnitInc() 13440b57cec5SDimitry Andric && NewMaxPressure[ID] <= (unsigned)std::numeric_limits<int16_t>::max()) 13450b57cec5SDimitry Andric RegionCriticalPSets[CritIdx].setUnitInc(NewMaxPressure[ID]); 13460b57cec5SDimitry Andric } 13470b57cec5SDimitry Andric unsigned Limit = RegClassInfo->getRegPressureSetLimit(ID); 13480b57cec5SDimitry Andric if (NewMaxPressure[ID] >= Limit - 2) { 13490b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << TRI->getRegPressureSetName(ID) << ": " 13500b57cec5SDimitry Andric << NewMaxPressure[ID] 13510b57cec5SDimitry Andric << ((NewMaxPressure[ID] > Limit) ? " > " : " <= ") 13520b57cec5SDimitry Andric << Limit << "(+ " << BotRPTracker.getLiveThru()[ID] 13530b57cec5SDimitry Andric << " livethru)\n"); 13540b57cec5SDimitry Andric } 13550b57cec5SDimitry Andric } 13560b57cec5SDimitry Andric } 13570b57cec5SDimitry Andric 13580b57cec5SDimitry Andric /// Update the PressureDiff array for liveness after scheduling this 13590b57cec5SDimitry Andric /// instruction. 13600b57cec5SDimitry Andric void ScheduleDAGMILive::updatePressureDiffs( 13610b57cec5SDimitry Andric ArrayRef<RegisterMaskPair> LiveUses) { 13620b57cec5SDimitry Andric for (const RegisterMaskPair &P : LiveUses) { 1363e8d8bef9SDimitry Andric Register Reg = P.RegUnit; 13640b57cec5SDimitry Andric /// FIXME: Currently assuming single-use physregs. 1365bdd1243dSDimitry Andric if (!Reg.isVirtual()) 13660b57cec5SDimitry Andric continue; 13670b57cec5SDimitry Andric 13680b57cec5SDimitry Andric if (ShouldTrackLaneMasks) { 13690b57cec5SDimitry Andric // If the register has just become live then other uses won't change 13700b57cec5SDimitry Andric // this fact anymore => decrement pressure. 13710b57cec5SDimitry Andric // If the register has just become dead then other uses make it come 13720b57cec5SDimitry Andric // back to life => increment pressure. 13730b57cec5SDimitry Andric bool Decrement = P.LaneMask.any(); 13740b57cec5SDimitry Andric 13750b57cec5SDimitry Andric for (const VReg2SUnit &V2SU 13760b57cec5SDimitry Andric : make_range(VRegUses.find(Reg), VRegUses.end())) { 13770b57cec5SDimitry Andric SUnit &SU = *V2SU.SU; 13780b57cec5SDimitry Andric if (SU.isScheduled || &SU == &ExitSU) 13790b57cec5SDimitry Andric continue; 13800b57cec5SDimitry Andric 13810b57cec5SDimitry Andric PressureDiff &PDiff = getPressureDiff(&SU); 13820b57cec5SDimitry Andric PDiff.addPressureChange(Reg, Decrement, &MRI); 13830b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " UpdateRegP: SU(" << SU.NodeNum << ") " 13840b57cec5SDimitry Andric << printReg(Reg, TRI) << ':' 13850b57cec5SDimitry Andric << PrintLaneMask(P.LaneMask) << ' ' << *SU.getInstr(); 13860b57cec5SDimitry Andric dbgs() << " to "; PDiff.dump(*TRI);); 13870b57cec5SDimitry Andric } 13880b57cec5SDimitry Andric } else { 13890b57cec5SDimitry Andric assert(P.LaneMask.any()); 13900b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " LiveReg: " << printVRegOrUnit(Reg, TRI) << "\n"); 13910b57cec5SDimitry Andric // This may be called before CurrentBottom has been initialized. However, 13920b57cec5SDimitry Andric // BotRPTracker must have a valid position. We want the value live into the 13930b57cec5SDimitry Andric // instruction or live out of the block, so ask for the previous 13940b57cec5SDimitry Andric // instruction's live-out. 13950b57cec5SDimitry Andric const LiveInterval &LI = LIS->getInterval(Reg); 13960b57cec5SDimitry Andric VNInfo *VNI; 13970b57cec5SDimitry Andric MachineBasicBlock::const_iterator I = 13980b57cec5SDimitry Andric nextIfDebug(BotRPTracker.getPos(), BB->end()); 13990b57cec5SDimitry Andric if (I == BB->end()) 14000b57cec5SDimitry Andric VNI = LI.getVNInfoBefore(LIS->getMBBEndIdx(BB)); 14010b57cec5SDimitry Andric else { 14020b57cec5SDimitry Andric LiveQueryResult LRQ = LI.Query(LIS->getInstructionIndex(*I)); 14030b57cec5SDimitry Andric VNI = LRQ.valueIn(); 14040b57cec5SDimitry Andric } 14050b57cec5SDimitry Andric // RegisterPressureTracker guarantees that readsReg is true for LiveUses. 14060b57cec5SDimitry Andric assert(VNI && "No live value at use."); 14070b57cec5SDimitry Andric for (const VReg2SUnit &V2SU 14080b57cec5SDimitry Andric : make_range(VRegUses.find(Reg), VRegUses.end())) { 14090b57cec5SDimitry Andric SUnit *SU = V2SU.SU; 14100b57cec5SDimitry Andric // If this use comes before the reaching def, it cannot be a last use, 14110b57cec5SDimitry Andric // so decrease its pressure change. 14120b57cec5SDimitry Andric if (!SU->isScheduled && SU != &ExitSU) { 14130b57cec5SDimitry Andric LiveQueryResult LRQ = 14140b57cec5SDimitry Andric LI.Query(LIS->getInstructionIndex(*SU->getInstr())); 14150b57cec5SDimitry Andric if (LRQ.valueIn() == VNI) { 14160b57cec5SDimitry Andric PressureDiff &PDiff = getPressureDiff(SU); 14170b57cec5SDimitry Andric PDiff.addPressureChange(Reg, true, &MRI); 14180b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " UpdateRegP: SU(" << SU->NodeNum << ") " 14190b57cec5SDimitry Andric << *SU->getInstr(); 14200b57cec5SDimitry Andric dbgs() << " to "; PDiff.dump(*TRI);); 14210b57cec5SDimitry Andric } 14220b57cec5SDimitry Andric } 14230b57cec5SDimitry Andric } 14240b57cec5SDimitry Andric } 14250b57cec5SDimitry Andric } 14260b57cec5SDimitry Andric } 14270b57cec5SDimitry Andric 14280b57cec5SDimitry Andric void ScheduleDAGMILive::dump() const { 14290b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 14300b57cec5SDimitry Andric if (EntrySU.getInstr() != nullptr) 14310b57cec5SDimitry Andric dumpNodeAll(EntrySU); 14320b57cec5SDimitry Andric for (const SUnit &SU : SUnits) { 14330b57cec5SDimitry Andric dumpNodeAll(SU); 14340b57cec5SDimitry Andric if (ShouldTrackPressure) { 14350b57cec5SDimitry Andric dbgs() << " Pressure Diff : "; 14360b57cec5SDimitry Andric getPressureDiff(&SU).dump(*TRI); 14370b57cec5SDimitry Andric } 14380b57cec5SDimitry Andric dbgs() << " Single Issue : "; 14390b57cec5SDimitry Andric if (SchedModel.mustBeginGroup(SU.getInstr()) && 14400b57cec5SDimitry Andric SchedModel.mustEndGroup(SU.getInstr())) 14410b57cec5SDimitry Andric dbgs() << "true;"; 14420b57cec5SDimitry Andric else 14430b57cec5SDimitry Andric dbgs() << "false;"; 14440b57cec5SDimitry Andric dbgs() << '\n'; 14450b57cec5SDimitry Andric } 14460b57cec5SDimitry Andric if (ExitSU.getInstr() != nullptr) 14470b57cec5SDimitry Andric dumpNodeAll(ExitSU); 14480b57cec5SDimitry Andric #endif 14490b57cec5SDimitry Andric } 14500b57cec5SDimitry Andric 14510b57cec5SDimitry Andric /// schedule - Called back from MachineScheduler::runOnMachineFunction 14520b57cec5SDimitry Andric /// after setting up the current scheduling region. [RegionBegin, RegionEnd) 14530b57cec5SDimitry Andric /// only includes instructions that have DAG nodes, not scheduling boundaries. 14540b57cec5SDimitry Andric /// 14550b57cec5SDimitry Andric /// This is a skeletal driver, with all the functionality pushed into helpers, 14560b57cec5SDimitry Andric /// so that it can be easily extended by experimental schedulers. Generally, 14570b57cec5SDimitry Andric /// implementing MachineSchedStrategy should be sufficient to implement a new 14580b57cec5SDimitry Andric /// scheduling algorithm. However, if a scheduler further subclasses 14590b57cec5SDimitry Andric /// ScheduleDAGMILive then it will want to override this virtual method in order 14600b57cec5SDimitry Andric /// to update any specialized state. 14610b57cec5SDimitry Andric void ScheduleDAGMILive::schedule() { 14620b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "ScheduleDAGMILive::schedule starting\n"); 14630b57cec5SDimitry Andric LLVM_DEBUG(SchedImpl->dumpPolicy()); 14640b57cec5SDimitry Andric buildDAGWithRegPressure(); 14650b57cec5SDimitry Andric 146606c3fb27SDimitry Andric postProcessDAG(); 14670b57cec5SDimitry Andric 14680b57cec5SDimitry Andric SmallVector<SUnit*, 8> TopRoots, BotRoots; 14690b57cec5SDimitry Andric findRootsAndBiasEdges(TopRoots, BotRoots); 14700b57cec5SDimitry Andric 14710b57cec5SDimitry Andric // Initialize the strategy before modifying the DAG. 14720b57cec5SDimitry Andric // This may initialize a DFSResult to be used for queue priority. 14730b57cec5SDimitry Andric SchedImpl->initialize(this); 14740b57cec5SDimitry Andric 14750b57cec5SDimitry Andric LLVM_DEBUG(dump()); 14760b57cec5SDimitry Andric if (PrintDAGs) dump(); 14770b57cec5SDimitry Andric if (ViewMISchedDAGs) viewGraph(); 14780b57cec5SDimitry Andric 14790b57cec5SDimitry Andric // Initialize ready queues now that the DAG and priority data are finalized. 14800b57cec5SDimitry Andric initQueues(TopRoots, BotRoots); 14810b57cec5SDimitry Andric 14820b57cec5SDimitry Andric bool IsTopNode = false; 14830b57cec5SDimitry Andric while (true) { 14840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** ScheduleDAGMILive::schedule picking next node\n"); 14850b57cec5SDimitry Andric SUnit *SU = SchedImpl->pickNode(IsTopNode); 14860b57cec5SDimitry Andric if (!SU) break; 14870b57cec5SDimitry Andric 14880b57cec5SDimitry Andric assert(!SU->isScheduled && "Node already scheduled"); 14890b57cec5SDimitry Andric if (!checkSchedLimit()) 14900b57cec5SDimitry Andric break; 14910b57cec5SDimitry Andric 14920b57cec5SDimitry Andric scheduleMI(SU, IsTopNode); 14930b57cec5SDimitry Andric 14940b57cec5SDimitry Andric if (DFSResult) { 14950b57cec5SDimitry Andric unsigned SubtreeID = DFSResult->getSubtreeID(SU); 14960b57cec5SDimitry Andric if (!ScheduledTrees.test(SubtreeID)) { 14970b57cec5SDimitry Andric ScheduledTrees.set(SubtreeID); 14980b57cec5SDimitry Andric DFSResult->scheduleTree(SubtreeID); 14990b57cec5SDimitry Andric SchedImpl->scheduleTree(SubtreeID); 15000b57cec5SDimitry Andric } 15010b57cec5SDimitry Andric } 15020b57cec5SDimitry Andric 15030b57cec5SDimitry Andric // Notify the scheduling strategy after updating the DAG. 15040b57cec5SDimitry Andric SchedImpl->schedNode(SU, IsTopNode); 15050b57cec5SDimitry Andric 15060b57cec5SDimitry Andric updateQueues(SU, IsTopNode); 15070b57cec5SDimitry Andric } 15080b57cec5SDimitry Andric assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); 15090b57cec5SDimitry Andric 15100b57cec5SDimitry Andric placeDebugValues(); 15110b57cec5SDimitry Andric 15120b57cec5SDimitry Andric LLVM_DEBUG({ 15130b57cec5SDimitry Andric dbgs() << "*** Final schedule for " 15140b57cec5SDimitry Andric << printMBBReference(*begin()->getParent()) << " ***\n"; 15150b57cec5SDimitry Andric dumpSchedule(); 15160b57cec5SDimitry Andric dbgs() << '\n'; 15170b57cec5SDimitry Andric }); 15180b57cec5SDimitry Andric } 15190b57cec5SDimitry Andric 15200b57cec5SDimitry Andric /// Build the DAG and setup three register pressure trackers. 15210b57cec5SDimitry Andric void ScheduleDAGMILive::buildDAGWithRegPressure() { 15220b57cec5SDimitry Andric if (!ShouldTrackPressure) { 15230b57cec5SDimitry Andric RPTracker.reset(); 15240b57cec5SDimitry Andric RegionCriticalPSets.clear(); 15250b57cec5SDimitry Andric buildSchedGraph(AA); 15260b57cec5SDimitry Andric return; 15270b57cec5SDimitry Andric } 15280b57cec5SDimitry Andric 15290b57cec5SDimitry Andric // Initialize the register pressure tracker used by buildSchedGraph. 15300b57cec5SDimitry Andric RPTracker.init(&MF, RegClassInfo, LIS, BB, LiveRegionEnd, 15310b57cec5SDimitry Andric ShouldTrackLaneMasks, /*TrackUntiedDefs=*/true); 15320b57cec5SDimitry Andric 15330b57cec5SDimitry Andric // Account for liveness generate by the region boundary. 15340b57cec5SDimitry Andric if (LiveRegionEnd != RegionEnd) 15350b57cec5SDimitry Andric RPTracker.recede(); 15360b57cec5SDimitry Andric 15370b57cec5SDimitry Andric // Build the DAG, and compute current register pressure. 15380b57cec5SDimitry Andric buildSchedGraph(AA, &RPTracker, &SUPressureDiffs, LIS, ShouldTrackLaneMasks); 15390b57cec5SDimitry Andric 15400b57cec5SDimitry Andric // Initialize top/bottom trackers after computing region pressure. 15410b57cec5SDimitry Andric initRegPressure(); 15420b57cec5SDimitry Andric } 15430b57cec5SDimitry Andric 15440b57cec5SDimitry Andric void ScheduleDAGMILive::computeDFSResult() { 15450b57cec5SDimitry Andric if (!DFSResult) 15460b57cec5SDimitry Andric DFSResult = new SchedDFSResult(/*BottomU*/true, MinSubtreeSize); 15470b57cec5SDimitry Andric DFSResult->clear(); 15480b57cec5SDimitry Andric ScheduledTrees.clear(); 15490b57cec5SDimitry Andric DFSResult->resize(SUnits.size()); 15500b57cec5SDimitry Andric DFSResult->compute(SUnits); 15510b57cec5SDimitry Andric ScheduledTrees.resize(DFSResult->getNumSubtrees()); 15520b57cec5SDimitry Andric } 15530b57cec5SDimitry Andric 15540b57cec5SDimitry Andric /// Compute the max cyclic critical path through the DAG. The scheduling DAG 15550b57cec5SDimitry Andric /// only provides the critical path for single block loops. To handle loops that 15560b57cec5SDimitry Andric /// span blocks, we could use the vreg path latencies provided by 15570b57cec5SDimitry Andric /// MachineTraceMetrics instead. However, MachineTraceMetrics is not currently 15580b57cec5SDimitry Andric /// available for use in the scheduler. 15590b57cec5SDimitry Andric /// 15600b57cec5SDimitry Andric /// The cyclic path estimation identifies a def-use pair that crosses the back 15610b57cec5SDimitry Andric /// edge and considers the depth and height of the nodes. For example, consider 15620b57cec5SDimitry Andric /// the following instruction sequence where each instruction has unit latency 1563e8d8bef9SDimitry Andric /// and defines an eponymous virtual register: 15640b57cec5SDimitry Andric /// 15650b57cec5SDimitry Andric /// a->b(a,c)->c(b)->d(c)->exit 15660b57cec5SDimitry Andric /// 15670b57cec5SDimitry Andric /// The cyclic critical path is a two cycles: b->c->b 15680b57cec5SDimitry Andric /// The acyclic critical path is four cycles: a->b->c->d->exit 15690b57cec5SDimitry Andric /// LiveOutHeight = height(c) = len(c->d->exit) = 2 15700b57cec5SDimitry Andric /// LiveOutDepth = depth(c) + 1 = len(a->b->c) + 1 = 3 15710b57cec5SDimitry Andric /// LiveInHeight = height(b) + 1 = len(b->c->d->exit) + 1 = 4 15720b57cec5SDimitry Andric /// LiveInDepth = depth(b) = len(a->b) = 1 15730b57cec5SDimitry Andric /// 15740b57cec5SDimitry Andric /// LiveOutDepth - LiveInDepth = 3 - 1 = 2 15750b57cec5SDimitry Andric /// LiveInHeight - LiveOutHeight = 4 - 2 = 2 15760b57cec5SDimitry Andric /// CyclicCriticalPath = min(2, 2) = 2 15770b57cec5SDimitry Andric /// 15780b57cec5SDimitry Andric /// This could be relevant to PostRA scheduling, but is currently implemented 15790b57cec5SDimitry Andric /// assuming LiveIntervals. 15800b57cec5SDimitry Andric unsigned ScheduleDAGMILive::computeCyclicCriticalPath() { 15810b57cec5SDimitry Andric // This only applies to single block loop. 15820b57cec5SDimitry Andric if (!BB->isSuccessor(BB)) 15830b57cec5SDimitry Andric return 0; 15840b57cec5SDimitry Andric 15850b57cec5SDimitry Andric unsigned MaxCyclicLatency = 0; 15860b57cec5SDimitry Andric // Visit each live out vreg def to find def/use pairs that cross iterations. 15870b57cec5SDimitry Andric for (const RegisterMaskPair &P : RPTracker.getPressure().LiveOutRegs) { 1588e8d8bef9SDimitry Andric Register Reg = P.RegUnit; 1589bdd1243dSDimitry Andric if (!Reg.isVirtual()) 15900b57cec5SDimitry Andric continue; 15910b57cec5SDimitry Andric const LiveInterval &LI = LIS->getInterval(Reg); 15920b57cec5SDimitry Andric const VNInfo *DefVNI = LI.getVNInfoBefore(LIS->getMBBEndIdx(BB)); 15930b57cec5SDimitry Andric if (!DefVNI) 15940b57cec5SDimitry Andric continue; 15950b57cec5SDimitry Andric 15960b57cec5SDimitry Andric MachineInstr *DefMI = LIS->getInstructionFromIndex(DefVNI->def); 15970b57cec5SDimitry Andric const SUnit *DefSU = getSUnit(DefMI); 15980b57cec5SDimitry Andric if (!DefSU) 15990b57cec5SDimitry Andric continue; 16000b57cec5SDimitry Andric 16010b57cec5SDimitry Andric unsigned LiveOutHeight = DefSU->getHeight(); 16020b57cec5SDimitry Andric unsigned LiveOutDepth = DefSU->getDepth() + DefSU->Latency; 16030b57cec5SDimitry Andric // Visit all local users of the vreg def. 16040b57cec5SDimitry Andric for (const VReg2SUnit &V2SU 16050b57cec5SDimitry Andric : make_range(VRegUses.find(Reg), VRegUses.end())) { 16060b57cec5SDimitry Andric SUnit *SU = V2SU.SU; 16070b57cec5SDimitry Andric if (SU == &ExitSU) 16080b57cec5SDimitry Andric continue; 16090b57cec5SDimitry Andric 16100b57cec5SDimitry Andric // Only consider uses of the phi. 16110b57cec5SDimitry Andric LiveQueryResult LRQ = LI.Query(LIS->getInstructionIndex(*SU->getInstr())); 16120b57cec5SDimitry Andric if (!LRQ.valueIn()->isPHIDef()) 16130b57cec5SDimitry Andric continue; 16140b57cec5SDimitry Andric 16150b57cec5SDimitry Andric // Assume that a path spanning two iterations is a cycle, which could 16160b57cec5SDimitry Andric // overestimate in strange cases. This allows cyclic latency to be 16170b57cec5SDimitry Andric // estimated as the minimum slack of the vreg's depth or height. 16180b57cec5SDimitry Andric unsigned CyclicLatency = 0; 16190b57cec5SDimitry Andric if (LiveOutDepth > SU->getDepth()) 16200b57cec5SDimitry Andric CyclicLatency = LiveOutDepth - SU->getDepth(); 16210b57cec5SDimitry Andric 16220b57cec5SDimitry Andric unsigned LiveInHeight = SU->getHeight() + DefSU->Latency; 16230b57cec5SDimitry Andric if (LiveInHeight > LiveOutHeight) { 16240b57cec5SDimitry Andric if (LiveInHeight - LiveOutHeight < CyclicLatency) 16250b57cec5SDimitry Andric CyclicLatency = LiveInHeight - LiveOutHeight; 16260b57cec5SDimitry Andric } else 16270b57cec5SDimitry Andric CyclicLatency = 0; 16280b57cec5SDimitry Andric 16290b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cyclic Path: SU(" << DefSU->NodeNum << ") -> SU(" 16300b57cec5SDimitry Andric << SU->NodeNum << ") = " << CyclicLatency << "c\n"); 16310b57cec5SDimitry Andric if (CyclicLatency > MaxCyclicLatency) 16320b57cec5SDimitry Andric MaxCyclicLatency = CyclicLatency; 16330b57cec5SDimitry Andric } 16340b57cec5SDimitry Andric } 16350b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cyclic Critical Path: " << MaxCyclicLatency << "c\n"); 16360b57cec5SDimitry Andric return MaxCyclicLatency; 16370b57cec5SDimitry Andric } 16380b57cec5SDimitry Andric 16390b57cec5SDimitry Andric /// Release ExitSU predecessors and setup scheduler queues. Re-position 16400b57cec5SDimitry Andric /// the Top RP tracker in case the region beginning has changed. 16410b57cec5SDimitry Andric void ScheduleDAGMILive::initQueues(ArrayRef<SUnit*> TopRoots, 16420b57cec5SDimitry Andric ArrayRef<SUnit*> BotRoots) { 16430b57cec5SDimitry Andric ScheduleDAGMI::initQueues(TopRoots, BotRoots); 16440b57cec5SDimitry Andric if (ShouldTrackPressure) { 16450b57cec5SDimitry Andric assert(TopRPTracker.getPos() == RegionBegin && "bad initial Top tracker"); 16460b57cec5SDimitry Andric TopRPTracker.setPos(CurrentTop); 16470b57cec5SDimitry Andric } 16480b57cec5SDimitry Andric } 16490b57cec5SDimitry Andric 16500b57cec5SDimitry Andric /// Move an instruction and update register pressure. 16510b57cec5SDimitry Andric void ScheduleDAGMILive::scheduleMI(SUnit *SU, bool IsTopNode) { 16520b57cec5SDimitry Andric // Move the instruction to its new location in the instruction stream. 16530b57cec5SDimitry Andric MachineInstr *MI = SU->getInstr(); 16540b57cec5SDimitry Andric 16550b57cec5SDimitry Andric if (IsTopNode) { 16560b57cec5SDimitry Andric assert(SU->isTopReady() && "node still has unscheduled dependencies"); 16570b57cec5SDimitry Andric if (&*CurrentTop == MI) 16580b57cec5SDimitry Andric CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom); 16590b57cec5SDimitry Andric else { 16600b57cec5SDimitry Andric moveInstruction(MI, CurrentTop); 16610b57cec5SDimitry Andric TopRPTracker.setPos(MI); 16620b57cec5SDimitry Andric } 16630b57cec5SDimitry Andric 16640b57cec5SDimitry Andric if (ShouldTrackPressure) { 16650b57cec5SDimitry Andric // Update top scheduled pressure. 16660b57cec5SDimitry Andric RegisterOperands RegOpers; 1667*0fca6ea1SDimitry Andric RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, 1668*0fca6ea1SDimitry Andric /*IgnoreDead=*/false); 16690b57cec5SDimitry Andric if (ShouldTrackLaneMasks) { 16700b57cec5SDimitry Andric // Adjust liveness and add missing dead+read-undef flags. 16710b57cec5SDimitry Andric SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot(); 16720b57cec5SDimitry Andric RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI); 16730b57cec5SDimitry Andric } else { 16740b57cec5SDimitry Andric // Adjust for missing dead-def flags. 16750b57cec5SDimitry Andric RegOpers.detectDeadDefs(*MI, *LIS); 16760b57cec5SDimitry Andric } 16770b57cec5SDimitry Andric 16780b57cec5SDimitry Andric TopRPTracker.advance(RegOpers); 16790b57cec5SDimitry Andric assert(TopRPTracker.getPos() == CurrentTop && "out of sync"); 16800b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Top Pressure:\n"; dumpRegSetPressure( 16810b57cec5SDimitry Andric TopRPTracker.getRegSetPressureAtPos(), TRI);); 16820b57cec5SDimitry Andric 16830b57cec5SDimitry Andric updateScheduledPressure(SU, TopRPTracker.getPressure().MaxSetPressure); 16840b57cec5SDimitry Andric } 16850b57cec5SDimitry Andric } else { 16860b57cec5SDimitry Andric assert(SU->isBottomReady() && "node still has unscheduled dependencies"); 16870b57cec5SDimitry Andric MachineBasicBlock::iterator priorII = 16880b57cec5SDimitry Andric priorNonDebug(CurrentBottom, CurrentTop); 16890b57cec5SDimitry Andric if (&*priorII == MI) 16900b57cec5SDimitry Andric CurrentBottom = priorII; 16910b57cec5SDimitry Andric else { 16920b57cec5SDimitry Andric if (&*CurrentTop == MI) { 16930b57cec5SDimitry Andric CurrentTop = nextIfDebug(++CurrentTop, priorII); 16940b57cec5SDimitry Andric TopRPTracker.setPos(CurrentTop); 16950b57cec5SDimitry Andric } 16960b57cec5SDimitry Andric moveInstruction(MI, CurrentBottom); 16970b57cec5SDimitry Andric CurrentBottom = MI; 16980b57cec5SDimitry Andric BotRPTracker.setPos(CurrentBottom); 16990b57cec5SDimitry Andric } 17000b57cec5SDimitry Andric if (ShouldTrackPressure) { 17010b57cec5SDimitry Andric RegisterOperands RegOpers; 1702*0fca6ea1SDimitry Andric RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, 1703*0fca6ea1SDimitry Andric /*IgnoreDead=*/false); 17040b57cec5SDimitry Andric if (ShouldTrackLaneMasks) { 17050b57cec5SDimitry Andric // Adjust liveness and add missing dead+read-undef flags. 17060b57cec5SDimitry Andric SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot(); 17070b57cec5SDimitry Andric RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI); 17080b57cec5SDimitry Andric } else { 17090b57cec5SDimitry Andric // Adjust for missing dead-def flags. 17100b57cec5SDimitry Andric RegOpers.detectDeadDefs(*MI, *LIS); 17110b57cec5SDimitry Andric } 17120b57cec5SDimitry Andric 17130b57cec5SDimitry Andric if (BotRPTracker.getPos() != CurrentBottom) 17140b57cec5SDimitry Andric BotRPTracker.recedeSkipDebugValues(); 17150b57cec5SDimitry Andric SmallVector<RegisterMaskPair, 8> LiveUses; 17160b57cec5SDimitry Andric BotRPTracker.recede(RegOpers, &LiveUses); 17170b57cec5SDimitry Andric assert(BotRPTracker.getPos() == CurrentBottom && "out of sync"); 17180b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Bottom Pressure:\n"; dumpRegSetPressure( 17190b57cec5SDimitry Andric BotRPTracker.getRegSetPressureAtPos(), TRI);); 17200b57cec5SDimitry Andric 17210b57cec5SDimitry Andric updateScheduledPressure(SU, BotRPTracker.getPressure().MaxSetPressure); 17220b57cec5SDimitry Andric updatePressureDiffs(LiveUses); 17230b57cec5SDimitry Andric } 17240b57cec5SDimitry Andric } 17250b57cec5SDimitry Andric } 17260b57cec5SDimitry Andric 17270b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 17280b57cec5SDimitry Andric // BaseMemOpClusterMutation - DAG post-processing to cluster loads or stores. 17290b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 17300b57cec5SDimitry Andric 17310b57cec5SDimitry Andric namespace { 17320b57cec5SDimitry Andric 17330b57cec5SDimitry Andric /// Post-process the DAG to create cluster edges between neighboring 17340b57cec5SDimitry Andric /// loads or between neighboring stores. 17350b57cec5SDimitry Andric class BaseMemOpClusterMutation : public ScheduleDAGMutation { 17360b57cec5SDimitry Andric struct MemOpInfo { 17370b57cec5SDimitry Andric SUnit *SU; 17385ffd83dbSDimitry Andric SmallVector<const MachineOperand *, 4> BaseOps; 17390b57cec5SDimitry Andric int64_t Offset; 1740*0fca6ea1SDimitry Andric LocationSize Width; 17415f757f3fSDimitry Andric bool OffsetIsScalable; 17420b57cec5SDimitry Andric 17435ffd83dbSDimitry Andric MemOpInfo(SUnit *SU, ArrayRef<const MachineOperand *> BaseOps, 1744*0fca6ea1SDimitry Andric int64_t Offset, bool OffsetIsScalable, LocationSize Width) 17455ffd83dbSDimitry Andric : SU(SU), BaseOps(BaseOps.begin(), BaseOps.end()), Offset(Offset), 17465f757f3fSDimitry Andric Width(Width), OffsetIsScalable(OffsetIsScalable) {} 17470b57cec5SDimitry Andric 17485ffd83dbSDimitry Andric static bool Compare(const MachineOperand *const &A, 17495ffd83dbSDimitry Andric const MachineOperand *const &B) { 17505ffd83dbSDimitry Andric if (A->getType() != B->getType()) 17515ffd83dbSDimitry Andric return A->getType() < B->getType(); 17525ffd83dbSDimitry Andric if (A->isReg()) 17535ffd83dbSDimitry Andric return A->getReg() < B->getReg(); 17545ffd83dbSDimitry Andric if (A->isFI()) { 17555ffd83dbSDimitry Andric const MachineFunction &MF = *A->getParent()->getParent()->getParent(); 17560b57cec5SDimitry Andric const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering(); 17570b57cec5SDimitry Andric bool StackGrowsDown = TFI.getStackGrowthDirection() == 17580b57cec5SDimitry Andric TargetFrameLowering::StackGrowsDown; 17595ffd83dbSDimitry Andric return StackGrowsDown ? A->getIndex() > B->getIndex() 17605ffd83dbSDimitry Andric : A->getIndex() < B->getIndex(); 17610b57cec5SDimitry Andric } 17620b57cec5SDimitry Andric 17630b57cec5SDimitry Andric llvm_unreachable("MemOpClusterMutation only supports register or frame " 17640b57cec5SDimitry Andric "index bases."); 17650b57cec5SDimitry Andric } 17665ffd83dbSDimitry Andric 17675ffd83dbSDimitry Andric bool operator<(const MemOpInfo &RHS) const { 17685ffd83dbSDimitry Andric // FIXME: Don't compare everything twice. Maybe use C++20 three way 17695ffd83dbSDimitry Andric // comparison instead when it's available. 17705ffd83dbSDimitry Andric if (std::lexicographical_compare(BaseOps.begin(), BaseOps.end(), 17715ffd83dbSDimitry Andric RHS.BaseOps.begin(), RHS.BaseOps.end(), 17725ffd83dbSDimitry Andric Compare)) 17735ffd83dbSDimitry Andric return true; 17745ffd83dbSDimitry Andric if (std::lexicographical_compare(RHS.BaseOps.begin(), RHS.BaseOps.end(), 17755ffd83dbSDimitry Andric BaseOps.begin(), BaseOps.end(), Compare)) 17765ffd83dbSDimitry Andric return false; 17775ffd83dbSDimitry Andric if (Offset != RHS.Offset) 17785ffd83dbSDimitry Andric return Offset < RHS.Offset; 17795ffd83dbSDimitry Andric return SU->NodeNum < RHS.SU->NodeNum; 17805ffd83dbSDimitry Andric } 17810b57cec5SDimitry Andric }; 17820b57cec5SDimitry Andric 17830b57cec5SDimitry Andric const TargetInstrInfo *TII; 17840b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 17850b57cec5SDimitry Andric bool IsLoad; 17867a6dacacSDimitry Andric bool ReorderWhileClustering; 17870b57cec5SDimitry Andric 17880b57cec5SDimitry Andric public: 17890b57cec5SDimitry Andric BaseMemOpClusterMutation(const TargetInstrInfo *tii, 17907a6dacacSDimitry Andric const TargetRegisterInfo *tri, bool IsLoad, 17917a6dacacSDimitry Andric bool ReorderWhileClustering) 17927a6dacacSDimitry Andric : TII(tii), TRI(tri), IsLoad(IsLoad), 17937a6dacacSDimitry Andric ReorderWhileClustering(ReorderWhileClustering) {} 17940b57cec5SDimitry Andric 17950b57cec5SDimitry Andric void apply(ScheduleDAGInstrs *DAGInstrs) override; 17960b57cec5SDimitry Andric 17970b57cec5SDimitry Andric protected: 1798e8d8bef9SDimitry Andric void clusterNeighboringMemOps(ArrayRef<MemOpInfo> MemOps, bool FastCluster, 1799e8d8bef9SDimitry Andric ScheduleDAGInstrs *DAG); 1800e8d8bef9SDimitry Andric void collectMemOpRecords(std::vector<SUnit> &SUnits, 1801e8d8bef9SDimitry Andric SmallVectorImpl<MemOpInfo> &MemOpRecords); 1802e8d8bef9SDimitry Andric bool groupMemOps(ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG, 1803e8d8bef9SDimitry Andric DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups); 18040b57cec5SDimitry Andric }; 18050b57cec5SDimitry Andric 18060b57cec5SDimitry Andric class StoreClusterMutation : public BaseMemOpClusterMutation { 18070b57cec5SDimitry Andric public: 18080b57cec5SDimitry Andric StoreClusterMutation(const TargetInstrInfo *tii, 18097a6dacacSDimitry Andric const TargetRegisterInfo *tri, 18107a6dacacSDimitry Andric bool ReorderWhileClustering) 18117a6dacacSDimitry Andric : BaseMemOpClusterMutation(tii, tri, false, ReorderWhileClustering) {} 18120b57cec5SDimitry Andric }; 18130b57cec5SDimitry Andric 18140b57cec5SDimitry Andric class LoadClusterMutation : public BaseMemOpClusterMutation { 18150b57cec5SDimitry Andric public: 18167a6dacacSDimitry Andric LoadClusterMutation(const TargetInstrInfo *tii, const TargetRegisterInfo *tri, 18177a6dacacSDimitry Andric bool ReorderWhileClustering) 18187a6dacacSDimitry Andric : BaseMemOpClusterMutation(tii, tri, true, ReorderWhileClustering) {} 18190b57cec5SDimitry Andric }; 18200b57cec5SDimitry Andric 18210b57cec5SDimitry Andric } // end anonymous namespace 18220b57cec5SDimitry Andric 18230b57cec5SDimitry Andric namespace llvm { 18240b57cec5SDimitry Andric 18250b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation> 18260b57cec5SDimitry Andric createLoadClusterDAGMutation(const TargetInstrInfo *TII, 18277a6dacacSDimitry Andric const TargetRegisterInfo *TRI, 18287a6dacacSDimitry Andric bool ReorderWhileClustering) { 18297a6dacacSDimitry Andric return EnableMemOpCluster ? std::make_unique<LoadClusterMutation>( 18307a6dacacSDimitry Andric TII, TRI, ReorderWhileClustering) 18310b57cec5SDimitry Andric : nullptr; 18320b57cec5SDimitry Andric } 18330b57cec5SDimitry Andric 18340b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation> 18350b57cec5SDimitry Andric createStoreClusterDAGMutation(const TargetInstrInfo *TII, 18367a6dacacSDimitry Andric const TargetRegisterInfo *TRI, 18377a6dacacSDimitry Andric bool ReorderWhileClustering) { 18387a6dacacSDimitry Andric return EnableMemOpCluster ? std::make_unique<StoreClusterMutation>( 18397a6dacacSDimitry Andric TII, TRI, ReorderWhileClustering) 18400b57cec5SDimitry Andric : nullptr; 18410b57cec5SDimitry Andric } 18420b57cec5SDimitry Andric 18430b57cec5SDimitry Andric } // end namespace llvm 18440b57cec5SDimitry Andric 1845e8d8bef9SDimitry Andric // Sorting all the loads/stores first, then for each load/store, checking the 1846e8d8bef9SDimitry Andric // following load/store one by one, until reach the first non-dependent one and 1847e8d8bef9SDimitry Andric // call target hook to see if they can cluster. 1848e8d8bef9SDimitry Andric // If FastCluster is enabled, we assume that, all the loads/stores have been 1849e8d8bef9SDimitry Andric // preprocessed and now, they didn't have dependencies on each other. 18500b57cec5SDimitry Andric void BaseMemOpClusterMutation::clusterNeighboringMemOps( 1851e8d8bef9SDimitry Andric ArrayRef<MemOpInfo> MemOpRecords, bool FastCluster, 1852e8d8bef9SDimitry Andric ScheduleDAGInstrs *DAG) { 1853e8d8bef9SDimitry Andric // Keep track of the current cluster length and bytes for each SUnit. 1854e8d8bef9SDimitry Andric DenseMap<unsigned, std::pair<unsigned, unsigned>> SUnit2ClusterInfo; 18555ffd83dbSDimitry Andric 18565ffd83dbSDimitry Andric // At this point, `MemOpRecords` array must hold atleast two mem ops. Try to 18575ffd83dbSDimitry Andric // cluster mem ops collected within `MemOpRecords` array. 18580b57cec5SDimitry Andric for (unsigned Idx = 0, End = MemOpRecords.size(); Idx < (End - 1); ++Idx) { 18595ffd83dbSDimitry Andric // Decision to cluster mem ops is taken based on target dependent logic 18605ffd83dbSDimitry Andric auto MemOpa = MemOpRecords[Idx]; 1861e8d8bef9SDimitry Andric 1862e8d8bef9SDimitry Andric // Seek for the next load/store to do the cluster. 1863e8d8bef9SDimitry Andric unsigned NextIdx = Idx + 1; 1864e8d8bef9SDimitry Andric for (; NextIdx < End; ++NextIdx) 1865e8d8bef9SDimitry Andric // Skip if MemOpb has been clustered already or has dependency with 1866e8d8bef9SDimitry Andric // MemOpa. 1867e8d8bef9SDimitry Andric if (!SUnit2ClusterInfo.count(MemOpRecords[NextIdx].SU->NodeNum) && 1868e8d8bef9SDimitry Andric (FastCluster || 1869e8d8bef9SDimitry Andric (!DAG->IsReachable(MemOpRecords[NextIdx].SU, MemOpa.SU) && 1870e8d8bef9SDimitry Andric !DAG->IsReachable(MemOpa.SU, MemOpRecords[NextIdx].SU)))) 1871e8d8bef9SDimitry Andric break; 1872e8d8bef9SDimitry Andric if (NextIdx == End) 18735ffd83dbSDimitry Andric continue; 1874e8d8bef9SDimitry Andric 1875e8d8bef9SDimitry Andric auto MemOpb = MemOpRecords[NextIdx]; 1876e8d8bef9SDimitry Andric unsigned ClusterLength = 2; 1877*0fca6ea1SDimitry Andric unsigned CurrentClusterBytes = MemOpa.Width.getValue().getKnownMinValue() + 1878*0fca6ea1SDimitry Andric MemOpb.Width.getValue().getKnownMinValue(); 1879e8d8bef9SDimitry Andric if (SUnit2ClusterInfo.count(MemOpa.SU->NodeNum)) { 1880e8d8bef9SDimitry Andric ClusterLength = SUnit2ClusterInfo[MemOpa.SU->NodeNum].first + 1; 1881*0fca6ea1SDimitry Andric CurrentClusterBytes = SUnit2ClusterInfo[MemOpa.SU->NodeNum].second + 1882*0fca6ea1SDimitry Andric MemOpb.Width.getValue().getKnownMinValue(); 18835ffd83dbSDimitry Andric } 18845ffd83dbSDimitry Andric 18855f757f3fSDimitry Andric if (!TII->shouldClusterMemOps(MemOpa.BaseOps, MemOpa.Offset, 18865f757f3fSDimitry Andric MemOpa.OffsetIsScalable, MemOpb.BaseOps, 18875f757f3fSDimitry Andric MemOpb.Offset, MemOpb.OffsetIsScalable, 18885f757f3fSDimitry Andric ClusterLength, CurrentClusterBytes)) 1889e8d8bef9SDimitry Andric continue; 1890e8d8bef9SDimitry Andric 18915ffd83dbSDimitry Andric SUnit *SUa = MemOpa.SU; 18925ffd83dbSDimitry Andric SUnit *SUb = MemOpb.SU; 18937a6dacacSDimitry Andric if (!ReorderWhileClustering && SUa->NodeNum > SUb->NodeNum) 1894480093f4SDimitry Andric std::swap(SUa, SUb); 18955ffd83dbSDimitry Andric 18965ffd83dbSDimitry Andric // FIXME: Is this check really required? 1897e8d8bef9SDimitry Andric if (!DAG->addEdge(SUb, SDep(SUa, SDep::Cluster))) 18985ffd83dbSDimitry Andric continue; 18995ffd83dbSDimitry Andric 19000b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cluster ld/st SU(" << SUa->NodeNum << ") - SU(" 19010b57cec5SDimitry Andric << SUb->NodeNum << ")\n"); 1902e8d8bef9SDimitry Andric ++NumClustered; 19035ffd83dbSDimitry Andric 1904e8d8bef9SDimitry Andric if (IsLoad) { 19050b57cec5SDimitry Andric // Copy successor edges from SUa to SUb. Interleaving computation 19060b57cec5SDimitry Andric // dependent on SUa can prevent load combining due to register reuse. 19075ffd83dbSDimitry Andric // Predecessor edges do not need to be copied from SUb to SUa since 19085ffd83dbSDimitry Andric // nearby loads should have effectively the same inputs. 19090b57cec5SDimitry Andric for (const SDep &Succ : SUa->Succs) { 19100b57cec5SDimitry Andric if (Succ.getSUnit() == SUb) 19110b57cec5SDimitry Andric continue; 19120b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Copy Succ SU(" << Succ.getSUnit()->NodeNum 19130b57cec5SDimitry Andric << ")\n"); 19140b57cec5SDimitry Andric DAG->addEdge(Succ.getSUnit(), SDep(SUb, SDep::Artificial)); 19150b57cec5SDimitry Andric } 1916e8d8bef9SDimitry Andric } else { 1917e8d8bef9SDimitry Andric // Copy predecessor edges from SUb to SUa to avoid the SUnits that 1918e8d8bef9SDimitry Andric // SUb dependent on scheduled in-between SUb and SUa. Successor edges 1919e8d8bef9SDimitry Andric // do not need to be copied from SUa to SUb since no one will depend 1920e8d8bef9SDimitry Andric // on stores. 1921e8d8bef9SDimitry Andric // Notice that, we don't need to care about the memory dependency as 1922e8d8bef9SDimitry Andric // we won't try to cluster them if they have any memory dependency. 1923e8d8bef9SDimitry Andric for (const SDep &Pred : SUb->Preds) { 1924e8d8bef9SDimitry Andric if (Pred.getSUnit() == SUa) 1925e8d8bef9SDimitry Andric continue; 1926e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Copy Pred SU(" << Pred.getSUnit()->NodeNum 1927e8d8bef9SDimitry Andric << ")\n"); 1928e8d8bef9SDimitry Andric DAG->addEdge(SUa, SDep(Pred.getSUnit(), SDep::Artificial)); 1929e8d8bef9SDimitry Andric } 1930e8d8bef9SDimitry Andric } 1931e8d8bef9SDimitry Andric 1932e8d8bef9SDimitry Andric SUnit2ClusterInfo[MemOpb.SU->NodeNum] = {ClusterLength, 1933e8d8bef9SDimitry Andric CurrentClusterBytes}; 19345ffd83dbSDimitry Andric 19355ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " Curr cluster length: " << ClusterLength 19365ffd83dbSDimitry Andric << ", Curr cluster bytes: " << CurrentClusterBytes 19375ffd83dbSDimitry Andric << "\n"); 19380b57cec5SDimitry Andric } 19390b57cec5SDimitry Andric } 19400b57cec5SDimitry Andric 1941e8d8bef9SDimitry Andric void BaseMemOpClusterMutation::collectMemOpRecords( 1942e8d8bef9SDimitry Andric std::vector<SUnit> &SUnits, SmallVectorImpl<MemOpInfo> &MemOpRecords) { 1943e8d8bef9SDimitry Andric for (auto &SU : SUnits) { 19440b57cec5SDimitry Andric if ((IsLoad && !SU.getInstr()->mayLoad()) || 19450b57cec5SDimitry Andric (!IsLoad && !SU.getInstr()->mayStore())) 19460b57cec5SDimitry Andric continue; 19470b57cec5SDimitry Andric 1948e8d8bef9SDimitry Andric const MachineInstr &MI = *SU.getInstr(); 1949e8d8bef9SDimitry Andric SmallVector<const MachineOperand *, 4> BaseOps; 1950e8d8bef9SDimitry Andric int64_t Offset; 1951e8d8bef9SDimitry Andric bool OffsetIsScalable; 1952*0fca6ea1SDimitry Andric LocationSize Width = 0; 1953e8d8bef9SDimitry Andric if (TII->getMemOperandsWithOffsetWidth(MI, BaseOps, Offset, 1954e8d8bef9SDimitry Andric OffsetIsScalable, Width, TRI)) { 19555f757f3fSDimitry Andric MemOpRecords.push_back( 19565f757f3fSDimitry Andric MemOpInfo(&SU, BaseOps, Offset, OffsetIsScalable, Width)); 1957e8d8bef9SDimitry Andric 1958e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Num BaseOps: " << BaseOps.size() << ", Offset: " 1959e8d8bef9SDimitry Andric << Offset << ", OffsetIsScalable: " << OffsetIsScalable 1960e8d8bef9SDimitry Andric << ", Width: " << Width << "\n"); 1961e8d8bef9SDimitry Andric } 1962e8d8bef9SDimitry Andric #ifndef NDEBUG 1963fcaf7f86SDimitry Andric for (const auto *Op : BaseOps) 1964e8d8bef9SDimitry Andric assert(Op); 1965e8d8bef9SDimitry Andric #endif 1966e8d8bef9SDimitry Andric } 1967e8d8bef9SDimitry Andric } 1968e8d8bef9SDimitry Andric 1969e8d8bef9SDimitry Andric bool BaseMemOpClusterMutation::groupMemOps( 1970e8d8bef9SDimitry Andric ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG, 1971e8d8bef9SDimitry Andric DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups) { 1972e8d8bef9SDimitry Andric bool FastCluster = 1973e8d8bef9SDimitry Andric ForceFastCluster || 1974e8d8bef9SDimitry Andric MemOps.size() * DAG->SUnits.size() / 1000 > FastClusterThreshold; 1975e8d8bef9SDimitry Andric 1976e8d8bef9SDimitry Andric for (const auto &MemOp : MemOps) { 19770b57cec5SDimitry Andric unsigned ChainPredID = DAG->SUnits.size(); 1978e8d8bef9SDimitry Andric if (FastCluster) { 1979e8d8bef9SDimitry Andric for (const SDep &Pred : MemOp.SU->Preds) { 1980e8d8bef9SDimitry Andric // We only want to cluster the mem ops that have the same ctrl(non-data) 1981e8d8bef9SDimitry Andric // pred so that they didn't have ctrl dependency for each other. But for 1982e8d8bef9SDimitry Andric // store instrs, we can still cluster them if the pred is load instr. 1983e8d8bef9SDimitry Andric if ((Pred.isCtrl() && 1984e8d8bef9SDimitry Andric (IsLoad || 1985e8d8bef9SDimitry Andric (Pred.getSUnit() && Pred.getSUnit()->getInstr()->mayStore()))) && 1986e8d8bef9SDimitry Andric !Pred.isArtificial()) { 19870b57cec5SDimitry Andric ChainPredID = Pred.getSUnit()->NodeNum; 19880b57cec5SDimitry Andric break; 19890b57cec5SDimitry Andric } 19900b57cec5SDimitry Andric } 1991e8d8bef9SDimitry Andric } else 1992e8d8bef9SDimitry Andric ChainPredID = 0; 1993e8d8bef9SDimitry Andric 1994e8d8bef9SDimitry Andric Groups[ChainPredID].push_back(MemOp); 1995e8d8bef9SDimitry Andric } 1996e8d8bef9SDimitry Andric return FastCluster; 19970b57cec5SDimitry Andric } 19980b57cec5SDimitry Andric 1999e8d8bef9SDimitry Andric /// Callback from DAG postProcessing to create cluster edges for loads/stores. 2000e8d8bef9SDimitry Andric void BaseMemOpClusterMutation::apply(ScheduleDAGInstrs *DAG) { 2001e8d8bef9SDimitry Andric // Collect all the clusterable loads/stores 2002e8d8bef9SDimitry Andric SmallVector<MemOpInfo, 32> MemOpRecords; 2003e8d8bef9SDimitry Andric collectMemOpRecords(DAG->SUnits, MemOpRecords); 2004e8d8bef9SDimitry Andric 2005e8d8bef9SDimitry Andric if (MemOpRecords.size() < 2) 2006e8d8bef9SDimitry Andric return; 2007e8d8bef9SDimitry Andric 2008e8d8bef9SDimitry Andric // Put the loads/stores without dependency into the same group with some 2009e8d8bef9SDimitry Andric // heuristic if the DAG is too complex to avoid compiling time blow up. 2010e8d8bef9SDimitry Andric // Notice that, some fusion pair could be lost with this. 2011e8d8bef9SDimitry Andric DenseMap<unsigned, SmallVector<MemOpInfo, 32>> Groups; 2012e8d8bef9SDimitry Andric bool FastCluster = groupMemOps(MemOpRecords, DAG, Groups); 2013e8d8bef9SDimitry Andric 2014e8d8bef9SDimitry Andric for (auto &Group : Groups) { 2015e8d8bef9SDimitry Andric // Sorting the loads/stores, so that, we can stop the cluster as early as 2016e8d8bef9SDimitry Andric // possible. 2017e8d8bef9SDimitry Andric llvm::sort(Group.second); 2018e8d8bef9SDimitry Andric 2019e8d8bef9SDimitry Andric // Trying to cluster all the neighboring loads/stores. 2020e8d8bef9SDimitry Andric clusterNeighboringMemOps(Group.second, FastCluster, DAG); 2021e8d8bef9SDimitry Andric } 20220b57cec5SDimitry Andric } 20230b57cec5SDimitry Andric 20240b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 20250b57cec5SDimitry Andric // CopyConstrain - DAG post-processing to encourage copy elimination. 20260b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 20270b57cec5SDimitry Andric 20280b57cec5SDimitry Andric namespace { 20290b57cec5SDimitry Andric 20300b57cec5SDimitry Andric /// Post-process the DAG to create weak edges from all uses of a copy to 20310b57cec5SDimitry Andric /// the one use that defines the copy's source vreg, most likely an induction 20320b57cec5SDimitry Andric /// variable increment. 20330b57cec5SDimitry Andric class CopyConstrain : public ScheduleDAGMutation { 20340b57cec5SDimitry Andric // Transient state. 20350b57cec5SDimitry Andric SlotIndex RegionBeginIdx; 20360b57cec5SDimitry Andric 20370b57cec5SDimitry Andric // RegionEndIdx is the slot index of the last non-debug instruction in the 20380b57cec5SDimitry Andric // scheduling region. So we may have RegionBeginIdx == RegionEndIdx. 20390b57cec5SDimitry Andric SlotIndex RegionEndIdx; 20400b57cec5SDimitry Andric 20410b57cec5SDimitry Andric public: 20420b57cec5SDimitry Andric CopyConstrain(const TargetInstrInfo *, const TargetRegisterInfo *) {} 20430b57cec5SDimitry Andric 20440b57cec5SDimitry Andric void apply(ScheduleDAGInstrs *DAGInstrs) override; 20450b57cec5SDimitry Andric 20460b57cec5SDimitry Andric protected: 20470b57cec5SDimitry Andric void constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG); 20480b57cec5SDimitry Andric }; 20490b57cec5SDimitry Andric 20500b57cec5SDimitry Andric } // end anonymous namespace 20510b57cec5SDimitry Andric 20520b57cec5SDimitry Andric namespace llvm { 20530b57cec5SDimitry Andric 20540b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation> 20550b57cec5SDimitry Andric createCopyConstrainDAGMutation(const TargetInstrInfo *TII, 20560b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 20578bcb0991SDimitry Andric return std::make_unique<CopyConstrain>(TII, TRI); 20580b57cec5SDimitry Andric } 20590b57cec5SDimitry Andric 20600b57cec5SDimitry Andric } // end namespace llvm 20610b57cec5SDimitry Andric 20620b57cec5SDimitry Andric /// constrainLocalCopy handles two possibilities: 20630b57cec5SDimitry Andric /// 1) Local src: 20640b57cec5SDimitry Andric /// I0: = dst 20650b57cec5SDimitry Andric /// I1: src = ... 20660b57cec5SDimitry Andric /// I2: = dst 20670b57cec5SDimitry Andric /// I3: dst = src (copy) 20680b57cec5SDimitry Andric /// (create pred->succ edges I0->I1, I2->I1) 20690b57cec5SDimitry Andric /// 20700b57cec5SDimitry Andric /// 2) Local copy: 20710b57cec5SDimitry Andric /// I0: dst = src (copy) 20720b57cec5SDimitry Andric /// I1: = dst 20730b57cec5SDimitry Andric /// I2: src = ... 20740b57cec5SDimitry Andric /// I3: = dst 20750b57cec5SDimitry Andric /// (create pred->succ edges I1->I2, I3->I2) 20760b57cec5SDimitry Andric /// 20770b57cec5SDimitry Andric /// Although the MachineScheduler is currently constrained to single blocks, 20780b57cec5SDimitry Andric /// this algorithm should handle extended blocks. An EBB is a set of 20790b57cec5SDimitry Andric /// contiguously numbered blocks such that the previous block in the EBB is 20800b57cec5SDimitry Andric /// always the single predecessor. 20810b57cec5SDimitry Andric void CopyConstrain::constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG) { 20820b57cec5SDimitry Andric LiveIntervals *LIS = DAG->getLIS(); 20830b57cec5SDimitry Andric MachineInstr *Copy = CopySU->getInstr(); 20840b57cec5SDimitry Andric 20850b57cec5SDimitry Andric // Check for pure vreg copies. 20860b57cec5SDimitry Andric const MachineOperand &SrcOp = Copy->getOperand(1); 20878bcb0991SDimitry Andric Register SrcReg = SrcOp.getReg(); 2088bdd1243dSDimitry Andric if (!SrcReg.isVirtual() || !SrcOp.readsReg()) 20890b57cec5SDimitry Andric return; 20900b57cec5SDimitry Andric 20910b57cec5SDimitry Andric const MachineOperand &DstOp = Copy->getOperand(0); 20928bcb0991SDimitry Andric Register DstReg = DstOp.getReg(); 2093bdd1243dSDimitry Andric if (!DstReg.isVirtual() || DstOp.isDead()) 20940b57cec5SDimitry Andric return; 20950b57cec5SDimitry Andric 20960b57cec5SDimitry Andric // Check if either the dest or source is local. If it's live across a back 20970b57cec5SDimitry Andric // edge, it's not local. Note that if both vregs are live across the back 20980b57cec5SDimitry Andric // edge, we cannot successfully contrain the copy without cyclic scheduling. 20990b57cec5SDimitry Andric // If both the copy's source and dest are local live intervals, then we 21000b57cec5SDimitry Andric // should treat the dest as the global for the purpose of adding 21010b57cec5SDimitry Andric // constraints. This adds edges from source's other uses to the copy. 21020b57cec5SDimitry Andric unsigned LocalReg = SrcReg; 21030b57cec5SDimitry Andric unsigned GlobalReg = DstReg; 21040b57cec5SDimitry Andric LiveInterval *LocalLI = &LIS->getInterval(LocalReg); 21050b57cec5SDimitry Andric if (!LocalLI->isLocal(RegionBeginIdx, RegionEndIdx)) { 21060b57cec5SDimitry Andric LocalReg = DstReg; 21070b57cec5SDimitry Andric GlobalReg = SrcReg; 21080b57cec5SDimitry Andric LocalLI = &LIS->getInterval(LocalReg); 21090b57cec5SDimitry Andric if (!LocalLI->isLocal(RegionBeginIdx, RegionEndIdx)) 21100b57cec5SDimitry Andric return; 21110b57cec5SDimitry Andric } 21120b57cec5SDimitry Andric LiveInterval *GlobalLI = &LIS->getInterval(GlobalReg); 21130b57cec5SDimitry Andric 21140b57cec5SDimitry Andric // Find the global segment after the start of the local LI. 21150b57cec5SDimitry Andric LiveInterval::iterator GlobalSegment = GlobalLI->find(LocalLI->beginIndex()); 21160b57cec5SDimitry Andric // If GlobalLI does not overlap LocalLI->start, then a copy directly feeds a 21170b57cec5SDimitry Andric // local live range. We could create edges from other global uses to the local 21180b57cec5SDimitry Andric // start, but the coalescer should have already eliminated these cases, so 21190b57cec5SDimitry Andric // don't bother dealing with it. 21200b57cec5SDimitry Andric if (GlobalSegment == GlobalLI->end()) 21210b57cec5SDimitry Andric return; 21220b57cec5SDimitry Andric 21230b57cec5SDimitry Andric // If GlobalSegment is killed at the LocalLI->start, the call to find() 21240b57cec5SDimitry Andric // returned the next global segment. But if GlobalSegment overlaps with 21250b57cec5SDimitry Andric // LocalLI->start, then advance to the next segment. If a hole in GlobalLI 21260b57cec5SDimitry Andric // exists in LocalLI's vicinity, GlobalSegment will be the end of the hole. 21270b57cec5SDimitry Andric if (GlobalSegment->contains(LocalLI->beginIndex())) 21280b57cec5SDimitry Andric ++GlobalSegment; 21290b57cec5SDimitry Andric 21300b57cec5SDimitry Andric if (GlobalSegment == GlobalLI->end()) 21310b57cec5SDimitry Andric return; 21320b57cec5SDimitry Andric 21330b57cec5SDimitry Andric // Check if GlobalLI contains a hole in the vicinity of LocalLI. 21340b57cec5SDimitry Andric if (GlobalSegment != GlobalLI->begin()) { 21350b57cec5SDimitry Andric // Two address defs have no hole. 21360b57cec5SDimitry Andric if (SlotIndex::isSameInstr(std::prev(GlobalSegment)->end, 21370b57cec5SDimitry Andric GlobalSegment->start)) { 21380b57cec5SDimitry Andric return; 21390b57cec5SDimitry Andric } 21400b57cec5SDimitry Andric // If the prior global segment may be defined by the same two-address 21410b57cec5SDimitry Andric // instruction that also defines LocalLI, then can't make a hole here. 21420b57cec5SDimitry Andric if (SlotIndex::isSameInstr(std::prev(GlobalSegment)->start, 21430b57cec5SDimitry Andric LocalLI->beginIndex())) { 21440b57cec5SDimitry Andric return; 21450b57cec5SDimitry Andric } 21460b57cec5SDimitry Andric // If GlobalLI has a prior segment, it must be live into the EBB. Otherwise 21470b57cec5SDimitry Andric // it would be a disconnected component in the live range. 21480b57cec5SDimitry Andric assert(std::prev(GlobalSegment)->start < LocalLI->beginIndex() && 21490b57cec5SDimitry Andric "Disconnected LRG within the scheduling region."); 21500b57cec5SDimitry Andric } 21510b57cec5SDimitry Andric MachineInstr *GlobalDef = LIS->getInstructionFromIndex(GlobalSegment->start); 21520b57cec5SDimitry Andric if (!GlobalDef) 21530b57cec5SDimitry Andric return; 21540b57cec5SDimitry Andric 21550b57cec5SDimitry Andric SUnit *GlobalSU = DAG->getSUnit(GlobalDef); 21560b57cec5SDimitry Andric if (!GlobalSU) 21570b57cec5SDimitry Andric return; 21580b57cec5SDimitry Andric 21590b57cec5SDimitry Andric // GlobalDef is the bottom of the GlobalLI hole. Open the hole by 21600b57cec5SDimitry Andric // constraining the uses of the last local def to precede GlobalDef. 21610b57cec5SDimitry Andric SmallVector<SUnit*,8> LocalUses; 21620b57cec5SDimitry Andric const VNInfo *LastLocalVN = LocalLI->getVNInfoBefore(LocalLI->endIndex()); 21630b57cec5SDimitry Andric MachineInstr *LastLocalDef = LIS->getInstructionFromIndex(LastLocalVN->def); 21640b57cec5SDimitry Andric SUnit *LastLocalSU = DAG->getSUnit(LastLocalDef); 21650b57cec5SDimitry Andric for (const SDep &Succ : LastLocalSU->Succs) { 21660b57cec5SDimitry Andric if (Succ.getKind() != SDep::Data || Succ.getReg() != LocalReg) 21670b57cec5SDimitry Andric continue; 21680b57cec5SDimitry Andric if (Succ.getSUnit() == GlobalSU) 21690b57cec5SDimitry Andric continue; 21700b57cec5SDimitry Andric if (!DAG->canAddEdge(GlobalSU, Succ.getSUnit())) 21710b57cec5SDimitry Andric return; 21720b57cec5SDimitry Andric LocalUses.push_back(Succ.getSUnit()); 21730b57cec5SDimitry Andric } 21740b57cec5SDimitry Andric // Open the top of the GlobalLI hole by constraining any earlier global uses 21750b57cec5SDimitry Andric // to precede the start of LocalLI. 21760b57cec5SDimitry Andric SmallVector<SUnit*,8> GlobalUses; 21770b57cec5SDimitry Andric MachineInstr *FirstLocalDef = 21780b57cec5SDimitry Andric LIS->getInstructionFromIndex(LocalLI->beginIndex()); 21790b57cec5SDimitry Andric SUnit *FirstLocalSU = DAG->getSUnit(FirstLocalDef); 21800b57cec5SDimitry Andric for (const SDep &Pred : GlobalSU->Preds) { 21810b57cec5SDimitry Andric if (Pred.getKind() != SDep::Anti || Pred.getReg() != GlobalReg) 21820b57cec5SDimitry Andric continue; 21830b57cec5SDimitry Andric if (Pred.getSUnit() == FirstLocalSU) 21840b57cec5SDimitry Andric continue; 21850b57cec5SDimitry Andric if (!DAG->canAddEdge(FirstLocalSU, Pred.getSUnit())) 21860b57cec5SDimitry Andric return; 21870b57cec5SDimitry Andric GlobalUses.push_back(Pred.getSUnit()); 21880b57cec5SDimitry Andric } 21890b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Constraining copy SU(" << CopySU->NodeNum << ")\n"); 21900b57cec5SDimitry Andric // Add the weak edges. 2191fe6060f1SDimitry Andric for (SUnit *LU : LocalUses) { 2192fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << " Local use SU(" << LU->NodeNum << ") -> SU(" 21930b57cec5SDimitry Andric << GlobalSU->NodeNum << ")\n"); 2194fe6060f1SDimitry Andric DAG->addEdge(GlobalSU, SDep(LU, SDep::Weak)); 21950b57cec5SDimitry Andric } 2196fe6060f1SDimitry Andric for (SUnit *GU : GlobalUses) { 2197fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << " Global use SU(" << GU->NodeNum << ") -> SU(" 21980b57cec5SDimitry Andric << FirstLocalSU->NodeNum << ")\n"); 2199fe6060f1SDimitry Andric DAG->addEdge(FirstLocalSU, SDep(GU, SDep::Weak)); 22000b57cec5SDimitry Andric } 22010b57cec5SDimitry Andric } 22020b57cec5SDimitry Andric 22030b57cec5SDimitry Andric /// Callback from DAG postProcessing to create weak edges to encourage 22040b57cec5SDimitry Andric /// copy elimination. 22050b57cec5SDimitry Andric void CopyConstrain::apply(ScheduleDAGInstrs *DAGInstrs) { 22060b57cec5SDimitry Andric ScheduleDAGMI *DAG = static_cast<ScheduleDAGMI*>(DAGInstrs); 22070b57cec5SDimitry Andric assert(DAG->hasVRegLiveness() && "Expect VRegs with LiveIntervals"); 22080b57cec5SDimitry Andric 22090b57cec5SDimitry Andric MachineBasicBlock::iterator FirstPos = nextIfDebug(DAG->begin(), DAG->end()); 22100b57cec5SDimitry Andric if (FirstPos == DAG->end()) 22110b57cec5SDimitry Andric return; 22120b57cec5SDimitry Andric RegionBeginIdx = DAG->getLIS()->getInstructionIndex(*FirstPos); 22130b57cec5SDimitry Andric RegionEndIdx = DAG->getLIS()->getInstructionIndex( 22140b57cec5SDimitry Andric *priorNonDebug(DAG->end(), DAG->begin())); 22150b57cec5SDimitry Andric 22160b57cec5SDimitry Andric for (SUnit &SU : DAG->SUnits) { 22170b57cec5SDimitry Andric if (!SU.getInstr()->isCopy()) 22180b57cec5SDimitry Andric continue; 22190b57cec5SDimitry Andric 22200b57cec5SDimitry Andric constrainLocalCopy(&SU, static_cast<ScheduleDAGMILive*>(DAG)); 22210b57cec5SDimitry Andric } 22220b57cec5SDimitry Andric } 22230b57cec5SDimitry Andric 22240b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 22250b57cec5SDimitry Andric // MachineSchedStrategy helpers used by GenericScheduler, GenericPostScheduler 22260b57cec5SDimitry Andric // and possibly other custom schedulers. 22270b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 22280b57cec5SDimitry Andric 22290b57cec5SDimitry Andric static const unsigned InvalidCycle = ~0U; 22300b57cec5SDimitry Andric 22310b57cec5SDimitry Andric SchedBoundary::~SchedBoundary() { delete HazardRec; } 22320b57cec5SDimitry Andric 22330b57cec5SDimitry Andric /// Given a Count of resource usage and a Latency value, return true if a 22340b57cec5SDimitry Andric /// SchedBoundary becomes resource limited. 22350b57cec5SDimitry Andric /// If we are checking after scheduling a node, we should return true when 22360b57cec5SDimitry Andric /// we just reach the resource limit. 22370b57cec5SDimitry Andric static bool checkResourceLimit(unsigned LFactor, unsigned Count, 22380b57cec5SDimitry Andric unsigned Latency, bool AfterSchedNode) { 22390b57cec5SDimitry Andric int ResCntFactor = (int)(Count - (Latency * LFactor)); 22400b57cec5SDimitry Andric if (AfterSchedNode) 22410b57cec5SDimitry Andric return ResCntFactor >= (int)LFactor; 22420b57cec5SDimitry Andric else 22430b57cec5SDimitry Andric return ResCntFactor > (int)LFactor; 22440b57cec5SDimitry Andric } 22450b57cec5SDimitry Andric 22460b57cec5SDimitry Andric void SchedBoundary::reset() { 22470b57cec5SDimitry Andric // A new HazardRec is created for each DAG and owned by SchedBoundary. 22480b57cec5SDimitry Andric // Destroying and reconstructing it is very expensive though. So keep 22490b57cec5SDimitry Andric // invalid, placeholder HazardRecs. 22500b57cec5SDimitry Andric if (HazardRec && HazardRec->isEnabled()) { 22510b57cec5SDimitry Andric delete HazardRec; 22520b57cec5SDimitry Andric HazardRec = nullptr; 22530b57cec5SDimitry Andric } 22540b57cec5SDimitry Andric Available.clear(); 22550b57cec5SDimitry Andric Pending.clear(); 22560b57cec5SDimitry Andric CheckPending = false; 22570b57cec5SDimitry Andric CurrCycle = 0; 22580b57cec5SDimitry Andric CurrMOps = 0; 22590b57cec5SDimitry Andric MinReadyCycle = std::numeric_limits<unsigned>::max(); 22600b57cec5SDimitry Andric ExpectedLatency = 0; 22610b57cec5SDimitry Andric DependentLatency = 0; 22620b57cec5SDimitry Andric RetiredMOps = 0; 22630b57cec5SDimitry Andric MaxExecutedResCount = 0; 22640b57cec5SDimitry Andric ZoneCritResIdx = 0; 22650b57cec5SDimitry Andric IsResourceLimited = false; 22660b57cec5SDimitry Andric ReservedCycles.clear(); 226706c3fb27SDimitry Andric ReservedResourceSegments.clear(); 22680b57cec5SDimitry Andric ReservedCyclesIndex.clear(); 2269fe6060f1SDimitry Andric ResourceGroupSubUnitMasks.clear(); 227081ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 22710b57cec5SDimitry Andric // Track the maximum number of stall cycles that could arise either from the 22720b57cec5SDimitry Andric // latency of a DAG edge or the number of cycles that a processor resource is 22730b57cec5SDimitry Andric // reserved (SchedBoundary::ReservedCycles). 22740b57cec5SDimitry Andric MaxObservedStall = 0; 22750b57cec5SDimitry Andric #endif 22760b57cec5SDimitry Andric // Reserve a zero-count for invalid CritResIdx. 22770b57cec5SDimitry Andric ExecutedResCounts.resize(1); 22780b57cec5SDimitry Andric assert(!ExecutedResCounts[0] && "nonzero count for bad resource"); 22790b57cec5SDimitry Andric } 22800b57cec5SDimitry Andric 22810b57cec5SDimitry Andric void SchedRemainder:: 22820b57cec5SDimitry Andric init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel) { 22830b57cec5SDimitry Andric reset(); 22840b57cec5SDimitry Andric if (!SchedModel->hasInstrSchedModel()) 22850b57cec5SDimitry Andric return; 22860b57cec5SDimitry Andric RemainingCounts.resize(SchedModel->getNumProcResourceKinds()); 22870b57cec5SDimitry Andric for (SUnit &SU : DAG->SUnits) { 22880b57cec5SDimitry Andric const MCSchedClassDesc *SC = DAG->getSchedClass(&SU); 22890b57cec5SDimitry Andric RemIssueCount += SchedModel->getNumMicroOps(SU.getInstr(), SC) 22900b57cec5SDimitry Andric * SchedModel->getMicroOpFactor(); 22910b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter 22920b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC), 22930b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) { 22940b57cec5SDimitry Andric unsigned PIdx = PI->ProcResourceIdx; 22950b57cec5SDimitry Andric unsigned Factor = SchedModel->getResourceFactor(PIdx); 22965f757f3fSDimitry Andric assert(PI->ReleaseAtCycle >= PI->AcquireAtCycle); 22975f757f3fSDimitry Andric RemainingCounts[PIdx] += 22985f757f3fSDimitry Andric (Factor * (PI->ReleaseAtCycle - PI->AcquireAtCycle)); 22990b57cec5SDimitry Andric } 23000b57cec5SDimitry Andric } 23010b57cec5SDimitry Andric } 23020b57cec5SDimitry Andric 23030b57cec5SDimitry Andric void SchedBoundary:: 23040b57cec5SDimitry Andric init(ScheduleDAGMI *dag, const TargetSchedModel *smodel, SchedRemainder *rem) { 23050b57cec5SDimitry Andric reset(); 23060b57cec5SDimitry Andric DAG = dag; 23070b57cec5SDimitry Andric SchedModel = smodel; 23080b57cec5SDimitry Andric Rem = rem; 23090b57cec5SDimitry Andric if (SchedModel->hasInstrSchedModel()) { 23100b57cec5SDimitry Andric unsigned ResourceCount = SchedModel->getNumProcResourceKinds(); 23110b57cec5SDimitry Andric ReservedCyclesIndex.resize(ResourceCount); 23120b57cec5SDimitry Andric ExecutedResCounts.resize(ResourceCount); 2313fe6060f1SDimitry Andric ResourceGroupSubUnitMasks.resize(ResourceCount, APInt(ResourceCount, 0)); 23140b57cec5SDimitry Andric unsigned NumUnits = 0; 23150b57cec5SDimitry Andric 23160b57cec5SDimitry Andric for (unsigned i = 0; i < ResourceCount; ++i) { 23170b57cec5SDimitry Andric ReservedCyclesIndex[i] = NumUnits; 23180b57cec5SDimitry Andric NumUnits += SchedModel->getProcResource(i)->NumUnits; 2319fe6060f1SDimitry Andric if (isUnbufferedGroup(i)) { 2320fe6060f1SDimitry Andric auto SubUnits = SchedModel->getProcResource(i)->SubUnitsIdxBegin; 2321fe6060f1SDimitry Andric for (unsigned U = 0, UE = SchedModel->getProcResource(i)->NumUnits; 2322fe6060f1SDimitry Andric U != UE; ++U) 2323fe6060f1SDimitry Andric ResourceGroupSubUnitMasks[i].setBit(SubUnits[U]); 2324fe6060f1SDimitry Andric } 23250b57cec5SDimitry Andric } 23260b57cec5SDimitry Andric 23270b57cec5SDimitry Andric ReservedCycles.resize(NumUnits, InvalidCycle); 23280b57cec5SDimitry Andric } 23290b57cec5SDimitry Andric } 23300b57cec5SDimitry Andric 23310b57cec5SDimitry Andric /// Compute the stall cycles based on this SUnit's ready time. Heuristics treat 23320b57cec5SDimitry Andric /// these "soft stalls" differently than the hard stall cycles based on CPU 23330b57cec5SDimitry Andric /// resources and computed by checkHazard(). A fully in-order model 23340b57cec5SDimitry Andric /// (MicroOpBufferSize==0) will not make use of this since instructions are not 23350b57cec5SDimitry Andric /// available for scheduling until they are ready. However, a weaker in-order 23360b57cec5SDimitry Andric /// model may use this for heuristics. For example, if a processor has in-order 23370b57cec5SDimitry Andric /// behavior when reading certain resources, this may come into play. 23380b57cec5SDimitry Andric unsigned SchedBoundary::getLatencyStallCycles(SUnit *SU) { 23390b57cec5SDimitry Andric if (!SU->isUnbuffered) 23400b57cec5SDimitry Andric return 0; 23410b57cec5SDimitry Andric 23420b57cec5SDimitry Andric unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle); 23430b57cec5SDimitry Andric if (ReadyCycle > CurrCycle) 23440b57cec5SDimitry Andric return ReadyCycle - CurrCycle; 23450b57cec5SDimitry Andric return 0; 23460b57cec5SDimitry Andric } 23470b57cec5SDimitry Andric 23480b57cec5SDimitry Andric /// Compute the next cycle at which the given processor resource unit 23490b57cec5SDimitry Andric /// can be scheduled. 23500b57cec5SDimitry Andric unsigned SchedBoundary::getNextResourceCycleByInstance(unsigned InstanceIdx, 23515f757f3fSDimitry Andric unsigned ReleaseAtCycle, 23525f757f3fSDimitry Andric unsigned AcquireAtCycle) { 235306c3fb27SDimitry Andric if (SchedModel && SchedModel->enableIntervals()) { 235406c3fb27SDimitry Andric if (isTop()) 235506c3fb27SDimitry Andric return ReservedResourceSegments[InstanceIdx].getFirstAvailableAtFromTop( 23565f757f3fSDimitry Andric CurrCycle, AcquireAtCycle, ReleaseAtCycle); 235706c3fb27SDimitry Andric 235806c3fb27SDimitry Andric return ReservedResourceSegments[InstanceIdx].getFirstAvailableAtFromBottom( 23595f757f3fSDimitry Andric CurrCycle, AcquireAtCycle, ReleaseAtCycle); 236006c3fb27SDimitry Andric } 236106c3fb27SDimitry Andric 23620b57cec5SDimitry Andric unsigned NextUnreserved = ReservedCycles[InstanceIdx]; 23630b57cec5SDimitry Andric // If this resource has never been used, always return cycle zero. 23640b57cec5SDimitry Andric if (NextUnreserved == InvalidCycle) 236506c3fb27SDimitry Andric return CurrCycle; 23660b57cec5SDimitry Andric // For bottom-up scheduling add the cycles needed for the current operation. 23670b57cec5SDimitry Andric if (!isTop()) 23685f757f3fSDimitry Andric NextUnreserved = std::max(CurrCycle, NextUnreserved + ReleaseAtCycle); 23690b57cec5SDimitry Andric return NextUnreserved; 23700b57cec5SDimitry Andric } 23710b57cec5SDimitry Andric 23720b57cec5SDimitry Andric /// Compute the next cycle at which the given processor resource can be 23730b57cec5SDimitry Andric /// scheduled. Returns the next cycle and the index of the processor resource 23740b57cec5SDimitry Andric /// instance in the reserved cycles vector. 23750b57cec5SDimitry Andric std::pair<unsigned, unsigned> 2376fe6060f1SDimitry Andric SchedBoundary::getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx, 23775f757f3fSDimitry Andric unsigned ReleaseAtCycle, 23785f757f3fSDimitry Andric unsigned AcquireAtCycle) { 237906c3fb27SDimitry Andric if (MischedDetailResourceBooking) { 238006c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << " Resource booking (@" << CurrCycle << "c): \n"); 238106c3fb27SDimitry Andric LLVM_DEBUG(dumpReservedCycles()); 238206c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << " getNextResourceCycle (@" << CurrCycle << "c): \n"); 238306c3fb27SDimitry Andric } 23840b57cec5SDimitry Andric unsigned MinNextUnreserved = InvalidCycle; 23850b57cec5SDimitry Andric unsigned InstanceIdx = 0; 23860b57cec5SDimitry Andric unsigned StartIndex = ReservedCyclesIndex[PIdx]; 23870b57cec5SDimitry Andric unsigned NumberOfInstances = SchedModel->getProcResource(PIdx)->NumUnits; 23880b57cec5SDimitry Andric assert(NumberOfInstances > 0 && 23890b57cec5SDimitry Andric "Cannot have zero instances of a ProcResource"); 23900b57cec5SDimitry Andric 2391fe6060f1SDimitry Andric if (isUnbufferedGroup(PIdx)) { 23925f757f3fSDimitry Andric // If any subunits are used by the instruction, report that the 23935f757f3fSDimitry Andric // subunits of the resource group are available at the first cycle 23945f757f3fSDimitry Andric // in which the unit is available, effectively removing the group 23955f757f3fSDimitry Andric // record from hazarding and basing the hazarding decisions on the 23965f757f3fSDimitry Andric // subunit records. Otherwise, choose the first available instance 23975f757f3fSDimitry Andric // from among the subunits. Specifications which assign cycles to 23985f757f3fSDimitry Andric // both the subunits and the group or which use an unbuffered 23995f757f3fSDimitry Andric // group with buffered subunits will appear to schedule 24005f757f3fSDimitry Andric // strangely. In the first case, the additional cycles for the 24015f757f3fSDimitry Andric // group will be ignored. In the second, the group will be 24025f757f3fSDimitry Andric // ignored entirely. 2403fe6060f1SDimitry Andric for (const MCWriteProcResEntry &PE : 2404fe6060f1SDimitry Andric make_range(SchedModel->getWriteProcResBegin(SC), 2405fe6060f1SDimitry Andric SchedModel->getWriteProcResEnd(SC))) 2406fe6060f1SDimitry Andric if (ResourceGroupSubUnitMasks[PIdx][PE.ProcResourceIdx]) 24075f757f3fSDimitry Andric return std::make_pair(getNextResourceCycleByInstance( 24085f757f3fSDimitry Andric StartIndex, ReleaseAtCycle, AcquireAtCycle), 24095f757f3fSDimitry Andric StartIndex); 2410fe6060f1SDimitry Andric 2411fe6060f1SDimitry Andric auto SubUnits = SchedModel->getProcResource(PIdx)->SubUnitsIdxBegin; 2412fe6060f1SDimitry Andric for (unsigned I = 0, End = NumberOfInstances; I < End; ++I) { 2413fe6060f1SDimitry Andric unsigned NextUnreserved, NextInstanceIdx; 2414fe6060f1SDimitry Andric std::tie(NextUnreserved, NextInstanceIdx) = 24155f757f3fSDimitry Andric getNextResourceCycle(SC, SubUnits[I], ReleaseAtCycle, AcquireAtCycle); 2416fe6060f1SDimitry Andric if (MinNextUnreserved > NextUnreserved) { 2417fe6060f1SDimitry Andric InstanceIdx = NextInstanceIdx; 2418fe6060f1SDimitry Andric MinNextUnreserved = NextUnreserved; 2419fe6060f1SDimitry Andric } 2420fe6060f1SDimitry Andric } 2421fe6060f1SDimitry Andric return std::make_pair(MinNextUnreserved, InstanceIdx); 2422fe6060f1SDimitry Andric } 2423fe6060f1SDimitry Andric 24240b57cec5SDimitry Andric for (unsigned I = StartIndex, End = StartIndex + NumberOfInstances; I < End; 24250b57cec5SDimitry Andric ++I) { 242606c3fb27SDimitry Andric unsigned NextUnreserved = 24275f757f3fSDimitry Andric getNextResourceCycleByInstance(I, ReleaseAtCycle, AcquireAtCycle); 242806c3fb27SDimitry Andric if (MischedDetailResourceBooking) 242906c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << " Instance " << I - StartIndex << " available @" 243006c3fb27SDimitry Andric << NextUnreserved << "c\n"); 24310b57cec5SDimitry Andric if (MinNextUnreserved > NextUnreserved) { 24320b57cec5SDimitry Andric InstanceIdx = I; 24330b57cec5SDimitry Andric MinNextUnreserved = NextUnreserved; 24340b57cec5SDimitry Andric } 24350b57cec5SDimitry Andric } 243606c3fb27SDimitry Andric if (MischedDetailResourceBooking) 243706c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << " selecting " << SchedModel->getResourceName(PIdx) 243806c3fb27SDimitry Andric << "[" << InstanceIdx - StartIndex << "]" 243906c3fb27SDimitry Andric << " available @" << MinNextUnreserved << "c" 244006c3fb27SDimitry Andric << "\n"); 24410b57cec5SDimitry Andric return std::make_pair(MinNextUnreserved, InstanceIdx); 24420b57cec5SDimitry Andric } 24430b57cec5SDimitry Andric 24440b57cec5SDimitry Andric /// Does this SU have a hazard within the current instruction group. 24450b57cec5SDimitry Andric /// 24460b57cec5SDimitry Andric /// The scheduler supports two modes of hazard recognition. The first is the 24470b57cec5SDimitry Andric /// ScheduleHazardRecognizer API. It is a fully general hazard recognizer that 24480b57cec5SDimitry Andric /// supports highly complicated in-order reservation tables 24490b57cec5SDimitry Andric /// (ScoreboardHazardRecognizer) and arbitrary target-specific logic. 24500b57cec5SDimitry Andric /// 24510b57cec5SDimitry Andric /// The second is a streamlined mechanism that checks for hazards based on 24520b57cec5SDimitry Andric /// simple counters that the scheduler itself maintains. It explicitly checks 24530b57cec5SDimitry Andric /// for instruction dispatch limitations, including the number of micro-ops that 24540b57cec5SDimitry Andric /// can dispatch per cycle. 24550b57cec5SDimitry Andric /// 24560b57cec5SDimitry Andric /// TODO: Also check whether the SU must start a new group. 24570b57cec5SDimitry Andric bool SchedBoundary::checkHazard(SUnit *SU) { 24580b57cec5SDimitry Andric if (HazardRec->isEnabled() 24590b57cec5SDimitry Andric && HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard) { 24600b57cec5SDimitry Andric return true; 24610b57cec5SDimitry Andric } 24620b57cec5SDimitry Andric 24630b57cec5SDimitry Andric unsigned uops = SchedModel->getNumMicroOps(SU->getInstr()); 24640b57cec5SDimitry Andric if ((CurrMOps > 0) && (CurrMOps + uops > SchedModel->getIssueWidth())) { 24650b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " SU(" << SU->NodeNum << ") uops=" 24660b57cec5SDimitry Andric << SchedModel->getNumMicroOps(SU->getInstr()) << '\n'); 24670b57cec5SDimitry Andric return true; 24680b57cec5SDimitry Andric } 24690b57cec5SDimitry Andric 24700b57cec5SDimitry Andric if (CurrMOps > 0 && 24710b57cec5SDimitry Andric ((isTop() && SchedModel->mustBeginGroup(SU->getInstr())) || 24720b57cec5SDimitry Andric (!isTop() && SchedModel->mustEndGroup(SU->getInstr())))) { 24730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " hazard: SU(" << SU->NodeNum << ") must " 24740b57cec5SDimitry Andric << (isTop() ? "begin" : "end") << " group\n"); 24750b57cec5SDimitry Andric return true; 24760b57cec5SDimitry Andric } 24770b57cec5SDimitry Andric 24780b57cec5SDimitry Andric if (SchedModel->hasInstrSchedModel() && SU->hasReservedResource) { 24790b57cec5SDimitry Andric const MCSchedClassDesc *SC = DAG->getSchedClass(SU); 24800b57cec5SDimitry Andric for (const MCWriteProcResEntry &PE : 24810b57cec5SDimitry Andric make_range(SchedModel->getWriteProcResBegin(SC), 24820b57cec5SDimitry Andric SchedModel->getWriteProcResEnd(SC))) { 24830b57cec5SDimitry Andric unsigned ResIdx = PE.ProcResourceIdx; 24845f757f3fSDimitry Andric unsigned ReleaseAtCycle = PE.ReleaseAtCycle; 24855f757f3fSDimitry Andric unsigned AcquireAtCycle = PE.AcquireAtCycle; 24860b57cec5SDimitry Andric unsigned NRCycle, InstanceIdx; 248706c3fb27SDimitry Andric std::tie(NRCycle, InstanceIdx) = 24885f757f3fSDimitry Andric getNextResourceCycle(SC, ResIdx, ReleaseAtCycle, AcquireAtCycle); 24890b57cec5SDimitry Andric if (NRCycle > CurrCycle) { 249081ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 24915f757f3fSDimitry Andric MaxObservedStall = std::max(ReleaseAtCycle, MaxObservedStall); 24920b57cec5SDimitry Andric #endif 24930b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " SU(" << SU->NodeNum << ") " 24940b57cec5SDimitry Andric << SchedModel->getResourceName(ResIdx) 24950b57cec5SDimitry Andric << '[' << InstanceIdx - ReservedCyclesIndex[ResIdx] << ']' 24960b57cec5SDimitry Andric << "=" << NRCycle << "c\n"); 24970b57cec5SDimitry Andric return true; 24980b57cec5SDimitry Andric } 24990b57cec5SDimitry Andric } 25000b57cec5SDimitry Andric } 25010b57cec5SDimitry Andric return false; 25020b57cec5SDimitry Andric } 25030b57cec5SDimitry Andric 25040b57cec5SDimitry Andric // Find the unscheduled node in ReadySUs with the highest latency. 25050b57cec5SDimitry Andric unsigned SchedBoundary:: 25060b57cec5SDimitry Andric findMaxLatency(ArrayRef<SUnit*> ReadySUs) { 25070b57cec5SDimitry Andric SUnit *LateSU = nullptr; 25080b57cec5SDimitry Andric unsigned RemLatency = 0; 25090b57cec5SDimitry Andric for (SUnit *SU : ReadySUs) { 25100b57cec5SDimitry Andric unsigned L = getUnscheduledLatency(SU); 25110b57cec5SDimitry Andric if (L > RemLatency) { 25120b57cec5SDimitry Andric RemLatency = L; 25130b57cec5SDimitry Andric LateSU = SU; 25140b57cec5SDimitry Andric } 25150b57cec5SDimitry Andric } 25160b57cec5SDimitry Andric if (LateSU) { 25170b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << Available.getName() << " RemLatency SU(" 25180b57cec5SDimitry Andric << LateSU->NodeNum << ") " << RemLatency << "c\n"); 25190b57cec5SDimitry Andric } 25200b57cec5SDimitry Andric return RemLatency; 25210b57cec5SDimitry Andric } 25220b57cec5SDimitry Andric 25230b57cec5SDimitry Andric // Count resources in this zone and the remaining unscheduled 25240b57cec5SDimitry Andric // instruction. Return the max count, scaled. Set OtherCritIdx to the critical 25250b57cec5SDimitry Andric // resource index, or zero if the zone is issue limited. 25260b57cec5SDimitry Andric unsigned SchedBoundary:: 25270b57cec5SDimitry Andric getOtherResourceCount(unsigned &OtherCritIdx) { 25280b57cec5SDimitry Andric OtherCritIdx = 0; 25290b57cec5SDimitry Andric if (!SchedModel->hasInstrSchedModel()) 25300b57cec5SDimitry Andric return 0; 25310b57cec5SDimitry Andric 25320b57cec5SDimitry Andric unsigned OtherCritCount = Rem->RemIssueCount 25330b57cec5SDimitry Andric + (RetiredMOps * SchedModel->getMicroOpFactor()); 25340b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << Available.getName() << " + Remain MOps: " 25350b57cec5SDimitry Andric << OtherCritCount / SchedModel->getMicroOpFactor() << '\n'); 25360b57cec5SDimitry Andric for (unsigned PIdx = 1, PEnd = SchedModel->getNumProcResourceKinds(); 25370b57cec5SDimitry Andric PIdx != PEnd; ++PIdx) { 25380b57cec5SDimitry Andric unsigned OtherCount = getResourceCount(PIdx) + Rem->RemainingCounts[PIdx]; 25390b57cec5SDimitry Andric if (OtherCount > OtherCritCount) { 25400b57cec5SDimitry Andric OtherCritCount = OtherCount; 25410b57cec5SDimitry Andric OtherCritIdx = PIdx; 25420b57cec5SDimitry Andric } 25430b57cec5SDimitry Andric } 25440b57cec5SDimitry Andric if (OtherCritIdx) { 25450b57cec5SDimitry Andric LLVM_DEBUG( 25460b57cec5SDimitry Andric dbgs() << " " << Available.getName() << " + Remain CritRes: " 25470b57cec5SDimitry Andric << OtherCritCount / SchedModel->getResourceFactor(OtherCritIdx) 25480b57cec5SDimitry Andric << " " << SchedModel->getResourceName(OtherCritIdx) << "\n"); 25490b57cec5SDimitry Andric } 25500b57cec5SDimitry Andric return OtherCritCount; 25510b57cec5SDimitry Andric } 25520b57cec5SDimitry Andric 2553480093f4SDimitry Andric void SchedBoundary::releaseNode(SUnit *SU, unsigned ReadyCycle, bool InPQueue, 2554480093f4SDimitry Andric unsigned Idx) { 25550b57cec5SDimitry Andric assert(SU->getInstr() && "Scheduled SUnit must have instr"); 25560b57cec5SDimitry Andric 255781ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 25580b57cec5SDimitry Andric // ReadyCycle was been bumped up to the CurrCycle when this node was 25590b57cec5SDimitry Andric // scheduled, but CurrCycle may have been eagerly advanced immediately after 25600b57cec5SDimitry Andric // scheduling, so may now be greater than ReadyCycle. 25610b57cec5SDimitry Andric if (ReadyCycle > CurrCycle) 25620b57cec5SDimitry Andric MaxObservedStall = std::max(ReadyCycle - CurrCycle, MaxObservedStall); 25630b57cec5SDimitry Andric #endif 25640b57cec5SDimitry Andric 25650b57cec5SDimitry Andric if (ReadyCycle < MinReadyCycle) 25660b57cec5SDimitry Andric MinReadyCycle = ReadyCycle; 25670b57cec5SDimitry Andric 25680b57cec5SDimitry Andric // Check for interlocks first. For the purpose of other heuristics, an 25690b57cec5SDimitry Andric // instruction that cannot issue appears as if it's not in the ReadyQueue. 25700b57cec5SDimitry Andric bool IsBuffered = SchedModel->getMicroOpBufferSize() != 0; 2571480093f4SDimitry Andric bool HazardDetected = (!IsBuffered && ReadyCycle > CurrCycle) || 2572480093f4SDimitry Andric checkHazard(SU) || (Available.size() >= ReadyListLimit); 2573480093f4SDimitry Andric 2574480093f4SDimitry Andric if (!HazardDetected) { 25750b57cec5SDimitry Andric Available.push(SU); 2576480093f4SDimitry Andric 2577480093f4SDimitry Andric if (InPQueue) 2578480093f4SDimitry Andric Pending.remove(Pending.begin() + Idx); 2579480093f4SDimitry Andric return; 2580480093f4SDimitry Andric } 2581480093f4SDimitry Andric 2582480093f4SDimitry Andric if (!InPQueue) 2583480093f4SDimitry Andric Pending.push(SU); 25840b57cec5SDimitry Andric } 25850b57cec5SDimitry Andric 25860b57cec5SDimitry Andric /// Move the boundary of scheduled code by one cycle. 25870b57cec5SDimitry Andric void SchedBoundary::bumpCycle(unsigned NextCycle) { 25880b57cec5SDimitry Andric if (SchedModel->getMicroOpBufferSize() == 0) { 25890b57cec5SDimitry Andric assert(MinReadyCycle < std::numeric_limits<unsigned>::max() && 25900b57cec5SDimitry Andric "MinReadyCycle uninitialized"); 25910b57cec5SDimitry Andric if (MinReadyCycle > NextCycle) 25920b57cec5SDimitry Andric NextCycle = MinReadyCycle; 25930b57cec5SDimitry Andric } 25940b57cec5SDimitry Andric // Update the current micro-ops, which will issue in the next cycle. 25950b57cec5SDimitry Andric unsigned DecMOps = SchedModel->getIssueWidth() * (NextCycle - CurrCycle); 25960b57cec5SDimitry Andric CurrMOps = (CurrMOps <= DecMOps) ? 0 : CurrMOps - DecMOps; 25970b57cec5SDimitry Andric 25980b57cec5SDimitry Andric // Decrement DependentLatency based on the next cycle. 25990b57cec5SDimitry Andric if ((NextCycle - CurrCycle) > DependentLatency) 26000b57cec5SDimitry Andric DependentLatency = 0; 26010b57cec5SDimitry Andric else 26020b57cec5SDimitry Andric DependentLatency -= (NextCycle - CurrCycle); 26030b57cec5SDimitry Andric 26040b57cec5SDimitry Andric if (!HazardRec->isEnabled()) { 26050b57cec5SDimitry Andric // Bypass HazardRec virtual calls. 26060b57cec5SDimitry Andric CurrCycle = NextCycle; 26070b57cec5SDimitry Andric } else { 26080b57cec5SDimitry Andric // Bypass getHazardType calls in case of long latency. 26090b57cec5SDimitry Andric for (; CurrCycle != NextCycle; ++CurrCycle) { 26100b57cec5SDimitry Andric if (isTop()) 26110b57cec5SDimitry Andric HazardRec->AdvanceCycle(); 26120b57cec5SDimitry Andric else 26130b57cec5SDimitry Andric HazardRec->RecedeCycle(); 26140b57cec5SDimitry Andric } 26150b57cec5SDimitry Andric } 26160b57cec5SDimitry Andric CheckPending = true; 26170b57cec5SDimitry Andric IsResourceLimited = 26180b57cec5SDimitry Andric checkResourceLimit(SchedModel->getLatencyFactor(), getCriticalCount(), 26190b57cec5SDimitry Andric getScheduledLatency(), true); 26200b57cec5SDimitry Andric 26210b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cycle: " << CurrCycle << ' ' << Available.getName() 26220b57cec5SDimitry Andric << '\n'); 26230b57cec5SDimitry Andric } 26240b57cec5SDimitry Andric 26250b57cec5SDimitry Andric void SchedBoundary::incExecutedResources(unsigned PIdx, unsigned Count) { 26260b57cec5SDimitry Andric ExecutedResCounts[PIdx] += Count; 26270b57cec5SDimitry Andric if (ExecutedResCounts[PIdx] > MaxExecutedResCount) 26280b57cec5SDimitry Andric MaxExecutedResCount = ExecutedResCounts[PIdx]; 26290b57cec5SDimitry Andric } 26300b57cec5SDimitry Andric 26310b57cec5SDimitry Andric /// Add the given processor resource to this scheduled zone. 26320b57cec5SDimitry Andric /// 26335f757f3fSDimitry Andric /// \param ReleaseAtCycle indicates the number of consecutive (non-pipelined) 26345f757f3fSDimitry Andric /// cycles during which this resource is released. 26355f757f3fSDimitry Andric /// 26365f757f3fSDimitry Andric /// \param AcquireAtCycle indicates the number of consecutive (non-pipelined) 26375f757f3fSDimitry Andric /// cycles at which the resource is aquired after issue (assuming no stalls). 26380b57cec5SDimitry Andric /// 26390b57cec5SDimitry Andric /// \return the next cycle at which the instruction may execute without 26400b57cec5SDimitry Andric /// oversubscribing resources. 2641fe6060f1SDimitry Andric unsigned SchedBoundary::countResource(const MCSchedClassDesc *SC, unsigned PIdx, 26425f757f3fSDimitry Andric unsigned ReleaseAtCycle, 26435f757f3fSDimitry Andric unsigned NextCycle, 26445f757f3fSDimitry Andric unsigned AcquireAtCycle) { 26450b57cec5SDimitry Andric unsigned Factor = SchedModel->getResourceFactor(PIdx); 26465f757f3fSDimitry Andric unsigned Count = Factor * (ReleaseAtCycle- AcquireAtCycle); 26470b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << SchedModel->getResourceName(PIdx) << " +" 26485f757f3fSDimitry Andric << ReleaseAtCycle << "x" << Factor << "u\n"); 26490b57cec5SDimitry Andric 26500b57cec5SDimitry Andric // Update Executed resources counts. 26510b57cec5SDimitry Andric incExecutedResources(PIdx, Count); 26520b57cec5SDimitry Andric assert(Rem->RemainingCounts[PIdx] >= Count && "resource double counted"); 26530b57cec5SDimitry Andric Rem->RemainingCounts[PIdx] -= Count; 26540b57cec5SDimitry Andric 26550b57cec5SDimitry Andric // Check if this resource exceeds the current critical resource. If so, it 26560b57cec5SDimitry Andric // becomes the critical resource. 26570b57cec5SDimitry Andric if (ZoneCritResIdx != PIdx && (getResourceCount(PIdx) > getCriticalCount())) { 26580b57cec5SDimitry Andric ZoneCritResIdx = PIdx; 26590b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " *** Critical resource " 26600b57cec5SDimitry Andric << SchedModel->getResourceName(PIdx) << ": " 26610b57cec5SDimitry Andric << getResourceCount(PIdx) / SchedModel->getLatencyFactor() 26620b57cec5SDimitry Andric << "c\n"); 26630b57cec5SDimitry Andric } 26640b57cec5SDimitry Andric // For reserved resources, record the highest cycle using the resource. 26650b57cec5SDimitry Andric unsigned NextAvailable, InstanceIdx; 266606c3fb27SDimitry Andric std::tie(NextAvailable, InstanceIdx) = 26675f757f3fSDimitry Andric getNextResourceCycle(SC, PIdx, ReleaseAtCycle, AcquireAtCycle); 26680b57cec5SDimitry Andric if (NextAvailable > CurrCycle) { 26690b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Resource conflict: " 26700b57cec5SDimitry Andric << SchedModel->getResourceName(PIdx) 26710b57cec5SDimitry Andric << '[' << InstanceIdx - ReservedCyclesIndex[PIdx] << ']' 26720b57cec5SDimitry Andric << " reserved until @" << NextAvailable << "\n"); 26730b57cec5SDimitry Andric } 26740b57cec5SDimitry Andric return NextAvailable; 26750b57cec5SDimitry Andric } 26760b57cec5SDimitry Andric 26770b57cec5SDimitry Andric /// Move the boundary of scheduled code by one SUnit. 26780b57cec5SDimitry Andric void SchedBoundary::bumpNode(SUnit *SU) { 26790b57cec5SDimitry Andric // Update the reservation table. 26800b57cec5SDimitry Andric if (HazardRec->isEnabled()) { 26810b57cec5SDimitry Andric if (!isTop() && SU->isCall) { 26820b57cec5SDimitry Andric // Calls are scheduled with their preceding instructions. For bottom-up 26830b57cec5SDimitry Andric // scheduling, clear the pipeline state before emitting. 26840b57cec5SDimitry Andric HazardRec->Reset(); 26850b57cec5SDimitry Andric } 26860b57cec5SDimitry Andric HazardRec->EmitInstruction(SU); 26870b57cec5SDimitry Andric // Scheduling an instruction may have made pending instructions available. 26880b57cec5SDimitry Andric CheckPending = true; 26890b57cec5SDimitry Andric } 26900b57cec5SDimitry Andric // checkHazard should prevent scheduling multiple instructions per cycle that 26910b57cec5SDimitry Andric // exceed the issue width. 26920b57cec5SDimitry Andric const MCSchedClassDesc *SC = DAG->getSchedClass(SU); 26930b57cec5SDimitry Andric unsigned IncMOps = SchedModel->getNumMicroOps(SU->getInstr()); 26940b57cec5SDimitry Andric assert( 26950b57cec5SDimitry Andric (CurrMOps == 0 || (CurrMOps + IncMOps) <= SchedModel->getIssueWidth()) && 26960b57cec5SDimitry Andric "Cannot schedule this instruction's MicroOps in the current cycle."); 26970b57cec5SDimitry Andric 26980b57cec5SDimitry Andric unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle); 26990b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Ready @" << ReadyCycle << "c\n"); 27000b57cec5SDimitry Andric 27010b57cec5SDimitry Andric unsigned NextCycle = CurrCycle; 27020b57cec5SDimitry Andric switch (SchedModel->getMicroOpBufferSize()) { 27030b57cec5SDimitry Andric case 0: 27040b57cec5SDimitry Andric assert(ReadyCycle <= CurrCycle && "Broken PendingQueue"); 27050b57cec5SDimitry Andric break; 27060b57cec5SDimitry Andric case 1: 27070b57cec5SDimitry Andric if (ReadyCycle > NextCycle) { 27080b57cec5SDimitry Andric NextCycle = ReadyCycle; 27090b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " *** Stall until: " << ReadyCycle << "\n"); 27100b57cec5SDimitry Andric } 27110b57cec5SDimitry Andric break; 27120b57cec5SDimitry Andric default: 27130b57cec5SDimitry Andric // We don't currently model the OOO reorder buffer, so consider all 27140b57cec5SDimitry Andric // scheduled MOps to be "retired". We do loosely model in-order resource 27150b57cec5SDimitry Andric // latency. If this instruction uses an in-order resource, account for any 27160b57cec5SDimitry Andric // likely stall cycles. 27170b57cec5SDimitry Andric if (SU->isUnbuffered && ReadyCycle > NextCycle) 27180b57cec5SDimitry Andric NextCycle = ReadyCycle; 27190b57cec5SDimitry Andric break; 27200b57cec5SDimitry Andric } 27210b57cec5SDimitry Andric RetiredMOps += IncMOps; 27220b57cec5SDimitry Andric 27230b57cec5SDimitry Andric // Update resource counts and critical resource. 27240b57cec5SDimitry Andric if (SchedModel->hasInstrSchedModel()) { 27250b57cec5SDimitry Andric unsigned DecRemIssue = IncMOps * SchedModel->getMicroOpFactor(); 27260b57cec5SDimitry Andric assert(Rem->RemIssueCount >= DecRemIssue && "MOps double counted"); 27270b57cec5SDimitry Andric Rem->RemIssueCount -= DecRemIssue; 27280b57cec5SDimitry Andric if (ZoneCritResIdx) { 27290b57cec5SDimitry Andric // Scale scheduled micro-ops for comparing with the critical resource. 27300b57cec5SDimitry Andric unsigned ScaledMOps = 27310b57cec5SDimitry Andric RetiredMOps * SchedModel->getMicroOpFactor(); 27320b57cec5SDimitry Andric 27330b57cec5SDimitry Andric // If scaled micro-ops are now more than the previous critical resource by 27340b57cec5SDimitry Andric // a full cycle, then micro-ops issue becomes critical. 27350b57cec5SDimitry Andric if ((int)(ScaledMOps - getResourceCount(ZoneCritResIdx)) 27360b57cec5SDimitry Andric >= (int)SchedModel->getLatencyFactor()) { 27370b57cec5SDimitry Andric ZoneCritResIdx = 0; 27380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " *** Critical resource NumMicroOps: " 27390b57cec5SDimitry Andric << ScaledMOps / SchedModel->getLatencyFactor() 27400b57cec5SDimitry Andric << "c\n"); 27410b57cec5SDimitry Andric } 27420b57cec5SDimitry Andric } 27430b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter 27440b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC), 27450b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) { 27465f757f3fSDimitry Andric unsigned RCycle = 27475f757f3fSDimitry Andric countResource(SC, PI->ProcResourceIdx, PI->ReleaseAtCycle, NextCycle, 27485f757f3fSDimitry Andric PI->AcquireAtCycle); 27490b57cec5SDimitry Andric if (RCycle > NextCycle) 27500b57cec5SDimitry Andric NextCycle = RCycle; 27510b57cec5SDimitry Andric } 27520b57cec5SDimitry Andric if (SU->hasReservedResource) { 27530b57cec5SDimitry Andric // For reserved resources, record the highest cycle using the resource. 27540b57cec5SDimitry Andric // For top-down scheduling, this is the cycle in which we schedule this 27550b57cec5SDimitry Andric // instruction plus the number of cycles the operations reserves the 27560b57cec5SDimitry Andric // resource. For bottom-up is it simply the instruction's cycle. 27570b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter 27580b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC), 27590b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) { 27600b57cec5SDimitry Andric unsigned PIdx = PI->ProcResourceIdx; 27610b57cec5SDimitry Andric if (SchedModel->getProcResource(PIdx)->BufferSize == 0) { 276206c3fb27SDimitry Andric 276306c3fb27SDimitry Andric if (SchedModel && SchedModel->enableIntervals()) { 27640b57cec5SDimitry Andric unsigned ReservedUntil, InstanceIdx; 27655f757f3fSDimitry Andric std::tie(ReservedUntil, InstanceIdx) = getNextResourceCycle( 27665f757f3fSDimitry Andric SC, PIdx, PI->ReleaseAtCycle, PI->AcquireAtCycle); 276706c3fb27SDimitry Andric if (isTop()) { 276806c3fb27SDimitry Andric ReservedResourceSegments[InstanceIdx].add( 276906c3fb27SDimitry Andric ResourceSegments::getResourceIntervalTop( 27705f757f3fSDimitry Andric NextCycle, PI->AcquireAtCycle, PI->ReleaseAtCycle), 277106c3fb27SDimitry Andric MIResourceCutOff); 277206c3fb27SDimitry Andric } else { 277306c3fb27SDimitry Andric ReservedResourceSegments[InstanceIdx].add( 277406c3fb27SDimitry Andric ResourceSegments::getResourceIntervalBottom( 27755f757f3fSDimitry Andric NextCycle, PI->AcquireAtCycle, PI->ReleaseAtCycle), 277606c3fb27SDimitry Andric MIResourceCutOff); 277706c3fb27SDimitry Andric } 277806c3fb27SDimitry Andric } else { 277906c3fb27SDimitry Andric 278006c3fb27SDimitry Andric unsigned ReservedUntil, InstanceIdx; 27815f757f3fSDimitry Andric std::tie(ReservedUntil, InstanceIdx) = getNextResourceCycle( 27825f757f3fSDimitry Andric SC, PIdx, PI->ReleaseAtCycle, PI->AcquireAtCycle); 27830b57cec5SDimitry Andric if (isTop()) { 27840b57cec5SDimitry Andric ReservedCycles[InstanceIdx] = 27855f757f3fSDimitry Andric std::max(ReservedUntil, NextCycle + PI->ReleaseAtCycle); 27860b57cec5SDimitry Andric } else 27870b57cec5SDimitry Andric ReservedCycles[InstanceIdx] = NextCycle; 27880b57cec5SDimitry Andric } 27890b57cec5SDimitry Andric } 27900b57cec5SDimitry Andric } 27910b57cec5SDimitry Andric } 279206c3fb27SDimitry Andric } 27930b57cec5SDimitry Andric // Update ExpectedLatency and DependentLatency. 27940b57cec5SDimitry Andric unsigned &TopLatency = isTop() ? ExpectedLatency : DependentLatency; 27950b57cec5SDimitry Andric unsigned &BotLatency = isTop() ? DependentLatency : ExpectedLatency; 27960b57cec5SDimitry Andric if (SU->getDepth() > TopLatency) { 27970b57cec5SDimitry Andric TopLatency = SU->getDepth(); 27980b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << Available.getName() << " TopLatency SU(" 27990b57cec5SDimitry Andric << SU->NodeNum << ") " << TopLatency << "c\n"); 28000b57cec5SDimitry Andric } 28010b57cec5SDimitry Andric if (SU->getHeight() > BotLatency) { 28020b57cec5SDimitry Andric BotLatency = SU->getHeight(); 28030b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << Available.getName() << " BotLatency SU(" 28040b57cec5SDimitry Andric << SU->NodeNum << ") " << BotLatency << "c\n"); 28050b57cec5SDimitry Andric } 28060b57cec5SDimitry Andric // If we stall for any reason, bump the cycle. 28070b57cec5SDimitry Andric if (NextCycle > CurrCycle) 28080b57cec5SDimitry Andric bumpCycle(NextCycle); 28090b57cec5SDimitry Andric else 28100b57cec5SDimitry Andric // After updating ZoneCritResIdx and ExpectedLatency, check if we're 28110b57cec5SDimitry Andric // resource limited. If a stall occurred, bumpCycle does this. 28120b57cec5SDimitry Andric IsResourceLimited = 28130b57cec5SDimitry Andric checkResourceLimit(SchedModel->getLatencyFactor(), getCriticalCount(), 28140b57cec5SDimitry Andric getScheduledLatency(), true); 28150b57cec5SDimitry Andric 28160b57cec5SDimitry Andric // Update CurrMOps after calling bumpCycle to handle stalls, since bumpCycle 28170b57cec5SDimitry Andric // resets CurrMOps. Loop to handle instructions with more MOps than issue in 28180b57cec5SDimitry Andric // one cycle. Since we commonly reach the max MOps here, opportunistically 28190b57cec5SDimitry Andric // bump the cycle to avoid uselessly checking everything in the readyQ. 28200b57cec5SDimitry Andric CurrMOps += IncMOps; 28210b57cec5SDimitry Andric 28220b57cec5SDimitry Andric // Bump the cycle count for issue group constraints. 28230b57cec5SDimitry Andric // This must be done after NextCycle has been adjust for all other stalls. 28240b57cec5SDimitry Andric // Calling bumpCycle(X) will reduce CurrMOps by one issue group and set 28250b57cec5SDimitry Andric // currCycle to X. 28260b57cec5SDimitry Andric if ((isTop() && SchedModel->mustEndGroup(SU->getInstr())) || 28270b57cec5SDimitry Andric (!isTop() && SchedModel->mustBeginGroup(SU->getInstr()))) { 28280b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Bump cycle to " << (isTop() ? "end" : "begin") 28290b57cec5SDimitry Andric << " group\n"); 28300b57cec5SDimitry Andric bumpCycle(++NextCycle); 28310b57cec5SDimitry Andric } 28320b57cec5SDimitry Andric 28330b57cec5SDimitry Andric while (CurrMOps >= SchedModel->getIssueWidth()) { 28340b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " *** Max MOps " << CurrMOps << " at cycle " 28350b57cec5SDimitry Andric << CurrCycle << '\n'); 28360b57cec5SDimitry Andric bumpCycle(++NextCycle); 28370b57cec5SDimitry Andric } 28380b57cec5SDimitry Andric LLVM_DEBUG(dumpScheduledState()); 28390b57cec5SDimitry Andric } 28400b57cec5SDimitry Andric 28410b57cec5SDimitry Andric /// Release pending ready nodes in to the available queue. This makes them 28420b57cec5SDimitry Andric /// visible to heuristics. 28430b57cec5SDimitry Andric void SchedBoundary::releasePending() { 28440b57cec5SDimitry Andric // If the available queue is empty, it is safe to reset MinReadyCycle. 28450b57cec5SDimitry Andric if (Available.empty()) 28460b57cec5SDimitry Andric MinReadyCycle = std::numeric_limits<unsigned>::max(); 28470b57cec5SDimitry Andric 28480b57cec5SDimitry Andric // Check to see if any of the pending instructions are ready to issue. If 28490b57cec5SDimitry Andric // so, add them to the available queue. 2850480093f4SDimitry Andric for (unsigned I = 0, E = Pending.size(); I < E; ++I) { 2851480093f4SDimitry Andric SUnit *SU = *(Pending.begin() + I); 28520b57cec5SDimitry Andric unsigned ReadyCycle = isTop() ? SU->TopReadyCycle : SU->BotReadyCycle; 28530b57cec5SDimitry Andric 28540b57cec5SDimitry Andric if (ReadyCycle < MinReadyCycle) 28550b57cec5SDimitry Andric MinReadyCycle = ReadyCycle; 28560b57cec5SDimitry Andric 28570b57cec5SDimitry Andric if (Available.size() >= ReadyListLimit) 28580b57cec5SDimitry Andric break; 28590b57cec5SDimitry Andric 2860480093f4SDimitry Andric releaseNode(SU, ReadyCycle, true, I); 2861480093f4SDimitry Andric if (E != Pending.size()) { 2862480093f4SDimitry Andric --I; 2863480093f4SDimitry Andric --E; 2864480093f4SDimitry Andric } 28650b57cec5SDimitry Andric } 28660b57cec5SDimitry Andric CheckPending = false; 28670b57cec5SDimitry Andric } 28680b57cec5SDimitry Andric 28690b57cec5SDimitry Andric /// Remove SU from the ready set for this boundary. 28700b57cec5SDimitry Andric void SchedBoundary::removeReady(SUnit *SU) { 28710b57cec5SDimitry Andric if (Available.isInQueue(SU)) 28720b57cec5SDimitry Andric Available.remove(Available.find(SU)); 28730b57cec5SDimitry Andric else { 28740b57cec5SDimitry Andric assert(Pending.isInQueue(SU) && "bad ready count"); 28750b57cec5SDimitry Andric Pending.remove(Pending.find(SU)); 28760b57cec5SDimitry Andric } 28770b57cec5SDimitry Andric } 28780b57cec5SDimitry Andric 28790b57cec5SDimitry Andric /// If this queue only has one ready candidate, return it. As a side effect, 28800b57cec5SDimitry Andric /// defer any nodes that now hit a hazard, and advance the cycle until at least 28810b57cec5SDimitry Andric /// one node is ready. If multiple instructions are ready, return NULL. 28820b57cec5SDimitry Andric SUnit *SchedBoundary::pickOnlyChoice() { 28830b57cec5SDimitry Andric if (CheckPending) 28840b57cec5SDimitry Andric releasePending(); 28850b57cec5SDimitry Andric 28860b57cec5SDimitry Andric // Defer any ready instrs that now have a hazard. 28870b57cec5SDimitry Andric for (ReadyQueue::iterator I = Available.begin(); I != Available.end();) { 28880b57cec5SDimitry Andric if (checkHazard(*I)) { 28890b57cec5SDimitry Andric Pending.push(*I); 28900b57cec5SDimitry Andric I = Available.remove(I); 28910b57cec5SDimitry Andric continue; 28920b57cec5SDimitry Andric } 28930b57cec5SDimitry Andric ++I; 28940b57cec5SDimitry Andric } 28950b57cec5SDimitry Andric for (unsigned i = 0; Available.empty(); ++i) { 28960b57cec5SDimitry Andric // FIXME: Re-enable assert once PR20057 is resolved. 28970b57cec5SDimitry Andric // assert(i <= (HazardRec->getMaxLookAhead() + MaxObservedStall) && 28980b57cec5SDimitry Andric // "permanent hazard"); 28990b57cec5SDimitry Andric (void)i; 29000b57cec5SDimitry Andric bumpCycle(CurrCycle + 1); 29010b57cec5SDimitry Andric releasePending(); 29020b57cec5SDimitry Andric } 29030b57cec5SDimitry Andric 29040b57cec5SDimitry Andric LLVM_DEBUG(Pending.dump()); 29050b57cec5SDimitry Andric LLVM_DEBUG(Available.dump()); 29060b57cec5SDimitry Andric 29070b57cec5SDimitry Andric if (Available.size() == 1) 29080b57cec5SDimitry Andric return *Available.begin(); 29090b57cec5SDimitry Andric return nullptr; 29100b57cec5SDimitry Andric } 29110b57cec5SDimitry Andric 29120b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2913bdd1243dSDimitry Andric 2914bdd1243dSDimitry Andric /// Dump the content of the \ref ReservedCycles vector for the 2915bdd1243dSDimitry Andric /// resources that are used in the basic block. 2916bdd1243dSDimitry Andric /// 2917bdd1243dSDimitry Andric LLVM_DUMP_METHOD void SchedBoundary::dumpReservedCycles() const { 2918bdd1243dSDimitry Andric if (!SchedModel->hasInstrSchedModel()) 2919bdd1243dSDimitry Andric return; 2920bdd1243dSDimitry Andric 2921bdd1243dSDimitry Andric unsigned ResourceCount = SchedModel->getNumProcResourceKinds(); 2922bdd1243dSDimitry Andric unsigned StartIdx = 0; 2923bdd1243dSDimitry Andric 2924bdd1243dSDimitry Andric for (unsigned ResIdx = 0; ResIdx < ResourceCount; ++ResIdx) { 2925bdd1243dSDimitry Andric const unsigned NumUnits = SchedModel->getProcResource(ResIdx)->NumUnits; 2926bdd1243dSDimitry Andric std::string ResName = SchedModel->getResourceName(ResIdx); 2927bdd1243dSDimitry Andric for (unsigned UnitIdx = 0; UnitIdx < NumUnits; ++UnitIdx) { 292806c3fb27SDimitry Andric dbgs() << ResName << "(" << UnitIdx << ") = "; 292906c3fb27SDimitry Andric if (SchedModel && SchedModel->enableIntervals()) { 293006c3fb27SDimitry Andric if (ReservedResourceSegments.count(StartIdx + UnitIdx)) 293106c3fb27SDimitry Andric dbgs() << ReservedResourceSegments.at(StartIdx + UnitIdx); 293206c3fb27SDimitry Andric else 293306c3fb27SDimitry Andric dbgs() << "{ }\n"; 293406c3fb27SDimitry Andric } else 293506c3fb27SDimitry Andric dbgs() << ReservedCycles[StartIdx + UnitIdx] << "\n"; 2936bdd1243dSDimitry Andric } 2937bdd1243dSDimitry Andric StartIdx += NumUnits; 2938bdd1243dSDimitry Andric } 2939bdd1243dSDimitry Andric } 2940bdd1243dSDimitry Andric 29410b57cec5SDimitry Andric // This is useful information to dump after bumpNode. 29420b57cec5SDimitry Andric // Note that the Queue contents are more useful before pickNodeFromQueue. 29430b57cec5SDimitry Andric LLVM_DUMP_METHOD void SchedBoundary::dumpScheduledState() const { 29440b57cec5SDimitry Andric unsigned ResFactor; 29450b57cec5SDimitry Andric unsigned ResCount; 29460b57cec5SDimitry Andric if (ZoneCritResIdx) { 29470b57cec5SDimitry Andric ResFactor = SchedModel->getResourceFactor(ZoneCritResIdx); 29480b57cec5SDimitry Andric ResCount = getResourceCount(ZoneCritResIdx); 29490b57cec5SDimitry Andric } else { 29500b57cec5SDimitry Andric ResFactor = SchedModel->getMicroOpFactor(); 29510b57cec5SDimitry Andric ResCount = RetiredMOps * ResFactor; 29520b57cec5SDimitry Andric } 29530b57cec5SDimitry Andric unsigned LFactor = SchedModel->getLatencyFactor(); 29540b57cec5SDimitry Andric dbgs() << Available.getName() << " @" << CurrCycle << "c\n" 29550b57cec5SDimitry Andric << " Retired: " << RetiredMOps; 29560b57cec5SDimitry Andric dbgs() << "\n Executed: " << getExecutedCount() / LFactor << "c"; 29570b57cec5SDimitry Andric dbgs() << "\n Critical: " << ResCount / LFactor << "c, " 29580b57cec5SDimitry Andric << ResCount / ResFactor << " " 29590b57cec5SDimitry Andric << SchedModel->getResourceName(ZoneCritResIdx) 29600b57cec5SDimitry Andric << "\n ExpectedLatency: " << ExpectedLatency << "c\n" 29610b57cec5SDimitry Andric << (IsResourceLimited ? " - Resource" : " - Latency") 29620b57cec5SDimitry Andric << " limited.\n"; 2963bdd1243dSDimitry Andric if (MISchedDumpReservedCycles) 2964bdd1243dSDimitry Andric dumpReservedCycles(); 29650b57cec5SDimitry Andric } 29660b57cec5SDimitry Andric #endif 29670b57cec5SDimitry Andric 29680b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 29690b57cec5SDimitry Andric // GenericScheduler - Generic implementation of MachineSchedStrategy. 29700b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 29710b57cec5SDimitry Andric 29720b57cec5SDimitry Andric void GenericSchedulerBase::SchedCandidate:: 29730b57cec5SDimitry Andric initResourceDelta(const ScheduleDAGMI *DAG, 29740b57cec5SDimitry Andric const TargetSchedModel *SchedModel) { 29750b57cec5SDimitry Andric if (!Policy.ReduceResIdx && !Policy.DemandResIdx) 29760b57cec5SDimitry Andric return; 29770b57cec5SDimitry Andric 29780b57cec5SDimitry Andric const MCSchedClassDesc *SC = DAG->getSchedClass(SU); 29790b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter 29800b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC), 29810b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) { 29820b57cec5SDimitry Andric if (PI->ProcResourceIdx == Policy.ReduceResIdx) 29835f757f3fSDimitry Andric ResDelta.CritResources += PI->ReleaseAtCycle; 29840b57cec5SDimitry Andric if (PI->ProcResourceIdx == Policy.DemandResIdx) 29855f757f3fSDimitry Andric ResDelta.DemandedResources += PI->ReleaseAtCycle; 29860b57cec5SDimitry Andric } 29870b57cec5SDimitry Andric } 29880b57cec5SDimitry Andric 29890b57cec5SDimitry Andric /// Compute remaining latency. We need this both to determine whether the 29900b57cec5SDimitry Andric /// overall schedule has become latency-limited and whether the instructions 29910b57cec5SDimitry Andric /// outside this zone are resource or latency limited. 29920b57cec5SDimitry Andric /// 29930b57cec5SDimitry Andric /// The "dependent" latency is updated incrementally during scheduling as the 29940b57cec5SDimitry Andric /// max height/depth of scheduled nodes minus the cycles since it was 29950b57cec5SDimitry Andric /// scheduled: 29960b57cec5SDimitry Andric /// DLat = max (N.depth - (CurrCycle - N.ReadyCycle) for N in Zone 29970b57cec5SDimitry Andric /// 29980b57cec5SDimitry Andric /// The "independent" latency is the max ready queue depth: 29990b57cec5SDimitry Andric /// ILat = max N.depth for N in Available|Pending 30000b57cec5SDimitry Andric /// 30010b57cec5SDimitry Andric /// RemainingLatency is the greater of independent and dependent latency. 30020b57cec5SDimitry Andric /// 30030b57cec5SDimitry Andric /// These computations are expensive, especially in DAGs with many edges, so 30040b57cec5SDimitry Andric /// only do them if necessary. 30050b57cec5SDimitry Andric static unsigned computeRemLatency(SchedBoundary &CurrZone) { 30060b57cec5SDimitry Andric unsigned RemLatency = CurrZone.getDependentLatency(); 30070b57cec5SDimitry Andric RemLatency = std::max(RemLatency, 30080b57cec5SDimitry Andric CurrZone.findMaxLatency(CurrZone.Available.elements())); 30090b57cec5SDimitry Andric RemLatency = std::max(RemLatency, 30100b57cec5SDimitry Andric CurrZone.findMaxLatency(CurrZone.Pending.elements())); 30110b57cec5SDimitry Andric return RemLatency; 30120b57cec5SDimitry Andric } 30130b57cec5SDimitry Andric 30140b57cec5SDimitry Andric /// Returns true if the current cycle plus remaning latency is greater than 30150b57cec5SDimitry Andric /// the critical path in the scheduling region. 30160b57cec5SDimitry Andric bool GenericSchedulerBase::shouldReduceLatency(const CandPolicy &Policy, 30170b57cec5SDimitry Andric SchedBoundary &CurrZone, 30180b57cec5SDimitry Andric bool ComputeRemLatency, 30190b57cec5SDimitry Andric unsigned &RemLatency) const { 30200b57cec5SDimitry Andric // The current cycle is already greater than the critical path, so we are 30210b57cec5SDimitry Andric // already latency limited and don't need to compute the remaining latency. 30220b57cec5SDimitry Andric if (CurrZone.getCurrCycle() > Rem.CriticalPath) 30230b57cec5SDimitry Andric return true; 30240b57cec5SDimitry Andric 30250b57cec5SDimitry Andric // If we haven't scheduled anything yet, then we aren't latency limited. 30260b57cec5SDimitry Andric if (CurrZone.getCurrCycle() == 0) 30270b57cec5SDimitry Andric return false; 30280b57cec5SDimitry Andric 30290b57cec5SDimitry Andric if (ComputeRemLatency) 30300b57cec5SDimitry Andric RemLatency = computeRemLatency(CurrZone); 30310b57cec5SDimitry Andric 30320b57cec5SDimitry Andric return RemLatency + CurrZone.getCurrCycle() > Rem.CriticalPath; 30330b57cec5SDimitry Andric } 30340b57cec5SDimitry Andric 30350b57cec5SDimitry Andric /// Set the CandPolicy given a scheduling zone given the current resources and 30360b57cec5SDimitry Andric /// latencies inside and outside the zone. 30370b57cec5SDimitry Andric void GenericSchedulerBase::setPolicy(CandPolicy &Policy, bool IsPostRA, 30380b57cec5SDimitry Andric SchedBoundary &CurrZone, 30390b57cec5SDimitry Andric SchedBoundary *OtherZone) { 30400b57cec5SDimitry Andric // Apply preemptive heuristics based on the total latency and resources 30410b57cec5SDimitry Andric // inside and outside this zone. Potential stalls should be considered before 30420b57cec5SDimitry Andric // following this policy. 30430b57cec5SDimitry Andric 30440b57cec5SDimitry Andric // Compute the critical resource outside the zone. 30450b57cec5SDimitry Andric unsigned OtherCritIdx = 0; 30460b57cec5SDimitry Andric unsigned OtherCount = 30470b57cec5SDimitry Andric OtherZone ? OtherZone->getOtherResourceCount(OtherCritIdx) : 0; 30480b57cec5SDimitry Andric 30490b57cec5SDimitry Andric bool OtherResLimited = false; 30500b57cec5SDimitry Andric unsigned RemLatency = 0; 30510b57cec5SDimitry Andric bool RemLatencyComputed = false; 30520b57cec5SDimitry Andric if (SchedModel->hasInstrSchedModel() && OtherCount != 0) { 30530b57cec5SDimitry Andric RemLatency = computeRemLatency(CurrZone); 30540b57cec5SDimitry Andric RemLatencyComputed = true; 30550b57cec5SDimitry Andric OtherResLimited = checkResourceLimit(SchedModel->getLatencyFactor(), 30560b57cec5SDimitry Andric OtherCount, RemLatency, false); 30570b57cec5SDimitry Andric } 30580b57cec5SDimitry Andric 30590b57cec5SDimitry Andric // Schedule aggressively for latency in PostRA mode. We don't check for 30600b57cec5SDimitry Andric // acyclic latency during PostRA, and highly out-of-order processors will 30610b57cec5SDimitry Andric // skip PostRA scheduling. 30620b57cec5SDimitry Andric if (!OtherResLimited && 30630b57cec5SDimitry Andric (IsPostRA || shouldReduceLatency(Policy, CurrZone, !RemLatencyComputed, 30640b57cec5SDimitry Andric RemLatency))) { 30650b57cec5SDimitry Andric Policy.ReduceLatency |= true; 30660b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << CurrZone.Available.getName() 30670b57cec5SDimitry Andric << " RemainingLatency " << RemLatency << " + " 30680b57cec5SDimitry Andric << CurrZone.getCurrCycle() << "c > CritPath " 30690b57cec5SDimitry Andric << Rem.CriticalPath << "\n"); 30700b57cec5SDimitry Andric } 30710b57cec5SDimitry Andric // If the same resource is limiting inside and outside the zone, do nothing. 30720b57cec5SDimitry Andric if (CurrZone.getZoneCritResIdx() == OtherCritIdx) 30730b57cec5SDimitry Andric return; 30740b57cec5SDimitry Andric 30750b57cec5SDimitry Andric LLVM_DEBUG(if (CurrZone.isResourceLimited()) { 30760b57cec5SDimitry Andric dbgs() << " " << CurrZone.Available.getName() << " ResourceLimited: " 30770b57cec5SDimitry Andric << SchedModel->getResourceName(CurrZone.getZoneCritResIdx()) << "\n"; 30780b57cec5SDimitry Andric } if (OtherResLimited) dbgs() 30790b57cec5SDimitry Andric << " RemainingLimit: " 30800b57cec5SDimitry Andric << SchedModel->getResourceName(OtherCritIdx) << "\n"; 30810b57cec5SDimitry Andric if (!CurrZone.isResourceLimited() && !OtherResLimited) dbgs() 30820b57cec5SDimitry Andric << " Latency limited both directions.\n"); 30830b57cec5SDimitry Andric 30840b57cec5SDimitry Andric if (CurrZone.isResourceLimited() && !Policy.ReduceResIdx) 30850b57cec5SDimitry Andric Policy.ReduceResIdx = CurrZone.getZoneCritResIdx(); 30860b57cec5SDimitry Andric 30870b57cec5SDimitry Andric if (OtherResLimited) 30880b57cec5SDimitry Andric Policy.DemandResIdx = OtherCritIdx; 30890b57cec5SDimitry Andric } 30900b57cec5SDimitry Andric 30910b57cec5SDimitry Andric #ifndef NDEBUG 30920b57cec5SDimitry Andric const char *GenericSchedulerBase::getReasonStr( 30930b57cec5SDimitry Andric GenericSchedulerBase::CandReason Reason) { 30940b57cec5SDimitry Andric switch (Reason) { 30950b57cec5SDimitry Andric case NoCand: return "NOCAND "; 30960b57cec5SDimitry Andric case Only1: return "ONLY1 "; 30970b57cec5SDimitry Andric case PhysReg: return "PHYS-REG "; 30980b57cec5SDimitry Andric case RegExcess: return "REG-EXCESS"; 30990b57cec5SDimitry Andric case RegCritical: return "REG-CRIT "; 31000b57cec5SDimitry Andric case Stall: return "STALL "; 31010b57cec5SDimitry Andric case Cluster: return "CLUSTER "; 31020b57cec5SDimitry Andric case Weak: return "WEAK "; 31030b57cec5SDimitry Andric case RegMax: return "REG-MAX "; 31040b57cec5SDimitry Andric case ResourceReduce: return "RES-REDUCE"; 31050b57cec5SDimitry Andric case ResourceDemand: return "RES-DEMAND"; 31060b57cec5SDimitry Andric case TopDepthReduce: return "TOP-DEPTH "; 31070b57cec5SDimitry Andric case TopPathReduce: return "TOP-PATH "; 31080b57cec5SDimitry Andric case BotHeightReduce:return "BOT-HEIGHT"; 31090b57cec5SDimitry Andric case BotPathReduce: return "BOT-PATH "; 31100b57cec5SDimitry Andric case NextDefUse: return "DEF-USE "; 31110b57cec5SDimitry Andric case NodeOrder: return "ORDER "; 31120b57cec5SDimitry Andric }; 31130b57cec5SDimitry Andric llvm_unreachable("Unknown reason!"); 31140b57cec5SDimitry Andric } 31150b57cec5SDimitry Andric 31160b57cec5SDimitry Andric void GenericSchedulerBase::traceCandidate(const SchedCandidate &Cand) { 31170b57cec5SDimitry Andric PressureChange P; 31180b57cec5SDimitry Andric unsigned ResIdx = 0; 31190b57cec5SDimitry Andric unsigned Latency = 0; 31200b57cec5SDimitry Andric switch (Cand.Reason) { 31210b57cec5SDimitry Andric default: 31220b57cec5SDimitry Andric break; 31230b57cec5SDimitry Andric case RegExcess: 31240b57cec5SDimitry Andric P = Cand.RPDelta.Excess; 31250b57cec5SDimitry Andric break; 31260b57cec5SDimitry Andric case RegCritical: 31270b57cec5SDimitry Andric P = Cand.RPDelta.CriticalMax; 31280b57cec5SDimitry Andric break; 31290b57cec5SDimitry Andric case RegMax: 31300b57cec5SDimitry Andric P = Cand.RPDelta.CurrentMax; 31310b57cec5SDimitry Andric break; 31320b57cec5SDimitry Andric case ResourceReduce: 31330b57cec5SDimitry Andric ResIdx = Cand.Policy.ReduceResIdx; 31340b57cec5SDimitry Andric break; 31350b57cec5SDimitry Andric case ResourceDemand: 31360b57cec5SDimitry Andric ResIdx = Cand.Policy.DemandResIdx; 31370b57cec5SDimitry Andric break; 31380b57cec5SDimitry Andric case TopDepthReduce: 31390b57cec5SDimitry Andric Latency = Cand.SU->getDepth(); 31400b57cec5SDimitry Andric break; 31410b57cec5SDimitry Andric case TopPathReduce: 31420b57cec5SDimitry Andric Latency = Cand.SU->getHeight(); 31430b57cec5SDimitry Andric break; 31440b57cec5SDimitry Andric case BotHeightReduce: 31450b57cec5SDimitry Andric Latency = Cand.SU->getHeight(); 31460b57cec5SDimitry Andric break; 31470b57cec5SDimitry Andric case BotPathReduce: 31480b57cec5SDimitry Andric Latency = Cand.SU->getDepth(); 31490b57cec5SDimitry Andric break; 31500b57cec5SDimitry Andric } 31510b57cec5SDimitry Andric dbgs() << " Cand SU(" << Cand.SU->NodeNum << ") " << getReasonStr(Cand.Reason); 31520b57cec5SDimitry Andric if (P.isValid()) 31530b57cec5SDimitry Andric dbgs() << " " << TRI->getRegPressureSetName(P.getPSet()) 31540b57cec5SDimitry Andric << ":" << P.getUnitInc() << " "; 31550b57cec5SDimitry Andric else 31560b57cec5SDimitry Andric dbgs() << " "; 31570b57cec5SDimitry Andric if (ResIdx) 31580b57cec5SDimitry Andric dbgs() << " " << SchedModel->getProcResource(ResIdx)->Name << " "; 31590b57cec5SDimitry Andric else 31600b57cec5SDimitry Andric dbgs() << " "; 31610b57cec5SDimitry Andric if (Latency) 31620b57cec5SDimitry Andric dbgs() << " " << Latency << " cycles "; 31630b57cec5SDimitry Andric else 31640b57cec5SDimitry Andric dbgs() << " "; 31650b57cec5SDimitry Andric dbgs() << '\n'; 31660b57cec5SDimitry Andric } 31670b57cec5SDimitry Andric #endif 31680b57cec5SDimitry Andric 31690b57cec5SDimitry Andric namespace llvm { 31700b57cec5SDimitry Andric /// Return true if this heuristic determines order. 3171fe6060f1SDimitry Andric /// TODO: Consider refactor return type of these functions as integer or enum, 3172fe6060f1SDimitry Andric /// as we may need to differentiate whether TryCand is better than Cand. 31730b57cec5SDimitry Andric bool tryLess(int TryVal, int CandVal, 31740b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &TryCand, 31750b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &Cand, 31760b57cec5SDimitry Andric GenericSchedulerBase::CandReason Reason) { 31770b57cec5SDimitry Andric if (TryVal < CandVal) { 31780b57cec5SDimitry Andric TryCand.Reason = Reason; 31790b57cec5SDimitry Andric return true; 31800b57cec5SDimitry Andric } 31810b57cec5SDimitry Andric if (TryVal > CandVal) { 31820b57cec5SDimitry Andric if (Cand.Reason > Reason) 31830b57cec5SDimitry Andric Cand.Reason = Reason; 31840b57cec5SDimitry Andric return true; 31850b57cec5SDimitry Andric } 31860b57cec5SDimitry Andric return false; 31870b57cec5SDimitry Andric } 31880b57cec5SDimitry Andric 31890b57cec5SDimitry Andric bool tryGreater(int TryVal, int CandVal, 31900b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &TryCand, 31910b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &Cand, 31920b57cec5SDimitry Andric GenericSchedulerBase::CandReason Reason) { 31930b57cec5SDimitry Andric if (TryVal > CandVal) { 31940b57cec5SDimitry Andric TryCand.Reason = Reason; 31950b57cec5SDimitry Andric return true; 31960b57cec5SDimitry Andric } 31970b57cec5SDimitry Andric if (TryVal < CandVal) { 31980b57cec5SDimitry Andric if (Cand.Reason > Reason) 31990b57cec5SDimitry Andric Cand.Reason = Reason; 32000b57cec5SDimitry Andric return true; 32010b57cec5SDimitry Andric } 32020b57cec5SDimitry Andric return false; 32030b57cec5SDimitry Andric } 32040b57cec5SDimitry Andric 32050b57cec5SDimitry Andric bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand, 32060b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &Cand, 32070b57cec5SDimitry Andric SchedBoundary &Zone) { 32080b57cec5SDimitry Andric if (Zone.isTop()) { 3209e8d8bef9SDimitry Andric // Prefer the candidate with the lesser depth, but only if one of them has 3210e8d8bef9SDimitry Andric // depth greater than the total latency scheduled so far, otherwise either 3211e8d8bef9SDimitry Andric // of them could be scheduled now with no stall. 3212e8d8bef9SDimitry Andric if (std::max(TryCand.SU->getDepth(), Cand.SU->getDepth()) > 3213e8d8bef9SDimitry Andric Zone.getScheduledLatency()) { 32140b57cec5SDimitry Andric if (tryLess(TryCand.SU->getDepth(), Cand.SU->getDepth(), 32150b57cec5SDimitry Andric TryCand, Cand, GenericSchedulerBase::TopDepthReduce)) 32160b57cec5SDimitry Andric return true; 32170b57cec5SDimitry Andric } 32180b57cec5SDimitry Andric if (tryGreater(TryCand.SU->getHeight(), Cand.SU->getHeight(), 32190b57cec5SDimitry Andric TryCand, Cand, GenericSchedulerBase::TopPathReduce)) 32200b57cec5SDimitry Andric return true; 32210b57cec5SDimitry Andric } else { 3222e8d8bef9SDimitry Andric // Prefer the candidate with the lesser height, but only if one of them has 3223e8d8bef9SDimitry Andric // height greater than the total latency scheduled so far, otherwise either 3224e8d8bef9SDimitry Andric // of them could be scheduled now with no stall. 3225e8d8bef9SDimitry Andric if (std::max(TryCand.SU->getHeight(), Cand.SU->getHeight()) > 3226e8d8bef9SDimitry Andric Zone.getScheduledLatency()) { 32270b57cec5SDimitry Andric if (tryLess(TryCand.SU->getHeight(), Cand.SU->getHeight(), 32280b57cec5SDimitry Andric TryCand, Cand, GenericSchedulerBase::BotHeightReduce)) 32290b57cec5SDimitry Andric return true; 32300b57cec5SDimitry Andric } 32310b57cec5SDimitry Andric if (tryGreater(TryCand.SU->getDepth(), Cand.SU->getDepth(), 32320b57cec5SDimitry Andric TryCand, Cand, GenericSchedulerBase::BotPathReduce)) 32330b57cec5SDimitry Andric return true; 32340b57cec5SDimitry Andric } 32350b57cec5SDimitry Andric return false; 32360b57cec5SDimitry Andric } 32370b57cec5SDimitry Andric } // end namespace llvm 32380b57cec5SDimitry Andric 32390b57cec5SDimitry Andric static void tracePick(GenericSchedulerBase::CandReason Reason, bool IsTop) { 32400b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Pick " << (IsTop ? "Top " : "Bot ") 32410b57cec5SDimitry Andric << GenericSchedulerBase::getReasonStr(Reason) << '\n'); 32420b57cec5SDimitry Andric } 32430b57cec5SDimitry Andric 32440b57cec5SDimitry Andric static void tracePick(const GenericSchedulerBase::SchedCandidate &Cand) { 32450b57cec5SDimitry Andric tracePick(Cand.Reason, Cand.AtTop); 32460b57cec5SDimitry Andric } 32470b57cec5SDimitry Andric 32480b57cec5SDimitry Andric void GenericScheduler::initialize(ScheduleDAGMI *dag) { 32490b57cec5SDimitry Andric assert(dag->hasVRegLiveness() && 32500b57cec5SDimitry Andric "(PreRA)GenericScheduler needs vreg liveness"); 32510b57cec5SDimitry Andric DAG = static_cast<ScheduleDAGMILive*>(dag); 32520b57cec5SDimitry Andric SchedModel = DAG->getSchedModel(); 32530b57cec5SDimitry Andric TRI = DAG->TRI; 32540b57cec5SDimitry Andric 32555ffd83dbSDimitry Andric if (RegionPolicy.ComputeDFSResult) 32565ffd83dbSDimitry Andric DAG->computeDFSResult(); 32575ffd83dbSDimitry Andric 32580b57cec5SDimitry Andric Rem.init(DAG, SchedModel); 32590b57cec5SDimitry Andric Top.init(DAG, SchedModel, &Rem); 32600b57cec5SDimitry Andric Bot.init(DAG, SchedModel, &Rem); 32610b57cec5SDimitry Andric 32620b57cec5SDimitry Andric // Initialize resource counts. 32630b57cec5SDimitry Andric 32640b57cec5SDimitry Andric // Initialize the HazardRecognizers. If itineraries don't exist, are empty, or 32650b57cec5SDimitry Andric // are disabled, then these HazardRecs will be disabled. 32660b57cec5SDimitry Andric const InstrItineraryData *Itin = SchedModel->getInstrItineraries(); 32670b57cec5SDimitry Andric if (!Top.HazardRec) { 3268*0fca6ea1SDimitry Andric Top.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG); 32690b57cec5SDimitry Andric } 32700b57cec5SDimitry Andric if (!Bot.HazardRec) { 3271*0fca6ea1SDimitry Andric Bot.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG); 32720b57cec5SDimitry Andric } 32730b57cec5SDimitry Andric TopCand.SU = nullptr; 32740b57cec5SDimitry Andric BotCand.SU = nullptr; 32750b57cec5SDimitry Andric } 32760b57cec5SDimitry Andric 32770b57cec5SDimitry Andric /// Initialize the per-region scheduling policy. 32780b57cec5SDimitry Andric void GenericScheduler::initPolicy(MachineBasicBlock::iterator Begin, 32790b57cec5SDimitry Andric MachineBasicBlock::iterator End, 32800b57cec5SDimitry Andric unsigned NumRegionInstrs) { 32810b57cec5SDimitry Andric const MachineFunction &MF = *Begin->getMF(); 32820b57cec5SDimitry Andric const TargetLowering *TLI = MF.getSubtarget().getTargetLowering(); 32830b57cec5SDimitry Andric 32840b57cec5SDimitry Andric // Avoid setting up the register pressure tracker for small regions to save 32850b57cec5SDimitry Andric // compile time. As a rough heuristic, only track pressure when the number of 3286*0fca6ea1SDimitry Andric // schedulable instructions exceeds half the allocatable integer register file 3287*0fca6ea1SDimitry Andric // that is the largest legal integer regiser type. 32880b57cec5SDimitry Andric RegionPolicy.ShouldTrackPressure = true; 3289*0fca6ea1SDimitry Andric for (unsigned VT = MVT::i64; VT > (unsigned)MVT::i1; --VT) { 32900b57cec5SDimitry Andric MVT::SimpleValueType LegalIntVT = (MVT::SimpleValueType)VT; 32910b57cec5SDimitry Andric if (TLI->isTypeLegal(LegalIntVT)) { 32920b57cec5SDimitry Andric unsigned NIntRegs = Context->RegClassInfo->getNumAllocatableRegs( 32930b57cec5SDimitry Andric TLI->getRegClassFor(LegalIntVT)); 32940b57cec5SDimitry Andric RegionPolicy.ShouldTrackPressure = NumRegionInstrs > (NIntRegs / 2); 3295*0fca6ea1SDimitry Andric break; 32960b57cec5SDimitry Andric } 32970b57cec5SDimitry Andric } 32980b57cec5SDimitry Andric 32990b57cec5SDimitry Andric // For generic targets, we default to bottom-up, because it's simpler and more 33000b57cec5SDimitry Andric // compile-time optimizations have been implemented in that direction. 33010b57cec5SDimitry Andric RegionPolicy.OnlyBottomUp = true; 33020b57cec5SDimitry Andric 33030b57cec5SDimitry Andric // Allow the subtarget to override default policy. 33040b57cec5SDimitry Andric MF.getSubtarget().overrideSchedPolicy(RegionPolicy, NumRegionInstrs); 33050b57cec5SDimitry Andric 33060b57cec5SDimitry Andric // After subtarget overrides, apply command line options. 33070b57cec5SDimitry Andric if (!EnableRegPressure) { 33080b57cec5SDimitry Andric RegionPolicy.ShouldTrackPressure = false; 33090b57cec5SDimitry Andric RegionPolicy.ShouldTrackLaneMasks = false; 33100b57cec5SDimitry Andric } 33110b57cec5SDimitry Andric 33120b57cec5SDimitry Andric // Check -misched-topdown/bottomup can force or unforce scheduling direction. 33130b57cec5SDimitry Andric // e.g. -misched-bottomup=false allows scheduling in both directions. 33140b57cec5SDimitry Andric assert((!ForceTopDown || !ForceBottomUp) && 33150b57cec5SDimitry Andric "-misched-topdown incompatible with -misched-bottomup"); 33160b57cec5SDimitry Andric if (ForceBottomUp.getNumOccurrences() > 0) { 33170b57cec5SDimitry Andric RegionPolicy.OnlyBottomUp = ForceBottomUp; 33180b57cec5SDimitry Andric if (RegionPolicy.OnlyBottomUp) 33190b57cec5SDimitry Andric RegionPolicy.OnlyTopDown = false; 33200b57cec5SDimitry Andric } 33210b57cec5SDimitry Andric if (ForceTopDown.getNumOccurrences() > 0) { 33220b57cec5SDimitry Andric RegionPolicy.OnlyTopDown = ForceTopDown; 33230b57cec5SDimitry Andric if (RegionPolicy.OnlyTopDown) 33240b57cec5SDimitry Andric RegionPolicy.OnlyBottomUp = false; 33250b57cec5SDimitry Andric } 33260b57cec5SDimitry Andric } 33270b57cec5SDimitry Andric 33280b57cec5SDimitry Andric void GenericScheduler::dumpPolicy() const { 33290b57cec5SDimitry Andric // Cannot completely remove virtual function even in release mode. 33300b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 33310b57cec5SDimitry Andric dbgs() << "GenericScheduler RegionPolicy: " 33320b57cec5SDimitry Andric << " ShouldTrackPressure=" << RegionPolicy.ShouldTrackPressure 33330b57cec5SDimitry Andric << " OnlyTopDown=" << RegionPolicy.OnlyTopDown 33340b57cec5SDimitry Andric << " OnlyBottomUp=" << RegionPolicy.OnlyBottomUp 33350b57cec5SDimitry Andric << "\n"; 33360b57cec5SDimitry Andric #endif 33370b57cec5SDimitry Andric } 33380b57cec5SDimitry Andric 33390b57cec5SDimitry Andric /// Set IsAcyclicLatencyLimited if the acyclic path is longer than the cyclic 33400b57cec5SDimitry Andric /// critical path by more cycles than it takes to drain the instruction buffer. 33410b57cec5SDimitry Andric /// We estimate an upper bounds on in-flight instructions as: 33420b57cec5SDimitry Andric /// 33430b57cec5SDimitry Andric /// CyclesPerIteration = max( CyclicPath, Loop-Resource-Height ) 33440b57cec5SDimitry Andric /// InFlightIterations = AcyclicPath / CyclesPerIteration 33450b57cec5SDimitry Andric /// InFlightResources = InFlightIterations * LoopResources 33460b57cec5SDimitry Andric /// 33470b57cec5SDimitry Andric /// TODO: Check execution resources in addition to IssueCount. 33480b57cec5SDimitry Andric void GenericScheduler::checkAcyclicLatency() { 33490b57cec5SDimitry Andric if (Rem.CyclicCritPath == 0 || Rem.CyclicCritPath >= Rem.CriticalPath) 33500b57cec5SDimitry Andric return; 33510b57cec5SDimitry Andric 33520b57cec5SDimitry Andric // Scaled number of cycles per loop iteration. 33530b57cec5SDimitry Andric unsigned IterCount = 33540b57cec5SDimitry Andric std::max(Rem.CyclicCritPath * SchedModel->getLatencyFactor(), 33550b57cec5SDimitry Andric Rem.RemIssueCount); 33560b57cec5SDimitry Andric // Scaled acyclic critical path. 33570b57cec5SDimitry Andric unsigned AcyclicCount = Rem.CriticalPath * SchedModel->getLatencyFactor(); 33580b57cec5SDimitry Andric // InFlightCount = (AcyclicPath / IterCycles) * InstrPerLoop 33590b57cec5SDimitry Andric unsigned InFlightCount = 33600b57cec5SDimitry Andric (AcyclicCount * Rem.RemIssueCount + IterCount-1) / IterCount; 33610b57cec5SDimitry Andric unsigned BufferLimit = 33620b57cec5SDimitry Andric SchedModel->getMicroOpBufferSize() * SchedModel->getMicroOpFactor(); 33630b57cec5SDimitry Andric 33640b57cec5SDimitry Andric Rem.IsAcyclicLatencyLimited = InFlightCount > BufferLimit; 33650b57cec5SDimitry Andric 33660b57cec5SDimitry Andric LLVM_DEBUG( 33670b57cec5SDimitry Andric dbgs() << "IssueCycles=" 33680b57cec5SDimitry Andric << Rem.RemIssueCount / SchedModel->getLatencyFactor() << "c " 33690b57cec5SDimitry Andric << "IterCycles=" << IterCount / SchedModel->getLatencyFactor() 33700b57cec5SDimitry Andric << "c NumIters=" << (AcyclicCount + IterCount - 1) / IterCount 33710b57cec5SDimitry Andric << " InFlight=" << InFlightCount / SchedModel->getMicroOpFactor() 33720b57cec5SDimitry Andric << "m BufferLim=" << SchedModel->getMicroOpBufferSize() << "m\n"; 33730b57cec5SDimitry Andric if (Rem.IsAcyclicLatencyLimited) dbgs() << " ACYCLIC LATENCY LIMIT\n"); 33740b57cec5SDimitry Andric } 33750b57cec5SDimitry Andric 33760b57cec5SDimitry Andric void GenericScheduler::registerRoots() { 33770b57cec5SDimitry Andric Rem.CriticalPath = DAG->ExitSU.getDepth(); 33780b57cec5SDimitry Andric 33790b57cec5SDimitry Andric // Some roots may not feed into ExitSU. Check all of them in case. 33800b57cec5SDimitry Andric for (const SUnit *SU : Bot.Available) { 33810b57cec5SDimitry Andric if (SU->getDepth() > Rem.CriticalPath) 33820b57cec5SDimitry Andric Rem.CriticalPath = SU->getDepth(); 33830b57cec5SDimitry Andric } 33840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << '\n'); 33850b57cec5SDimitry Andric if (DumpCriticalPathLength) { 33860b57cec5SDimitry Andric errs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << " \n"; 33870b57cec5SDimitry Andric } 33880b57cec5SDimitry Andric 33890b57cec5SDimitry Andric if (EnableCyclicPath && SchedModel->getMicroOpBufferSize() > 0) { 33900b57cec5SDimitry Andric Rem.CyclicCritPath = DAG->computeCyclicCriticalPath(); 33910b57cec5SDimitry Andric checkAcyclicLatency(); 33920b57cec5SDimitry Andric } 33930b57cec5SDimitry Andric } 33940b57cec5SDimitry Andric 33950b57cec5SDimitry Andric namespace llvm { 33960b57cec5SDimitry Andric bool tryPressure(const PressureChange &TryP, 33970b57cec5SDimitry Andric const PressureChange &CandP, 33980b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &TryCand, 33990b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &Cand, 34000b57cec5SDimitry Andric GenericSchedulerBase::CandReason Reason, 34010b57cec5SDimitry Andric const TargetRegisterInfo *TRI, 34020b57cec5SDimitry Andric const MachineFunction &MF) { 34030b57cec5SDimitry Andric // If one candidate decreases and the other increases, go with it. 34040b57cec5SDimitry Andric // Invalid candidates have UnitInc==0. 34050b57cec5SDimitry Andric if (tryGreater(TryP.getUnitInc() < 0, CandP.getUnitInc() < 0, TryCand, Cand, 34060b57cec5SDimitry Andric Reason)) { 34070b57cec5SDimitry Andric return true; 34080b57cec5SDimitry Andric } 34090b57cec5SDimitry Andric // Do not compare the magnitude of pressure changes between top and bottom 34100b57cec5SDimitry Andric // boundary. 34110b57cec5SDimitry Andric if (Cand.AtTop != TryCand.AtTop) 34120b57cec5SDimitry Andric return false; 34130b57cec5SDimitry Andric 34140b57cec5SDimitry Andric // If both candidates affect the same set in the same boundary, go with the 34150b57cec5SDimitry Andric // smallest increase. 34160b57cec5SDimitry Andric unsigned TryPSet = TryP.getPSetOrMax(); 34170b57cec5SDimitry Andric unsigned CandPSet = CandP.getPSetOrMax(); 34180b57cec5SDimitry Andric if (TryPSet == CandPSet) { 34190b57cec5SDimitry Andric return tryLess(TryP.getUnitInc(), CandP.getUnitInc(), TryCand, Cand, 34200b57cec5SDimitry Andric Reason); 34210b57cec5SDimitry Andric } 34220b57cec5SDimitry Andric 34230b57cec5SDimitry Andric int TryRank = TryP.isValid() ? TRI->getRegPressureSetScore(MF, TryPSet) : 34240b57cec5SDimitry Andric std::numeric_limits<int>::max(); 34250b57cec5SDimitry Andric 34260b57cec5SDimitry Andric int CandRank = CandP.isValid() ? TRI->getRegPressureSetScore(MF, CandPSet) : 34270b57cec5SDimitry Andric std::numeric_limits<int>::max(); 34280b57cec5SDimitry Andric 34290b57cec5SDimitry Andric // If the candidates are decreasing pressure, reverse priority. 34300b57cec5SDimitry Andric if (TryP.getUnitInc() < 0) 34310b57cec5SDimitry Andric std::swap(TryRank, CandRank); 34320b57cec5SDimitry Andric return tryGreater(TryRank, CandRank, TryCand, Cand, Reason); 34330b57cec5SDimitry Andric } 34340b57cec5SDimitry Andric 34350b57cec5SDimitry Andric unsigned getWeakLeft(const SUnit *SU, bool isTop) { 34360b57cec5SDimitry Andric return (isTop) ? SU->WeakPredsLeft : SU->WeakSuccsLeft; 34370b57cec5SDimitry Andric } 34380b57cec5SDimitry Andric 34390b57cec5SDimitry Andric /// Minimize physical register live ranges. Regalloc wants them adjacent to 34400b57cec5SDimitry Andric /// their physreg def/use. 34410b57cec5SDimitry Andric /// 34420b57cec5SDimitry Andric /// FIXME: This is an unnecessary check on the critical path. Most are root/leaf 34430b57cec5SDimitry Andric /// copies which can be prescheduled. The rest (e.g. x86 MUL) could be bundled 34440b57cec5SDimitry Andric /// with the operation that produces or consumes the physreg. We'll do this when 34450b57cec5SDimitry Andric /// regalloc has support for parallel copies. 34460b57cec5SDimitry Andric int biasPhysReg(const SUnit *SU, bool isTop) { 34470b57cec5SDimitry Andric const MachineInstr *MI = SU->getInstr(); 34480b57cec5SDimitry Andric 34490b57cec5SDimitry Andric if (MI->isCopy()) { 34500b57cec5SDimitry Andric unsigned ScheduledOper = isTop ? 1 : 0; 34510b57cec5SDimitry Andric unsigned UnscheduledOper = isTop ? 0 : 1; 34520b57cec5SDimitry Andric // If we have already scheduled the physreg produce/consumer, immediately 34530b57cec5SDimitry Andric // schedule the copy. 3454bdd1243dSDimitry Andric if (MI->getOperand(ScheduledOper).getReg().isPhysical()) 34550b57cec5SDimitry Andric return 1; 34560b57cec5SDimitry Andric // If the physreg is at the boundary, defer it. Otherwise schedule it 34570b57cec5SDimitry Andric // immediately to free the dependent. We can hoist the copy later. 34580b57cec5SDimitry Andric bool AtBoundary = isTop ? !SU->NumSuccsLeft : !SU->NumPredsLeft; 3459bdd1243dSDimitry Andric if (MI->getOperand(UnscheduledOper).getReg().isPhysical()) 34600b57cec5SDimitry Andric return AtBoundary ? -1 : 1; 34610b57cec5SDimitry Andric } 34620b57cec5SDimitry Andric 34630b57cec5SDimitry Andric if (MI->isMoveImmediate()) { 34640b57cec5SDimitry Andric // If we have a move immediate and all successors have been assigned, bias 34650b57cec5SDimitry Andric // towards scheduling this later. Make sure all register defs are to 34660b57cec5SDimitry Andric // physical registers. 34670b57cec5SDimitry Andric bool DoBias = true; 34680b57cec5SDimitry Andric for (const MachineOperand &Op : MI->defs()) { 3469bdd1243dSDimitry Andric if (Op.isReg() && !Op.getReg().isPhysical()) { 34700b57cec5SDimitry Andric DoBias = false; 34710b57cec5SDimitry Andric break; 34720b57cec5SDimitry Andric } 34730b57cec5SDimitry Andric } 34740b57cec5SDimitry Andric 34750b57cec5SDimitry Andric if (DoBias) 34760b57cec5SDimitry Andric return isTop ? -1 : 1; 34770b57cec5SDimitry Andric } 34780b57cec5SDimitry Andric 34790b57cec5SDimitry Andric return 0; 34800b57cec5SDimitry Andric } 34810b57cec5SDimitry Andric } // end namespace llvm 34820b57cec5SDimitry Andric 34830b57cec5SDimitry Andric void GenericScheduler::initCandidate(SchedCandidate &Cand, SUnit *SU, 34840b57cec5SDimitry Andric bool AtTop, 34850b57cec5SDimitry Andric const RegPressureTracker &RPTracker, 34860b57cec5SDimitry Andric RegPressureTracker &TempTracker) { 34870b57cec5SDimitry Andric Cand.SU = SU; 34880b57cec5SDimitry Andric Cand.AtTop = AtTop; 34890b57cec5SDimitry Andric if (DAG->isTrackingPressure()) { 34900b57cec5SDimitry Andric if (AtTop) { 34910b57cec5SDimitry Andric TempTracker.getMaxDownwardPressureDelta( 34920b57cec5SDimitry Andric Cand.SU->getInstr(), 34930b57cec5SDimitry Andric Cand.RPDelta, 34940b57cec5SDimitry Andric DAG->getRegionCriticalPSets(), 34950b57cec5SDimitry Andric DAG->getRegPressure().MaxSetPressure); 34960b57cec5SDimitry Andric } else { 34970b57cec5SDimitry Andric if (VerifyScheduling) { 34980b57cec5SDimitry Andric TempTracker.getMaxUpwardPressureDelta( 34990b57cec5SDimitry Andric Cand.SU->getInstr(), 35000b57cec5SDimitry Andric &DAG->getPressureDiff(Cand.SU), 35010b57cec5SDimitry Andric Cand.RPDelta, 35020b57cec5SDimitry Andric DAG->getRegionCriticalPSets(), 35030b57cec5SDimitry Andric DAG->getRegPressure().MaxSetPressure); 35040b57cec5SDimitry Andric } else { 35050b57cec5SDimitry Andric RPTracker.getUpwardPressureDelta( 35060b57cec5SDimitry Andric Cand.SU->getInstr(), 35070b57cec5SDimitry Andric DAG->getPressureDiff(Cand.SU), 35080b57cec5SDimitry Andric Cand.RPDelta, 35090b57cec5SDimitry Andric DAG->getRegionCriticalPSets(), 35100b57cec5SDimitry Andric DAG->getRegPressure().MaxSetPressure); 35110b57cec5SDimitry Andric } 35120b57cec5SDimitry Andric } 35130b57cec5SDimitry Andric } 35140b57cec5SDimitry Andric LLVM_DEBUG(if (Cand.RPDelta.Excess.isValid()) dbgs() 35150b57cec5SDimitry Andric << " Try SU(" << Cand.SU->NodeNum << ") " 35160b57cec5SDimitry Andric << TRI->getRegPressureSetName(Cand.RPDelta.Excess.getPSet()) << ":" 35170b57cec5SDimitry Andric << Cand.RPDelta.Excess.getUnitInc() << "\n"); 35180b57cec5SDimitry Andric } 35190b57cec5SDimitry Andric 35200b57cec5SDimitry Andric /// Apply a set of heuristics to a new candidate. Heuristics are currently 35210b57cec5SDimitry Andric /// hierarchical. This may be more efficient than a graduated cost model because 35220b57cec5SDimitry Andric /// we don't need to evaluate all aspects of the model for each node in the 35230b57cec5SDimitry Andric /// queue. But it's really done to make the heuristics easier to debug and 35240b57cec5SDimitry Andric /// statistically analyze. 35250b57cec5SDimitry Andric /// 35260b57cec5SDimitry Andric /// \param Cand provides the policy and current best candidate. 35270b57cec5SDimitry Andric /// \param TryCand refers to the next SUnit candidate, otherwise uninitialized. 35280b57cec5SDimitry Andric /// \param Zone describes the scheduled zone that we are extending, or nullptr 3529fe6060f1SDimitry Andric /// if Cand is from a different zone than TryCand. 3530fe6060f1SDimitry Andric /// \return \c true if TryCand is better than Cand (Reason is NOT NoCand) 3531fe6060f1SDimitry Andric bool GenericScheduler::tryCandidate(SchedCandidate &Cand, 35320b57cec5SDimitry Andric SchedCandidate &TryCand, 35330b57cec5SDimitry Andric SchedBoundary *Zone) const { 35340b57cec5SDimitry Andric // Initialize the candidate if needed. 35350b57cec5SDimitry Andric if (!Cand.isValid()) { 35360b57cec5SDimitry Andric TryCand.Reason = NodeOrder; 3537fe6060f1SDimitry Andric return true; 35380b57cec5SDimitry Andric } 35390b57cec5SDimitry Andric 35400b57cec5SDimitry Andric // Bias PhysReg Defs and copies to their uses and defined respectively. 35410b57cec5SDimitry Andric if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop), 35420b57cec5SDimitry Andric biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg)) 3543fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 35440b57cec5SDimitry Andric 35450b57cec5SDimitry Andric // Avoid exceeding the target's limit. 35460b57cec5SDimitry Andric if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.Excess, 35470b57cec5SDimitry Andric Cand.RPDelta.Excess, 35480b57cec5SDimitry Andric TryCand, Cand, RegExcess, TRI, 35490b57cec5SDimitry Andric DAG->MF)) 3550fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 35510b57cec5SDimitry Andric 35520b57cec5SDimitry Andric // Avoid increasing the max critical pressure in the scheduled region. 35530b57cec5SDimitry Andric if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.CriticalMax, 35540b57cec5SDimitry Andric Cand.RPDelta.CriticalMax, 35550b57cec5SDimitry Andric TryCand, Cand, RegCritical, TRI, 35560b57cec5SDimitry Andric DAG->MF)) 3557fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 35580b57cec5SDimitry Andric 35590b57cec5SDimitry Andric // We only compare a subset of features when comparing nodes between 35600b57cec5SDimitry Andric // Top and Bottom boundary. Some properties are simply incomparable, in many 35610b57cec5SDimitry Andric // other instances we should only override the other boundary if something 35620b57cec5SDimitry Andric // is a clear good pick on one boundary. Skip heuristics that are more 35630b57cec5SDimitry Andric // "tie-breaking" in nature. 35640b57cec5SDimitry Andric bool SameBoundary = Zone != nullptr; 35650b57cec5SDimitry Andric if (SameBoundary) { 35660b57cec5SDimitry Andric // For loops that are acyclic path limited, aggressively schedule for 35670b57cec5SDimitry Andric // latency. Within an single cycle, whenever CurrMOps > 0, allow normal 35680b57cec5SDimitry Andric // heuristics to take precedence. 35690b57cec5SDimitry Andric if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() && 35700b57cec5SDimitry Andric tryLatency(TryCand, Cand, *Zone)) 3571fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 35720b57cec5SDimitry Andric 35730b57cec5SDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles. 35740b57cec5SDimitry Andric if (tryLess(Zone->getLatencyStallCycles(TryCand.SU), 35750b57cec5SDimitry Andric Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall)) 3576fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 35770b57cec5SDimitry Andric } 35780b57cec5SDimitry Andric 35790b57cec5SDimitry Andric // Keep clustered nodes together to encourage downstream peephole 35800b57cec5SDimitry Andric // optimizations which may reduce resource requirements. 35810b57cec5SDimitry Andric // 35820b57cec5SDimitry Andric // This is a best effort to set things up for a post-RA pass. Optimizations 35830b57cec5SDimitry Andric // like generating loads of multiple registers should ideally be done within 35840b57cec5SDimitry Andric // the scheduler pass by combining the loads during DAG postprocessing. 35850b57cec5SDimitry Andric const SUnit *CandNextClusterSU = 35860b57cec5SDimitry Andric Cand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred(); 35870b57cec5SDimitry Andric const SUnit *TryCandNextClusterSU = 35880b57cec5SDimitry Andric TryCand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred(); 35890b57cec5SDimitry Andric if (tryGreater(TryCand.SU == TryCandNextClusterSU, 35900b57cec5SDimitry Andric Cand.SU == CandNextClusterSU, 35910b57cec5SDimitry Andric TryCand, Cand, Cluster)) 3592fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 35930b57cec5SDimitry Andric 35940b57cec5SDimitry Andric if (SameBoundary) { 35950b57cec5SDimitry Andric // Weak edges are for clustering and other constraints. 35960b57cec5SDimitry Andric if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop), 35970b57cec5SDimitry Andric getWeakLeft(Cand.SU, Cand.AtTop), 35980b57cec5SDimitry Andric TryCand, Cand, Weak)) 3599fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 36000b57cec5SDimitry Andric } 36010b57cec5SDimitry Andric 36020b57cec5SDimitry Andric // Avoid increasing the max pressure of the entire region. 36030b57cec5SDimitry Andric if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.CurrentMax, 36040b57cec5SDimitry Andric Cand.RPDelta.CurrentMax, 36050b57cec5SDimitry Andric TryCand, Cand, RegMax, TRI, 36060b57cec5SDimitry Andric DAG->MF)) 3607fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 36080b57cec5SDimitry Andric 36090b57cec5SDimitry Andric if (SameBoundary) { 36100b57cec5SDimitry Andric // Avoid critical resource consumption and balance the schedule. 36110b57cec5SDimitry Andric TryCand.initResourceDelta(DAG, SchedModel); 36120b57cec5SDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources, 36130b57cec5SDimitry Andric TryCand, Cand, ResourceReduce)) 3614fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 36150b57cec5SDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources, 36160b57cec5SDimitry Andric Cand.ResDelta.DemandedResources, 36170b57cec5SDimitry Andric TryCand, Cand, ResourceDemand)) 3618fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 36190b57cec5SDimitry Andric 36200b57cec5SDimitry Andric // Avoid serializing long latency dependence chains. 36210b57cec5SDimitry Andric // For acyclic path limited loops, latency was already checked above. 36220b57cec5SDimitry Andric if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency && 36230b57cec5SDimitry Andric !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone)) 3624fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 36250b57cec5SDimitry Andric 36260b57cec5SDimitry Andric // Fall through to original instruction order. 36270b57cec5SDimitry Andric if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) 36280b57cec5SDimitry Andric || (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) { 36290b57cec5SDimitry Andric TryCand.Reason = NodeOrder; 3630fe6060f1SDimitry Andric return true; 36310b57cec5SDimitry Andric } 36320b57cec5SDimitry Andric } 3633fe6060f1SDimitry Andric 3634fe6060f1SDimitry Andric return false; 36350b57cec5SDimitry Andric } 36360b57cec5SDimitry Andric 36370b57cec5SDimitry Andric /// Pick the best candidate from the queue. 36380b57cec5SDimitry Andric /// 36390b57cec5SDimitry Andric /// TODO: getMaxPressureDelta results can be mostly cached for each SUnit during 36400b57cec5SDimitry Andric /// DAG building. To adjust for the current scheduling location we need to 36410b57cec5SDimitry Andric /// maintain the number of vreg uses remaining to be top-scheduled. 36420b57cec5SDimitry Andric void GenericScheduler::pickNodeFromQueue(SchedBoundary &Zone, 36430b57cec5SDimitry Andric const CandPolicy &ZonePolicy, 36440b57cec5SDimitry Andric const RegPressureTracker &RPTracker, 36450b57cec5SDimitry Andric SchedCandidate &Cand) { 36460b57cec5SDimitry Andric // getMaxPressureDelta temporarily modifies the tracker. 36470b57cec5SDimitry Andric RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker); 36480b57cec5SDimitry Andric 36490b57cec5SDimitry Andric ReadyQueue &Q = Zone.Available; 36500b57cec5SDimitry Andric for (SUnit *SU : Q) { 36510b57cec5SDimitry Andric 36520b57cec5SDimitry Andric SchedCandidate TryCand(ZonePolicy); 36530b57cec5SDimitry Andric initCandidate(TryCand, SU, Zone.isTop(), RPTracker, TempTracker); 36540b57cec5SDimitry Andric // Pass SchedBoundary only when comparing nodes from the same boundary. 36550b57cec5SDimitry Andric SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr; 3656fe6060f1SDimitry Andric if (tryCandidate(Cand, TryCand, ZoneArg)) { 36570b57cec5SDimitry Andric // Initialize resource delta if needed in case future heuristics query it. 36580b57cec5SDimitry Andric if (TryCand.ResDelta == SchedResourceDelta()) 36590b57cec5SDimitry Andric TryCand.initResourceDelta(DAG, SchedModel); 36600b57cec5SDimitry Andric Cand.setBest(TryCand); 36610b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(Cand)); 36620b57cec5SDimitry Andric } 36630b57cec5SDimitry Andric } 36640b57cec5SDimitry Andric } 36650b57cec5SDimitry Andric 36660b57cec5SDimitry Andric /// Pick the best candidate node from either the top or bottom queue. 36670b57cec5SDimitry Andric SUnit *GenericScheduler::pickNodeBidirectional(bool &IsTopNode) { 36680b57cec5SDimitry Andric // Schedule as far as possible in the direction of no choice. This is most 36690b57cec5SDimitry Andric // efficient, but also provides the best heuristics for CriticalPSets. 36700b57cec5SDimitry Andric if (SUnit *SU = Bot.pickOnlyChoice()) { 36710b57cec5SDimitry Andric IsTopNode = false; 36720b57cec5SDimitry Andric tracePick(Only1, false); 36730b57cec5SDimitry Andric return SU; 36740b57cec5SDimitry Andric } 36750b57cec5SDimitry Andric if (SUnit *SU = Top.pickOnlyChoice()) { 36760b57cec5SDimitry Andric IsTopNode = true; 36770b57cec5SDimitry Andric tracePick(Only1, true); 36780b57cec5SDimitry Andric return SU; 36790b57cec5SDimitry Andric } 36800b57cec5SDimitry Andric // Set the bottom-up policy based on the state of the current bottom zone and 36810b57cec5SDimitry Andric // the instructions outside the zone, including the top zone. 36820b57cec5SDimitry Andric CandPolicy BotPolicy; 36830b57cec5SDimitry Andric setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top); 36840b57cec5SDimitry Andric // Set the top-down policy based on the state of the current top zone and 36850b57cec5SDimitry Andric // the instructions outside the zone, including the bottom zone. 36860b57cec5SDimitry Andric CandPolicy TopPolicy; 36870b57cec5SDimitry Andric setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot); 36880b57cec5SDimitry Andric 36890b57cec5SDimitry Andric // See if BotCand is still valid (because we previously scheduled from Top). 36900b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Picking from Bot:\n"); 36910b57cec5SDimitry Andric if (!BotCand.isValid() || BotCand.SU->isScheduled || 36920b57cec5SDimitry Andric BotCand.Policy != BotPolicy) { 36930b57cec5SDimitry Andric BotCand.reset(CandPolicy()); 36940b57cec5SDimitry Andric pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand); 36950b57cec5SDimitry Andric assert(BotCand.Reason != NoCand && "failed to find the first candidate"); 36960b57cec5SDimitry Andric } else { 36970b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(BotCand)); 36980b57cec5SDimitry Andric #ifndef NDEBUG 36990b57cec5SDimitry Andric if (VerifyScheduling) { 37000b57cec5SDimitry Andric SchedCandidate TCand; 37010b57cec5SDimitry Andric TCand.reset(CandPolicy()); 37020b57cec5SDimitry Andric pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand); 37030b57cec5SDimitry Andric assert(TCand.SU == BotCand.SU && 37040b57cec5SDimitry Andric "Last pick result should correspond to re-picking right now"); 37050b57cec5SDimitry Andric } 37060b57cec5SDimitry Andric #endif 37070b57cec5SDimitry Andric } 37080b57cec5SDimitry Andric 37090b57cec5SDimitry Andric // Check if the top Q has a better candidate. 37100b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Picking from Top:\n"); 37110b57cec5SDimitry Andric if (!TopCand.isValid() || TopCand.SU->isScheduled || 37120b57cec5SDimitry Andric TopCand.Policy != TopPolicy) { 37130b57cec5SDimitry Andric TopCand.reset(CandPolicy()); 37140b57cec5SDimitry Andric pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand); 37150b57cec5SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find the first candidate"); 37160b57cec5SDimitry Andric } else { 37170b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(TopCand)); 37180b57cec5SDimitry Andric #ifndef NDEBUG 37190b57cec5SDimitry Andric if (VerifyScheduling) { 37200b57cec5SDimitry Andric SchedCandidate TCand; 37210b57cec5SDimitry Andric TCand.reset(CandPolicy()); 37220b57cec5SDimitry Andric pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand); 37230b57cec5SDimitry Andric assert(TCand.SU == TopCand.SU && 37240b57cec5SDimitry Andric "Last pick result should correspond to re-picking right now"); 37250b57cec5SDimitry Andric } 37260b57cec5SDimitry Andric #endif 37270b57cec5SDimitry Andric } 37280b57cec5SDimitry Andric 37290b57cec5SDimitry Andric // Pick best from BotCand and TopCand. 37300b57cec5SDimitry Andric assert(BotCand.isValid()); 37310b57cec5SDimitry Andric assert(TopCand.isValid()); 37320b57cec5SDimitry Andric SchedCandidate Cand = BotCand; 37330b57cec5SDimitry Andric TopCand.Reason = NoCand; 3734fe6060f1SDimitry Andric if (tryCandidate(Cand, TopCand, nullptr)) { 37350b57cec5SDimitry Andric Cand.setBest(TopCand); 37360b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(Cand)); 37370b57cec5SDimitry Andric } 37380b57cec5SDimitry Andric 37390b57cec5SDimitry Andric IsTopNode = Cand.AtTop; 37400b57cec5SDimitry Andric tracePick(Cand); 37410b57cec5SDimitry Andric return Cand.SU; 37420b57cec5SDimitry Andric } 37430b57cec5SDimitry Andric 37440b57cec5SDimitry Andric /// Pick the best node to balance the schedule. Implements MachineSchedStrategy. 37450b57cec5SDimitry Andric SUnit *GenericScheduler::pickNode(bool &IsTopNode) { 37460b57cec5SDimitry Andric if (DAG->top() == DAG->bottom()) { 37470b57cec5SDimitry Andric assert(Top.Available.empty() && Top.Pending.empty() && 37480b57cec5SDimitry Andric Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage"); 37490b57cec5SDimitry Andric return nullptr; 37500b57cec5SDimitry Andric } 37510b57cec5SDimitry Andric SUnit *SU; 37520b57cec5SDimitry Andric do { 37530b57cec5SDimitry Andric if (RegionPolicy.OnlyTopDown) { 37540b57cec5SDimitry Andric SU = Top.pickOnlyChoice(); 37550b57cec5SDimitry Andric if (!SU) { 37560b57cec5SDimitry Andric CandPolicy NoPolicy; 37570b57cec5SDimitry Andric TopCand.reset(NoPolicy); 37580b57cec5SDimitry Andric pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand); 37590b57cec5SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find a candidate"); 37600b57cec5SDimitry Andric tracePick(TopCand); 37610b57cec5SDimitry Andric SU = TopCand.SU; 37620b57cec5SDimitry Andric } 37630b57cec5SDimitry Andric IsTopNode = true; 37640b57cec5SDimitry Andric } else if (RegionPolicy.OnlyBottomUp) { 37650b57cec5SDimitry Andric SU = Bot.pickOnlyChoice(); 37660b57cec5SDimitry Andric if (!SU) { 37670b57cec5SDimitry Andric CandPolicy NoPolicy; 37680b57cec5SDimitry Andric BotCand.reset(NoPolicy); 37690b57cec5SDimitry Andric pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand); 37700b57cec5SDimitry Andric assert(BotCand.Reason != NoCand && "failed to find a candidate"); 37710b57cec5SDimitry Andric tracePick(BotCand); 37720b57cec5SDimitry Andric SU = BotCand.SU; 37730b57cec5SDimitry Andric } 37740b57cec5SDimitry Andric IsTopNode = false; 37750b57cec5SDimitry Andric } else { 37760b57cec5SDimitry Andric SU = pickNodeBidirectional(IsTopNode); 37770b57cec5SDimitry Andric } 37780b57cec5SDimitry Andric } while (SU->isScheduled); 37790b57cec5SDimitry Andric 3780*0fca6ea1SDimitry Andric // If IsTopNode, then SU is in Top.Available and must be removed. Otherwise, 3781*0fca6ea1SDimitry Andric // if isTopReady(), then SU is in either Top.Available or Top.Pending. 3782*0fca6ea1SDimitry Andric // If !IsTopNode, then SU is in Bot.Available and must be removed. Otherwise, 3783*0fca6ea1SDimitry Andric // if isBottomReady(), then SU is in either Bot.Available or Bot.Pending. 3784*0fca6ea1SDimitry Andric // 3785*0fca6ea1SDimitry Andric // It is coincidental when !IsTopNode && isTopReady or when IsTopNode && 3786*0fca6ea1SDimitry Andric // isBottomReady. That is, it didn't factor into the decision to choose SU 3787*0fca6ea1SDimitry Andric // because it isTopReady or isBottomReady, respectively. In fact, if the 3788*0fca6ea1SDimitry Andric // RegionPolicy is OnlyTopDown or OnlyBottomUp, then the Bot queues and Top 3789*0fca6ea1SDimitry Andric // queues respectivley contain the original roots and don't get updated when 3790*0fca6ea1SDimitry Andric // picking a node. So if SU isTopReady on a OnlyBottomUp pick, then it was 3791*0fca6ea1SDimitry Andric // because we schduled everything but the top roots. Conversley, if SU 3792*0fca6ea1SDimitry Andric // isBottomReady on OnlyTopDown, then it was because we scheduled everything 3793*0fca6ea1SDimitry Andric // but the bottom roots. If its in a queue even coincidentally, it should be 3794*0fca6ea1SDimitry Andric // removed so it does not get re-picked in a subsequent pickNode call. 37950b57cec5SDimitry Andric if (SU->isTopReady()) 37960b57cec5SDimitry Andric Top.removeReady(SU); 37970b57cec5SDimitry Andric if (SU->isBottomReady()) 37980b57cec5SDimitry Andric Bot.removeReady(SU); 37990b57cec5SDimitry Andric 38000b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " 38010b57cec5SDimitry Andric << *SU->getInstr()); 38020b57cec5SDimitry Andric return SU; 38030b57cec5SDimitry Andric } 38040b57cec5SDimitry Andric 38050b57cec5SDimitry Andric void GenericScheduler::reschedulePhysReg(SUnit *SU, bool isTop) { 38060b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPos = SU->getInstr(); 38070b57cec5SDimitry Andric if (!isTop) 38080b57cec5SDimitry Andric ++InsertPos; 38090b57cec5SDimitry Andric SmallVectorImpl<SDep> &Deps = isTop ? SU->Preds : SU->Succs; 38100b57cec5SDimitry Andric 38110b57cec5SDimitry Andric // Find already scheduled copies with a single physreg dependence and move 38120b57cec5SDimitry Andric // them just above the scheduled instruction. 38130b57cec5SDimitry Andric for (SDep &Dep : Deps) { 38148bcb0991SDimitry Andric if (Dep.getKind() != SDep::Data || 38158bcb0991SDimitry Andric !Register::isPhysicalRegister(Dep.getReg())) 38160b57cec5SDimitry Andric continue; 38170b57cec5SDimitry Andric SUnit *DepSU = Dep.getSUnit(); 38180b57cec5SDimitry Andric if (isTop ? DepSU->Succs.size() > 1 : DepSU->Preds.size() > 1) 38190b57cec5SDimitry Andric continue; 38200b57cec5SDimitry Andric MachineInstr *Copy = DepSU->getInstr(); 38210b57cec5SDimitry Andric if (!Copy->isCopy() && !Copy->isMoveImmediate()) 38220b57cec5SDimitry Andric continue; 38230b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Rescheduling physreg copy "; 38240b57cec5SDimitry Andric DAG->dumpNode(*Dep.getSUnit())); 38250b57cec5SDimitry Andric DAG->moveInstruction(Copy, InsertPos); 38260b57cec5SDimitry Andric } 38270b57cec5SDimitry Andric } 38280b57cec5SDimitry Andric 38290b57cec5SDimitry Andric /// Update the scheduler's state after scheduling a node. This is the same node 38300b57cec5SDimitry Andric /// that was just returned by pickNode(). However, ScheduleDAGMILive needs to 38310b57cec5SDimitry Andric /// update it's state based on the current cycle before MachineSchedStrategy 38320b57cec5SDimitry Andric /// does. 38330b57cec5SDimitry Andric /// 38340b57cec5SDimitry Andric /// FIXME: Eventually, we may bundle physreg copies rather than rescheduling 38350b57cec5SDimitry Andric /// them here. See comments in biasPhysReg. 38360b57cec5SDimitry Andric void GenericScheduler::schedNode(SUnit *SU, bool IsTopNode) { 38370b57cec5SDimitry Andric if (IsTopNode) { 38380b57cec5SDimitry Andric SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle()); 38390b57cec5SDimitry Andric Top.bumpNode(SU); 38400b57cec5SDimitry Andric if (SU->hasPhysRegUses) 38410b57cec5SDimitry Andric reschedulePhysReg(SU, true); 38420b57cec5SDimitry Andric } else { 38430b57cec5SDimitry Andric SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle()); 38440b57cec5SDimitry Andric Bot.bumpNode(SU); 38450b57cec5SDimitry Andric if (SU->hasPhysRegDefs) 38460b57cec5SDimitry Andric reschedulePhysReg(SU, false); 38470b57cec5SDimitry Andric } 38480b57cec5SDimitry Andric } 38490b57cec5SDimitry Andric 38500b57cec5SDimitry Andric /// Create the standard converging machine scheduler. This will be used as the 38510b57cec5SDimitry Andric /// default scheduler if the target does not set a default. 38520b57cec5SDimitry Andric ScheduleDAGMILive *llvm::createGenericSchedLive(MachineSchedContext *C) { 38530b57cec5SDimitry Andric ScheduleDAGMILive *DAG = 38548bcb0991SDimitry Andric new ScheduleDAGMILive(C, std::make_unique<GenericScheduler>(C)); 38550b57cec5SDimitry Andric // Register DAG post-processors. 38560b57cec5SDimitry Andric // 38570b57cec5SDimitry Andric // FIXME: extend the mutation API to allow earlier mutations to instantiate 38580b57cec5SDimitry Andric // data and pass it to later mutations. Have a single mutation that gathers 38590b57cec5SDimitry Andric // the interesting nodes in one pass. 38600b57cec5SDimitry Andric DAG->addMutation(createCopyConstrainDAGMutation(DAG->TII, DAG->TRI)); 3861*0fca6ea1SDimitry Andric 3862*0fca6ea1SDimitry Andric const TargetSubtargetInfo &STI = C->MF->getSubtarget(); 3863*0fca6ea1SDimitry Andric // Add MacroFusion mutation if fusions are not empty. 3864*0fca6ea1SDimitry Andric const auto &MacroFusions = STI.getMacroFusions(); 3865*0fca6ea1SDimitry Andric if (!MacroFusions.empty()) 3866*0fca6ea1SDimitry Andric DAG->addMutation(createMacroFusionDAGMutation(MacroFusions)); 38670b57cec5SDimitry Andric return DAG; 38680b57cec5SDimitry Andric } 38690b57cec5SDimitry Andric 3870e8d8bef9SDimitry Andric static ScheduleDAGInstrs *createConvergingSched(MachineSchedContext *C) { 38710b57cec5SDimitry Andric return createGenericSchedLive(C); 38720b57cec5SDimitry Andric } 38730b57cec5SDimitry Andric 38740b57cec5SDimitry Andric static MachineSchedRegistry 38750b57cec5SDimitry Andric GenericSchedRegistry("converge", "Standard converging scheduler.", 3876e8d8bef9SDimitry Andric createConvergingSched); 38770b57cec5SDimitry Andric 38780b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 38790b57cec5SDimitry Andric // PostGenericScheduler - Generic PostRA implementation of MachineSchedStrategy. 38800b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 38810b57cec5SDimitry Andric 38820b57cec5SDimitry Andric void PostGenericScheduler::initialize(ScheduleDAGMI *Dag) { 38830b57cec5SDimitry Andric DAG = Dag; 38840b57cec5SDimitry Andric SchedModel = DAG->getSchedModel(); 38850b57cec5SDimitry Andric TRI = DAG->TRI; 38860b57cec5SDimitry Andric 38870b57cec5SDimitry Andric Rem.init(DAG, SchedModel); 38880b57cec5SDimitry Andric Top.init(DAG, SchedModel, &Rem); 3889*0fca6ea1SDimitry Andric Bot.init(DAG, SchedModel, &Rem); 38900b57cec5SDimitry Andric 38910b57cec5SDimitry Andric // Initialize the HazardRecognizers. If itineraries don't exist, are empty, 38920b57cec5SDimitry Andric // or are disabled, then these HazardRecs will be disabled. 38930b57cec5SDimitry Andric const InstrItineraryData *Itin = SchedModel->getInstrItineraries(); 38940b57cec5SDimitry Andric if (!Top.HazardRec) { 3895*0fca6ea1SDimitry Andric Top.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG); 3896*0fca6ea1SDimitry Andric } 3897*0fca6ea1SDimitry Andric if (!Bot.HazardRec) { 3898*0fca6ea1SDimitry Andric Bot.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG); 3899*0fca6ea1SDimitry Andric } 3900*0fca6ea1SDimitry Andric } 3901*0fca6ea1SDimitry Andric 3902*0fca6ea1SDimitry Andric void PostGenericScheduler::initPolicy(MachineBasicBlock::iterator Begin, 3903*0fca6ea1SDimitry Andric MachineBasicBlock::iterator End, 3904*0fca6ea1SDimitry Andric unsigned NumRegionInstrs) { 3905*0fca6ea1SDimitry Andric if (PostRADirection == MISchedPostRASched::TopDown) { 3906*0fca6ea1SDimitry Andric RegionPolicy.OnlyTopDown = true; 3907*0fca6ea1SDimitry Andric RegionPolicy.OnlyBottomUp = false; 3908*0fca6ea1SDimitry Andric } else if (PostRADirection == MISchedPostRASched::BottomUp) { 3909*0fca6ea1SDimitry Andric RegionPolicy.OnlyTopDown = false; 3910*0fca6ea1SDimitry Andric RegionPolicy.OnlyBottomUp = true; 3911*0fca6ea1SDimitry Andric } else if (PostRADirection == MISchedPostRASched::Bidirectional) { 3912*0fca6ea1SDimitry Andric RegionPolicy.OnlyBottomUp = false; 3913*0fca6ea1SDimitry Andric RegionPolicy.OnlyTopDown = false; 39140b57cec5SDimitry Andric } 39150b57cec5SDimitry Andric } 39160b57cec5SDimitry Andric 39170b57cec5SDimitry Andric void PostGenericScheduler::registerRoots() { 39180b57cec5SDimitry Andric Rem.CriticalPath = DAG->ExitSU.getDepth(); 39190b57cec5SDimitry Andric 39200b57cec5SDimitry Andric // Some roots may not feed into ExitSU. Check all of them in case. 3921*0fca6ea1SDimitry Andric for (const SUnit *SU : Bot.Available) { 39220b57cec5SDimitry Andric if (SU->getDepth() > Rem.CriticalPath) 39230b57cec5SDimitry Andric Rem.CriticalPath = SU->getDepth(); 39240b57cec5SDimitry Andric } 39250b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Critical Path: (PGS-RR) " << Rem.CriticalPath << '\n'); 39260b57cec5SDimitry Andric if (DumpCriticalPathLength) { 39270b57cec5SDimitry Andric errs() << "Critical Path(PGS-RR ): " << Rem.CriticalPath << " \n"; 39280b57cec5SDimitry Andric } 39290b57cec5SDimitry Andric } 39300b57cec5SDimitry Andric 39310b57cec5SDimitry Andric /// Apply a set of heuristics to a new candidate for PostRA scheduling. 39320b57cec5SDimitry Andric /// 39330b57cec5SDimitry Andric /// \param Cand provides the policy and current best candidate. 39340b57cec5SDimitry Andric /// \param TryCand refers to the next SUnit candidate, otherwise uninitialized. 3935fe6060f1SDimitry Andric /// \return \c true if TryCand is better than Cand (Reason is NOT NoCand) 3936fe6060f1SDimitry Andric bool PostGenericScheduler::tryCandidate(SchedCandidate &Cand, 39370b57cec5SDimitry Andric SchedCandidate &TryCand) { 39380b57cec5SDimitry Andric // Initialize the candidate if needed. 39390b57cec5SDimitry Andric if (!Cand.isValid()) { 39400b57cec5SDimitry Andric TryCand.Reason = NodeOrder; 3941fe6060f1SDimitry Andric return true; 39420b57cec5SDimitry Andric } 39430b57cec5SDimitry Andric 39440b57cec5SDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles. 39450b57cec5SDimitry Andric if (tryLess(Top.getLatencyStallCycles(TryCand.SU), 39460b57cec5SDimitry Andric Top.getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall)) 3947fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 39480b57cec5SDimitry Andric 39490b57cec5SDimitry Andric // Keep clustered nodes together. 39500b57cec5SDimitry Andric if (tryGreater(TryCand.SU == DAG->getNextClusterSucc(), 39510b57cec5SDimitry Andric Cand.SU == DAG->getNextClusterSucc(), 39520b57cec5SDimitry Andric TryCand, Cand, Cluster)) 3953fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 39540b57cec5SDimitry Andric 39550b57cec5SDimitry Andric // Avoid critical resource consumption and balance the schedule. 39560b57cec5SDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources, 39570b57cec5SDimitry Andric TryCand, Cand, ResourceReduce)) 3958fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 39590b57cec5SDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources, 39600b57cec5SDimitry Andric Cand.ResDelta.DemandedResources, 39610b57cec5SDimitry Andric TryCand, Cand, ResourceDemand)) 3962fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 39630b57cec5SDimitry Andric 39640b57cec5SDimitry Andric // Avoid serializing long latency dependence chains. 39650b57cec5SDimitry Andric if (Cand.Policy.ReduceLatency && tryLatency(TryCand, Cand, Top)) { 3966fe6060f1SDimitry Andric return TryCand.Reason != NoCand; 39670b57cec5SDimitry Andric } 39680b57cec5SDimitry Andric 39690b57cec5SDimitry Andric // Fall through to original instruction order. 3970fe6060f1SDimitry Andric if (TryCand.SU->NodeNum < Cand.SU->NodeNum) { 39710b57cec5SDimitry Andric TryCand.Reason = NodeOrder; 3972fe6060f1SDimitry Andric return true; 3973fe6060f1SDimitry Andric } 3974fe6060f1SDimitry Andric 3975fe6060f1SDimitry Andric return false; 39760b57cec5SDimitry Andric } 39770b57cec5SDimitry Andric 3978*0fca6ea1SDimitry Andric void PostGenericScheduler::pickNodeFromQueue(SchedBoundary &Zone, 3979*0fca6ea1SDimitry Andric SchedCandidate &Cand) { 3980*0fca6ea1SDimitry Andric ReadyQueue &Q = Zone.Available; 39810b57cec5SDimitry Andric for (SUnit *SU : Q) { 39820b57cec5SDimitry Andric SchedCandidate TryCand(Cand.Policy); 39830b57cec5SDimitry Andric TryCand.SU = SU; 3984*0fca6ea1SDimitry Andric TryCand.AtTop = Zone.isTop(); 39850b57cec5SDimitry Andric TryCand.initResourceDelta(DAG, SchedModel); 3986fe6060f1SDimitry Andric if (tryCandidate(Cand, TryCand)) { 39870b57cec5SDimitry Andric Cand.setBest(TryCand); 39880b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(Cand)); 39890b57cec5SDimitry Andric } 39900b57cec5SDimitry Andric } 39910b57cec5SDimitry Andric } 39920b57cec5SDimitry Andric 3993*0fca6ea1SDimitry Andric /// Pick the best candidate node from either the top or bottom queue. 3994*0fca6ea1SDimitry Andric SUnit *PostGenericScheduler::pickNodeBidirectional(bool &IsTopNode) { 3995*0fca6ea1SDimitry Andric // FIXME: This is similiar to GenericScheduler::pickNodeBidirectional. Factor 3996*0fca6ea1SDimitry Andric // out common parts. 3997*0fca6ea1SDimitry Andric 3998*0fca6ea1SDimitry Andric // Schedule as far as possible in the direction of no choice. This is most 3999*0fca6ea1SDimitry Andric // efficient, but also provides the best heuristics for CriticalPSets. 4000*0fca6ea1SDimitry Andric if (SUnit *SU = Bot.pickOnlyChoice()) { 4001*0fca6ea1SDimitry Andric IsTopNode = false; 4002*0fca6ea1SDimitry Andric tracePick(Only1, false); 4003*0fca6ea1SDimitry Andric return SU; 4004*0fca6ea1SDimitry Andric } 4005*0fca6ea1SDimitry Andric if (SUnit *SU = Top.pickOnlyChoice()) { 4006*0fca6ea1SDimitry Andric IsTopNode = true; 4007*0fca6ea1SDimitry Andric tracePick(Only1, true); 4008*0fca6ea1SDimitry Andric return SU; 4009*0fca6ea1SDimitry Andric } 4010*0fca6ea1SDimitry Andric // Set the bottom-up policy based on the state of the current bottom zone and 4011*0fca6ea1SDimitry Andric // the instructions outside the zone, including the top zone. 4012*0fca6ea1SDimitry Andric CandPolicy BotPolicy; 4013*0fca6ea1SDimitry Andric setPolicy(BotPolicy, /*IsPostRA=*/true, Bot, &Top); 4014*0fca6ea1SDimitry Andric // Set the top-down policy based on the state of the current top zone and 4015*0fca6ea1SDimitry Andric // the instructions outside the zone, including the bottom zone. 4016*0fca6ea1SDimitry Andric CandPolicy TopPolicy; 4017*0fca6ea1SDimitry Andric setPolicy(TopPolicy, /*IsPostRA=*/true, Top, &Bot); 4018*0fca6ea1SDimitry Andric 4019*0fca6ea1SDimitry Andric // See if BotCand is still valid (because we previously scheduled from Top). 4020*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << "Picking from Bot:\n"); 4021*0fca6ea1SDimitry Andric if (!BotCand.isValid() || BotCand.SU->isScheduled || 4022*0fca6ea1SDimitry Andric BotCand.Policy != BotPolicy) { 4023*0fca6ea1SDimitry Andric BotCand.reset(CandPolicy()); 4024*0fca6ea1SDimitry Andric pickNodeFromQueue(Bot, BotCand); 4025*0fca6ea1SDimitry Andric assert(BotCand.Reason != NoCand && "failed to find the first candidate"); 4026*0fca6ea1SDimitry Andric } else { 4027*0fca6ea1SDimitry Andric LLVM_DEBUG(traceCandidate(BotCand)); 4028*0fca6ea1SDimitry Andric #ifndef NDEBUG 4029*0fca6ea1SDimitry Andric if (VerifyScheduling) { 4030*0fca6ea1SDimitry Andric SchedCandidate TCand; 4031*0fca6ea1SDimitry Andric TCand.reset(CandPolicy()); 4032*0fca6ea1SDimitry Andric pickNodeFromQueue(Bot, BotCand); 4033*0fca6ea1SDimitry Andric assert(TCand.SU == BotCand.SU && 4034*0fca6ea1SDimitry Andric "Last pick result should correspond to re-picking right now"); 4035*0fca6ea1SDimitry Andric } 4036*0fca6ea1SDimitry Andric #endif 4037*0fca6ea1SDimitry Andric } 4038*0fca6ea1SDimitry Andric 4039*0fca6ea1SDimitry Andric // Check if the top Q has a better candidate. 4040*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << "Picking from Top:\n"); 4041*0fca6ea1SDimitry Andric if (!TopCand.isValid() || TopCand.SU->isScheduled || 4042*0fca6ea1SDimitry Andric TopCand.Policy != TopPolicy) { 4043*0fca6ea1SDimitry Andric TopCand.reset(CandPolicy()); 4044*0fca6ea1SDimitry Andric pickNodeFromQueue(Top, TopCand); 4045*0fca6ea1SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find the first candidate"); 4046*0fca6ea1SDimitry Andric } else { 4047*0fca6ea1SDimitry Andric LLVM_DEBUG(traceCandidate(TopCand)); 4048*0fca6ea1SDimitry Andric #ifndef NDEBUG 4049*0fca6ea1SDimitry Andric if (VerifyScheduling) { 4050*0fca6ea1SDimitry Andric SchedCandidate TCand; 4051*0fca6ea1SDimitry Andric TCand.reset(CandPolicy()); 4052*0fca6ea1SDimitry Andric pickNodeFromQueue(Top, TopCand); 4053*0fca6ea1SDimitry Andric assert(TCand.SU == TopCand.SU && 4054*0fca6ea1SDimitry Andric "Last pick result should correspond to re-picking right now"); 4055*0fca6ea1SDimitry Andric } 4056*0fca6ea1SDimitry Andric #endif 4057*0fca6ea1SDimitry Andric } 4058*0fca6ea1SDimitry Andric 4059*0fca6ea1SDimitry Andric // Pick best from BotCand and TopCand. 4060*0fca6ea1SDimitry Andric assert(BotCand.isValid()); 4061*0fca6ea1SDimitry Andric assert(TopCand.isValid()); 4062*0fca6ea1SDimitry Andric SchedCandidate Cand = BotCand; 4063*0fca6ea1SDimitry Andric TopCand.Reason = NoCand; 4064*0fca6ea1SDimitry Andric if (tryCandidate(Cand, TopCand)) { 4065*0fca6ea1SDimitry Andric Cand.setBest(TopCand); 4066*0fca6ea1SDimitry Andric LLVM_DEBUG(traceCandidate(Cand)); 4067*0fca6ea1SDimitry Andric } 4068*0fca6ea1SDimitry Andric 4069*0fca6ea1SDimitry Andric IsTopNode = Cand.AtTop; 4070*0fca6ea1SDimitry Andric tracePick(Cand); 4071*0fca6ea1SDimitry Andric return Cand.SU; 4072*0fca6ea1SDimitry Andric } 4073*0fca6ea1SDimitry Andric 40740b57cec5SDimitry Andric /// Pick the next node to schedule. 40750b57cec5SDimitry Andric SUnit *PostGenericScheduler::pickNode(bool &IsTopNode) { 40760b57cec5SDimitry Andric if (DAG->top() == DAG->bottom()) { 4077*0fca6ea1SDimitry Andric assert(Top.Available.empty() && Top.Pending.empty() && 4078*0fca6ea1SDimitry Andric Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage"); 40790b57cec5SDimitry Andric return nullptr; 40800b57cec5SDimitry Andric } 40810b57cec5SDimitry Andric SUnit *SU; 40820b57cec5SDimitry Andric do { 4083*0fca6ea1SDimitry Andric if (RegionPolicy.OnlyBottomUp) { 4084*0fca6ea1SDimitry Andric SU = Bot.pickOnlyChoice(); 4085*0fca6ea1SDimitry Andric if (SU) { 4086*0fca6ea1SDimitry Andric tracePick(Only1, true); 4087*0fca6ea1SDimitry Andric } else { 4088*0fca6ea1SDimitry Andric CandPolicy NoPolicy; 4089*0fca6ea1SDimitry Andric BotCand.reset(NoPolicy); 4090*0fca6ea1SDimitry Andric // Set the bottom-up policy based on the state of the current bottom 4091*0fca6ea1SDimitry Andric // zone and the instructions outside the zone, including the top zone. 4092*0fca6ea1SDimitry Andric setPolicy(BotCand.Policy, /*IsPostRA=*/true, Bot, nullptr); 4093*0fca6ea1SDimitry Andric pickNodeFromQueue(Bot, BotCand); 4094*0fca6ea1SDimitry Andric assert(BotCand.Reason != NoCand && "failed to find a candidate"); 4095*0fca6ea1SDimitry Andric tracePick(BotCand); 4096*0fca6ea1SDimitry Andric SU = BotCand.SU; 4097*0fca6ea1SDimitry Andric } 4098*0fca6ea1SDimitry Andric IsTopNode = false; 4099*0fca6ea1SDimitry Andric } else if (RegionPolicy.OnlyTopDown) { 41000b57cec5SDimitry Andric SU = Top.pickOnlyChoice(); 41010b57cec5SDimitry Andric if (SU) { 41020b57cec5SDimitry Andric tracePick(Only1, true); 41030b57cec5SDimitry Andric } else { 41040b57cec5SDimitry Andric CandPolicy NoPolicy; 4105*0fca6ea1SDimitry Andric TopCand.reset(NoPolicy); 4106*0fca6ea1SDimitry Andric // Set the top-down policy based on the state of the current top zone 4107*0fca6ea1SDimitry Andric // and the instructions outside the zone, including the bottom zone. 41080b57cec5SDimitry Andric setPolicy(TopCand.Policy, /*IsPostRA=*/true, Top, nullptr); 4109*0fca6ea1SDimitry Andric pickNodeFromQueue(Top, TopCand); 41100b57cec5SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find a candidate"); 41110b57cec5SDimitry Andric tracePick(TopCand); 41120b57cec5SDimitry Andric SU = TopCand.SU; 41130b57cec5SDimitry Andric } 4114*0fca6ea1SDimitry Andric IsTopNode = true; 4115*0fca6ea1SDimitry Andric } else { 4116*0fca6ea1SDimitry Andric SU = pickNodeBidirectional(IsTopNode); 4117*0fca6ea1SDimitry Andric } 41180b57cec5SDimitry Andric } while (SU->isScheduled); 41190b57cec5SDimitry Andric 4120*0fca6ea1SDimitry Andric if (SU->isTopReady()) 41210b57cec5SDimitry Andric Top.removeReady(SU); 4122*0fca6ea1SDimitry Andric if (SU->isBottomReady()) 4123*0fca6ea1SDimitry Andric Bot.removeReady(SU); 41240b57cec5SDimitry Andric 41250b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " 41260b57cec5SDimitry Andric << *SU->getInstr()); 41270b57cec5SDimitry Andric return SU; 41280b57cec5SDimitry Andric } 41290b57cec5SDimitry Andric 41300b57cec5SDimitry Andric /// Called after ScheduleDAGMI has scheduled an instruction and updated 41310b57cec5SDimitry Andric /// scheduled/remaining flags in the DAG nodes. 41320b57cec5SDimitry Andric void PostGenericScheduler::schedNode(SUnit *SU, bool IsTopNode) { 4133*0fca6ea1SDimitry Andric if (IsTopNode) { 41340b57cec5SDimitry Andric SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle()); 41350b57cec5SDimitry Andric Top.bumpNode(SU); 4136*0fca6ea1SDimitry Andric } else { 4137*0fca6ea1SDimitry Andric SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle()); 4138*0fca6ea1SDimitry Andric Bot.bumpNode(SU); 4139*0fca6ea1SDimitry Andric } 41400b57cec5SDimitry Andric } 41410b57cec5SDimitry Andric 41420b57cec5SDimitry Andric ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) { 4143*0fca6ea1SDimitry Andric ScheduleDAGMI *DAG = 4144*0fca6ea1SDimitry Andric new ScheduleDAGMI(C, std::make_unique<PostGenericScheduler>(C), 41450b57cec5SDimitry Andric /*RemoveKillFlags=*/true); 4146*0fca6ea1SDimitry Andric const TargetSubtargetInfo &STI = C->MF->getSubtarget(); 4147*0fca6ea1SDimitry Andric // Add MacroFusion mutation if fusions are not empty. 4148*0fca6ea1SDimitry Andric const auto &MacroFusions = STI.getMacroFusions(); 4149*0fca6ea1SDimitry Andric if (!MacroFusions.empty()) 4150*0fca6ea1SDimitry Andric DAG->addMutation(createMacroFusionDAGMutation(MacroFusions)); 4151*0fca6ea1SDimitry Andric return DAG; 41520b57cec5SDimitry Andric } 41530b57cec5SDimitry Andric 41540b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 41550b57cec5SDimitry Andric // ILP Scheduler. Currently for experimental analysis of heuristics. 41560b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 41570b57cec5SDimitry Andric 41580b57cec5SDimitry Andric namespace { 41590b57cec5SDimitry Andric 41600b57cec5SDimitry Andric /// Order nodes by the ILP metric. 41610b57cec5SDimitry Andric struct ILPOrder { 41620b57cec5SDimitry Andric const SchedDFSResult *DFSResult = nullptr; 41630b57cec5SDimitry Andric const BitVector *ScheduledTrees = nullptr; 41640b57cec5SDimitry Andric bool MaximizeILP; 41650b57cec5SDimitry Andric 41660b57cec5SDimitry Andric ILPOrder(bool MaxILP) : MaximizeILP(MaxILP) {} 41670b57cec5SDimitry Andric 41680b57cec5SDimitry Andric /// Apply a less-than relation on node priority. 41690b57cec5SDimitry Andric /// 41700b57cec5SDimitry Andric /// (Return true if A comes after B in the Q.) 41710b57cec5SDimitry Andric bool operator()(const SUnit *A, const SUnit *B) const { 41720b57cec5SDimitry Andric unsigned SchedTreeA = DFSResult->getSubtreeID(A); 41730b57cec5SDimitry Andric unsigned SchedTreeB = DFSResult->getSubtreeID(B); 41740b57cec5SDimitry Andric if (SchedTreeA != SchedTreeB) { 41750b57cec5SDimitry Andric // Unscheduled trees have lower priority. 41760b57cec5SDimitry Andric if (ScheduledTrees->test(SchedTreeA) != ScheduledTrees->test(SchedTreeB)) 41770b57cec5SDimitry Andric return ScheduledTrees->test(SchedTreeB); 41780b57cec5SDimitry Andric 41795f757f3fSDimitry Andric // Trees with shallower connections have lower priority. 41800b57cec5SDimitry Andric if (DFSResult->getSubtreeLevel(SchedTreeA) 41810b57cec5SDimitry Andric != DFSResult->getSubtreeLevel(SchedTreeB)) { 41820b57cec5SDimitry Andric return DFSResult->getSubtreeLevel(SchedTreeA) 41830b57cec5SDimitry Andric < DFSResult->getSubtreeLevel(SchedTreeB); 41840b57cec5SDimitry Andric } 41850b57cec5SDimitry Andric } 41860b57cec5SDimitry Andric if (MaximizeILP) 41870b57cec5SDimitry Andric return DFSResult->getILP(A) < DFSResult->getILP(B); 41880b57cec5SDimitry Andric else 41890b57cec5SDimitry Andric return DFSResult->getILP(A) > DFSResult->getILP(B); 41900b57cec5SDimitry Andric } 41910b57cec5SDimitry Andric }; 41920b57cec5SDimitry Andric 41930b57cec5SDimitry Andric /// Schedule based on the ILP metric. 41940b57cec5SDimitry Andric class ILPScheduler : public MachineSchedStrategy { 41950b57cec5SDimitry Andric ScheduleDAGMILive *DAG = nullptr; 41960b57cec5SDimitry Andric ILPOrder Cmp; 41970b57cec5SDimitry Andric 41980b57cec5SDimitry Andric std::vector<SUnit*> ReadyQ; 41990b57cec5SDimitry Andric 42000b57cec5SDimitry Andric public: 42010b57cec5SDimitry Andric ILPScheduler(bool MaximizeILP) : Cmp(MaximizeILP) {} 42020b57cec5SDimitry Andric 42030b57cec5SDimitry Andric void initialize(ScheduleDAGMI *dag) override { 42040b57cec5SDimitry Andric assert(dag->hasVRegLiveness() && "ILPScheduler needs vreg liveness"); 42050b57cec5SDimitry Andric DAG = static_cast<ScheduleDAGMILive*>(dag); 42060b57cec5SDimitry Andric DAG->computeDFSResult(); 42070b57cec5SDimitry Andric Cmp.DFSResult = DAG->getDFSResult(); 42080b57cec5SDimitry Andric Cmp.ScheduledTrees = &DAG->getScheduledTrees(); 42090b57cec5SDimitry Andric ReadyQ.clear(); 42100b57cec5SDimitry Andric } 42110b57cec5SDimitry Andric 42120b57cec5SDimitry Andric void registerRoots() override { 42130b57cec5SDimitry Andric // Restore the heap in ReadyQ with the updated DFS results. 42140b57cec5SDimitry Andric std::make_heap(ReadyQ.begin(), ReadyQ.end(), Cmp); 42150b57cec5SDimitry Andric } 42160b57cec5SDimitry Andric 42170b57cec5SDimitry Andric /// Implement MachineSchedStrategy interface. 42180b57cec5SDimitry Andric /// ----------------------------------------- 42190b57cec5SDimitry Andric 42200b57cec5SDimitry Andric /// Callback to select the highest priority node from the ready Q. 42210b57cec5SDimitry Andric SUnit *pickNode(bool &IsTopNode) override { 42220b57cec5SDimitry Andric if (ReadyQ.empty()) return nullptr; 42230b57cec5SDimitry Andric std::pop_heap(ReadyQ.begin(), ReadyQ.end(), Cmp); 42240b57cec5SDimitry Andric SUnit *SU = ReadyQ.back(); 42250b57cec5SDimitry Andric ReadyQ.pop_back(); 42260b57cec5SDimitry Andric IsTopNode = false; 42270b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Pick node " 42280b57cec5SDimitry Andric << "SU(" << SU->NodeNum << ") " 42290b57cec5SDimitry Andric << " ILP: " << DAG->getDFSResult()->getILP(SU) 42300b57cec5SDimitry Andric << " Tree: " << DAG->getDFSResult()->getSubtreeID(SU) 42310b57cec5SDimitry Andric << " @" 42320b57cec5SDimitry Andric << DAG->getDFSResult()->getSubtreeLevel( 42330b57cec5SDimitry Andric DAG->getDFSResult()->getSubtreeID(SU)) 42340b57cec5SDimitry Andric << '\n' 42350b57cec5SDimitry Andric << "Scheduling " << *SU->getInstr()); 42360b57cec5SDimitry Andric return SU; 42370b57cec5SDimitry Andric } 42380b57cec5SDimitry Andric 42390b57cec5SDimitry Andric /// Scheduler callback to notify that a new subtree is scheduled. 42400b57cec5SDimitry Andric void scheduleTree(unsigned SubtreeID) override { 42410b57cec5SDimitry Andric std::make_heap(ReadyQ.begin(), ReadyQ.end(), Cmp); 42420b57cec5SDimitry Andric } 42430b57cec5SDimitry Andric 42440b57cec5SDimitry Andric /// Callback after a node is scheduled. Mark a newly scheduled tree, notify 42450b57cec5SDimitry Andric /// DFSResults, and resort the priority Q. 42460b57cec5SDimitry Andric void schedNode(SUnit *SU, bool IsTopNode) override { 42470b57cec5SDimitry Andric assert(!IsTopNode && "SchedDFSResult needs bottom-up"); 42480b57cec5SDimitry Andric } 42490b57cec5SDimitry Andric 42500b57cec5SDimitry Andric void releaseTopNode(SUnit *) override { /*only called for top roots*/ } 42510b57cec5SDimitry Andric 42520b57cec5SDimitry Andric void releaseBottomNode(SUnit *SU) override { 42530b57cec5SDimitry Andric ReadyQ.push_back(SU); 42540b57cec5SDimitry Andric std::push_heap(ReadyQ.begin(), ReadyQ.end(), Cmp); 42550b57cec5SDimitry Andric } 42560b57cec5SDimitry Andric }; 42570b57cec5SDimitry Andric 42580b57cec5SDimitry Andric } // end anonymous namespace 42590b57cec5SDimitry Andric 42600b57cec5SDimitry Andric static ScheduleDAGInstrs *createILPMaxScheduler(MachineSchedContext *C) { 42618bcb0991SDimitry Andric return new ScheduleDAGMILive(C, std::make_unique<ILPScheduler>(true)); 42620b57cec5SDimitry Andric } 42630b57cec5SDimitry Andric static ScheduleDAGInstrs *createILPMinScheduler(MachineSchedContext *C) { 42648bcb0991SDimitry Andric return new ScheduleDAGMILive(C, std::make_unique<ILPScheduler>(false)); 42650b57cec5SDimitry Andric } 42660b57cec5SDimitry Andric 42670b57cec5SDimitry Andric static MachineSchedRegistry ILPMaxRegistry( 42680b57cec5SDimitry Andric "ilpmax", "Schedule bottom-up for max ILP", createILPMaxScheduler); 42690b57cec5SDimitry Andric static MachineSchedRegistry ILPMinRegistry( 42700b57cec5SDimitry Andric "ilpmin", "Schedule bottom-up for min ILP", createILPMinScheduler); 42710b57cec5SDimitry Andric 42720b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 42730b57cec5SDimitry Andric // Machine Instruction Shuffler for Correctness Testing 42740b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 42750b57cec5SDimitry Andric 42760b57cec5SDimitry Andric #ifndef NDEBUG 42770b57cec5SDimitry Andric namespace { 42780b57cec5SDimitry Andric 42790b57cec5SDimitry Andric /// Apply a less-than relation on the node order, which corresponds to the 42800b57cec5SDimitry Andric /// instruction order prior to scheduling. IsReverse implements greater-than. 42810b57cec5SDimitry Andric template<bool IsReverse> 42820b57cec5SDimitry Andric struct SUnitOrder { 42830b57cec5SDimitry Andric bool operator()(SUnit *A, SUnit *B) const { 42840b57cec5SDimitry Andric if (IsReverse) 42850b57cec5SDimitry Andric return A->NodeNum > B->NodeNum; 42860b57cec5SDimitry Andric else 42870b57cec5SDimitry Andric return A->NodeNum < B->NodeNum; 42880b57cec5SDimitry Andric } 42890b57cec5SDimitry Andric }; 42900b57cec5SDimitry Andric 42910b57cec5SDimitry Andric /// Reorder instructions as much as possible. 42920b57cec5SDimitry Andric class InstructionShuffler : public MachineSchedStrategy { 42930b57cec5SDimitry Andric bool IsAlternating; 42940b57cec5SDimitry Andric bool IsTopDown; 42950b57cec5SDimitry Andric 42960b57cec5SDimitry Andric // Using a less-than relation (SUnitOrder<false>) for the TopQ priority 42970b57cec5SDimitry Andric // gives nodes with a higher number higher priority causing the latest 42980b57cec5SDimitry Andric // instructions to be scheduled first. 42990b57cec5SDimitry Andric PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<false>> 43000b57cec5SDimitry Andric TopQ; 43010b57cec5SDimitry Andric 43020b57cec5SDimitry Andric // When scheduling bottom-up, use greater-than as the queue priority. 43030b57cec5SDimitry Andric PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<true>> 43040b57cec5SDimitry Andric BottomQ; 43050b57cec5SDimitry Andric 43060b57cec5SDimitry Andric public: 43070b57cec5SDimitry Andric InstructionShuffler(bool alternate, bool topdown) 43080b57cec5SDimitry Andric : IsAlternating(alternate), IsTopDown(topdown) {} 43090b57cec5SDimitry Andric 43100b57cec5SDimitry Andric void initialize(ScheduleDAGMI*) override { 43110b57cec5SDimitry Andric TopQ.clear(); 43120b57cec5SDimitry Andric BottomQ.clear(); 43130b57cec5SDimitry Andric } 43140b57cec5SDimitry Andric 43150b57cec5SDimitry Andric /// Implement MachineSchedStrategy interface. 43160b57cec5SDimitry Andric /// ----------------------------------------- 43170b57cec5SDimitry Andric 43180b57cec5SDimitry Andric SUnit *pickNode(bool &IsTopNode) override { 43190b57cec5SDimitry Andric SUnit *SU; 43200b57cec5SDimitry Andric if (IsTopDown) { 43210b57cec5SDimitry Andric do { 43220b57cec5SDimitry Andric if (TopQ.empty()) return nullptr; 43230b57cec5SDimitry Andric SU = TopQ.top(); 43240b57cec5SDimitry Andric TopQ.pop(); 43250b57cec5SDimitry Andric } while (SU->isScheduled); 43260b57cec5SDimitry Andric IsTopNode = true; 43270b57cec5SDimitry Andric } else { 43280b57cec5SDimitry Andric do { 43290b57cec5SDimitry Andric if (BottomQ.empty()) return nullptr; 43300b57cec5SDimitry Andric SU = BottomQ.top(); 43310b57cec5SDimitry Andric BottomQ.pop(); 43320b57cec5SDimitry Andric } while (SU->isScheduled); 43330b57cec5SDimitry Andric IsTopNode = false; 43340b57cec5SDimitry Andric } 43350b57cec5SDimitry Andric if (IsAlternating) 43360b57cec5SDimitry Andric IsTopDown = !IsTopDown; 43370b57cec5SDimitry Andric return SU; 43380b57cec5SDimitry Andric } 43390b57cec5SDimitry Andric 43400b57cec5SDimitry Andric void schedNode(SUnit *SU, bool IsTopNode) override {} 43410b57cec5SDimitry Andric 43420b57cec5SDimitry Andric void releaseTopNode(SUnit *SU) override { 43430b57cec5SDimitry Andric TopQ.push(SU); 43440b57cec5SDimitry Andric } 43450b57cec5SDimitry Andric void releaseBottomNode(SUnit *SU) override { 43460b57cec5SDimitry Andric BottomQ.push(SU); 43470b57cec5SDimitry Andric } 43480b57cec5SDimitry Andric }; 43490b57cec5SDimitry Andric 43500b57cec5SDimitry Andric } // end anonymous namespace 43510b57cec5SDimitry Andric 43520b57cec5SDimitry Andric static ScheduleDAGInstrs *createInstructionShuffler(MachineSchedContext *C) { 43530b57cec5SDimitry Andric bool Alternate = !ForceTopDown && !ForceBottomUp; 43540b57cec5SDimitry Andric bool TopDown = !ForceBottomUp; 43550b57cec5SDimitry Andric assert((TopDown || !ForceTopDown) && 43560b57cec5SDimitry Andric "-misched-topdown incompatible with -misched-bottomup"); 43570b57cec5SDimitry Andric return new ScheduleDAGMILive( 43588bcb0991SDimitry Andric C, std::make_unique<InstructionShuffler>(Alternate, TopDown)); 43590b57cec5SDimitry Andric } 43600b57cec5SDimitry Andric 43610b57cec5SDimitry Andric static MachineSchedRegistry ShufflerRegistry( 43620b57cec5SDimitry Andric "shuffle", "Shuffle machine instructions alternating directions", 43630b57cec5SDimitry Andric createInstructionShuffler); 43640b57cec5SDimitry Andric #endif // !NDEBUG 43650b57cec5SDimitry Andric 43660b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 43670b57cec5SDimitry Andric // GraphWriter support for ScheduleDAGMILive. 43680b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 43690b57cec5SDimitry Andric 43700b57cec5SDimitry Andric #ifndef NDEBUG 43710b57cec5SDimitry Andric namespace llvm { 43720b57cec5SDimitry Andric 43730b57cec5SDimitry Andric template<> struct GraphTraits< 43740b57cec5SDimitry Andric ScheduleDAGMI*> : public GraphTraits<ScheduleDAG*> {}; 43750b57cec5SDimitry Andric 43760b57cec5SDimitry Andric template<> 43770b57cec5SDimitry Andric struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits { 43780b57cec5SDimitry Andric DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} 43790b57cec5SDimitry Andric 43800b57cec5SDimitry Andric static std::string getGraphName(const ScheduleDAG *G) { 43815ffd83dbSDimitry Andric return std::string(G->MF.getName()); 43820b57cec5SDimitry Andric } 43830b57cec5SDimitry Andric 43840b57cec5SDimitry Andric static bool renderGraphFromBottomUp() { 43850b57cec5SDimitry Andric return true; 43860b57cec5SDimitry Andric } 43870b57cec5SDimitry Andric 4388e8d8bef9SDimitry Andric static bool isNodeHidden(const SUnit *Node, const ScheduleDAG *G) { 43890b57cec5SDimitry Andric if (ViewMISchedCutoff == 0) 43900b57cec5SDimitry Andric return false; 43910b57cec5SDimitry Andric return (Node->Preds.size() > ViewMISchedCutoff 43920b57cec5SDimitry Andric || Node->Succs.size() > ViewMISchedCutoff); 43930b57cec5SDimitry Andric } 43940b57cec5SDimitry Andric 43950b57cec5SDimitry Andric /// If you want to override the dot attributes printed for a particular 43960b57cec5SDimitry Andric /// edge, override this method. 43970b57cec5SDimitry Andric static std::string getEdgeAttributes(const SUnit *Node, 43980b57cec5SDimitry Andric SUnitIterator EI, 43990b57cec5SDimitry Andric const ScheduleDAG *Graph) { 44000b57cec5SDimitry Andric if (EI.isArtificialDep()) 44010b57cec5SDimitry Andric return "color=cyan,style=dashed"; 44020b57cec5SDimitry Andric if (EI.isCtrlDep()) 44030b57cec5SDimitry Andric return "color=blue,style=dashed"; 44040b57cec5SDimitry Andric return ""; 44050b57cec5SDimitry Andric } 44060b57cec5SDimitry Andric 44070b57cec5SDimitry Andric static std::string getNodeLabel(const SUnit *SU, const ScheduleDAG *G) { 44080b57cec5SDimitry Andric std::string Str; 44090b57cec5SDimitry Andric raw_string_ostream SS(Str); 44100b57cec5SDimitry Andric const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G); 44110b57cec5SDimitry Andric const SchedDFSResult *DFS = DAG->hasVRegLiveness() ? 44120b57cec5SDimitry Andric static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr; 44130b57cec5SDimitry Andric SS << "SU:" << SU->NodeNum; 44140b57cec5SDimitry Andric if (DFS) 44150b57cec5SDimitry Andric SS << " I:" << DFS->getNumInstrs(SU); 4416*0fca6ea1SDimitry Andric return Str; 44170b57cec5SDimitry Andric } 44180b57cec5SDimitry Andric 44190b57cec5SDimitry Andric static std::string getNodeDescription(const SUnit *SU, const ScheduleDAG *G) { 44200b57cec5SDimitry Andric return G->getGraphNodeLabel(SU); 44210b57cec5SDimitry Andric } 44220b57cec5SDimitry Andric 44230b57cec5SDimitry Andric static std::string getNodeAttributes(const SUnit *N, const ScheduleDAG *G) { 44240b57cec5SDimitry Andric std::string Str("shape=Mrecord"); 44250b57cec5SDimitry Andric const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G); 44260b57cec5SDimitry Andric const SchedDFSResult *DFS = DAG->hasVRegLiveness() ? 44270b57cec5SDimitry Andric static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr; 44280b57cec5SDimitry Andric if (DFS) { 44290b57cec5SDimitry Andric Str += ",style=filled,fillcolor=\"#"; 44300b57cec5SDimitry Andric Str += DOT::getColorString(DFS->getSubtreeID(N)); 44310b57cec5SDimitry Andric Str += '"'; 44320b57cec5SDimitry Andric } 44330b57cec5SDimitry Andric return Str; 44340b57cec5SDimitry Andric } 44350b57cec5SDimitry Andric }; 44360b57cec5SDimitry Andric 44370b57cec5SDimitry Andric } // end namespace llvm 44380b57cec5SDimitry Andric #endif // NDEBUG 44390b57cec5SDimitry Andric 44400b57cec5SDimitry Andric /// viewGraph - Pop up a ghostview window with the reachable parts of the DAG 44410b57cec5SDimitry Andric /// rendered using 'dot'. 44420b57cec5SDimitry Andric void ScheduleDAGMI::viewGraph(const Twine &Name, const Twine &Title) { 44430b57cec5SDimitry Andric #ifndef NDEBUG 44440b57cec5SDimitry Andric ViewGraph(this, Name, false, Title); 44450b57cec5SDimitry Andric #else 44460b57cec5SDimitry Andric errs() << "ScheduleDAGMI::viewGraph is only available in debug builds on " 44470b57cec5SDimitry Andric << "systems with Graphviz or gv!\n"; 44480b57cec5SDimitry Andric #endif // NDEBUG 44490b57cec5SDimitry Andric } 44500b57cec5SDimitry Andric 44510b57cec5SDimitry Andric /// Out-of-line implementation with no arguments is handy for gdb. 44520b57cec5SDimitry Andric void ScheduleDAGMI::viewGraph() { 44530b57cec5SDimitry Andric viewGraph(getDAGName(), "Scheduling-Units Graph for " + getDAGName()); 44540b57cec5SDimitry Andric } 445506c3fb27SDimitry Andric 445606c3fb27SDimitry Andric /// Sort predicate for the intervals stored in an instance of 445706c3fb27SDimitry Andric /// ResourceSegments. Intervals are always disjoint (no intersection 445806c3fb27SDimitry Andric /// for any pairs of intervals), therefore we can sort the totality of 445906c3fb27SDimitry Andric /// the intervals by looking only at the left boundary. 446006c3fb27SDimitry Andric static bool sortIntervals(const ResourceSegments::IntervalTy &A, 446106c3fb27SDimitry Andric const ResourceSegments::IntervalTy &B) { 446206c3fb27SDimitry Andric return A.first < B.first; 446306c3fb27SDimitry Andric } 446406c3fb27SDimitry Andric 446506c3fb27SDimitry Andric unsigned ResourceSegments::getFirstAvailableAt( 44667a6dacacSDimitry Andric unsigned CurrCycle, unsigned AcquireAtCycle, unsigned ReleaseAtCycle, 446706c3fb27SDimitry Andric std::function<ResourceSegments::IntervalTy(unsigned, unsigned, unsigned)> 446806c3fb27SDimitry Andric IntervalBuilder) const { 446906c3fb27SDimitry Andric assert(std::is_sorted(std::begin(_Intervals), std::end(_Intervals), 447006c3fb27SDimitry Andric sortIntervals) && 447106c3fb27SDimitry Andric "Cannot execute on an un-sorted set of intervals."); 4472*0fca6ea1SDimitry Andric 4473*0fca6ea1SDimitry Andric // Zero resource usage is allowed by TargetSchedule.td but we do not construct 4474*0fca6ea1SDimitry Andric // a ResourceSegment interval for that situation. 4475*0fca6ea1SDimitry Andric if (AcquireAtCycle == ReleaseAtCycle) 4476*0fca6ea1SDimitry Andric return CurrCycle; 4477*0fca6ea1SDimitry Andric 447806c3fb27SDimitry Andric unsigned RetCycle = CurrCycle; 447906c3fb27SDimitry Andric ResourceSegments::IntervalTy NewInterval = 44807a6dacacSDimitry Andric IntervalBuilder(RetCycle, AcquireAtCycle, ReleaseAtCycle); 448106c3fb27SDimitry Andric for (auto &Interval : _Intervals) { 448206c3fb27SDimitry Andric if (!intersects(NewInterval, Interval)) 448306c3fb27SDimitry Andric continue; 448406c3fb27SDimitry Andric 448506c3fb27SDimitry Andric // Move the interval right next to the top of the one it 448606c3fb27SDimitry Andric // intersects. 448706c3fb27SDimitry Andric assert(Interval.second > NewInterval.first && 448806c3fb27SDimitry Andric "Invalid intervals configuration."); 448906c3fb27SDimitry Andric RetCycle += (unsigned)Interval.second - (unsigned)NewInterval.first; 44907a6dacacSDimitry Andric NewInterval = IntervalBuilder(RetCycle, AcquireAtCycle, ReleaseAtCycle); 449106c3fb27SDimitry Andric } 449206c3fb27SDimitry Andric return RetCycle; 449306c3fb27SDimitry Andric } 449406c3fb27SDimitry Andric 449506c3fb27SDimitry Andric void ResourceSegments::add(ResourceSegments::IntervalTy A, 449606c3fb27SDimitry Andric const unsigned CutOff) { 4497*0fca6ea1SDimitry Andric assert(A.first <= A.second && "Cannot add negative resource usage"); 449806c3fb27SDimitry Andric assert(CutOff > 0 && "0-size interval history has no use."); 4499*0fca6ea1SDimitry Andric // Zero resource usage is allowed by TargetSchedule.td, in the case that the 4500*0fca6ea1SDimitry Andric // instruction needed the resource to be available but does not use it. 4501*0fca6ea1SDimitry Andric // However, ResourceSegment represents an interval that is closed on the left 4502*0fca6ea1SDimitry Andric // and open on the right. It is impossible to represent an empty interval when 4503*0fca6ea1SDimitry Andric // the left is closed. Do not add it to Intervals. 4504*0fca6ea1SDimitry Andric if (A.first == A.second) 4505*0fca6ea1SDimitry Andric return; 4506*0fca6ea1SDimitry Andric 450706c3fb27SDimitry Andric assert(all_of(_Intervals, 450806c3fb27SDimitry Andric [&A](const ResourceSegments::IntervalTy &Interval) -> bool { 450906c3fb27SDimitry Andric return !intersects(A, Interval); 451006c3fb27SDimitry Andric }) && 451106c3fb27SDimitry Andric "A resource is being overwritten"); 451206c3fb27SDimitry Andric _Intervals.push_back(A); 451306c3fb27SDimitry Andric 451406c3fb27SDimitry Andric sortAndMerge(); 451506c3fb27SDimitry Andric 451606c3fb27SDimitry Andric // Do not keep the full history of the intervals, just the 451706c3fb27SDimitry Andric // latest #CutOff. 451806c3fb27SDimitry Andric while (_Intervals.size() > CutOff) 451906c3fb27SDimitry Andric _Intervals.pop_front(); 452006c3fb27SDimitry Andric } 452106c3fb27SDimitry Andric 452206c3fb27SDimitry Andric bool ResourceSegments::intersects(ResourceSegments::IntervalTy A, 452306c3fb27SDimitry Andric ResourceSegments::IntervalTy B) { 452406c3fb27SDimitry Andric assert(A.first <= A.second && "Invalid interval"); 452506c3fb27SDimitry Andric assert(B.first <= B.second && "Invalid interval"); 452606c3fb27SDimitry Andric 452706c3fb27SDimitry Andric // Share one boundary. 452806c3fb27SDimitry Andric if ((A.first == B.first) || (A.second == B.second)) 452906c3fb27SDimitry Andric return true; 453006c3fb27SDimitry Andric 453106c3fb27SDimitry Andric // full intersersect: [ *** ) B 453206c3fb27SDimitry Andric // [***) A 453306c3fb27SDimitry Andric if ((A.first > B.first) && (A.second < B.second)) 453406c3fb27SDimitry Andric return true; 453506c3fb27SDimitry Andric 453606c3fb27SDimitry Andric // right intersect: [ ***) B 453706c3fb27SDimitry Andric // [*** ) A 453806c3fb27SDimitry Andric if ((A.first > B.first) && (A.first < B.second) && (A.second > B.second)) 453906c3fb27SDimitry Andric return true; 454006c3fb27SDimitry Andric 454106c3fb27SDimitry Andric // left intersect: [*** ) B 454206c3fb27SDimitry Andric // [ ***) A 454306c3fb27SDimitry Andric if ((A.first < B.first) && (B.first < A.second) && (B.second > B.first)) 454406c3fb27SDimitry Andric return true; 454506c3fb27SDimitry Andric 454606c3fb27SDimitry Andric return false; 454706c3fb27SDimitry Andric } 454806c3fb27SDimitry Andric 454906c3fb27SDimitry Andric void ResourceSegments::sortAndMerge() { 455006c3fb27SDimitry Andric if (_Intervals.size() <= 1) 455106c3fb27SDimitry Andric return; 455206c3fb27SDimitry Andric 455306c3fb27SDimitry Andric // First sort the collection. 455406c3fb27SDimitry Andric _Intervals.sort(sortIntervals); 455506c3fb27SDimitry Andric 455606c3fb27SDimitry Andric // can use next because I have at least 2 elements in the list 455706c3fb27SDimitry Andric auto next = std::next(std::begin(_Intervals)); 455806c3fb27SDimitry Andric auto E = std::end(_Intervals); 455906c3fb27SDimitry Andric for (; next != E; ++next) { 456006c3fb27SDimitry Andric if (std::prev(next)->second >= next->first) { 456106c3fb27SDimitry Andric next->first = std::prev(next)->first; 456206c3fb27SDimitry Andric _Intervals.erase(std::prev(next)); 456306c3fb27SDimitry Andric continue; 456406c3fb27SDimitry Andric } 456506c3fb27SDimitry Andric } 456606c3fb27SDimitry Andric } 4567