xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/SIMachineScheduler.h (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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