#ifndef LLVM_LIB_TARGET_AMDGPU_SIMACHINESCHEDULER_H
#define LLVM_LIB_TARGET_AMDGPU_SIMACHINESCHEDULER_H
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/RegisterPressure.h"
#include "llvm/CodeGen/ScheduleDAG.h"
#include <cstdint>
#include <set>
#include <vector>
namespace llvm {
class SIInstrInfo;
class SIRegisterInfo;
class SIScheduleDAGMI;
class SIScheduleBlockCreator;
enum SIScheduleCandReason {
NoCand,
RegUsage,
Latency,
Successor,
Depth,
NodeOrder
};
struct SISchedulerCandidate {
SIScheduleCandReason Reason = NoCand;
uint32_t RepeatReasonSet = 0;
SISchedulerCandidate() = default;
bool isRepeat(SIScheduleCandReason R) { return RepeatReasonSet & (1 << R); }
void setRepeat(SIScheduleCandReason R) { RepeatReasonSet |= (1 << R); }
};
enum SIScheduleBlockLinkKind {
NoData,
Data
};
class SIScheduleBlock {
SIScheduleDAGMI *DAG;
SIScheduleBlockCreator *BC;
std::vector<SUnit*> SUnits;
std::map<unsigned, unsigned> NodeNum2Index;
std::vector<SUnit*> TopReadySUs;
std::vector<SUnit*> ScheduledSUnits;
IntervalPressure TopPressure;
RegPressureTracker TopRPTracker;
std::vector<unsigned> InternalAdditionalPressure;
std::vector<unsigned> LiveInPressure;
std::vector<unsigned> LiveOutPressure;
std::set<unsigned> LiveInRegs;
std::set<unsigned> LiveOutRegs;
bool Scheduled = false;
bool HighLatencyBlock = false;
std::vector<unsigned> HasLowLatencyNonWaitedParent;
unsigned ID;
std::vector<SIScheduleBlock*> Preds; std::vector<std::pair<SIScheduleBlock*, SIScheduleBlockLinkKind>> Succs;
unsigned NumHighLatencySuccessors = 0;
public:
SIScheduleBlock(SIScheduleDAGMI *DAG, SIScheduleBlockCreator *BC,
unsigned ID):
DAG(DAG), BC(BC), TopRPTracker(TopPressure), ID(ID) {}
~SIScheduleBlock() = default;
unsigned getID() const { return ID; }
void addUnit(SUnit *SU);
void finalizeUnits();
void addPred(SIScheduleBlock *Pred);
void addSucc(SIScheduleBlock *Succ, SIScheduleBlockLinkKind Kind);
const std::vector<SIScheduleBlock*>& getPreds() const { return Preds; }
ArrayRef<std::pair<SIScheduleBlock*, SIScheduleBlockLinkKind>>
getSuccs() const { return Succs; }
unsigned Height; unsigned Depth;
unsigned getNumHighLatencySuccessors() const {
return NumHighLatencySuccessors;
}
bool isHighLatencyBlock() { return HighLatencyBlock; }
int getCost() { return SUnits.size(); }
void fastSchedule();
std::vector<SUnit*> getScheduledUnits() { return ScheduledSUnits; }
void schedule(MachineBasicBlock::iterator BeginBlock,
MachineBasicBlock::iterator EndBlock);
bool isScheduled() { return Scheduled; }
std::vector<unsigned> &getInternalAdditionalRegUsage() {
return InternalAdditionalPressure;
}
std::set<unsigned> &getInRegs() { return LiveInRegs; }
std::set<unsigned> &getOutRegs() { return LiveOutRegs; }
void printDebug(bool Full);
private:
struct SISchedCandidate : SISchedulerCandidate {
SUnit *SU = nullptr;
unsigned SGPRUsage;
unsigned VGPRUsage;
bool IsLowLatency;
unsigned LowLatencyOffset;
bool HasLowLatencyNonWaitedParent;
SISchedCandidate() = default;
bool isValid() const { return SU; }
void setBest(SISchedCandidate &Best) {
assert(Best.Reason != NoCand && "uninitialized Sched candidate");
SU = Best.SU;
Reason = Best.Reason;
SGPRUsage = Best.SGPRUsage;
VGPRUsage = Best.VGPRUsage;
IsLowLatency = Best.IsLowLatency;
LowLatencyOffset = Best.LowLatencyOffset;
HasLowLatencyNonWaitedParent = Best.HasLowLatencyNonWaitedParent;
}
};
void undoSchedule();
void undoReleaseSucc(SUnit *SU, SDep *SuccEdge);
void releaseSucc(SUnit *SU, SDep *SuccEdge);
void releaseSuccessors(SUnit *SU, bool InOrOutBlock);
void nodeScheduled(SUnit *SU);
void tryCandidateTopDown(SISchedCandidate &Cand, SISchedCandidate &TryCand);
void tryCandidateBottomUp(SISchedCandidate &Cand, SISchedCandidate &TryCand);
SUnit* pickNode();
void traceCandidate(const SISchedCandidate &Cand);
void initRegPressure(MachineBasicBlock::iterator BeginBlock,
MachineBasicBlock::iterator EndBlock);
};
struct SIScheduleBlocks {
std::vector<SIScheduleBlock*> Blocks;
std::vector<int> TopDownIndex2Block;
std::vector<int> TopDownBlock2Index;
};
enum SISchedulerBlockCreatorVariant {
LatenciesAlone,
LatenciesGrouped,
LatenciesAlonePlusConsecutive
};
class SIScheduleBlockCreator {
SIScheduleDAGMI *DAG;
std::vector<std::unique_ptr<SIScheduleBlock>> BlockPtrs;
std::map<SISchedulerBlockCreatorVariant,
SIScheduleBlocks> Blocks;
std::vector<SIScheduleBlock*> CurrentBlocks;
std::vector<int> Node2CurrentBlock;
std::vector<int> TopDownIndex2Block;
std::vector<int> TopDownBlock2Index;
std::vector<int> BottomUpIndex2Block;
int NextReservedID;
int NextNonReservedID;
std::vector<int> CurrentColoring;
std::vector<int> CurrentTopDownReservedDependencyColoring;
std::vector<int> CurrentBottomUpReservedDependencyColoring;
public:
SIScheduleBlockCreator(SIScheduleDAGMI *DAG);
SIScheduleBlocks
getBlocks(SISchedulerBlockCreatorVariant BlockVariant);
bool isSUInBlock(SUnit *SU, unsigned ID);
private:
void colorHighLatenciesAlone();
void colorHighLatenciesGroups();
void colorComputeReservedDependencies();
void colorAccordingToReservedDependencies();
void colorEndsAccordingToDependencies();
void colorForceConsecutiveOrderInGroup();
void colorMergeConstantLoadsNextGroup();
void colorMergeIfPossibleNextGroup();
void colorMergeIfPossibleNextGroupOnlyForReserved();
void colorMergeIfPossibleSmallGroupsToNextGroup();
void cutHugeBlocks();
void regroupNoUserInstructions();
void colorExports();
void createBlocksForVariant(SISchedulerBlockCreatorVariant BlockVariant);
void topologicalSort();
void scheduleInsideBlocks();
void fillStats();
};
enum SISchedulerBlockSchedulerVariant {
BlockLatencyRegUsage,
BlockRegUsageLatency,
BlockRegUsage
};
class SIScheduleBlockScheduler {
SIScheduleDAGMI *DAG;
SISchedulerBlockSchedulerVariant Variant;
std::vector<SIScheduleBlock*> Blocks;
std::vector<std::map<unsigned, unsigned>> LiveOutRegsNumUsages;
std::set<unsigned> LiveRegs;
std::map<unsigned, unsigned> LiveRegsConsumers;
std::vector<unsigned> LastPosHighLatencyParentScheduled;
int LastPosWaitedHighLatency;
std::vector<SIScheduleBlock*> BlocksScheduled;
unsigned NumBlockScheduled;
std::vector<SIScheduleBlock*> ReadyBlocks;
unsigned VregCurrentUsage;
unsigned SregCurrentUsage;
unsigned maxVregUsage;
unsigned maxSregUsage;
std::vector<unsigned> BlockNumPredsLeft;
std::vector<unsigned> BlockNumSuccsLeft;
public:
SIScheduleBlockScheduler(SIScheduleDAGMI *DAG,
SISchedulerBlockSchedulerVariant Variant,
SIScheduleBlocks BlocksStruct);
~SIScheduleBlockScheduler() = default;
std::vector<SIScheduleBlock*> getBlocks() { return BlocksScheduled; }
unsigned getVGPRUsage() { return maxVregUsage; }
unsigned getSGPRUsage() { return maxSregUsage; }
private:
struct SIBlockSchedCandidate : SISchedulerCandidate {
SIScheduleBlock *Block = nullptr;
bool IsHighLatency;
int VGPRUsageDiff;
unsigned NumSuccessors;
unsigned NumHighLatencySuccessors;
unsigned LastPosHighLatParentScheduled;
unsigned Height;
SIBlockSchedCandidate() = default;
bool isValid() const { return Block; }
void setBest(SIBlockSchedCandidate &Best) {
assert(Best.Reason != NoCand && "uninitialized Sched candidate");
Block = Best.Block;
Reason = Best.Reason;
IsHighLatency = Best.IsHighLatency;
VGPRUsageDiff = Best.VGPRUsageDiff;
NumSuccessors = Best.NumSuccessors;
NumHighLatencySuccessors = Best.NumHighLatencySuccessors;
LastPosHighLatParentScheduled = Best.LastPosHighLatParentScheduled;
Height = Best.Height;
}
};
bool tryCandidateLatency(SIBlockSchedCandidate &Cand,
SIBlockSchedCandidate &TryCand);
bool tryCandidateRegUsage(SIBlockSchedCandidate &Cand,
SIBlockSchedCandidate &TryCand);
SIScheduleBlock *pickBlock();
void addLiveRegs(std::set<unsigned> &Regs);
void decreaseLiveRegs(SIScheduleBlock *Block, std::set<unsigned> &Regs);
void releaseBlockSuccs(SIScheduleBlock *Parent);
void blockScheduled(SIScheduleBlock *Block);
std::vector<int> checkRegUsageImpact(std::set<unsigned> &InRegs,
std::set<unsigned> &OutRegs);
void schedule();
};
struct SIScheduleBlockResult {
std::vector<unsigned> SUs;
unsigned MaxSGPRUsage;
unsigned MaxVGPRUsage;
};
class SIScheduler {
SIScheduleDAGMI *DAG;
SIScheduleBlockCreator BlockCreator;
public:
SIScheduler(SIScheduleDAGMI *DAG) : DAG(DAG), BlockCreator(DAG) {}
~SIScheduler() = default;
struct SIScheduleBlockResult
scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant,
SISchedulerBlockSchedulerVariant ScheduleVariant);
};
class SIScheduleDAGMI final : public ScheduleDAGMILive {
const SIInstrInfo *SITII;
const SIRegisterInfo *SITRI;
std::vector<SUnit> SUnitsLinksBackup;
std::vector<unsigned> ScheduledSUnits;
std::vector<unsigned> ScheduledSUnitsInv;
public:
SIScheduleDAGMI(MachineSchedContext *C);
~SIScheduleDAGMI() override;
void schedule() override;
void initRPTracker(RegPressureTracker &RPTracker) {
RPTracker.init(&MF, RegClassInfo, LIS, BB, RegionBegin, false, false);
}
MachineBasicBlock *getBB() { return BB; }
MachineBasicBlock::iterator getCurrentTop() { return CurrentTop; }
MachineBasicBlock::iterator getCurrentBottom() { return CurrentBottom; }
LiveIntervals *getLIS() { return LIS; }
MachineRegisterInfo *getMRI() { return &MRI; }
const TargetRegisterInfo *getTRI() { return TRI; }
ScheduleDAGTopologicalSort *GetTopo() { return &Topo; }
SUnit &getEntrySU() { return EntrySU; }
SUnit& getExitSU() { return ExitSU; }
void restoreSULinksLeft();
template<typename _Iterator> void fillVgprSgprCost(_Iterator First,
_Iterator End,
unsigned &VgprUsage,
unsigned &SgprUsage);
std::set<unsigned> getInRegs() {
std::set<unsigned> InRegs;
for (const auto &RegMaskPair : RPTracker.getPressure().LiveInRegs) {
InRegs.insert(RegMaskPair.RegUnit);
}
return InRegs;
}
std::set<unsigned> getOutRegs() {
std::set<unsigned> OutRegs;
for (const auto &RegMaskPair : RPTracker.getPressure().LiveOutRegs) {
OutRegs.insert(RegMaskPair.RegUnit);
}
return OutRegs;
};
private:
void topologicalSort();
void moveLowLatencies();
public:
std::vector<unsigned> IsLowLatencySU;
std::vector<unsigned> LowLatencyOffset;
std::vector<unsigned> IsHighLatencySU;
std::vector<int> TopDownIndex2SU;
std::vector<int> BottomUpIndex2SU;
};
}
#endif