xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===-- GCNSchedStrategy.h - GCN Scheduler Strategy -*- 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 //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
140b57cec5SDimitry Andric #define LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "GCNRegPressure.h"
17*81ad6265SDimitry Andric #include "llvm/ADT/MapVector.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric namespace llvm {
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric class SIMachineFunctionInfo;
230b57cec5SDimitry Andric class SIRegisterInfo;
240b57cec5SDimitry Andric class GCNSubtarget;
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric /// This is a minimal scheduler strategy.  The main difference between this
270b57cec5SDimitry Andric /// and the GenericScheduler is that GCNSchedStrategy uses different
280b57cec5SDimitry Andric /// heuristics to determine excess/critical pressure sets.  Its goal is to
290b57cec5SDimitry Andric /// maximize kernel occupancy (i.e. maximum number of waves per simd).
300b57cec5SDimitry Andric class GCNMaxOccupancySchedStrategy final : public GenericScheduler {
310b57cec5SDimitry Andric   friend class GCNScheduleDAGMILive;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   SUnit *pickNodeBidirectional(bool &IsTopNode);
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy,
360b57cec5SDimitry Andric                          const RegPressureTracker &RPTracker,
370b57cec5SDimitry Andric                          SchedCandidate &Cand);
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   void initCandidate(SchedCandidate &Cand, SUnit *SU,
400b57cec5SDimitry Andric                      bool AtTop, const RegPressureTracker &RPTracker,
410b57cec5SDimitry Andric                      const SIRegisterInfo *SRI,
420b57cec5SDimitry Andric                      unsigned SGPRPressure, unsigned VGPRPressure);
430b57cec5SDimitry Andric 
448bcb0991SDimitry Andric   std::vector<unsigned> Pressure;
458bcb0991SDimitry Andric   std::vector<unsigned> MaxPressure;
468bcb0991SDimitry Andric 
470b57cec5SDimitry Andric   unsigned SGPRExcessLimit;
480b57cec5SDimitry Andric   unsigned VGPRExcessLimit;
490b57cec5SDimitry Andric   unsigned SGPRCriticalLimit;
500b57cec5SDimitry Andric   unsigned VGPRCriticalLimit;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   unsigned TargetOccupancy;
530b57cec5SDimitry Andric 
54fe6060f1SDimitry Andric   // schedule() have seen a clustered memory operation. Set it to false
55fe6060f1SDimitry Andric   // before a region scheduling to know if the region had such clusters.
56fe6060f1SDimitry Andric   bool HasClusteredNodes;
57fe6060f1SDimitry Andric 
58349cc55cSDimitry Andric   // schedule() have seen an excess register pressure and had to track
59fe6060f1SDimitry Andric   // register pressure for actual scheduling heuristics.
60fe6060f1SDimitry Andric   bool HasExcessPressure;
61fe6060f1SDimitry Andric 
620b57cec5SDimitry Andric   MachineFunction *MF;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric public:
650b57cec5SDimitry Andric   GCNMaxOccupancySchedStrategy(const MachineSchedContext *C);
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   SUnit *pickNode(bool &IsTopNode) override;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   void initialize(ScheduleDAGMI *DAG) override;
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   void setTargetOccupancy(unsigned Occ) { TargetOccupancy = Occ; }
720b57cec5SDimitry Andric };
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
750b57cec5SDimitry Andric 
765ffd83dbSDimitry Andric   enum : unsigned {
775ffd83dbSDimitry Andric     Collect,
785ffd83dbSDimitry Andric     InitialSchedule,
795ffd83dbSDimitry Andric     UnclusteredReschedule,
805ffd83dbSDimitry Andric     ClusteredLowOccupancyReschedule,
81*81ad6265SDimitry Andric     PreRARematerialize,
82*81ad6265SDimitry Andric     LastStage = PreRARematerialize
835ffd83dbSDimitry Andric   };
845ffd83dbSDimitry Andric 
850b57cec5SDimitry Andric   const GCNSubtarget &ST;
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   SIMachineFunctionInfo &MFI;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   // Occupancy target at the beginning of function scheduling cycle.
900b57cec5SDimitry Andric   unsigned StartingOccupancy;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   // Minimal real occupancy recorder for the function.
930b57cec5SDimitry Andric   unsigned MinOccupancy;
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   // Scheduling stage number.
960b57cec5SDimitry Andric   unsigned Stage;
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   // Current region index.
990b57cec5SDimitry Andric   size_t RegionIdx;
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   // Vector of regions recorder for later rescheduling
1020b57cec5SDimitry Andric   SmallVector<std::pair<MachineBasicBlock::iterator,
1030b57cec5SDimitry Andric                         MachineBasicBlock::iterator>, 32> Regions;
1040b57cec5SDimitry Andric 
1055ffd83dbSDimitry Andric   // Records if a region is not yet scheduled, or schedule has been reverted,
1065ffd83dbSDimitry Andric   // or we generally desire to reschedule it.
1075ffd83dbSDimitry Andric   BitVector RescheduleRegions;
1085ffd83dbSDimitry Andric 
109fe6060f1SDimitry Andric   // Record regions which use clustered loads/stores.
110fe6060f1SDimitry Andric   BitVector RegionsWithClusters;
111fe6060f1SDimitry Andric 
112fe6060f1SDimitry Andric   // Record regions with high register pressure.
113fe6060f1SDimitry Andric   BitVector RegionsWithHighRP;
114fe6060f1SDimitry Andric 
115*81ad6265SDimitry Andric   // Regions that has the same occupancy as the latest MinOccupancy
116*81ad6265SDimitry Andric   BitVector RegionsWithMinOcc;
117*81ad6265SDimitry Andric 
1180b57cec5SDimitry Andric   // Region live-in cache.
1190b57cec5SDimitry Andric   SmallVector<GCNRPTracker::LiveRegSet, 32> LiveIns;
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // Region pressure cache.
1220b57cec5SDimitry Andric   SmallVector<GCNRegPressure, 32> Pressure;
1230b57cec5SDimitry Andric 
124*81ad6265SDimitry Andric   // Each region at MinOccupancy will have their own list of trivially
125*81ad6265SDimitry Andric   // rematerializable instructions we can remat to reduce RP. The list maps an
126*81ad6265SDimitry Andric   // instruction to the position we should remat before, usually the MI using
127*81ad6265SDimitry Andric   // the rematerializable instruction.
128*81ad6265SDimitry Andric   MapVector<unsigned, MapVector<MachineInstr *, MachineInstr *>>
129*81ad6265SDimitry Andric       RematerializableInsts;
130*81ad6265SDimitry Andric 
131*81ad6265SDimitry Andric   // Map a trivially remateriazable def to a list of regions at MinOccupancy
132*81ad6265SDimitry Andric   // that has the defined reg as a live-in.
133*81ad6265SDimitry Andric   DenseMap<MachineInstr *, SmallVector<unsigned, 4>> RematDefToLiveInRegions;
134*81ad6265SDimitry Andric 
1350b57cec5SDimitry Andric   // Temporary basic block live-in cache.
1360b57cec5SDimitry Andric   DenseMap<const MachineBasicBlock*, GCNRPTracker::LiveRegSet> MBBLiveIns;
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> BBLiveInMap;
1390b57cec5SDimitry Andric   DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> getBBLiveInMap() const;
1400b57cec5SDimitry Andric 
141*81ad6265SDimitry Andric   // Collect all trivially rematerializable VGPR instructions with a single def
142*81ad6265SDimitry Andric   // and single use outside the defining block into RematerializableInsts.
143*81ad6265SDimitry Andric   void collectRematerializableInstructions();
144*81ad6265SDimitry Andric 
145*81ad6265SDimitry Andric   bool isTriviallyReMaterializable(const MachineInstr &MI, AAResults *AA);
146*81ad6265SDimitry Andric 
147*81ad6265SDimitry Andric   // TODO: Should also attempt to reduce RP of SGPRs and AGPRs
148*81ad6265SDimitry Andric   // Attempt to reduce RP of VGPR by sinking trivially rematerializable
149*81ad6265SDimitry Andric   // instructions. Returns true if we were able to sink instruction(s).
150*81ad6265SDimitry Andric   bool sinkTriviallyRematInsts(const GCNSubtarget &ST,
151*81ad6265SDimitry Andric                                const TargetInstrInfo *TII);
152*81ad6265SDimitry Andric 
1530b57cec5SDimitry Andric   // Return current region pressure.
1540b57cec5SDimitry Andric   GCNRegPressure getRealRegPressure() const;
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   // Compute and cache live-ins and pressure for all regions in block.
1570b57cec5SDimitry Andric   void computeBlockPressure(const MachineBasicBlock *MBB);
1580b57cec5SDimitry Andric 
159*81ad6265SDimitry Andric   // Update region boundaries when removing MI or inserting NewMI before MI.
160*81ad6265SDimitry Andric   void updateRegionBoundaries(
161*81ad6265SDimitry Andric       SmallVectorImpl<std::pair<MachineBasicBlock::iterator,
162*81ad6265SDimitry Andric                                 MachineBasicBlock::iterator>> &RegionBoundaries,
163*81ad6265SDimitry Andric       MachineBasicBlock::iterator MI, MachineInstr *NewMI,
164*81ad6265SDimitry Andric       bool Removing = false);
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric public:
1670b57cec5SDimitry Andric   GCNScheduleDAGMILive(MachineSchedContext *C,
1680b57cec5SDimitry Andric                        std::unique_ptr<MachineSchedStrategy> S);
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   void schedule() override;
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   void finalizeSchedule() override;
1730b57cec5SDimitry Andric };
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric } // End namespace llvm
1760b57cec5SDimitry Andric 
17704eeddc0SDimitry Andric #endif // LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
178