#ifndef LLVM_CODEGEN_MACHINEPIPELINER_H
#define LLVM_CODEGEN_MACHINEPIPELINER_H
#include "llvm/ADT/SetVector.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/CodeGen/RegisterClassInfo.h"
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
#include "llvm/CodeGen/ScheduleDAGMutation.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/InitializePasses.h"
#include <deque>
namespace llvm {
class AAResults;
class NodeSet;
class SMSchedule;
extern cl::opt<bool> SwpEnableCopyToPhi;
class MachinePipeliner : public MachineFunctionPass {
public:
MachineFunction *MF = nullptr;
MachineOptimizationRemarkEmitter *ORE = nullptr;
const MachineLoopInfo *MLI = nullptr;
const MachineDominatorTree *MDT = nullptr;
const InstrItineraryData *InstrItins;
const TargetInstrInfo *TII = nullptr;
RegisterClassInfo RegClassInfo;
bool disabledByPragma = false;
unsigned II_setByPragma = 0;
#ifndef NDEBUG
static int NumTries;
#endif
struct LoopInfo {
MachineBasicBlock *TBB = nullptr;
MachineBasicBlock *FBB = nullptr;
SmallVector<MachineOperand, 4> BrCond;
MachineInstr *LoopInductionVar = nullptr;
MachineInstr *LoopCompare = nullptr;
std::unique_ptr<TargetInstrInfo::PipelinerLoopInfo> LoopPipelinerInfo =
nullptr;
};
LoopInfo LI;
static char ID;
MachinePipeliner() : MachineFunctionPass(ID) {
initializeMachinePipelinerPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
private:
void preprocessPhiNodes(MachineBasicBlock &B);
bool canPipelineLoop(MachineLoop &L);
bool scheduleLoop(MachineLoop &L);
bool swingModuloScheduler(MachineLoop &L);
void setPragmaPipelineOptions(MachineLoop &L);
};
class SwingSchedulerDAG : public ScheduleDAGInstrs {
MachinePipeliner &Pass;
unsigned MII = 0;
unsigned MAX_II = 0;
bool Scheduled = false;
MachineLoop &Loop;
LiveIntervals &LIS;
const RegisterClassInfo &RegClassInfo;
unsigned II_setByPragma = 0;
TargetInstrInfo::PipelinerLoopInfo *LoopPipelinerInfo = nullptr;
ScheduleDAGTopologicalSort Topo;
struct NodeInfo {
int ASAP = 0;
int ALAP = 0;
int ZeroLatencyDepth = 0;
int ZeroLatencyHeight = 0;
NodeInfo() = default;
};
std::vector<NodeInfo> ScheduleInfo;
enum OrderKind { BottomUp = 0, TopDown = 1 };
SetVector<SUnit *> NodeOrder;
using NodeSetType = SmallVector<NodeSet, 8>;
using ValueMapTy = DenseMap<unsigned, unsigned>;
using MBBVectorTy = SmallVectorImpl<MachineBasicBlock *>;
using InstrMapTy = DenseMap<MachineInstr *, MachineInstr *>;
DenseMap<SUnit *, std::pair<unsigned, int64_t>> InstrChanges;
DenseMap<MachineInstr*, MachineInstr *> NewMIs;
std::vector<std::unique_ptr<ScheduleDAGMutation>> Mutations;
class Circuits {
std::vector<SUnit> &SUnits;
SetVector<SUnit *> Stack;
BitVector Blocked;
SmallVector<SmallPtrSet<SUnit *, 4>, 10> B;
SmallVector<SmallVector<int, 4>, 16> AdjK;
std::vector<int> *Node2Idx;
unsigned NumPaths;
static unsigned MaxPaths;
public:
Circuits(std::vector<SUnit> &SUs, ScheduleDAGTopologicalSort &Topo)
: SUnits(SUs), Blocked(SUs.size()), B(SUs.size()), AdjK(SUs.size()) {
Node2Idx = new std::vector<int>(SUs.size());
unsigned Idx = 0;
for (const auto &NodeNum : Topo)
Node2Idx->at(NodeNum) = Idx++;
}
~Circuits() { delete Node2Idx; }
void reset() {
Stack.clear();
Blocked.reset();
B.assign(SUnits.size(), SmallPtrSet<SUnit *, 4>());
NumPaths = 0;
}
void createAdjacencyStructure(SwingSchedulerDAG *DAG);
bool circuit(int V, int S, NodeSetType &NodeSets, bool HasBackedge = false);
void unblock(int U);
};
struct CopyToPhiMutation : public ScheduleDAGMutation {
void apply(ScheduleDAGInstrs *DAG) override;
};
public:
SwingSchedulerDAG(MachinePipeliner &P, MachineLoop &L, LiveIntervals &lis,
const RegisterClassInfo &rci, unsigned II,
TargetInstrInfo::PipelinerLoopInfo *PLI)
: ScheduleDAGInstrs(*P.MF, P.MLI, false), Pass(P), Loop(L), LIS(lis),
RegClassInfo(rci), II_setByPragma(II), LoopPipelinerInfo(PLI),
Topo(SUnits, &ExitSU) {
P.MF->getSubtarget().getSMSMutations(Mutations);
if (SwpEnableCopyToPhi)
Mutations.push_back(std::make_unique<CopyToPhiMutation>());
}
void schedule() override;
void finishBlock() override;
bool hasNewSchedule() { return Scheduled; }
int getASAP(SUnit *Node) { return ScheduleInfo[Node->NodeNum].ASAP; }
int getALAP(SUnit *Node) { return ScheduleInfo[Node->NodeNum].ALAP; }
int getMOV(SUnit *Node) { return getALAP(Node) - getASAP(Node); }
unsigned getDepth(SUnit *Node) { return Node->getDepth(); }
int getZeroLatencyDepth(SUnit *Node) {
return ScheduleInfo[Node->NodeNum].ZeroLatencyDepth;
}
unsigned getHeight(SUnit *Node) { return Node->getHeight(); }
int getZeroLatencyHeight(SUnit *Node) {
return ScheduleInfo[Node->NodeNum].ZeroLatencyHeight;
}
bool isBackedge(SUnit *Source, const SDep &Dep) {
if (Dep.getKind() != SDep::Anti)
return false;
return Source->getInstr()->isPHI() || Dep.getSUnit()->getInstr()->isPHI();
}
bool isLoopCarriedDep(SUnit *Source, const SDep &Dep, bool isSucc = true);
unsigned getDistance(SUnit *U, SUnit *V, const SDep &Dep) {
if (V->getInstr()->isPHI() && Dep.getKind() == SDep::Anti)
return 1;
return 0;
}
void applyInstrChange(MachineInstr *MI, SMSchedule &Schedule);
void fixupRegisterOverlaps(std::deque<SUnit *> &Instrs);
unsigned getInstrBaseReg(SUnit *SU) {
DenseMap<SUnit *, std::pair<unsigned, int64_t>>::iterator It =
InstrChanges.find(SU);
if (It != InstrChanges.end())
return It->second.first;
return 0;
}
void addMutation(std::unique_ptr<ScheduleDAGMutation> Mutation) {
Mutations.push_back(std::move(Mutation));
}
static bool classof(const ScheduleDAGInstrs *DAG) { return true; }
private:
void addLoopCarriedDependences(AAResults *AA);
void updatePhiDependences();
void changeDependences();
unsigned calculateResMII();
unsigned calculateRecMII(NodeSetType &RecNodeSets);
void findCircuits(NodeSetType &NodeSets);
void fuseRecs(NodeSetType &NodeSets);
void removeDuplicateNodes(NodeSetType &NodeSets);
void computeNodeFunctions(NodeSetType &NodeSets);
void registerPressureFilter(NodeSetType &NodeSets);
void colocateNodeSets(NodeSetType &NodeSets);
void checkNodeSets(NodeSetType &NodeSets);
void groupRemainingNodes(NodeSetType &NodeSets);
void addConnectedNodes(SUnit *SU, NodeSet &NewSet,
SetVector<SUnit *> &NodesAdded);
void computeNodeOrder(NodeSetType &NodeSets);
void checkValidNodeOrder(const NodeSetType &Circuits) const;
bool schedulePipeline(SMSchedule &Schedule);
bool computeDelta(MachineInstr &MI, unsigned &Delta);
MachineInstr *findDefInLoop(Register Reg);
bool canUseLastOffsetValue(MachineInstr *MI, unsigned &BasePos,
unsigned &OffsetPos, unsigned &NewBase,
int64_t &NewOffset);
void postprocessDAG();
void setMII(unsigned ResMII, unsigned RecMII);
void setMAX_II();
};
class NodeSet {
SetVector<SUnit *> Nodes;
bool HasRecurrence = false;
unsigned RecMII = 0;
int MaxMOV = 0;
unsigned MaxDepth = 0;
unsigned Colocate = 0;
SUnit *ExceedPressure = nullptr;
unsigned Latency = 0;
public:
using iterator = SetVector<SUnit *>::const_iterator;
NodeSet() = default;
NodeSet(iterator S, iterator E) : Nodes(S, E), HasRecurrence(true) {
Latency = 0;
for (const SUnit *Node : Nodes) {
DenseMap<SUnit *, unsigned> SuccSUnitLatency;
for (const SDep &Succ : Node->Succs) {
auto SuccSUnit = Succ.getSUnit();
if (!Nodes.count(SuccSUnit))
continue;
unsigned CurLatency = Succ.getLatency();
unsigned MaxLatency = 0;
if (SuccSUnitLatency.count(SuccSUnit))
MaxLatency = SuccSUnitLatency[SuccSUnit];
if (CurLatency > MaxLatency)
SuccSUnitLatency[SuccSUnit] = CurLatency;
}
for (auto SUnitLatency : SuccSUnitLatency)
Latency += SUnitLatency.second;
}
}
bool insert(SUnit *SU) { return Nodes.insert(SU); }
void insert(iterator S, iterator E) { Nodes.insert(S, E); }
template <typename UnaryPredicate> bool remove_if(UnaryPredicate P) {
return Nodes.remove_if(P);
}
unsigned count(SUnit *SU) const { return Nodes.count(SU); }
bool hasRecurrence() { return HasRecurrence; };
unsigned size() const { return Nodes.size(); }
bool empty() const { return Nodes.empty(); }
SUnit *getNode(unsigned i) const { return Nodes[i]; };
void setRecMII(unsigned mii) { RecMII = mii; };
void setColocate(unsigned c) { Colocate = c; };
void setExceedPressure(SUnit *SU) { ExceedPressure = SU; }
bool isExceedSU(SUnit *SU) { return ExceedPressure == SU; }
int compareRecMII(NodeSet &RHS) { return RecMII - RHS.RecMII; }
int getRecMII() { return RecMII; }
void computeNodeSetInfo(SwingSchedulerDAG *SSD) {
for (SUnit *SU : *this) {
MaxMOV = std::max(MaxMOV, SSD->getMOV(SU));
MaxDepth = std::max(MaxDepth, SSD->getDepth(SU));
}
}
unsigned getLatency() { return Latency; }
unsigned getMaxDepth() { return MaxDepth; }
void clear() {
Nodes.clear();
RecMII = 0;
HasRecurrence = false;
MaxMOV = 0;
MaxDepth = 0;
Colocate = 0;
ExceedPressure = nullptr;
}
operator SetVector<SUnit *> &() { return Nodes; }
bool operator>(const NodeSet &RHS) const {
if (RecMII == RHS.RecMII) {
if (Colocate != 0 && RHS.Colocate != 0 && Colocate != RHS.Colocate)
return Colocate < RHS.Colocate;
if (MaxMOV == RHS.MaxMOV)
return MaxDepth > RHS.MaxDepth;
return MaxMOV < RHS.MaxMOV;
}
return RecMII > RHS.RecMII;
}
bool operator==(const NodeSet &RHS) const {
return RecMII == RHS.RecMII && MaxMOV == RHS.MaxMOV &&
MaxDepth == RHS.MaxDepth;
}
bool operator!=(const NodeSet &RHS) const { return !operator==(RHS); }
iterator begin() { return Nodes.begin(); }
iterator end() { return Nodes.end(); }
void print(raw_ostream &os) const;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void dump() const;
#endif
};
static const int DefaultProcResSize = 16;
class ResourceManager {
private:
const MCSubtargetInfo *STI;
const MCSchedModel &SM;
const bool UseDFA;
std::unique_ptr<DFAPacketizer> DFAResources;
llvm::SmallVector<uint64_t, DefaultProcResSize> ProcResourceMasks;
llvm::SmallVector<uint64_t, DefaultProcResSize> ProcResourceCount;
public:
ResourceManager(const TargetSubtargetInfo *ST)
: STI(ST), SM(ST->getSchedModel()), UseDFA(ST->useDFAforSMS()),
ProcResourceMasks(SM.getNumProcResourceKinds(), 0),
ProcResourceCount(SM.getNumProcResourceKinds(), 0) {
if (UseDFA)
DFAResources.reset(ST->getInstrInfo()->CreateTargetScheduleState(*ST));
initProcResourceVectors(SM, ProcResourceMasks);
}
void initProcResourceVectors(const MCSchedModel &SM,
SmallVectorImpl<uint64_t> &Masks);
bool canReserveResources(const MCInstrDesc *MID) const;
void reserveResources(const MCInstrDesc *MID);
bool canReserveResources(const MachineInstr &MI) const;
void reserveResources(const MachineInstr &MI);
void clearResources();
};
class SMSchedule {
private:
DenseMap<int, std::deque<SUnit *>> ScheduledInstrs;
std::map<SUnit *, int> InstrToCycle;
int FirstCycle = 0;
int LastCycle = 0;
int InitiationInterval = 0;
const TargetSubtargetInfo &ST;
MachineRegisterInfo &MRI;
ResourceManager ProcItinResources;
public:
SMSchedule(MachineFunction *mf)
: ST(mf->getSubtarget()), MRI(mf->getRegInfo()), ProcItinResources(&ST) {}
void reset() {
ScheduledInstrs.clear();
InstrToCycle.clear();
FirstCycle = 0;
LastCycle = 0;
InitiationInterval = 0;
}
void setInitiationInterval(int ii) { InitiationInterval = ii; }
int getInitiationInterval() const { return InitiationInterval; }
int getFirstCycle() const { return FirstCycle; }
int getFinalCycle() const { return FirstCycle + InitiationInterval - 1; }
int earliestCycleInChain(const SDep &Dep);
int latestCycleInChain(const SDep &Dep);
void computeStart(SUnit *SU, int *MaxEarlyStart, int *MinLateStart,
int *MinEnd, int *MaxStart, int II, SwingSchedulerDAG *DAG);
bool insert(SUnit *SU, int StartCycle, int EndCycle, int II);
using sched_iterator = DenseMap<int, std::deque<SUnit *>>::iterator;
using const_sched_iterator =
DenseMap<int, std::deque<SUnit *>>::const_iterator;
bool isScheduledAtStage(SUnit *SU, unsigned StageNum) {
return (stageScheduled(SU) == (int)StageNum);
}
int stageScheduled(SUnit *SU) const {
std::map<SUnit *, int>::const_iterator it = InstrToCycle.find(SU);
if (it == InstrToCycle.end())
return -1;
return (it->second - FirstCycle) / InitiationInterval;
}
unsigned cycleScheduled(SUnit *SU) const {
std::map<SUnit *, int>::const_iterator it = InstrToCycle.find(SU);
assert(it != InstrToCycle.end() && "Instruction hasn't been scheduled.");
return (it->second - FirstCycle) % InitiationInterval;
}
unsigned getMaxStageCount() {
return (LastCycle - FirstCycle) / InitiationInterval;
}
std::deque<SUnit *> &getInstructions(int cycle) {
return ScheduledInstrs[cycle];
}
SmallSet<SUnit *, 8>
computeUnpipelineableNodes(SwingSchedulerDAG *SSD,
TargetInstrInfo::PipelinerLoopInfo *PLI);
bool
normalizeNonPipelinedInstructions(SwingSchedulerDAG *SSD,
TargetInstrInfo::PipelinerLoopInfo *PLI);
bool isValidSchedule(SwingSchedulerDAG *SSD);
void finalizeSchedule(SwingSchedulerDAG *SSD);
void orderDependence(SwingSchedulerDAG *SSD, SUnit *SU,
std::deque<SUnit *> &Insts);
bool isLoopCarried(SwingSchedulerDAG *SSD, MachineInstr &Phi);
bool isLoopCarriedDefOfUse(SwingSchedulerDAG *SSD, MachineInstr *Def,
MachineOperand &MO);
void print(raw_ostream &os) const;
void dump() const;
};
}
#endif