#ifndef LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
#define LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
#include "GCNRegPressure.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/CodeGen/MachineScheduler.h"
namespace llvm {
class SIMachineFunctionInfo;
class SIRegisterInfo;
class GCNSubtarget;
class GCNMaxOccupancySchedStrategy final : public GenericScheduler {
SUnit *pickNodeBidirectional(bool &IsTopNode);
void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy,
const RegPressureTracker &RPTracker,
SchedCandidate &Cand);
void initCandidate(SchedCandidate &Cand, SUnit *SU,
bool AtTop, const RegPressureTracker &RPTracker,
const SIRegisterInfo *SRI,
unsigned SGPRPressure, unsigned VGPRPressure);
std::vector<unsigned> Pressure;
std::vector<unsigned> MaxPressure;
unsigned SGPRExcessLimit;
unsigned VGPRExcessLimit;
unsigned TargetOccupancy;
MachineFunction *MF;
public:
bool HasClusteredNodes;
bool HasExcessPressure;
unsigned SGPRCriticalLimit;
unsigned VGPRCriticalLimit;
GCNMaxOccupancySchedStrategy(const MachineSchedContext *C);
SUnit *pickNode(bool &IsTopNode) override;
void initialize(ScheduleDAGMI *DAG) override;
unsigned getTargetOccupancy() { return TargetOccupancy; }
void setTargetOccupancy(unsigned Occ) { TargetOccupancy = Occ; }
};
enum class GCNSchedStageID : unsigned {
InitialSchedule = 0,
UnclusteredReschedule = 1,
ClusteredLowOccupancyReschedule = 2,
PreRARematerialize = 3,
LastStage = PreRARematerialize
};
#ifndef NDEBUG
raw_ostream &operator<<(raw_ostream &OS, const GCNSchedStageID &StageID);
#endif
inline GCNSchedStageID &operator++(GCNSchedStageID &Stage, int) {
assert(Stage != GCNSchedStageID::PreRARematerialize);
Stage = static_cast<GCNSchedStageID>(static_cast<unsigned>(Stage) + 1);
return Stage;
}
inline GCNSchedStageID nextStage(const GCNSchedStageID Stage) {
return static_cast<GCNSchedStageID>(static_cast<unsigned>(Stage) + 1);
}
inline bool operator>(GCNSchedStageID &LHS, GCNSchedStageID &RHS) {
return static_cast<unsigned>(LHS) > static_cast<unsigned>(RHS);
}
class GCNScheduleDAGMILive final : public ScheduleDAGMILive {
friend class GCNSchedStage;
friend class InitialScheduleStage;
friend class UnclusteredRescheduleStage;
friend class ClusteredLowOccStage;
friend class PreRARematStage;
const GCNSubtarget &ST;
SIMachineFunctionInfo &MFI;
unsigned StartingOccupancy;
unsigned MinOccupancy;
SmallVector<std::pair<MachineBasicBlock::iterator,
MachineBasicBlock::iterator>, 32> Regions;
BitVector RescheduleRegions;
BitVector RegionsWithClusters;
BitVector RegionsWithHighRP;
BitVector RegionsWithMinOcc;
SmallVector<GCNRPTracker::LiveRegSet, 32> LiveIns;
SmallVector<GCNRegPressure, 32> Pressure;
DenseMap<const MachineBasicBlock *, GCNRPTracker::LiveRegSet> MBBLiveIns;
DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> BBLiveInMap;
DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> getBBLiveInMap() const;
GCNRegPressure getRealRegPressure(unsigned RegionIdx) const;
void computeBlockPressure(unsigned RegionIdx, const MachineBasicBlock *MBB);
void updateRegionBoundaries(
SmallVectorImpl<std::pair<MachineBasicBlock::iterator,
MachineBasicBlock::iterator>> &RegionBoundaries,
MachineBasicBlock::iterator MI, MachineInstr *NewMI,
bool Removing = false);
void runSchedStages();
public:
GCNScheduleDAGMILive(MachineSchedContext *C,
std::unique_ptr<MachineSchedStrategy> S);
void schedule() override;
void finalizeSchedule() override;
};
class GCNSchedStage {
protected:
GCNScheduleDAGMILive &DAG;
GCNMaxOccupancySchedStrategy &S;
MachineFunction &MF;
SIMachineFunctionInfo &MFI;
const GCNSubtarget &ST;
const GCNSchedStageID StageID;
MachineBasicBlock *CurrentMBB = nullptr;
unsigned RegionIdx = 0;
std::vector<MachineInstr *> Unsched;
GCNRegPressure PressureBefore;
GCNRegPressure PressureAfter;
GCNSchedStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG);
public:
virtual bool initGCNSchedStage();
virtual void finalizeGCNSchedStage();
virtual bool initGCNRegion();
void setupNewBlock();
virtual void finalizeGCNRegion();
void checkScheduling();
virtual bool shouldRevertScheduling(unsigned WavesAfter);
bool mayCauseSpilling(unsigned WavesAfter);
void revertScheduling();
void advanceRegion() { RegionIdx++; }
virtual ~GCNSchedStage() = default;
};
class InitialScheduleStage : public GCNSchedStage {
public:
void finalizeGCNRegion() override;
bool shouldRevertScheduling(unsigned WavesAfter) override;
InitialScheduleStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
: GCNSchedStage(StageID, DAG) {}
};
class UnclusteredRescheduleStage : public GCNSchedStage {
private:
std::vector<std::unique_ptr<ScheduleDAGMutation>> SavedMutations;
public:
bool initGCNSchedStage() override;
void finalizeGCNSchedStage() override;
bool initGCNRegion() override;
bool shouldRevertScheduling(unsigned WavesAfter) override;
UnclusteredRescheduleStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
: GCNSchedStage(StageID, DAG) {}
};
class ClusteredLowOccStage : public GCNSchedStage {
public:
bool initGCNSchedStage() override;
bool initGCNRegion() override;
bool shouldRevertScheduling(unsigned WavesAfter) override;
ClusteredLowOccStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
: GCNSchedStage(StageID, DAG) {}
};
class PreRARematStage : public GCNSchedStage {
private:
MapVector<unsigned, MapVector<MachineInstr *, MachineInstr *>>
RematerializableInsts;
DenseMap<MachineInstr *, SmallVector<unsigned, 4>> RematDefToLiveInRegions;
void collectRematerializableInstructions();
bool isTriviallyReMaterializable(const MachineInstr &MI);
bool sinkTriviallyRematInsts(const GCNSubtarget &ST,
const TargetInstrInfo *TII);
public:
bool initGCNSchedStage() override;
bool initGCNRegion() override;
bool shouldRevertScheduling(unsigned WavesAfter) override;
PreRARematStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
: GCNSchedStage(StageID, DAG) {}
};
}
#endif