1 //===-- GCNSchedStrategy.h - GCN Scheduler Strategy -*- C++ -*-------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
14 #define LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
15 
16 #include "GCNRegPressure.h"
17 #include "llvm/CodeGen/MachineScheduler.h"
18 
19 namespace llvm {
20 
21 class SIMachineFunctionInfo;
22 class SIRegisterInfo;
23 class GCNSubtarget;
24 
25 /// This is a minimal scheduler strategy.  The main difference between this
26 /// and the GenericScheduler is that GCNSchedStrategy uses different
27 /// heuristics to determine excess/critical pressure sets.  Its goal is to
28 /// maximize kernel occupancy (i.e. maximum number of waves per simd).
29 class GCNMaxOccupancySchedStrategy final : public GenericScheduler {
30   friend class GCNScheduleDAGMILive;
31 
32   SUnit *pickNodeBidirectional(bool &IsTopNode);
33 
34   void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy,
35                          const RegPressureTracker &RPTracker,
36                          SchedCandidate &Cand);
37 
38   void initCandidate(SchedCandidate &Cand, SUnit *SU,
39                      bool AtTop, const RegPressureTracker &RPTracker,
40                      const SIRegisterInfo *SRI,
41                      unsigned SGPRPressure, unsigned VGPRPressure);
42 
43   std::vector<unsigned> Pressure;
44   std::vector<unsigned> MaxPressure;
45 
46   unsigned SGPRExcessLimit;
47   unsigned VGPRExcessLimit;
48   unsigned SGPRCriticalLimit;
49   unsigned VGPRCriticalLimit;
50 
51   unsigned TargetOccupancy;
52 
53   // schedule() have seen a clustered memory operation. Set it to false
54   // before a region scheduling to know if the region had such clusters.
55   bool HasClusteredNodes;
56 
57   // schedule() have seen an excess register pressure and had to track
58   // register pressure for actual scheduling heuristics.
59   bool HasExcessPressure;
60 
61   MachineFunction *MF;
62 
63 public:
64   GCNMaxOccupancySchedStrategy(const MachineSchedContext *C);
65 
66   SUnit *pickNode(bool &IsTopNode) override;
67 
68   void initialize(ScheduleDAGMI *DAG) override;
69 
70   void setTargetOccupancy(unsigned Occ) { TargetOccupancy = Occ; }
71 };
72 
73 class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
74 
75   enum : unsigned {
76     Collect,
77     InitialSchedule,
78     UnclusteredReschedule,
79     ClusteredLowOccupancyReschedule,
80     PreRARematerialize,
81     LastStage = PreRARematerialize
82   };
83 
84   const GCNSubtarget &ST;
85 
86   SIMachineFunctionInfo &MFI;
87 
88   // Occupancy target at the beginning of function scheduling cycle.
89   unsigned StartingOccupancy;
90 
91   // Minimal real occupancy recorder for the function.
92   unsigned MinOccupancy;
93 
94   // Scheduling stage number.
95   unsigned Stage;
96 
97   // Current region index.
98   size_t RegionIdx;
99 
100   // Vector of regions recorder for later rescheduling
101   SmallVector<std::pair<MachineBasicBlock::iterator,
102                         MachineBasicBlock::iterator>, 32> Regions;
103 
104   // Records if a region is not yet scheduled, or schedule has been reverted,
105   // or we generally desire to reschedule it.
106   BitVector RescheduleRegions;
107 
108   // Record regions which use clustered loads/stores.
109   BitVector RegionsWithClusters;
110 
111   // Record regions with high register pressure.
112   BitVector RegionsWithHighRP;
113 
114   // Regions that has the same occupancy as the latest MinOccupancy
115   BitVector RegionsWithMinOcc;
116 
117   // Region live-in cache.
118   SmallVector<GCNRPTracker::LiveRegSet, 32> LiveIns;
119 
120   // Region pressure cache.
121   SmallVector<GCNRegPressure, 32> Pressure;
122 
123   // List of trivially rematerializable instructions we can remat to reduce RP.
124   // First MI is the MI to remat and second MI is the position we should remat
125   // before, usually the MI using the rematerializable instruction.
126   SmallVector<std::pair<MachineInstr *, MachineInstr *>> RematerializableInsts;
127 
128   // Temporary basic block live-in cache.
129   DenseMap<const MachineBasicBlock*, GCNRPTracker::LiveRegSet> MBBLiveIns;
130 
131   DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> BBLiveInMap;
132   DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> getBBLiveInMap() const;
133 
134   // Collect all trivially rematerializable VGPR instructions with a single def
135   // and single use outside the defining block into RematerializableInsts.
136   void collectRematerializableInstructions(unsigned HighRPIdx);
137 
138   bool isTriviallyReMaterializable(const MachineInstr &MI, AAResults *AA);
139 
140   // TODO: Should also attempt to reduce RP of SGPRs and AGPRs
141   // Attempt to reduce RP of VGPR by sinking trivially rematerializable
142   // instructions. Returns true if we were able to sink instruction(s).
143   bool sinkTriviallyRematInsts(const GCNSubtarget &ST,
144                                const TargetInstrInfo *TII, unsigned HighRPIdx);
145 
146   // Return current region pressure.
147   GCNRegPressure getRealRegPressure() const;
148 
149   // Compute and cache live-ins and pressure for all regions in block.
150   void computeBlockPressure(const MachineBasicBlock *MBB);
151 
152   // Update region boundaries when removing MI or inserting NewMI before MI.
153   void updateRegionBoundaries(MachineBasicBlock::iterator MI,
154                               MachineInstr *NewMI, bool Removing = false);
155 
156 public:
157   GCNScheduleDAGMILive(MachineSchedContext *C,
158                        std::unique_ptr<MachineSchedStrategy> S);
159 
160   void schedule() override;
161 
162   void finalizeSchedule() override;
163 };
164 
165 } // End namespace llvm
166 
167 #endif // LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
168