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