10b57cec5SDimitry Andric //===-- SIMachineScheduler.h - SI Scheduler Interface -----------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// SI Machine Scheduler interface 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_AMDGPU_SIMACHINESCHEDULER_H 150b57cec5SDimitry Andric #define LLVM_LIB_TARGET_AMDGPU_SIMACHINESCHEDULER_H 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h" 200b57cec5SDimitry Andric #include <cstdint> 210b57cec5SDimitry Andric #include <set> 220b57cec5SDimitry Andric #include <vector> 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace llvm { 250b57cec5SDimitry Andric 26e8d8bef9SDimitry Andric class SIInstrInfo; 27e8d8bef9SDimitry Andric class SIRegisterInfo; 28*349cc55cSDimitry Andric class SIScheduleDAGMI; 29*349cc55cSDimitry Andric class SIScheduleBlockCreator; 30e8d8bef9SDimitry Andric 310b57cec5SDimitry Andric enum SIScheduleCandReason { 320b57cec5SDimitry Andric NoCand, 330b57cec5SDimitry Andric RegUsage, 340b57cec5SDimitry Andric Latency, 350b57cec5SDimitry Andric Successor, 360b57cec5SDimitry Andric Depth, 370b57cec5SDimitry Andric NodeOrder 380b57cec5SDimitry Andric }; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric struct SISchedulerCandidate { 410b57cec5SDimitry Andric // The reason for this candidate. 420b57cec5SDimitry Andric SIScheduleCandReason Reason = NoCand; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric // Set of reasons that apply to multiple candidates. 450b57cec5SDimitry Andric uint32_t RepeatReasonSet = 0; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric SISchedulerCandidate() = default; 480b57cec5SDimitry Andric isRepeatSISchedulerCandidate490b57cec5SDimitry Andric bool isRepeat(SIScheduleCandReason R) { return RepeatReasonSet & (1 << R); } setRepeatSISchedulerCandidate500b57cec5SDimitry Andric void setRepeat(SIScheduleCandReason R) { RepeatReasonSet |= (1 << R); } 510b57cec5SDimitry Andric }; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric enum SIScheduleBlockLinkKind { 540b57cec5SDimitry Andric NoData, 550b57cec5SDimitry Andric Data 560b57cec5SDimitry Andric }; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric class SIScheduleBlock { 590b57cec5SDimitry Andric SIScheduleDAGMI *DAG; 600b57cec5SDimitry Andric SIScheduleBlockCreator *BC; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric std::vector<SUnit*> SUnits; 630b57cec5SDimitry Andric std::map<unsigned, unsigned> NodeNum2Index; 640b57cec5SDimitry Andric std::vector<SUnit*> TopReadySUs; 650b57cec5SDimitry Andric std::vector<SUnit*> ScheduledSUnits; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric /// The top of the unscheduled zone. 680b57cec5SDimitry Andric IntervalPressure TopPressure; 690b57cec5SDimitry Andric RegPressureTracker TopRPTracker; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // Pressure: number of said class of registers needed to 720b57cec5SDimitry Andric // store the live virtual and real registers. 730b57cec5SDimitry Andric // We do care only of SGPR32 and VGPR32 and do track only virtual registers. 740b57cec5SDimitry Andric // Pressure of additional registers required inside the block. 75*349cc55cSDimitry Andric std::vector<unsigned> InternalAdditionalPressure; 760b57cec5SDimitry Andric // Pressure of input and output registers 770b57cec5SDimitry Andric std::vector<unsigned> LiveInPressure; 780b57cec5SDimitry Andric std::vector<unsigned> LiveOutPressure; 790b57cec5SDimitry Andric // Registers required by the block, and outputs. 800b57cec5SDimitry Andric // We do track only virtual registers. 810b57cec5SDimitry Andric // Note that some registers are not 32 bits, 820b57cec5SDimitry Andric // and thus the pressure is not equal 830b57cec5SDimitry Andric // to the number of live registers. 840b57cec5SDimitry Andric std::set<unsigned> LiveInRegs; 850b57cec5SDimitry Andric std::set<unsigned> LiveOutRegs; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric bool Scheduled = false; 880b57cec5SDimitry Andric bool HighLatencyBlock = false; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric std::vector<unsigned> HasLowLatencyNonWaitedParent; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric // Unique ID, the index of the Block in the SIScheduleDAGMI Blocks table. 930b57cec5SDimitry Andric unsigned ID; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric std::vector<SIScheduleBlock*> Preds; // All blocks predecessors. 960b57cec5SDimitry Andric // All blocks successors, and the kind of link 970b57cec5SDimitry Andric std::vector<std::pair<SIScheduleBlock*, SIScheduleBlockLinkKind>> Succs; 980b57cec5SDimitry Andric unsigned NumHighLatencySuccessors = 0; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric public: SIScheduleBlock(SIScheduleDAGMI * DAG,SIScheduleBlockCreator * BC,unsigned ID)1010b57cec5SDimitry Andric SIScheduleBlock(SIScheduleDAGMI *DAG, SIScheduleBlockCreator *BC, 1020b57cec5SDimitry Andric unsigned ID): 1030b57cec5SDimitry Andric DAG(DAG), BC(BC), TopRPTracker(TopPressure), ID(ID) {} 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric ~SIScheduleBlock() = default; 1060b57cec5SDimitry Andric getID()1070b57cec5SDimitry Andric unsigned getID() const { return ID; } 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric /// Functions for Block construction. 1100b57cec5SDimitry Andric void addUnit(SUnit *SU); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric // When all SUs have been added. 1130b57cec5SDimitry Andric void finalizeUnits(); 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric // Add block pred, which has instruction predecessor of SU. 1160b57cec5SDimitry Andric void addPred(SIScheduleBlock *Pred); 1170b57cec5SDimitry Andric void addSucc(SIScheduleBlock *Succ, SIScheduleBlockLinkKind Kind); 1180b57cec5SDimitry Andric getPreds()1190b57cec5SDimitry Andric const std::vector<SIScheduleBlock*>& getPreds() const { return Preds; } 1200b57cec5SDimitry Andric ArrayRef<std::pair<SIScheduleBlock*, SIScheduleBlockLinkKind>> getSuccs()1210b57cec5SDimitry Andric getSuccs() const { return Succs; } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric unsigned Height; // Maximum topdown path length to block without outputs 1240b57cec5SDimitry Andric unsigned Depth; // Maximum bottomup path length to block without inputs 1250b57cec5SDimitry Andric getNumHighLatencySuccessors()1260b57cec5SDimitry Andric unsigned getNumHighLatencySuccessors() const { 1270b57cec5SDimitry Andric return NumHighLatencySuccessors; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric isHighLatencyBlock()1300b57cec5SDimitry Andric bool isHighLatencyBlock() { return HighLatencyBlock; } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric // This is approximative. 1330b57cec5SDimitry Andric // Ideally should take into accounts some instructions (rcp, etc) 1340b57cec5SDimitry Andric // are 4 times slower. getCost()1350b57cec5SDimitry Andric int getCost() { return SUnits.size(); } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric // The block Predecessors and Successors must be all registered 1380b57cec5SDimitry Andric // before fastSchedule(). 1390b57cec5SDimitry Andric // Fast schedule with no particular requirement. 1400b57cec5SDimitry Andric void fastSchedule(); 1410b57cec5SDimitry Andric getScheduledUnits()1420b57cec5SDimitry Andric std::vector<SUnit*> getScheduledUnits() { return ScheduledSUnits; } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric // Complete schedule that will try to minimize reg pressure and 1450b57cec5SDimitry Andric // low latencies, and will fill liveins and liveouts. 1460b57cec5SDimitry Andric // Needs all MIs to be grouped between BeginBlock and EndBlock. 1470b57cec5SDimitry Andric // The MIs can be moved after the scheduling, 1480b57cec5SDimitry Andric // it is just used to allow correct track of live registers. 1490b57cec5SDimitry Andric void schedule(MachineBasicBlock::iterator BeginBlock, 1500b57cec5SDimitry Andric MachineBasicBlock::iterator EndBlock); 1510b57cec5SDimitry Andric isScheduled()1520b57cec5SDimitry Andric bool isScheduled() { return Scheduled; } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric // Needs the block to be scheduled inside 1550b57cec5SDimitry Andric // TODO: find a way to compute it. getInternalAdditionalRegUsage()156*349cc55cSDimitry Andric std::vector<unsigned> &getInternalAdditionalRegUsage() { 157*349cc55cSDimitry Andric return InternalAdditionalPressure; 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric getInRegs()1600b57cec5SDimitry Andric std::set<unsigned> &getInRegs() { return LiveInRegs; } getOutRegs()1610b57cec5SDimitry Andric std::set<unsigned> &getOutRegs() { return LiveOutRegs; } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric void printDebug(bool Full); 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric private: 1660b57cec5SDimitry Andric struct SISchedCandidate : SISchedulerCandidate { 1670b57cec5SDimitry Andric // The best SUnit candidate. 1680b57cec5SDimitry Andric SUnit *SU = nullptr; 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric unsigned SGPRUsage; 1710b57cec5SDimitry Andric unsigned VGPRUsage; 1720b57cec5SDimitry Andric bool IsLowLatency; 1730b57cec5SDimitry Andric unsigned LowLatencyOffset; 1740b57cec5SDimitry Andric bool HasLowLatencyNonWaitedParent; 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric SISchedCandidate() = default; 1770b57cec5SDimitry Andric isValidSISchedCandidate1780b57cec5SDimitry Andric bool isValid() const { return SU; } 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric // Copy the status of another candidate without changing policy. setBestSISchedCandidate1810b57cec5SDimitry Andric void setBest(SISchedCandidate &Best) { 1820b57cec5SDimitry Andric assert(Best.Reason != NoCand && "uninitialized Sched candidate"); 1830b57cec5SDimitry Andric SU = Best.SU; 1840b57cec5SDimitry Andric Reason = Best.Reason; 1850b57cec5SDimitry Andric SGPRUsage = Best.SGPRUsage; 1860b57cec5SDimitry Andric VGPRUsage = Best.VGPRUsage; 1870b57cec5SDimitry Andric IsLowLatency = Best.IsLowLatency; 1880b57cec5SDimitry Andric LowLatencyOffset = Best.LowLatencyOffset; 1890b57cec5SDimitry Andric HasLowLatencyNonWaitedParent = Best.HasLowLatencyNonWaitedParent; 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric }; 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric void undoSchedule(); 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric void undoReleaseSucc(SUnit *SU, SDep *SuccEdge); 1960b57cec5SDimitry Andric void releaseSucc(SUnit *SU, SDep *SuccEdge); 1970b57cec5SDimitry Andric // InOrOutBlock: restrict to links pointing inside the block (true), 1980b57cec5SDimitry Andric // or restrict to links pointing outside the block (false). 1990b57cec5SDimitry Andric void releaseSuccessors(SUnit *SU, bool InOrOutBlock); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric void nodeScheduled(SUnit *SU); 2020b57cec5SDimitry Andric void tryCandidateTopDown(SISchedCandidate &Cand, SISchedCandidate &TryCand); 2030b57cec5SDimitry Andric void tryCandidateBottomUp(SISchedCandidate &Cand, SISchedCandidate &TryCand); 2040b57cec5SDimitry Andric SUnit* pickNode(); 2050b57cec5SDimitry Andric void traceCandidate(const SISchedCandidate &Cand); 2060b57cec5SDimitry Andric void initRegPressure(MachineBasicBlock::iterator BeginBlock, 2070b57cec5SDimitry Andric MachineBasicBlock::iterator EndBlock); 2080b57cec5SDimitry Andric }; 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric struct SIScheduleBlocks { 2110b57cec5SDimitry Andric std::vector<SIScheduleBlock*> Blocks; 2120b57cec5SDimitry Andric std::vector<int> TopDownIndex2Block; 2130b57cec5SDimitry Andric std::vector<int> TopDownBlock2Index; 2140b57cec5SDimitry Andric }; 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric enum SISchedulerBlockCreatorVariant { 2170b57cec5SDimitry Andric LatenciesAlone, 2180b57cec5SDimitry Andric LatenciesGrouped, 2190b57cec5SDimitry Andric LatenciesAlonePlusConsecutive 2200b57cec5SDimitry Andric }; 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric class SIScheduleBlockCreator { 2230b57cec5SDimitry Andric SIScheduleDAGMI *DAG; 2240b57cec5SDimitry Andric // unique_ptr handles freeing memory for us. 2250b57cec5SDimitry Andric std::vector<std::unique_ptr<SIScheduleBlock>> BlockPtrs; 2260b57cec5SDimitry Andric std::map<SISchedulerBlockCreatorVariant, 2270b57cec5SDimitry Andric SIScheduleBlocks> Blocks; 2280b57cec5SDimitry Andric std::vector<SIScheduleBlock*> CurrentBlocks; 2290b57cec5SDimitry Andric std::vector<int> Node2CurrentBlock; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric // Topological sort 2320b57cec5SDimitry Andric // Maps topological index to the node number. 2330b57cec5SDimitry Andric std::vector<int> TopDownIndex2Block; 2340b57cec5SDimitry Andric std::vector<int> TopDownBlock2Index; 2350b57cec5SDimitry Andric std::vector<int> BottomUpIndex2Block; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric // 0 -> Color not given. 2380b57cec5SDimitry Andric // 1 to SUnits.size() -> Reserved group (you should only add elements to them). 2390b57cec5SDimitry Andric // Above -> Other groups. 2400b57cec5SDimitry Andric int NextReservedID; 2410b57cec5SDimitry Andric int NextNonReservedID; 2420b57cec5SDimitry Andric std::vector<int> CurrentColoring; 2430b57cec5SDimitry Andric std::vector<int> CurrentTopDownReservedDependencyColoring; 2440b57cec5SDimitry Andric std::vector<int> CurrentBottomUpReservedDependencyColoring; 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric public: 2470b57cec5SDimitry Andric SIScheduleBlockCreator(SIScheduleDAGMI *DAG); 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric SIScheduleBlocks 2500b57cec5SDimitry Andric getBlocks(SISchedulerBlockCreatorVariant BlockVariant); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric bool isSUInBlock(SUnit *SU, unsigned ID); 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric private: 2550b57cec5SDimitry Andric // Give a Reserved color to every high latency. 2560b57cec5SDimitry Andric void colorHighLatenciesAlone(); 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric // Create groups of high latencies with a Reserved color. 2590b57cec5SDimitry Andric void colorHighLatenciesGroups(); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric // Compute coloring for topdown and bottom traversals with 2620b57cec5SDimitry Andric // different colors depending on dependencies on Reserved colors. 2630b57cec5SDimitry Andric void colorComputeReservedDependencies(); 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric // Give color to all non-colored SUs according to Reserved groups dependencies. 2660b57cec5SDimitry Andric void colorAccordingToReservedDependencies(); 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric // Divides Blocks having no bottom up or top down dependencies on Reserved groups. 2690b57cec5SDimitry Andric // The new colors are computed according to the dependencies on the other blocks 2700b57cec5SDimitry Andric // formed with colorAccordingToReservedDependencies. 2710b57cec5SDimitry Andric void colorEndsAccordingToDependencies(); 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric // Cut groups into groups with SUs in consecutive order (except for Reserved groups). 2740b57cec5SDimitry Andric void colorForceConsecutiveOrderInGroup(); 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric // Merge Constant loads that have all their users into another group to the group. 2770b57cec5SDimitry Andric // (TODO: else if all their users depend on the same group, put them there) 2780b57cec5SDimitry Andric void colorMergeConstantLoadsNextGroup(); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Merge SUs that have all their users into another group to the group 2810b57cec5SDimitry Andric void colorMergeIfPossibleNextGroup(); 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric // Merge SUs that have all their users into another group to the group, 2840b57cec5SDimitry Andric // but only for Reserved groups. 2850b57cec5SDimitry Andric void colorMergeIfPossibleNextGroupOnlyForReserved(); 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric // Merge SUs that have all their users into another group to the group, 2880b57cec5SDimitry Andric // but only if the group is no more than a few SUs. 2890b57cec5SDimitry Andric void colorMergeIfPossibleSmallGroupsToNextGroup(); 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric // Divides Blocks with important size. 2920b57cec5SDimitry Andric // Idea of implementation: attribute new colors depending on topdown and 2930b57cec5SDimitry Andric // bottom up links to other blocks. 2940b57cec5SDimitry Andric void cutHugeBlocks(); 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric // Put in one group all instructions with no users in this scheduling region 2970b57cec5SDimitry Andric // (we'd want these groups be at the end). 2980b57cec5SDimitry Andric void regroupNoUserInstructions(); 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric // Give Reserved color to export instructions 3010b57cec5SDimitry Andric void colorExports(); 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric void createBlocksForVariant(SISchedulerBlockCreatorVariant BlockVariant); 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric void topologicalSort(); 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric void scheduleInsideBlocks(); 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric void fillStats(); 3100b57cec5SDimitry Andric }; 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric enum SISchedulerBlockSchedulerVariant { 3130b57cec5SDimitry Andric BlockLatencyRegUsage, 3140b57cec5SDimitry Andric BlockRegUsageLatency, 3150b57cec5SDimitry Andric BlockRegUsage 3160b57cec5SDimitry Andric }; 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric class SIScheduleBlockScheduler { 3190b57cec5SDimitry Andric SIScheduleDAGMI *DAG; 3200b57cec5SDimitry Andric SISchedulerBlockSchedulerVariant Variant; 3210b57cec5SDimitry Andric std::vector<SIScheduleBlock*> Blocks; 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric std::vector<std::map<unsigned, unsigned>> LiveOutRegsNumUsages; 3240b57cec5SDimitry Andric std::set<unsigned> LiveRegs; 3250b57cec5SDimitry Andric // Num of schedulable unscheduled blocks reading the register. 3260b57cec5SDimitry Andric std::map<unsigned, unsigned> LiveRegsConsumers; 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric std::vector<unsigned> LastPosHighLatencyParentScheduled; 3290b57cec5SDimitry Andric int LastPosWaitedHighLatency; 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric std::vector<SIScheduleBlock*> BlocksScheduled; 3320b57cec5SDimitry Andric unsigned NumBlockScheduled; 3330b57cec5SDimitry Andric std::vector<SIScheduleBlock*> ReadyBlocks; 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric unsigned VregCurrentUsage; 3360b57cec5SDimitry Andric unsigned SregCurrentUsage; 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric // Currently is only approximation. 3390b57cec5SDimitry Andric unsigned maxVregUsage; 3400b57cec5SDimitry Andric unsigned maxSregUsage; 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric std::vector<unsigned> BlockNumPredsLeft; 3430b57cec5SDimitry Andric std::vector<unsigned> BlockNumSuccsLeft; 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric public: 3460b57cec5SDimitry Andric SIScheduleBlockScheduler(SIScheduleDAGMI *DAG, 3470b57cec5SDimitry Andric SISchedulerBlockSchedulerVariant Variant, 3480b57cec5SDimitry Andric SIScheduleBlocks BlocksStruct); 3490b57cec5SDimitry Andric ~SIScheduleBlockScheduler() = default; 3500b57cec5SDimitry Andric getBlocks()3510b57cec5SDimitry Andric std::vector<SIScheduleBlock*> getBlocks() { return BlocksScheduled; } 3520b57cec5SDimitry Andric getVGPRUsage()3530b57cec5SDimitry Andric unsigned getVGPRUsage() { return maxVregUsage; } getSGPRUsage()3540b57cec5SDimitry Andric unsigned getSGPRUsage() { return maxSregUsage; } 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric private: 3570b57cec5SDimitry Andric struct SIBlockSchedCandidate : SISchedulerCandidate { 3580b57cec5SDimitry Andric // The best Block candidate. 3590b57cec5SDimitry Andric SIScheduleBlock *Block = nullptr; 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric bool IsHighLatency; 3620b57cec5SDimitry Andric int VGPRUsageDiff; 3630b57cec5SDimitry Andric unsigned NumSuccessors; 3640b57cec5SDimitry Andric unsigned NumHighLatencySuccessors; 3650b57cec5SDimitry Andric unsigned LastPosHighLatParentScheduled; 3660b57cec5SDimitry Andric unsigned Height; 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric SIBlockSchedCandidate() = default; 3690b57cec5SDimitry Andric isValidSIBlockSchedCandidate3700b57cec5SDimitry Andric bool isValid() const { return Block; } 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric // Copy the status of another candidate without changing policy. setBestSIBlockSchedCandidate3730b57cec5SDimitry Andric void setBest(SIBlockSchedCandidate &Best) { 3740b57cec5SDimitry Andric assert(Best.Reason != NoCand && "uninitialized Sched candidate"); 3750b57cec5SDimitry Andric Block = Best.Block; 3760b57cec5SDimitry Andric Reason = Best.Reason; 3770b57cec5SDimitry Andric IsHighLatency = Best.IsHighLatency; 3780b57cec5SDimitry Andric VGPRUsageDiff = Best.VGPRUsageDiff; 3790b57cec5SDimitry Andric NumSuccessors = Best.NumSuccessors; 3800b57cec5SDimitry Andric NumHighLatencySuccessors = Best.NumHighLatencySuccessors; 3810b57cec5SDimitry Andric LastPosHighLatParentScheduled = Best.LastPosHighLatParentScheduled; 3820b57cec5SDimitry Andric Height = Best.Height; 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric }; 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric bool tryCandidateLatency(SIBlockSchedCandidate &Cand, 3870b57cec5SDimitry Andric SIBlockSchedCandidate &TryCand); 3880b57cec5SDimitry Andric bool tryCandidateRegUsage(SIBlockSchedCandidate &Cand, 3890b57cec5SDimitry Andric SIBlockSchedCandidate &TryCand); 3900b57cec5SDimitry Andric SIScheduleBlock *pickBlock(); 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric void addLiveRegs(std::set<unsigned> &Regs); 3930b57cec5SDimitry Andric void decreaseLiveRegs(SIScheduleBlock *Block, std::set<unsigned> &Regs); 3940b57cec5SDimitry Andric void releaseBlockSuccs(SIScheduleBlock *Parent); 3950b57cec5SDimitry Andric void blockScheduled(SIScheduleBlock *Block); 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric // Check register pressure change 3980b57cec5SDimitry Andric // by scheduling a block with these LiveIn and LiveOut. 3990b57cec5SDimitry Andric std::vector<int> checkRegUsageImpact(std::set<unsigned> &InRegs, 4000b57cec5SDimitry Andric std::set<unsigned> &OutRegs); 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric void schedule(); 4030b57cec5SDimitry Andric }; 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric struct SIScheduleBlockResult { 4060b57cec5SDimitry Andric std::vector<unsigned> SUs; 4070b57cec5SDimitry Andric unsigned MaxSGPRUsage; 4080b57cec5SDimitry Andric unsigned MaxVGPRUsage; 4090b57cec5SDimitry Andric }; 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric class SIScheduler { 4120b57cec5SDimitry Andric SIScheduleDAGMI *DAG; 4130b57cec5SDimitry Andric SIScheduleBlockCreator BlockCreator; 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric public: SIScheduler(SIScheduleDAGMI * DAG)4160b57cec5SDimitry Andric SIScheduler(SIScheduleDAGMI *DAG) : DAG(DAG), BlockCreator(DAG) {} 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric ~SIScheduler() = default; 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric struct SIScheduleBlockResult 4210b57cec5SDimitry Andric scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant, 4220b57cec5SDimitry Andric SISchedulerBlockSchedulerVariant ScheduleVariant); 4230b57cec5SDimitry Andric }; 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric class SIScheduleDAGMI final : public ScheduleDAGMILive { 4260b57cec5SDimitry Andric const SIInstrInfo *SITII; 4270b57cec5SDimitry Andric const SIRegisterInfo *SITRI; 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric std::vector<SUnit> SUnitsLinksBackup; 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric // For moveLowLatencies. After all Scheduling variants are tested. 4320b57cec5SDimitry Andric std::vector<unsigned> ScheduledSUnits; 4330b57cec5SDimitry Andric std::vector<unsigned> ScheduledSUnitsInv; 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric public: 4360b57cec5SDimitry Andric SIScheduleDAGMI(MachineSchedContext *C); 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric ~SIScheduleDAGMI() override; 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric // Entry point for the schedule. 4410b57cec5SDimitry Andric void schedule() override; 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric // To init Block's RPTracker. initRPTracker(RegPressureTracker & RPTracker)4440b57cec5SDimitry Andric void initRPTracker(RegPressureTracker &RPTracker) { 4450b57cec5SDimitry Andric RPTracker.init(&MF, RegClassInfo, LIS, BB, RegionBegin, false, false); 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric getBB()4480b57cec5SDimitry Andric MachineBasicBlock *getBB() { return BB; } getCurrentTop()4490b57cec5SDimitry Andric MachineBasicBlock::iterator getCurrentTop() { return CurrentTop; } getCurrentBottom()4500b57cec5SDimitry Andric MachineBasicBlock::iterator getCurrentBottom() { return CurrentBottom; } getLIS()4510b57cec5SDimitry Andric LiveIntervals *getLIS() { return LIS; } getMRI()4520b57cec5SDimitry Andric MachineRegisterInfo *getMRI() { return &MRI; } getTRI()4530b57cec5SDimitry Andric const TargetRegisterInfo *getTRI() { return TRI; } GetTopo()4540b57cec5SDimitry Andric ScheduleDAGTopologicalSort *GetTopo() { return &Topo; } getEntrySU()4550b57cec5SDimitry Andric SUnit &getEntrySU() { return EntrySU; } getExitSU()4560b57cec5SDimitry Andric SUnit& getExitSU() { return ExitSU; } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric void restoreSULinksLeft(); 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric template<typename _Iterator> void fillVgprSgprCost(_Iterator First, 4610b57cec5SDimitry Andric _Iterator End, 4620b57cec5SDimitry Andric unsigned &VgprUsage, 4630b57cec5SDimitry Andric unsigned &SgprUsage); 4640b57cec5SDimitry Andric getInRegs()4650b57cec5SDimitry Andric std::set<unsigned> getInRegs() { 4660b57cec5SDimitry Andric std::set<unsigned> InRegs; 4670b57cec5SDimitry Andric for (const auto &RegMaskPair : RPTracker.getPressure().LiveInRegs) { 4680b57cec5SDimitry Andric InRegs.insert(RegMaskPair.RegUnit); 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric return InRegs; 4710b57cec5SDimitry Andric } 4720b57cec5SDimitry Andric getOutRegs()4730b57cec5SDimitry Andric std::set<unsigned> getOutRegs() { 4740b57cec5SDimitry Andric std::set<unsigned> OutRegs; 4750b57cec5SDimitry Andric for (const auto &RegMaskPair : RPTracker.getPressure().LiveOutRegs) { 4760b57cec5SDimitry Andric OutRegs.insert(RegMaskPair.RegUnit); 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric return OutRegs; 4790b57cec5SDimitry Andric }; 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric private: 4820b57cec5SDimitry Andric void topologicalSort(); 4830b57cec5SDimitry Andric // After scheduling is done, improve low latency placements. 4840b57cec5SDimitry Andric void moveLowLatencies(); 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric public: 4870b57cec5SDimitry Andric // Some stats for scheduling inside blocks. 4880b57cec5SDimitry Andric std::vector<unsigned> IsLowLatencySU; 4890b57cec5SDimitry Andric std::vector<unsigned> LowLatencyOffset; 4900b57cec5SDimitry Andric std::vector<unsigned> IsHighLatencySU; 4910b57cec5SDimitry Andric // Topological sort 4920b57cec5SDimitry Andric // Maps topological index to the node number. 4930b57cec5SDimitry Andric std::vector<int> TopDownIndex2SU; 4940b57cec5SDimitry Andric std::vector<int> BottomUpIndex2SU; 4950b57cec5SDimitry Andric }; 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric } // end namespace llvm 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric #endif // LLVM_LIB_TARGET_AMDGPU_SIMACHINESCHEDULER_H 500