72#include "llvm/Config/llvm-config.h"
101#define DEBUG_TYPE "pipeliner"
103STATISTIC(NumTrytoPipeline,
"Number of loops that we attempt to pipeline");
104STATISTIC(NumPipelined,
"Number of loops software pipelined");
105STATISTIC(NumNodeOrderIssues,
"Number of node order issues found");
106STATISTIC(NumFailBranch,
"Pipeliner abort due to unknown branch");
107STATISTIC(NumFailLoop,
"Pipeliner abort due to unsupported loop");
108STATISTIC(NumFailPreheader,
"Pipeliner abort due to missing preheader");
109STATISTIC(NumFailLargeMaxMII,
"Pipeliner abort due to MaxMII too large");
110STATISTIC(NumFailZeroMII,
"Pipeliner abort due to zero MII");
111STATISTIC(NumFailNoSchedule,
"Pipeliner abort due to no schedule found");
112STATISTIC(NumFailZeroStage,
"Pipeliner abort due to zero stage");
113STATISTIC(NumFailLargeMaxStage,
"Pipeliner abort due to too many stages");
114STATISTIC(NumFailTooManyStores,
"Pipeliner abort due to too many stores");
123 cl::desc(
"Size limit for the MII."),
129 cl::desc(
"Force pipeliner to use specified II."),
135 cl::desc(
"Maximum stages allowed in the generated scheduled."),
142 cl::desc(
"Prune dependences between unrelated Phi nodes."),
149 cl::desc(
"Prune loop carried order dependences."),
167 cl::desc(
"Instead of emitting the pipelined code, annotate instructions "
168 "with the generated schedule for feeding into the "
169 "-modulo-schedule-test pass"));
174 "Use the experimental peeling code generator for software pipelining"));
182 cl::desc(
"Limit register pressure of scheduled loop"));
187 cl::desc(
"Margin representing the unused percentage of "
188 "the register pressure limit"));
192 cl::desc(
"Use the MVE code generator for software pipelining"));
197 "pipeliner-max-num-stores",
205 cl::desc(
"Enable CopyToPhi DAG Mutation"));
210 "pipeliner-force-issue-width",
217 cl::desc(
"Set how to use window scheduling algorithm."),
219 "Turn off window algorithm."),
221 "Use window algorithm after SMS algorithm fails."),
223 "Use window algorithm instead of SMS algorithm.")));
225unsigned SwingSchedulerDAG::Circuits::MaxPaths = 5;
230 "Modulo Software Pipelining",
false,
false)
272 enum class InstrTag {
281 TaggedSUnit(
SUnit *SU, InstrTag Tag)
284 InstrTag
getTag()
const {
return InstrTag(getInt()); }
289 struct NoBarrierInstsChunk {
294 void append(
SUnit *SU);
299 std::vector<SUnit> &SUnits;
305 std::vector<BitVector> LoopCarried;
318 std::vector<TaggedSUnit> TaggedSUnits;
330 return LoopCarried[Idx];
335 std::optional<InstrTag> getInstrTag(
SUnit *SU)
const;
337 void addLoopCarriedDepenenciesForChunks(
const NoBarrierInstsChunk &From,
338 const NoBarrierInstsChunk &To);
345 void computeDependenciesAux();
347 void setLoopCarriedDep(
const SUnit *Src,
const SUnit *Dst) {
348 LoopCarried[Src->NodeNum].set(Dst->NodeNum);
401 bool useSwingModuloScheduler();
402 bool useWindowScheduler(
bool Changed);
408int MachinePipelinerImpl::NumTries = 0;
417 TM(&
MF.getTarget()) {}
422 for (
const auto &L : *
MLI)
449 MachinePipelinerImpl MP(MF, GetMLI(), LIS, GetAA(), GetORE(), GetRCI(),
478 return MDTWrapper ? &MDTWrapper->getDomTree() :
nullptr;
520bool MachinePipelinerImpl::scheduleLoop(
MachineLoop &L) {
522 for (
const auto &InnerLoop : L)
523 Changed |= scheduleLoop(*InnerLoop);
535 setPragmaPipelineOptions(L);
536 if (!canPipelineLoop(L)) {
540 L.getStartLoc(), L.getHeader())
541 <<
"Failed to pipeline loop";
544 LI.LoopPipelinerInfo.reset();
549 if (useSwingModuloScheduler())
550 Changed = swingModuloScheduler(L);
552 if (useWindowScheduler(
Changed))
553 Changed = runWindowScheduler(L);
555#ifdef EXPENSIVE_CHECKS
557 "Dominator tree not updated for the pipelined loop");
560 LI.LoopPipelinerInfo.reset();
564void MachinePipelinerImpl::setPragmaPipelineOptions(MachineLoop &L) {
569 MachineBasicBlock *LBLK =
L.getTopBlock();
579 MDNode *LoopID = TI->
getMetadata(LLVMContext::MD_loop);
580 if (LoopID ==
nullptr)
597 if (S->
getString() ==
"llvm.loop.pipeline.initiationinterval") {
599 "Pipeline initiation interval hint metadata should have two operands.");
603 }
else if (S->
getString() ==
"llvm.loop.pipeline.disable") {
616 auto It = PhiDeps.find(
Reg);
617 if (It == PhiDeps.end())
628 for (
unsigned Dep : It->second) {
643 unsigned DefReg =
MI.getOperand(0).getReg();
647 for (
unsigned I = 1;
I <
MI.getNumOperands();
I += 2)
648 Ins->second.push_back(
MI.getOperand(
I).getReg());
655 for (
const auto &KV : PhiDeps) {
656 unsigned Reg = KV.first;
667bool MachinePipelinerImpl::canPipelineLoop(MachineLoop &L) {
668 if (
L.getNumBlocks() != 1) {
670 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
671 L.getStartLoc(),
L.getHeader())
672 <<
"Not a single basic block: "
673 <<
ore::NV(
"NumBlocks",
L.getNumBlocks());
685 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
686 L.getStartLoc(),
L.getHeader())
687 <<
"Disabled by Pragma.";
697 if (
TII->analyzeBranch(*
L.getHeader(),
LI.TBB,
LI.FBB,
LI.BrCond)) {
698 LLVM_DEBUG(
dbgs() <<
"Unable to analyzeBranch, can NOT pipeline Loop\n");
701 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
702 L.getStartLoc(),
L.getHeader())
703 <<
"The branch can't be understood";
708 LI.LoopInductionVar =
nullptr;
709 LI.LoopCompare =
nullptr;
710 LI.LoopPipelinerInfo =
TII->analyzeLoopForPipelining(
L.getTopBlock());
711 if (!
LI.LoopPipelinerInfo) {
712 LLVM_DEBUG(
dbgs() <<
"Unable to analyzeLoop, can NOT pipeline Loop\n");
715 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
716 L.getStartLoc(),
L.getHeader())
717 <<
"The loop structure is not supported";
722 if (!
L.getLoopPreheader()) {
723 LLVM_DEBUG(
dbgs() <<
"Preheader not found, can NOT pipeline Loop\n");
726 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
727 L.getStartLoc(),
L.getHeader())
728 <<
"No loop preheader found";
733 unsigned NumStores = 0;
734 for (MachineInstr &
MI : *
L.getHeader())
739 NumFailTooManyStores++;
741 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
742 L.getStartLoc(),
L.getHeader())
743 <<
"Too many store instructions in the loop: "
744 <<
ore::NV(
"NumStores", NumStores) <<
" > "
751 preprocessPhiNodes(*
L.getHeader());
755void MachinePipelinerImpl::preprocessPhiNodes(MachineBasicBlock &
B) {
756 MachineRegisterInfo &
MRI =
MF->getRegInfo();
757 SlotIndexes &Slots = *
LIS->getSlotIndexes();
759 for (MachineInstr &PI :
B.phis()) {
760 MachineOperand &DefOp = PI.getOperand(0);
764 for (
unsigned i = 1, n = PI.getNumOperands(); i != n; i += 2) {
765 MachineOperand &RegOp = PI.getOperand(i);
772 MachineBasicBlock &PredB = *PI.getOperand(i+1).getMBB();
789bool MachinePipelinerImpl::swingModuloScheduler(MachineLoop &L) {
790 assert(
L.getBlocks().size() == 1 &&
"SMS works on single blocks only.");
793 LI.LoopPipelinerInfo.get(),
AA,
MDT);
795 MachineBasicBlock *
MBB =
L.getHeader();
813 return SMS.hasNewSchedule();
829bool MachinePipelinerImpl::runWindowScheduler(
MachineLoop &L) {
841bool MachinePipelinerImpl::useSwingModuloScheduler() {
846bool MachinePipelinerImpl::useWindowScheduler(
bool Changed) {
853 "llvm.loop.pipeline.initiationinterval is set.\n");
861void SwingSchedulerDAG::setMII(
unsigned ResMII,
unsigned RecMII) {
864 else if (II_setByPragma > 0)
865 MII = II_setByPragma;
867 MII = std::max(ResMII, RecMII);
870void SwingSchedulerDAG::setMAX_II() {
873 else if (II_setByPragma > 0)
874 MAX_II = II_setByPragma;
888 RegClassInfo(rci), II_setByPragma(
II), LoopPipelinerInfo(PLI),
891 MF.getSubtarget().getSMSMutations(Mutations);
893 Mutations.push_back(std::make_unique<CopyToPhiMutation>());
894 BAA.enableCrossIterationMode();
902 updatePhiDependences();
903 Topo.InitDAGTopologicalSorting();
909 dbgs() <<
"===== Loop Carried Edges Begin =====\n";
912 dbgs() <<
"===== Loop Carried Edges End =====\n";
915 NodeSetType NodeSets;
916 findCircuits(NodeSets);
917 NodeSetType Circuits = NodeSets;
920 unsigned ResMII = calculateResMII();
921 unsigned RecMII = calculateRecMII(NodeSets);
929 setMII(ResMII, RecMII);
933 <<
" (rec=" << RecMII <<
", res=" << ResMII <<
")\n");
941 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
942 <<
"Invalid Minimal Initiation Interval: 0";
950 <<
", we don't pipeline large loops\n");
951 NumFailLargeMaxMII++;
954 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
955 <<
"Minimal Initiation Interval too large: "
956 <<
ore::NV(
"MII", (
int)MII) <<
" > "
958 <<
"Refer to -pipeliner-max-mii.";
963 computeNodeFunctions(NodeSets);
965 registerPressureFilter(NodeSets);
967 colocateNodeSets(NodeSets);
969 checkNodeSets(NodeSets);
972 for (
auto &
I : NodeSets) {
973 dbgs() <<
" Rec NodeSet ";
980 groupRemainingNodes(NodeSets);
982 removeDuplicateNodes(NodeSets);
985 for (
auto &
I : NodeSets) {
986 dbgs() <<
" NodeSet ";
991 computeNodeOrder(NodeSets);
994 checkValidNodeOrder(Circuits);
997 Scheduled = schedulePipeline(Schedule);
1001 NumFailNoSchedule++;
1004 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
1005 <<
"Unable to find schedule";
1012 if (numStages == 0) {
1017 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
1018 <<
"No need to pipeline - no overlapped iterations in schedule.";
1025 <<
" : too many stages, abort\n");
1026 NumFailLargeMaxStage++;
1029 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
1030 <<
"Too many stages in schedule: "
1031 <<
ore::NV(
"numStages", (
int)numStages) <<
" > "
1033 <<
". Refer to -pipeliner-max-stages.";
1041 <<
"Pipelined succesfully!";
1046 std::vector<MachineInstr *> OrderedInsts;
1050 OrderedInsts.push_back(SU->getInstr());
1051 Cycles[SU->getInstr()] = Cycle;
1056 for (
auto &KV : NewMIs) {
1057 Cycles[KV.first] = Cycles[KV.second];
1058 Stages[KV.first] = Stages[KV.second];
1059 NewInstrChanges[KV.first] = InstrChanges[
getSUnit(KV.first)];
1066 "Cannot serialize a schedule with InstrChanges!");
1076 LoopPipelinerInfo->isMVEExpanderSupported() &&
1090 for (
auto &KV : NewMIs)
1091 MF.deleteMachineInstr(KV.second);
1102 assert(Phi.isPHI() &&
"Expecting a Phi.");
1106 for (
unsigned i = 1, e = Phi.getNumOperands(); i != e; i += 2)
1107 if (Phi.getOperand(i + 1).getMBB() !=
Loop)
1108 InitVal = Phi.getOperand(i).getReg();
1110 LoopVal = Phi.getOperand(i).getReg();
1112 assert(InitVal && LoopVal &&
"Unexpected Phi structure.");
1118 for (
unsigned i = 1, e = Phi.getNumOperands(); i != e; i += 2)
1119 if (Phi.getOperand(i + 1).getMBB() == LoopBB)
1120 return Phi.getOperand(i).getReg();
1129 while (!Worklist.
empty()) {
1131 for (
const auto &
SI : SU->
Succs) {
1132 SUnit *SuccSU =
SI.getSUnit();
1134 if (Visited.
count(SuccSU))
1147 if (!getUnderlyingObjects())
1172bool SUnitWithMemInfo::getUnderlyingObjects() {
1174 if (!
MI->hasOneMemOperand())
1192 const SUnitWithMemInfo &Dst,
1195 if (Src.isTriviallyDisjoint(Dst))
1211 if (Src.isUnknown() || Dst.isUnknown())
1213 if (Src.MemOpValue == Dst.MemOpValue && Src.MemOpOffset <= Dst.MemOpOffset)
1224 for (
const Value *SrcObj : Src.UnderlyingObjs)
1225 for (
const Value *DstObj : Dst.UnderlyingObjs)
1233void LoopCarriedOrderDepsTracker::NoBarrierInstsChunk::append(SUnit *SU) {
1236 Stores.emplace_back(SU);
1237 else if (
MI->mayLoad())
1238 Loads.emplace_back(SU);
1239 else if (
MI->mayRaiseFPException())
1240 FPExceptions.emplace_back(SU);
1247 : DAG(SSD), BAA(BAA), SUnits(DAG->SUnits), N(SUnits.
size()),
1248 LoopCarried(N,
BitVector(N)), TII(TII) {}
1252 for (
auto &SU : SUnits) {
1253 auto Tagged = getInstrTag(&SU);
1258 TaggedSUnits.emplace_back(&SU, *Tagged);
1261 computeDependenciesAux();
1264std::optional<LoopCarriedOrderDepsTracker::InstrTag>
1265LoopCarriedOrderDepsTracker::getInstrTag(
SUnit *SU)
const {
1267 if (
TII->isGlobalMemoryObject(
MI))
1268 return InstrTag::Barrier;
1270 if (
MI->mayStore() ||
1271 (
MI->mayLoad() && !
MI->isDereferenceableInvariantLoad()))
1272 return InstrTag::LoadOrStore;
1274 if (
MI->mayRaiseFPException())
1275 return InstrTag::FPExceptions;
1277 return std::nullopt;
1280void LoopCarriedOrderDepsTracker::addDependenciesBetweenSUs(
1281 const SUnitWithMemInfo &Src,
const SUnitWithMemInfo &Dst) {
1283 if (Src.SU == Dst.SU)
1287 setLoopCarriedDep(Src.SU, Dst.SU);
1290void LoopCarriedOrderDepsTracker::addLoopCarriedDepenenciesForChunks(
1291 const NoBarrierInstsChunk &From,
const NoBarrierInstsChunk &To) {
1293 for (
const SUnitWithMemInfo &Src : From.Loads)
1294 for (
const SUnitWithMemInfo &Dst : To.Stores)
1295 addDependenciesBetweenSUs(Src, Dst);
1298 for (
const SUnitWithMemInfo &Src : From.Stores)
1299 for (
const SUnitWithMemInfo &Dst : To.Loads)
1300 addDependenciesBetweenSUs(Src, Dst);
1303 for (
const SUnitWithMemInfo &Src : From.Stores)
1304 for (
const SUnitWithMemInfo &Dst : To.Stores)
1305 addDependenciesBetweenSUs(Src, Dst);
1308void LoopCarriedOrderDepsTracker::computeDependenciesAux() {
1310 SUnit *FirstBarrier =
nullptr;
1311 SUnit *LastBarrier =
nullptr;
1312 for (
const auto &TSU : TaggedSUnits) {
1313 InstrTag
Tag = TSU.getTag();
1314 SUnit *SU = TSU.getPointer();
1316 case InstrTag::Barrier:
1320 Chunks.emplace_back();
1322 case InstrTag::LoadOrStore:
1323 case InstrTag::FPExceptions:
1324 Chunks.back().append(SU);
1332 for (
const NoBarrierInstsChunk &Chunk : Chunks)
1333 addLoopCarriedDepenenciesForChunks(Chunk, Chunk);
1362 assert(LastBarrier &&
"Both barriers should be set.");
1365 for (
const SUnitWithMemInfo &Dst : Chunks.front().Loads)
1366 setLoopCarriedDep(LastBarrier, Dst.SU);
1367 for (
const SUnitWithMemInfo &Dst : Chunks.front().Stores)
1368 setLoopCarriedDep(LastBarrier, Dst.SU);
1369 for (
const SUnitWithMemInfo &Dst : Chunks.front().FPExceptions)
1370 setLoopCarriedDep(LastBarrier, Dst.SU);
1373 for (
const SUnitWithMemInfo &Src : Chunks.back().Loads)
1374 setLoopCarriedDep(Src.SU, FirstBarrier);
1375 for (
const SUnitWithMemInfo &Src : Chunks.back().Stores)
1376 setLoopCarriedDep(Src.SU, FirstBarrier);
1377 for (
const SUnitWithMemInfo &Src : Chunks.back().FPExceptions)
1378 setLoopCarriedDep(Src.SU, FirstBarrier);
1381 if (FirstBarrier != LastBarrier)
1382 setLoopCarriedDep(LastBarrier, FirstBarrier);
1391LoopCarriedEdges SwingSchedulerDAG::addLoopCarriedDependences() {
1392 LoopCarriedEdges LCE;
1396 LCODTracker.computeDependencies();
1397 for (
unsigned I = 0;
I != SUnits.size();
I++)
1398 for (
const int Succ : LCODTracker.getLoopCarried(
I).set_bits())
1411void SwingSchedulerDAG::updatePhiDependences() {
1413 const TargetSubtargetInfo &
ST = MF.
getSubtarget<TargetSubtargetInfo>();
1416 for (SUnit &
I : SUnits) {
1421 MachineInstr *
MI =
I.getInstr();
1423 for (
const MachineOperand &MO :
MI->operands()) {
1436 MachineInstr *
UseMI = &*UI;
1437 SUnit *SU = getSUnit(
UseMI);
1463 }
else if (MO.isUse()) {
1466 if (
DefMI ==
nullptr)
1468 SUnit *SU = getSUnit(
DefMI);
1473 ST.adjustSchedDependency(SU, 0, &
I, MO.getOperandNo(), Dep,
1480 if (SU->
NodeNum <
I.NodeNum && !
I.isPred(SU))
1489 for (
auto &PI :
I.Preds) {
1490 MachineInstr *PMI = PI.getSUnit()->getInstr();
1492 if (
I.getInstr()->isPHI()) {
1501 for (
const SDep &
D : RemoveDeps)
1508void SwingSchedulerDAG::changeDependences() {
1512 for (SUnit &
I : SUnits) {
1513 unsigned BasePos = 0, OffsetPos = 0;
1515 int64_t NewOffset = 0;
1516 if (!canUseLastOffsetValue(
I.getInstr(), BasePos, OffsetPos, NewBase,
1521 Register OrigBase =
I.getInstr()->getOperand(BasePos).getReg();
1525 SUnit *DefSU = getSUnit(
DefMI);
1532 SUnit *LastSU = getSUnit(LastMI);
1536 if (Topo.IsReachable(&
I, LastSU))
1541 for (
const SDep &
P :
I.Preds)
1542 if (
P.getSUnit() == DefSU)
1544 for (
const SDep &
D : Deps) {
1545 Topo.RemovePred(&
I,
D.getSUnit());
1550 for (
auto &
P : LastSU->
Preds)
1553 for (
const SDep &
D : Deps) {
1554 Topo.RemovePred(LastSU,
D.getSUnit());
1561 Topo.AddPred(LastSU, &
I);
1566 InstrChanges[&
I] = std::make_pair(NewBase, NewOffset);
1577 std::vector<MachineInstr *> &OrderedInsts,
1585 Stage <= LastStage; ++Stage) {
1588 Instrs[Cycle].push_front(SU);
1595 std::deque<SUnit *> &CycleInstrs = Instrs[Cycle];
1597 for (
SUnit *SU : CycleInstrs) {
1599 OrderedInsts.push_back(
MI);
1609struct FuncUnitSorter {
1610 const InstrItineraryData *InstrItins;
1611 const MCSubtargetInfo *STI;
1612 DenseMap<InstrStage::FuncUnits, unsigned>
Resources;
1614 FuncUnitSorter(
const TargetSubtargetInfo &TSI)
1615 : InstrItins(TSI.getInstrItineraryData()), STI(&TSI) {}
1620 unsigned minFuncUnits(
const MachineInstr *Inst,
1623 unsigned min = UINT_MAX;
1624 if (InstrItins && !InstrItins->
isEmpty()) {
1625 for (
const InstrStage &IS :
1627 InstrItins->
endStage(SchedClass))) {
1630 if (numAlternatives <
min) {
1631 min = numAlternatives;
1638 const MCSchedClassDesc *SCDesc =
1645 for (
const MCWriteProcResEntry &PRE :
1648 if (!PRE.ReleaseAtCycle)
1650 const MCProcResourceDesc *ProcResource =
1652 unsigned NumUnits = ProcResource->
NumUnits;
1653 if (NumUnits <
min) {
1655 F = PRE.ProcResourceIdx;
1660 llvm_unreachable(
"Should have non-empty InstrItins or hasInstrSchedModel!");
1668 void calcCriticalResources(MachineInstr &
MI) {
1669 unsigned SchedClass =
MI.getDesc().getSchedClass();
1670 if (InstrItins && !InstrItins->
isEmpty()) {
1671 for (
const InstrStage &IS :
1673 InstrItins->
endStage(SchedClass))) {
1681 const MCSchedClassDesc *SCDesc =
1688 for (
const MCWriteProcResEntry &PRE :
1691 if (!PRE.ReleaseAtCycle)
1697 llvm_unreachable(
"Should have non-empty InstrItins or hasInstrSchedModel!");
1701 bool operator()(
const MachineInstr *IS1,
const MachineInstr *IS2)
const {
1703 unsigned MFUs1 = minFuncUnits(IS1, F1);
1704 unsigned MFUs2 = minFuncUnits(IS2, F2);
1707 return MFUs1 > MFUs2;
1712class HighRegisterPressureDetector {
1713 MachineBasicBlock *OrigMBB;
1714 const MachineRegisterInfo &
MRI;
1715 const TargetRegisterInfo *
TRI;
1717 const unsigned PSetNum;
1723 std::vector<unsigned> InitSetPressure;
1727 std::vector<unsigned> PressureSetLimit;
1729 DenseMap<MachineInstr *, RegisterOperands> ROMap;
1731 using Instr2LastUsesTy = DenseMap<MachineInstr *, SmallSet<VirtRegOrUnit, 4>>;
1734 using OrderedInstsTy = std::vector<MachineInstr *>;
1735 using Instr2StageTy = DenseMap<MachineInstr *, unsigned>;
1738 static void dumpRegisterPressures(
const std::vector<unsigned> &Pressures) {
1739 if (Pressures.size() == 0) {
1743 for (
unsigned P : Pressures) {
1751 void dumpPSet(VirtRegOrUnit VRegOrUnit)
const {
1755 dbgs() << *PSetIter <<
' ';
1760 void increaseRegisterPressure(std::vector<unsigned> &Pressure,
1761 VirtRegOrUnit VRegOrUnit)
const {
1764 for (; PSetIter.isValid(); ++PSetIter)
1765 Pressure[*PSetIter] += Weight;
1768 void decreaseRegisterPressure(std::vector<unsigned> &Pressure,
1769 VirtRegOrUnit VRegOrUnit)
const {
1771 unsigned Weight = PSetIter.getWeight();
1772 for (; PSetIter.isValid(); ++PSetIter) {
1773 auto &
P = Pressure[*PSetIter];
1775 "register pressure must be greater than or equal weight");
1781 bool isReservedRegUnit(VirtRegOrUnit VRegOrUnit)
const {
1786 bool isDefinedInThisLoop(VirtRegOrUnit VRegOrUnit)
const {
1799 void computeLiveIn() {
1800 SmallSet<VirtRegOrUnit, 8>
Used;
1801 for (
auto &
MI : *OrigMBB) {
1802 if (
MI.isDebugInstr())
1804 for (
auto &Use : ROMap[&
MI].
Uses) {
1805 VirtRegOrUnit
Reg =
Use.VRegOrUnit;
1808 if (
MI.isPHI() &&
Reg.isVirtualReg() &&
1811 if (isReservedRegUnit(
Reg))
1813 if (isDefinedInThisLoop(
Reg))
1819 for (
auto LiveIn : Used)
1820 increaseRegisterPressure(InitSetPressure, LiveIn);
1824 void computePressureSetLimit(
const RegisterClassInfo &RCI) {
1825 for (
unsigned PSet = 0; PSet < PSetNum; PSet++)
1840 Instr2LastUsesTy computeLastUses(
const OrderedInstsTy &OrderedInsts,
1841 Instr2StageTy &Stages)
const {
1846 SmallSet<VirtRegOrUnit, 8> TargetRegs;
1847 const auto UpdateTargetRegs = [
this, &TargetRegs](VirtRegOrUnit
Reg) {
1848 if (isDefinedInThisLoop(
Reg))
1851 for (MachineInstr *
MI : OrderedInsts) {
1854 UpdateTargetRegs(VirtRegOrUnit(
Reg));
1856 for (
auto &Use : ROMap.
find(
MI)->getSecond().Uses)
1857 UpdateTargetRegs(
Use.VRegOrUnit);
1861 const auto InstrScore = [&Stages](MachineInstr *
MI) {
1862 return Stages[
MI] +
MI->isPHI();
1865 std::map<VirtRegOrUnit, MachineInstr *> LastUseMI;
1867 for (
auto &Use : ROMap.
find(
MI)->getSecond().Uses) {
1868 VirtRegOrUnit
Reg =
Use.VRegOrUnit;
1873 MachineInstr *Orig = Ite->second;
1874 MachineInstr *
New =
MI;
1875 if (InstrScore(Orig) < InstrScore(New))
1881 Instr2LastUsesTy LastUses;
1882 for (
auto [
Reg,
MI] : LastUseMI)
1883 LastUses[
MI].insert(
Reg);
1899 std::vector<unsigned>
1900 computeMaxSetPressure(
const OrderedInstsTy &OrderedInsts,
1901 Instr2StageTy &Stages,
1902 const unsigned StageCount)
const {
1903 using RegSetTy = SmallSet<VirtRegOrUnit, 16>;
1909 auto CurSetPressure = InitSetPressure;
1910 auto MaxSetPressure = InitSetPressure;
1911 auto LastUses = computeLastUses(OrderedInsts, Stages);
1914 dbgs() <<
"Ordered instructions:\n";
1915 for (MachineInstr *
MI : OrderedInsts) {
1916 dbgs() <<
"Stage " << Stages[
MI] <<
": ";
1921 const auto InsertReg = [
this, &CurSetPressure](RegSetTy &RegSet,
1922 VirtRegOrUnit
Reg) {
1923 if (isReservedRegUnit(
Reg))
1931 increaseRegisterPressure(CurSetPressure,
Reg);
1935 const auto EraseReg = [
this, &CurSetPressure](RegSetTy &RegSet,
1936 VirtRegOrUnit
Reg) {
1937 if (isReservedRegUnit(
Reg))
1941 if (!RegSet.contains(
Reg))
1946 decreaseRegisterPressure(CurSetPressure,
Reg);
1950 for (
unsigned I = 0;
I < StageCount;
I++) {
1951 for (MachineInstr *
MI : OrderedInsts) {
1952 const auto Stage = Stages[
MI];
1956 const unsigned Iter =
I - Stage;
1958 for (
auto &Def : ROMap.
find(
MI)->getSecond().Defs)
1959 InsertReg(LiveRegSets[Iter],
Def.VRegOrUnit);
1961 for (
auto LastUse : LastUses[
MI]) {
1964 EraseReg(LiveRegSets[Iter - 1], LastUse);
1966 EraseReg(LiveRegSets[Iter], LastUse);
1970 for (
unsigned PSet = 0; PSet < PSetNum; PSet++)
1971 MaxSetPressure[PSet] =
1972 std::max(MaxSetPressure[PSet], CurSetPressure[PSet]);
1975 dbgs() <<
"CurSetPressure=";
1976 dumpRegisterPressures(CurSetPressure);
1977 dbgs() <<
" iter=" << Iter <<
" stage=" << Stage <<
":";
1983 return MaxSetPressure;
1987 HighRegisterPressureDetector(MachineBasicBlock *OrigMBB,
1989 : OrigMBB(OrigMBB),
MRI(MF.getRegInfo()),
1990 TRI(MF.getSubtarget().getRegisterInfo()),
1991 PSetNum(
TRI->getNumRegPressureSets()), InitSetPressure(PSetNum, 0),
1992 PressureSetLimit(PSetNum, 0) {}
1996 void init(
const RegisterClassInfo &RCI) {
1997 for (MachineInstr &
MI : *OrigMBB) {
1998 if (
MI.isDebugInstr())
2000 ROMap[&
MI].collect(
MI, *
TRI,
MRI,
false,
true);
2004 computePressureSetLimit(RCI);
2009 bool detect(
const SwingSchedulerDAG *SSD, SMSchedule &Schedule,
2010 const unsigned MaxStage)
const {
2012 "the percentage of the margin must be between 0 to 100");
2014 OrderedInstsTy OrderedInsts;
2015 Instr2StageTy Stages;
2017 const auto MaxSetPressure =
2018 computeMaxSetPressure(OrderedInsts, Stages, MaxStage + 1);
2021 dbgs() <<
"Dump MaxSetPressure:\n";
2022 for (
unsigned I = 0;
I < MaxSetPressure.size();
I++) {
2023 dbgs() <<
format(
"MaxSetPressure[%d]=%d\n",
I, MaxSetPressure[
I]);
2028 for (
unsigned PSet = 0; PSet < PSetNum; PSet++) {
2029 unsigned Limit = PressureSetLimit[PSet];
2032 <<
" Margin=" << Margin <<
"\n");
2033 if (Limit < MaxSetPressure[PSet] + Margin) {
2036 <<
"Rejected the schedule because of too high register pressure\n");
2052unsigned SwingSchedulerDAG::calculateResMII() {
2055 return RM.calculateResMII();
2064unsigned SwingSchedulerDAG::calculateRecMII(NodeSetType &NodeSets) {
2065 unsigned RecMII = 0;
2067 for (NodeSet &Nodes : NodeSets) {
2071 unsigned Delay = Nodes.getLatency();
2072 unsigned Distance = 1;
2075 unsigned CurMII = (Delay + Distance - 1) / Distance;
2076 Nodes.setRecMII(CurMII);
2077 if (CurMII > RecMII)
2085void SwingSchedulerDAG::Circuits::createAdjacencyStructure(
2086 SwingSchedulerDDG *DDG) {
2087 BitVector
Added(SUnits.size());
2088 DenseMap<int, int> OutputDeps;
2089 for (
int i = 0, e = SUnits.size(); i != e; ++i) {
2095 if (OE.isOutputDep()) {
2096 int N = OE.getDst()->NodeNum;
2098 auto Dep = OutputDeps.
find(BackEdge);
2099 if (Dep != OutputDeps.
end()) {
2100 BackEdge = Dep->second;
2101 OutputDeps.
erase(Dep);
2103 OutputDeps[
N] = BackEdge;
2106 if (OE.getDst()->isBoundaryNode() || OE.isArtificial())
2118 int N = OE.getDst()->NodeNum;
2120 AdjK[i].push_back(
N);
2127 int N = Dst->NodeNum;
2129 AdjK[i].push_back(
N);
2136 for (
auto &OD : OutputDeps)
2137 if (!
Added.test(OD.second)) {
2138 AdjK[OD.first].push_back(OD.second);
2139 Added.set(OD.second);
2145bool SwingSchedulerDAG::Circuits::circuit(
int V,
int S, NodeSetType &NodeSets,
2146 const SwingSchedulerDAG *DAG,
2148 SUnit *
SV = &SUnits[
V];
2153 for (
auto W : AdjK[V]) {
2154 if (NumPaths > MaxPaths)
2165 if (!Blocked.test(W)) {
2166 if (circuit(W, S, NodeSets, DAG,
2167 Node2Idx->at(W) < Node2Idx->at(V) ?
true : HasBackedge))
2175 for (
auto W : AdjK[V]) {
2186void SwingSchedulerDAG::Circuits::unblock(
int U) {
2188 SmallPtrSet<SUnit *, 4> &BU =
B[
U];
2189 while (!BU.
empty()) {
2190 SmallPtrSet<SUnit *, 4>::iterator
SI = BU.
begin();
2191 assert(SI != BU.
end() &&
"Invalid B set.");
2194 if (Blocked.test(
W->NodeNum))
2195 unblock(
W->NodeNum);
2201void SwingSchedulerDAG::findCircuits(NodeSetType &NodeSets) {
2202 Circuits Cir(SUnits, Topo);
2204 Cir.createAdjacencyStructure(&*DDG);
2205 for (
int I = 0,
E = SUnits.size();
I !=
E; ++
I) {
2207 Cir.circuit(
I,
I, NodeSets,
this);
2229void SwingSchedulerDAG::CopyToPhiMutation::apply(ScheduleDAGInstrs *DAG) {
2230 for (SUnit &SU : DAG->
SUnits) {
2240 for (
auto &Dep : SU.
Preds) {
2241 SUnit *TmpSU = Dep.getSUnit();
2242 MachineInstr *TmpMI = TmpSU->
getInstr();
2253 if (PHISUs.
size() == 0 || SrcSUs.
size() == 0)
2261 for (
auto &Dep : PHISUs[Index]->Succs) {
2265 SUnit *TmpSU = Dep.getSUnit();
2266 MachineInstr *TmpMI = TmpSU->
getInstr();
2275 if (UseSUs.
size() == 0)
2280 for (
auto *
I : UseSUs) {
2281 for (
auto *Src : SrcSUs) {
2297void SwingSchedulerDAG::computeNodeFunctions(NodeSetType &NodeSets) {
2298 ScheduleInfo.resize(SUnits.size());
2301 for (
int I : Topo) {
2302 const SUnit &SU = SUnits[
I];
2309 for (
int I : Topo) {
2311 int zeroLatencyDepth = 0;
2312 SUnit *SU = &SUnits[
I];
2314 SUnit *Pred =
IE.getSrc();
2315 if (
IE.getLatency() == 0)
2317 std::max(zeroLatencyDepth, getZeroLatencyDepth(Pred) + 1);
2318 if (
IE.ignoreDependence(
true))
2320 asap = std::max(asap, (
int)(getASAP(Pred) +
IE.getLatency() -
2321 IE.getDistance() * MII));
2323 maxASAP = std::max(maxASAP, asap);
2324 ScheduleInfo[
I].ASAP = asap;
2325 ScheduleInfo[
I].ZeroLatencyDepth = zeroLatencyDepth;
2331 int zeroLatencyHeight = 0;
2332 SUnit *SU = &SUnits[
I];
2334 SUnit *Succ = OE.getDst();
2337 if (OE.getLatency() == 0)
2339 std::max(zeroLatencyHeight, getZeroLatencyHeight(Succ) + 1);
2340 if (OE.ignoreDependence(
true))
2342 alap = std::min(alap, (
int)(getALAP(Succ) - OE.getLatency() +
2343 OE.getDistance() * MII));
2346 ScheduleInfo[
I].ALAP = alap;
2347 ScheduleInfo[
I].ZeroLatencyHeight = zeroLatencyHeight;
2351 for (NodeSet &
I : NodeSets)
2352 I.computeNodeSetInfo(
this);
2355 for (
unsigned i = 0; i < SUnits.size(); i++) {
2356 dbgs() <<
"\tNode " << i <<
":\n";
2357 dbgs() <<
"\t ASAP = " << getASAP(&SUnits[i]) <<
"\n";
2358 dbgs() <<
"\t ALAP = " << getALAP(&SUnits[i]) <<
"\n";
2359 dbgs() <<
"\t MOV = " << getMOV(&SUnits[i]) <<
"\n";
2360 dbgs() <<
"\t D = " << getDepth(&SUnits[i]) <<
"\n";
2361 dbgs() <<
"\t H = " << getHeight(&SUnits[i]) <<
"\n";
2362 dbgs() <<
"\t ZLD = " << getZeroLatencyDepth(&SUnits[i]) <<
"\n";
2363 dbgs() <<
"\t ZLH = " << getZeroLatencyHeight(&SUnits[i]) <<
"\n";
2378 SUnit *PredSU = IE.getSrc();
2379 if (S && S->count(PredSU) == 0)
2381 if (IE.ignoreDependence(
true))
2392 SUnit *SuccSU = OE.getDst();
2393 if (!OE.isAntiDep())
2395 if (S && S->count(SuccSU) == 0)
2401 return !Preds.
empty();
2414 SUnit *SuccSU = OE.getDst();
2415 if (S && S->count(SuccSU) == 0)
2417 if (OE.ignoreDependence(
false))
2428 SUnit *PredSU = IE.getSrc();
2429 if (!IE.isAntiDep())
2431 if (S && S->count(PredSU) == 0)
2437 return !Succs.
empty();
2453 if (!Visited.
insert(Cur).second)
2454 return Path.contains(Cur);
2455 bool FoundPath =
false;
2457 if (!OE.ignoreDependence(
false))
2459 computePath(OE.getDst(), Path, DestNodes, Exclude, Visited, DDG);
2461 if (IE.isAntiDep() && IE.getDistance() == 0)
2463 computePath(IE.getSrc(), Path, DestNodes, Exclude, Visited, DDG);
2478 for (
SUnit *SU : NS) {
2484 if (
Reg.isVirtual())
2486 else if (
MRI.isAllocatable(
Reg))
2487 for (MCRegUnit Unit :
TRI->regunits(
Reg.asMCReg()))
2491 for (
SUnit *SU : NS)
2495 if (
Reg.isVirtual()) {
2499 }
else if (
MRI.isAllocatable(
Reg)) {
2500 for (MCRegUnit Unit :
TRI->regunits(
Reg.asMCReg()))
2511void SwingSchedulerDAG::registerPressureFilter(NodeSetType &NodeSets) {
2512 for (
auto &NS : NodeSets) {
2516 IntervalPressure RecRegPressure;
2517 RegPressureTracker RecRPTracker(RecRegPressure);
2518 RecRPTracker.init(&MF, &RegClassInfo, &LIS, BB, BB->end(),
false,
true);
2520 RecRPTracker.closeBottom();
2522 std::vector<SUnit *> SUnits(NS.begin(), NS.end());
2523 llvm::sort(SUnits, [](
const SUnit *
A,
const SUnit *
B) {
2524 return A->NodeNum >
B->NodeNum;
2527 for (
auto &SU : SUnits) {
2533 RecRPTracker.setPos(std::next(CurInstI));
2535 RegPressureDelta RPDelta;
2537 RecRPTracker.getMaxUpwardPressureDelta(SU->
getInstr(),
nullptr, RPDelta,
2542 dbgs() <<
"Excess register pressure: " << *SU <<
" "
2545 NS.setExceedPressure(SU);
2548 RecRPTracker.recede();
2555void SwingSchedulerDAG::colocateNodeSets(NodeSetType &NodeSets) {
2556 unsigned Colocate = 0;
2557 for (
int i = 0, e = NodeSets.size(); i < e; ++i) {
2559 SmallSetVector<SUnit *, 8>
S1;
2562 for (
int j = i + 1;
j <
e; ++
j) {
2566 SmallSetVector<SUnit *, 8> S2;
2583void SwingSchedulerDAG::checkNodeSets(NodeSetType &NodeSets) {
2588 for (
auto &NS : NodeSets) {
2589 if (NS.getRecMII() > 2)
2591 if (NS.getMaxDepth() > MII)
2600void SwingSchedulerDAG::groupRemainingNodes(NodeSetType &NodeSets) {
2601 SetVector<SUnit *> NodesAdded;
2602 SmallPtrSet<SUnit *, 8> Visited;
2605 for (NodeSet &
I : NodeSets) {
2606 SmallSetVector<SUnit *, 8>
N;
2609 SetVector<SUnit *>
Path;
2610 for (SUnit *NI :
N) {
2612 computePath(NI, Path, NodesAdded,
I, Visited, DDG.get());
2619 if (
succ_L(NodesAdded,
N, DDG.get())) {
2620 SetVector<SUnit *>
Path;
2621 for (SUnit *NI :
N) {
2623 computePath(NI, Path,
I, NodesAdded, Visited, DDG.get());
2634 SmallSetVector<SUnit *, 8>
N;
2635 if (
succ_L(NodesAdded,
N, DDG.get()))
2637 addConnectedNodes(
I, NewSet, NodesAdded);
2638 if (!NewSet.
empty())
2639 NodeSets.push_back(NewSet);
2644 if (
pred_L(NodesAdded,
N, DDG.get()))
2646 addConnectedNodes(
I, NewSet, NodesAdded);
2647 if (!NewSet.
empty())
2648 NodeSets.push_back(NewSet);
2652 for (SUnit &SU : SUnits) {
2653 if (NodesAdded.
count(&SU) == 0) {
2655 addConnectedNodes(&SU, NewSet, NodesAdded);
2656 if (!NewSet.
empty())
2657 NodeSets.push_back(NewSet);
2663void SwingSchedulerDAG::addConnectedNodes(SUnit *SU, NodeSet &NewSet,
2664 SetVector<SUnit *> &NodesAdded) {
2669 if (!OE.isArtificial() && !
Successor->isBoundaryNode() &&
2671 addConnectedNodes(
Successor, NewSet, NodesAdded);
2674 SUnit *Predecessor =
IE.getSrc();
2675 if (!
IE.isArtificial() && NodesAdded.
count(Predecessor) == 0)
2676 addConnectedNodes(Predecessor, NewSet, NodesAdded);
2685 for (
SUnit *SU : Set1) {
2686 if (Set2.
count(SU) != 0)
2689 return !Result.empty();
2693void SwingSchedulerDAG::fuseRecs(NodeSetType &NodeSets) {
2694 for (NodeSetType::iterator
I = NodeSets.begin(),
E = NodeSets.end();
I !=
E;
2697 for (NodeSetType::iterator J =
I + 1; J !=
E;) {
2702 for (SUnit *SU : *J)
2714void SwingSchedulerDAG::removeDuplicateNodes(NodeSetType &NodeSets) {
2715 for (NodeSetType::iterator
I = NodeSets.begin(),
E = NodeSets.end();
I !=
E;
2717 for (NodeSetType::iterator J =
I + 1; J !=
E;) {
2718 J->remove_if([&](SUnit *SUJ) {
return I->count(SUJ); });
2733void SwingSchedulerDAG::computeNodeOrder(NodeSetType &NodeSets) {
2734 SmallSetVector<SUnit *, 8>
R;
2737 for (
auto &Nodes : NodeSets) {
2740 SmallSetVector<SUnit *, 8>
N;
2755 }
else if (NodeSets.size() == 1) {
2756 for (
const auto &
N : Nodes)
2757 if (
N->Succs.size() == 0)
2763 SUnit *maxASAP =
nullptr;
2764 for (SUnit *SU : Nodes) {
2765 if (maxASAP ==
nullptr || getASAP(SU) > getASAP(maxASAP) ||
2766 (getASAP(SU) == getASAP(maxASAP) && SU->
NodeNum > maxASAP->
NodeNum))
2774 while (!
R.empty()) {
2775 if (Order == TopDown) {
2779 while (!
R.empty()) {
2780 SUnit *maxHeight =
nullptr;
2781 for (SUnit *
I : R) {
2782 if (maxHeight ==
nullptr || getHeight(
I) > getHeight(maxHeight))
2784 else if (getHeight(
I) == getHeight(maxHeight) &&
2785 getZeroLatencyHeight(
I) > getZeroLatencyHeight(maxHeight))
2787 else if (getHeight(
I) == getHeight(maxHeight) &&
2788 getZeroLatencyHeight(
I) ==
2789 getZeroLatencyHeight(maxHeight) &&
2790 getMOV(
I) < getMOV(maxHeight))
2795 R.remove(maxHeight);
2796 for (
const auto &OE : DDG->
getOutEdges(maxHeight)) {
2797 SUnit *SU = OE.getDst();
2798 if (Nodes.count(SU) == 0)
2802 if (OE.ignoreDependence(
false))
2811 for (
const auto &IE : DDG->
getInEdges(maxHeight)) {
2812 SUnit *SU =
IE.getSrc();
2813 if (!
IE.isAntiDep())
2815 if (Nodes.count(SU) == 0)
2824 SmallSetVector<SUnit *, 8>
N;
2831 while (!
R.empty()) {
2832 SUnit *maxDepth =
nullptr;
2833 for (SUnit *
I : R) {
2834 if (maxDepth ==
nullptr || getDepth(
I) > getDepth(maxDepth))
2836 else if (getDepth(
I) == getDepth(maxDepth) &&
2837 getZeroLatencyDepth(
I) > getZeroLatencyDepth(maxDepth))
2839 else if (getDepth(
I) == getDepth(maxDepth) &&
2840 getZeroLatencyDepth(
I) == getZeroLatencyDepth(maxDepth) &&
2841 getMOV(
I) < getMOV(maxDepth))
2847 if (Nodes.isExceedSU(maxDepth)) {
2850 R.insert(Nodes.getNode(0));
2853 for (
const auto &IE : DDG->
getInEdges(maxDepth)) {
2854 SUnit *SU =
IE.getSrc();
2855 if (Nodes.count(SU) == 0)
2866 for (
const auto &OE : DDG->
getOutEdges(maxDepth)) {
2867 SUnit *SU = OE.getDst();
2868 if (!OE.isAntiDep())
2870 if (Nodes.count(SU) == 0)
2879 SmallSetVector<SUnit *, 8>
N;
2888 dbgs() <<
"Node order: ";
2890 dbgs() <<
" " << *
I <<
" ";
2896void SwingSchedulerDAG::initPolicy() {
2906bool SwingSchedulerDAG::schedulePipeline(SMSchedule &Schedule) {
2913 bool scheduleFound =
false;
2914 std::unique_ptr<HighRegisterPressureDetector> HRPDetector;
2915 if (Policy.ShouldLimitRegPressure) {
2917 std::make_unique<HighRegisterPressureDetector>(
Loop.getHeader(), MF);
2918 HRPDetector->init(RegClassInfo);
2921 for (
unsigned II = MII;
II <= MAX_II && !scheduleFound; ++
II) {
2933 int EarlyStart = INT_MIN;
2934 int LateStart = INT_MAX;
2938 dbgs() << *SU <<
" ";
2943 dbgs() <<
format(
"\tes: %8x ls: %8x\n", EarlyStart, LateStart));
2945 if (EarlyStart > LateStart)
2946 scheduleFound =
false;
2947 else if (EarlyStart != INT_MIN && LateStart == INT_MAX)
2949 Schedule.
insert(SU, EarlyStart, EarlyStart + (
int)
II - 1,
II);
2950 else if (EarlyStart == INT_MIN && LateStart != INT_MAX)
2952 Schedule.
insert(SU, LateStart, LateStart - (
int)
II + 1,
II);
2953 else if (EarlyStart != INT_MIN && LateStart != INT_MAX) {
2954 LateStart = std::min(LateStart, EarlyStart + (
int)
II - 1);
2963 scheduleFound = Schedule.
insert(SU, LateStart, EarlyStart,
II);
2965 scheduleFound = Schedule.
insert(SU, EarlyStart, LateStart,
II);
2968 scheduleFound = Schedule.
insert(SU, FirstCycle + getASAP(SU),
2969 FirstCycle + getASAP(SU) +
II - 1,
II);
2977 scheduleFound =
false;
2981 dbgs() <<
"\tCan't schedule\n";
2983 }
while (++NI != NE && scheduleFound);
3001 if (scheduleFound && HRPDetector)
3010 if (scheduleFound) {
3011 scheduleFound = LoopPipelinerInfo->shouldUseSchedule(*
this, Schedule);
3016 if (scheduleFound) {
3019 return MachineOptimizationRemarkAnalysis(
3021 <<
"Schedule found with Initiation Interval: "
3023 <<
", MaxStageCount: "
3037 if (!
Reg.isVirtual())
3039 if (
MRI.getDefBlock(
Reg) !=
MI.getParent())
3052 if (!
Op.isReg() || !
Op.getReg().isVirtual())
3077 if (!Def || Def->getParent() != LoopBB)
3080 if (Def->isCopy()) {
3082 if (Def->getOperand(0).getSubReg() || Def->getOperand(1).getSubReg())
3084 CurReg = Def->getOperand(1).getReg();
3085 }
else if (Def->isPHI()) {
3091 }
else if (
TII->getIncrementValue(*Def,
Value)) {
3099 bool OffsetIsScalable;
3100 if (
TII->getMemOperandWithOffset(*Def, BaseOp,
Offset,
3101 OffsetIsScalable)) {
3103 CurReg = BaseOp->
getReg();
3115 if (CurReg == OrgReg)
3131 bool OffsetIsScalable;
3132 if (!
TII.getMemOperandWithOffset(
MI, BaseOp,
Offset, OffsetIsScalable))
3136 if (OffsetIsScalable)
3139 if (!BaseOp->
isReg())
3152bool SwingSchedulerDAG::canUseLastOffsetValue(MachineInstr *
MI,
3154 unsigned &OffsetPos,
3160 unsigned BasePosLd, OffsetPosLd;
3168 if (!Phi || !
Phi->isPHI())
3177 if (!PrevDef || PrevDef ==
MI)
3183 unsigned BasePos1 = 0, OffsetPos1 = 0;
3191 MachineInstr *NewMI = MF.CloneMachineInstr(
MI);
3194 MF.deleteMachineInstr(NewMI);
3199 BasePos = BasePosLd;
3200 OffsetPos = OffsetPosLd;
3212 InstrChanges.find(SU);
3213 if (It != InstrChanges.
end()) {
3214 std::pair<Register, int64_t> RegAndOffset = It->second;
3215 unsigned BasePos, OffsetPos;
3216 if (!
TII->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos))
3218 Register BaseReg =
MI->getOperand(BasePos).getReg();
3224 if (BaseStageNum < DefStageNum) {
3226 int OffsetDiff = DefStageNum - BaseStageNum;
3227 if (DefCycleNum < BaseCycleNum) {
3233 MI->getOperand(OffsetPos).getImm() + RegAndOffset.second * OffsetDiff;
3248 while (Def->isPHI()) {
3249 if (!Visited.
insert(Def).second)
3251 for (
unsigned i = 1, e = Def->getNumOperands(); i < e; i += 2)
3252 if (Def->getOperand(i + 1).getMBB() == BB) {
3253 Def =
MRI.getVRegDef(Def->getOperand(i).getReg());
3267 int DeltaB, DeltaO, Delta;
3274 int64_t OffsetB, OffsetO;
3275 bool OffsetBIsScalable, OffsetOIsScalable;
3276 if (!
TII.getMemOperandWithOffset(*BaseMI, BaseOpB, OffsetB,
3277 OffsetBIsScalable) ||
3278 !
TII.getMemOperandWithOffset(*OtherMI, BaseOpO, OffsetO,
3282 if (OffsetBIsScalable || OffsetOIsScalable)
3292 if (!RegB.
isVirtual() || !RegO.isVirtual())
3297 if (!DefB || !DefO || !DefB->
isPHI() || !DefO->
isPHI())
3300 Register InitValB, LoopValB, InitValO, LoopValO;
3301 getPhiRegs(*DefB, LoopBB, InitValB, LoopValB);
3302 getPhiRegs(*DefO, LoopBB, InitValO, LoopValO);
3307 if (!InitDefB || !InitDefO || !InitDefB->
isIdenticalTo(*InitDefO))
3322 dbgs() <<
"Overlap check:\n";
3323 dbgs() <<
" BaseMI: ";
3325 dbgs() <<
" Base + " << OffsetB <<
" + I * " << Delta
3326 <<
", Len: " << AccessSizeB.
getValue() <<
"\n";
3327 dbgs() <<
" OtherMI: ";
3329 dbgs() <<
" Base + " << OffsetO <<
" + I * " << Delta
3330 <<
", Len: " << AccessSizeO.
getValue() <<
"\n";
3338 int64_t BaseMinAddr = OffsetB;
3339 int64_t OhterNextIterMaxAddr = OffsetO + Delta + AccessSizeO.
getValue() - 1;
3340 if (BaseMinAddr > OhterNextIterMaxAddr) {
3345 int64_t BaseMaxAddr = OffsetB + AccessSizeB.
getValue() - 1;
3346 int64_t OtherNextIterMinAddr = OffsetO + Delta;
3347 if (BaseMaxAddr < OtherNextIterMinAddr) {
3356void SwingSchedulerDAG::postProcessDAG() {
3357 for (
auto &M : Mutations)
3367 bool forward =
true;
3369 dbgs() <<
"Trying to insert node between " << StartCycle <<
" and "
3370 << EndCycle <<
" II: " <<
II <<
"\n";
3372 if (StartCycle > EndCycle)
3376 int termCycle = forward ? EndCycle + 1 : EndCycle - 1;
3377 for (
int curCycle = StartCycle; curCycle != termCycle;
3378 forward ? ++curCycle : --curCycle) {
3381 ProcItinResources.canReserveResources(*SU, curCycle)) {
3383 dbgs() <<
"\tinsert at cycle " << curCycle <<
" ";
3388 ProcItinResources.reserveResources(*SU, curCycle);
3389 ScheduledInstrs[curCycle].push_back(SU);
3390 InstrToCycle.insert(std::make_pair(SU, curCycle));
3391 if (curCycle > LastCycle)
3392 LastCycle = curCycle;
3393 if (curCycle < FirstCycle)
3394 FirstCycle = curCycle;
3398 dbgs() <<
"\tfailed to insert at cycle " << curCycle <<
" ";
3409 for (
auto &
P : SU->
Preds)
3410 if (
P.getKind() ==
SDep::Anti &&
P.getSUnit()->getInstr()->isPHI())
3411 for (
auto &S :
P.getSUnit()->Succs)
3412 if (S.getKind() ==
SDep::Data && S.getSUnit()->getInstr()->isPHI())
3413 return P.getSUnit();
3426 for (
int cycle =
getFirstCycle(); cycle <= LastCycle; ++cycle) {
3429 if (IE.getSrc() ==
I) {
3430 int EarlyStart = cycle + IE.getLatency() - IE.getDistance() *
II;
3431 *MaxEarlyStart = std::max(*MaxEarlyStart, EarlyStart);
3436 if (OE.getDst() ==
I) {
3437 int LateStart = cycle - OE.getLatency() + OE.getDistance() *
II;
3438 *MinLateStart = std::min(*MinLateStart, LateStart);
3443 for (
const auto &Dep : SU->
Preds) {
3446 if (BE && Dep.getSUnit() == BE && !SU->
getInstr()->
isPHI() &&
3448 *MinLateStart = std::min(*MinLateStart, cycle);
3458 std::deque<SUnit *> &Insts)
const {
3460 bool OrderBeforeUse =
false;
3461 bool OrderAfterDef =
false;
3462 bool OrderBeforeDef =
false;
3463 unsigned MoveDef = 0;
3464 unsigned MoveUse = 0;
3469 for (std::deque<SUnit *>::iterator
I = Insts.begin(), E = Insts.end();
I != E;
3472 if (!MO.isReg() || !MO.getReg().isVirtual())
3476 unsigned BasePos, OffsetPos;
3477 if (ST.getInstrInfo()->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos))
3478 if (
MI->getOperand(BasePos).getReg() == Reg)
3482 std::tie(Reads, Writes) =
3483 (*I)->getInstr()->readsWritesVirtualRegister(Reg);
3485 OrderBeforeUse =
true;
3490 OrderAfterDef =
true;
3492 }
else if (MO.isUse() && Writes &&
stageScheduled(*
I) == StageInst1) {
3494 OrderBeforeUse =
true;
3498 OrderAfterDef =
true;
3502 OrderBeforeUse =
true;
3506 OrderAfterDef =
true;
3511 OrderBeforeUse =
true;
3517 OrderBeforeDef =
true;
3525 if (OE.getDst() != *
I)
3528 OrderBeforeUse =
true;
3535 else if ((OE.isAntiDep() || OE.isOutputDep()) &&
3537 OrderBeforeUse =
true;
3538 if ((MoveUse == 0) || (Pos < MoveUse))
3543 if (IE.getSrc() != *
I)
3545 if ((IE.isAntiDep() || IE.isOutputDep() || IE.isOrderDep()) &&
3547 OrderAfterDef =
true;
3554 if (OrderAfterDef && OrderBeforeUse && MoveUse == MoveDef)
3555 OrderBeforeUse =
false;
3560 OrderBeforeUse = !OrderAfterDef || (MoveUse > MoveDef);
3564 if (OrderBeforeUse && OrderAfterDef) {
3565 SUnit *UseSU = Insts.at(MoveUse);
3566 SUnit *DefSU = Insts.at(MoveDef);
3567 if (MoveUse > MoveDef) {
3568 Insts.erase(Insts.begin() + MoveUse);
3569 Insts.erase(Insts.begin() + MoveDef);
3571 Insts.erase(Insts.begin() + MoveDef);
3572 Insts.erase(Insts.begin() + MoveUse);
3582 Insts.push_front(SU);
3584 Insts.push_back(SU);
3592 assert(Phi.isPHI() &&
"Expecting a Phi.");
3599 getPhiRegs(Phi, Phi.getParent(), InitVal, LoopVal);
3607 return (LoopCycle > DefCycle) || (LoopStage <= DefStage);
3625 if (!Phi || !Phi->isPHI() || Phi->getParent() != Def->getParent())
3631 if (DMO.getReg() == LoopReg)
3642 if (InstrToCycle.count(IE.getSrc()))
3653 for (
auto &SU : SSD->
SUnits)
3658 while (!Worklist.
empty()) {
3660 if (DoNotPipeline.
count(SU))
3663 DoNotPipeline.
insert(SU);
3670 if (OE.getDistance() == 1)
3673 return DoNotPipeline;
3682 int NewLastCycle = INT_MIN;
3687 NewLastCycle = std::max(NewLastCycle, InstrToCycle[&SU]);
3694 if (IE.getDistance() == 0)
3695 NewCycle = std::max(InstrToCycle[IE.getSrc()], NewCycle);
3700 if (OE.getDistance() == 1)
3701 NewCycle = std::max(InstrToCycle[OE.getDst()], NewCycle);
3703 int OldCycle = InstrToCycle[&SU];
3704 if (OldCycle != NewCycle) {
3705 InstrToCycle[&SU] = NewCycle;
3709 LLVM_DEBUG(
dbgs() << SU <<
" is not pipelined; moving from cycle "
3710 << OldCycle <<
" to " << NewCycle
3736 if (FirstCycle + InitiationInterval <= NewCycle)
3739 NewLastCycle = std::max(NewLastCycle, NewCycle);
3741 LastCycle = NewLastCycle;
3758 int CycleDef = InstrToCycle[&SU];
3759 assert(StageDef != -1 &&
"Instruction should have been scheduled.");
3761 SUnit *Dst = OE.getDst();
3762 if (OE.isAssignedRegDep() && !Dst->isBoundaryNode())
3763 if (OE.getReg().isPhysical()) {
3766 if (InstrToCycle[Dst] <= CycleDef)
3784void SwingSchedulerDAG::checkValidNodeOrder(
const NodeSetType &Circuits)
const {
3787 typedef std::pair<SUnit *, unsigned> UnitIndex;
3788 std::vector<UnitIndex> Indices(
NodeOrder.size(), std::make_pair(
nullptr, 0));
3790 for (
unsigned i = 0, s =
NodeOrder.size(); i < s; ++i)
3791 Indices.push_back(std::make_pair(
NodeOrder[i], i));
3793 auto CompareKey = [](UnitIndex i1, UnitIndex i2) {
3794 return std::get<0>(i1) < std::get<0>(i2);
3807 for (
unsigned i = 0, s =
NodeOrder.size(); i < s; ++i) {
3811 bool PredBefore =
false;
3812 bool SuccBefore =
false;
3820 SUnit *PredSU = IE.getSrc();
3821 unsigned PredIndex = std::get<1>(
3831 SUnit *SuccSU = OE.getDst();
3837 unsigned SuccIndex = std::get<1>(
3850 Circuits, [SU](
const NodeSet &Circuit) {
return Circuit.
count(SU); });
3855 NumNodeOrderIssues++;
3859 <<
" are scheduled before node " << *SU <<
"\n");
3865 dbgs() <<
"Invalid node order found!\n";
3878 for (
SUnit *SU : Instrs) {
3880 for (
unsigned i = 0, e =
MI->getNumOperands(); i < e; ++i) {
3888 InstrChanges.find(SU);
3889 if (It != InstrChanges.
end()) {
3890 unsigned BasePos, OffsetPos;
3892 if (
TII->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos)) {
3896 MI->getOperand(OffsetPos).getImm() - It->second.second;
3909 unsigned TiedUseIdx = 0;
3910 if (
MI->isRegTiedToUseOperand(i, &TiedUseIdx)) {
3912 OverlapReg =
MI->getOperand(TiedUseIdx).getReg();
3914 NewBaseReg =
MI->getOperand(i).getReg();
3923 const std::deque<SUnit *> &Instrs)
const {
3924 std::deque<SUnit *> NewOrderPhi;
3925 for (
SUnit *SU : Instrs) {
3927 NewOrderPhi.push_back(SU);
3929 std::deque<SUnit *> NewOrderI;
3930 for (
SUnit *SU : Instrs) {
3946 std::deque<SUnit *> &cycleInstrs =
3947 ScheduledInstrs[cycle + (stage * InitiationInterval)];
3949 ScheduledInstrs[cycle].push_front(SU);
3955 for (
int cycle =
getFinalCycle() + 1; cycle <= LastCycle; ++cycle)
3956 ScheduledInstrs.erase(cycle);
3966 std::deque<SUnit *> &cycleInstrs = ScheduledInstrs[Cycle];
3974#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3976 os <<
"Num nodes " <<
size() <<
" rec " << RecMII <<
" mov " << MaxMOV
3977 <<
" depth " << MaxDepth <<
" col " << Colocate <<
"\n";
3978 for (
const auto &
I : Nodes)
3979 os <<
" " << *
I <<
" " << *(
I->getInstr());
3989 for (
SUnit *CI : cycleInstrs->second) {
4002void ResourceManager::dumpMRT()
const {
4006 std::stringstream SS;
4008 SS << std::setw(4) <<
"Slot";
4009 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I)
4010 SS << std::setw(3) <<
I;
4011 SS << std::setw(7) <<
"#Mops"
4013 for (
int Slot = 0; Slot < InitiationInterval; ++Slot) {
4014 SS << std::setw(4) << Slot;
4015 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I)
4016 SS << std::setw(3) << MRT[Slot][
I];
4017 SS << std::setw(7) << NumScheduledMops[Slot] <<
"\n";
4026 : STI(ST), SM(ST->getSchedModel()), ST(ST), TII(ST->getInstrInfo()),
4027 DAG(DAG), UseDFA(ST->useDFAforSMS()),
4028 ProcResourceMasks(SM.getNumProcResourceKinds(), 0),
4029 IssueWidth(SM.IssueWidth) {
4031 if (IssueWidth <= 0)
4040 unsigned ProcResourceID = 0;
4044 assert(SM.getNumProcResourceKinds() < 64 &&
4045 "Too many kinds of resources, unsupported");
4048 Masks.
resize(SM.getNumProcResourceKinds());
4049 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4051 if (
Desc.SubUnitsIdxBegin)
4053 Masks[
I] = 1ULL << ProcResourceID;
4057 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4059 if (!
Desc.SubUnitsIdxBegin)
4061 Masks[
I] = 1ULL << ProcResourceID;
4062 for (
unsigned U = 0; U <
Desc.NumUnits; ++U)
4063 Masks[
I] |= Masks[
Desc.SubUnitsIdxBegin[U]];
4068 dbgs() <<
"ProcResourceDesc:\n";
4069 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4071 dbgs() <<
format(
" %16s(%2d): Mask: 0x%08x, NumUnits:%2d\n",
4072 ProcResource->
Name,
I, Masks[
I],
4075 dbgs() <<
" -----------------\n";
4083 dbgs() <<
"canReserveResources:\n";
4086 return DFAResources[positiveModulo(Cycle, InitiationInterval)]
4092 dbgs() <<
"No valid Schedule Class Desc for schedClass!\n";
4098 reserveResources(SCDesc, Cycle);
4099 bool Result = !isOverbooked();
4100 unreserveResources(SCDesc, Cycle);
4106void ResourceManager::reserveResources(
SUnit &SU,
int Cycle) {
4109 dbgs() <<
"reserveResources:\n";
4112 return DFAResources[positiveModulo(Cycle, InitiationInterval)]
4118 dbgs() <<
"No valid Schedule Class Desc for schedClass!\n";
4124 reserveResources(SCDesc, Cycle);
4129 dbgs() <<
"reserveResources: done!\n\n";
4139 for (
int C = Cycle;
C < Cycle + PRE.ReleaseAtCycle; ++
C)
4140 ++MRT[positiveModulo(
C, InitiationInterval)][PRE.ProcResourceIdx];
4143 ++NumScheduledMops[positiveModulo(
C, InitiationInterval)];
4151 for (
int C = Cycle;
C < Cycle + PRE.ReleaseAtCycle; ++
C)
4152 --MRT[positiveModulo(
C, InitiationInterval)][PRE.ProcResourceIdx];
4155 --NumScheduledMops[positiveModulo(
C, InitiationInterval)];
4158bool ResourceManager::isOverbooked()
const {
4160 for (
int Slot = 0;
Slot < InitiationInterval; ++
Slot) {
4161 for (
unsigned I = 1,
E = SM.getNumProcResourceKinds();
I <
E; ++
I) {
4162 const MCProcResourceDesc *
Desc = SM.getProcResource(
I);
4163 if (MRT[Slot][
I] >
Desc->NumUnits)
4166 if (NumScheduledMops[Slot] > IssueWidth)
4172int ResourceManager::calculateResMIIDFA()
const {
4177 FuncUnitSorter FUS = FuncUnitSorter(*ST);
4178 for (SUnit &SU : DAG->SUnits)
4179 FUS.calcCriticalResources(*SU.
getInstr());
4180 PriorityQueue<MachineInstr *, std::vector<MachineInstr *>, FuncUnitSorter>
4183 for (SUnit &SU : DAG->SUnits)
4188 std::unique_ptr<DFAPacketizer>(TII->CreateTargetScheduleState(*ST)));
4190 while (!FuncUnitOrder.empty()) {
4191 MachineInstr *
MI = FuncUnitOrder.top();
4192 FuncUnitOrder.pop();
4193 if (TII->isZeroCost(
MI->getOpcode()))
4198 unsigned NumCycles = DAG->getSUnit(
MI)->Latency;
4199 unsigned ReservedCycles = 0;
4203 dbgs() <<
"Trying to reserve resource for " << NumCycles
4204 <<
" cycles for \n";
4207 for (
unsigned C = 0;
C < NumCycles; ++
C)
4209 if ((*RI)->canReserveResources(*
MI)) {
4210 (*RI)->reserveResources(*
MI);
4217 <<
", NumCycles:" << NumCycles <<
"\n");
4219 for (
unsigned C = ReservedCycles;
C < NumCycles; ++
C) {
4221 <<
"NewResource created to reserve resources"
4223 auto *NewResource = TII->CreateTargetScheduleState(*ST);
4224 assert(NewResource->canReserveResources(*
MI) &&
"Reserve error.");
4225 NewResource->reserveResources(*
MI);
4226 Resources.push_back(std::unique_ptr<DFAPacketizer>(NewResource));
4237 return calculateResMIIDFA();
4244 for (
SUnit &SU : DAG->SUnits) {
4256 <<
" WriteProcRes: ";
4261 make_range(STI->getWriteProcResBegin(SCDesc),
4262 STI->getWriteProcResEnd(SCDesc))) {
4266 SM.getProcResource(PRE.ProcResourceIdx);
4267 dbgs() <<
Desc->Name <<
": " << PRE.ReleaseAtCycle <<
", ";
4270 ResourceCount[PRE.ProcResourceIdx] += PRE.ReleaseAtCycle;
4275 int Result = (NumMops + IssueWidth - 1) / IssueWidth;
4278 dbgs() <<
"#Mops: " << NumMops <<
", "
4279 <<
"IssueWidth: " << IssueWidth <<
", "
4280 <<
"Cycles: " << Result <<
"\n";
4285 std::stringstream SS;
4286 SS << std::setw(2) <<
"ID" << std::setw(16) <<
"Name" << std::setw(10)
4287 <<
"Units" << std::setw(10) <<
"Consumed" << std::setw(10) <<
"Cycles"
4292 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4294 int Cycles = (ResourceCount[
I] +
Desc->NumUnits - 1) /
Desc->NumUnits;
4297 std::stringstream SS;
4298 SS << std::setw(2) <<
I << std::setw(16) <<
Desc->Name << std::setw(10)
4299 <<
Desc->NumUnits << std::setw(10) << ResourceCount[
I]
4300 << std::setw(10) << Cycles <<
"\n";
4304 if (Cycles > Result)
4311 InitiationInterval =
II;
4312 DFAResources.clear();
4313 DFAResources.resize(
II);
4314 for (
auto &
I : DFAResources)
4315 I.reset(ST->getInstrInfo()->CreateTargetScheduleState(*ST));
4318 NumScheduledMops.clear();
4319 NumScheduledMops.resize(
II);
4323 if (Pred.isArtificial() || Dst->isBoundaryNode())
4328 return IgnoreAnti && (Pred.getKind() ==
SDep::Kind::Anti || Distance != 0);
4331SwingSchedulerDDG::SwingSchedulerDDGEdges &
4332SwingSchedulerDDG::getEdges(
const SUnit *SU) {
4334 return EntrySUEdges;
4340const SwingSchedulerDDG::SwingSchedulerDDGEdges &
4341SwingSchedulerDDG::getEdges(
const SUnit *SU)
const {
4343 return EntrySUEdges;
4349void SwingSchedulerDDG::addEdge(
const SUnit *SU,
4352 "Validation-only edges are not expected here.");
4354 auto &Edges = getEdges(SU);
4355 if (
Edge.getSrc() == SU)
4356 Edges.Succs.push_back(
Edge);
4358 Edges.Preds.push_back(
Edge);
4361void SwingSchedulerDDG::initEdges(
SUnit *SU) {
4362 for (
const auto &PI : SU->
Preds) {
4363 SwingSchedulerDDGEdge
Edge(SU, PI,
false,
4368 for (
const auto &SI : SU->
Succs) {
4369 SwingSchedulerDDGEdge
Edge(SU, SI,
true,
4377 : EntrySU(EntrySU), ExitSU(ExitSU) {
4378 EdgesVec.resize(SUnits.size());
4383 for (
auto &SU : SUnits)
4387 for (
SUnit &SU : SUnits) {
4392 for (
SUnit *Dst : *OD) {
4395 Edge.setDistance(1);
4396 ValidationOnlyEdges.push_back(Edge);
4408 bool UseAsExtraEdge = [&]() {
4409 if (Edge.getDistance() == 0 || !Edge.isOrderDep())
4412 SUnit *Src = Edge.getSrc();
4413 SUnit *Dst = Edge.getDst();
4414 if (Src->NodeNum < Dst->NodeNum)
4422 getEdges(Edge.getSrc()).ExtraSuccs.push_back(Edge.getDst());
4428const SwingSchedulerDDG::EdgesType &
4430 return getEdges(SU).Preds;
4433const SwingSchedulerDDG::EdgesType &
4435 return getEdges(SU).Succs;
4439 return getEdges(SU).ExtraSuccs;
4446 auto ExpandCycle = [&](
SUnit *SU) {
4449 return Cycle + (Stage *
II);
4453 SUnit *Src = Edge.getSrc();
4454 SUnit *Dst = Edge.getDst();
4455 if (!Src->isInstr() || !Dst->isInstr())
4457 int CycleSrc = ExpandCycle(Src);
4458 int CycleDst = ExpandCycle(Dst);
4459 int MaxLateStart = CycleDst + Edge.getDistance() *
II - Edge.getLatency();
4460 if (CycleSrc > MaxLateStart) {
4462 dbgs() <<
"Validation failed for edge from " << *Src <<
" to " << *Dst
4473 for (
SUnit &SU : SUnits) {
4502 !
TII->isGlobalMemoryObject(FromMI) &&
4513#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
4522 const auto DumpSU = [](
const SUnit *SU) {
4529 dbgs() <<
" Loop carried edges from " << DumpSU(SU) <<
"\n"
4531 for (
SUnit *Dst : *Order)
4532 dbgs() <<
" " << DumpSU(Dst) <<
"\n";
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::optional< unsigned > getTag(const TargetRegisterInfo *TRI, const MachineInstr &MI, const LoadInfo &LI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
This file contains the simple types necessary to represent the attributes associated with functions a...
This file implements the BitVector class.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
DXIL Remove Unused Resources
This file defines the DenseMap class.
const HexagonInstrInfo * TII
A common definition of LaneBitmask for use in TableGen and CodeGen.
static cl::opt< int > SwpForceII("pipeliner-force-ii", cl::desc("Force pipeliner to use specified II."), cl::Hidden, cl::init(-1))
A command line argument to force pipeliner to use specified initial interval.
static cl::opt< bool > ExperimentalCodeGen("pipeliner-experimental-cg", cl::Hidden, cl::init(false), cl::desc("Use the experimental peeling code generator for software pipelining"))
static bool hasPHICycleDFS(unsigned Reg, const DenseMap< unsigned, SmallVector< unsigned, 2 > > &PhiDeps, SmallSet< unsigned, 8 > &Visited, SmallSet< unsigned, 8 > &RecStack)
Depth-first search to detect cycles among PHI dependencies.
static cl::opt< bool > MVECodeGen("pipeliner-mve-cg", cl::Hidden, cl::init(false), cl::desc("Use the MVE code generator for software pipelining"))
static cl::opt< int > RegPressureMargin("pipeliner-register-pressure-margin", cl::Hidden, cl::init(5), cl::desc("Margin representing the unused percentage of " "the register pressure limit"))
static cl::opt< bool > SwpDebugResource("pipeliner-dbg-res", cl::Hidden, cl::init(false))
static void computeLiveOuts(MachineFunction &MF, RegPressureTracker &RPTracker, NodeSet &NS)
Compute the live-out registers for the instructions in a node-set.
static cl::opt< bool > SwpEnableCopyToPhi("pipeliner-enable-copytophi", cl::ReallyHidden, cl::init(true), cl::desc("Enable CopyToPhi DAG Mutation"))
static void computeScheduledInsts(const SwingSchedulerDAG *SSD, SMSchedule &Schedule, std::vector< MachineInstr * > &OrderedInsts, DenseMap< MachineInstr *, unsigned > &Stages)
Create an instruction stream that represents a single iteration and stage of each instruction.
static cl::opt< bool > EmitTestAnnotations("pipeliner-annotate-for-testing", cl::Hidden, cl::init(false), cl::desc("Instead of emitting the pipelined code, annotate instructions " "with the generated schedule for feeding into the " "-modulo-schedule-test pass"))
static bool findLoopIncrementValue(const MachineInstr &MI, const MachineOperand &Op, int &Value)
When Op is a value that is incremented recursively in a loop and there is a unique instruction that i...
static Register getLoopPhiReg(const MachineInstr &Phi, const MachineBasicBlock *LoopBB)
Return the Phi register value that comes the loop block.
static bool hasLoopCarriedMemDep(const SUnitWithMemInfo &Src, const SUnitWithMemInfo &Dst, BatchAAResults &BAA, const TargetInstrInfo *TII)
Returns true if there is a loop-carried order dependency from Src to Dst.
static bool isIntersect(SmallSetVector< SUnit *, 8 > &Set1, const NodeSet &Set2, SmallSetVector< SUnit *, 8 > &Result)
Return true if Set1 contains elements in Set2.
static cl::opt< bool > SwpIgnoreRecMII("pipeliner-ignore-recmii", cl::ReallyHidden, cl::desc("Ignore RecMII"))
static cl::opt< int > SwpLoopLimit("pipeliner-max", cl::Hidden, cl::init(-1))
static bool computeDelta(const MachineInstr &MI, const TargetInstrInfo &TII, int &Delta)
Return true if we can compute the amount the instruction changes during each iteration.
static cl::opt< bool > SwpPruneLoopCarried("pipeliner-prune-loop-carried", cl::desc("Prune loop carried order dependences."), cl::Hidden, cl::init(true))
A command line option to disable the pruning of loop carried order dependences.
static cl::opt< unsigned > SwpMaxNumStores("pipeliner-max-num-stores", cl::desc("Maximum number of stores allwed in the target loop."), cl::Hidden, cl::init(200))
A command line argument to limit the number of store instructions in the target basic block.
static cl::opt< int > SwpMaxMii("pipeliner-max-mii", cl::desc("Size limit for the MII."), cl::Hidden, cl::init(27))
A command line argument to limit minimum initial interval for pipelining.
static cl::opt< int > SwpForceIssueWidth("pipeliner-force-issue-width", cl::desc("Force pipeliner to use specified issue width."), cl::Hidden, cl::init(-1))
A command line argument to force pipeliner to use specified issue width.
static bool isSuccOrder(SUnit *SUa, SUnit *SUb)
Return true if SUb can be reached from SUa following the chain edges.
static cl::opt< int > SwpMaxStages("pipeliner-max-stages", cl::desc("Maximum stages allowed in the generated scheduled."), cl::Hidden, cl::init(3))
A command line argument to limit the number of stages in the pipeline.
static cl::opt< bool > EnableSWPOptSize("enable-pipeliner-opt-size", cl::desc("Enable SWP at Os."), cl::Hidden, cl::init(false))
A command line option to enable SWP at -Os.
static bool hasPHICycle(const MachineBasicBlock *LoopHeader, const MachineRegisterInfo &MRI)
static bool runMachinePipeliner(MachineFunction &MF, function_ref< const MachineLoopInfo &()> GetMLI, function_ref< LiveIntervals &()> GetLIS, function_ref< AAResults &()> GetAA, function_ref< MachineOptimizationRemarkEmitter &()> GetORE, function_ref< RegisterClassInfo &()> GetRCI, function_ref< MachineDominatorTree *()> GetMDT)
static cl::opt< WindowSchedulingFlag > WindowSchedulingOption("window-sched", cl::Hidden, cl::init(WindowSchedulingFlag::WS_On), cl::desc("Set how to use window scheduling algorithm."), cl::values(clEnumValN(WindowSchedulingFlag::WS_Off, "off", "Turn off window algorithm."), clEnumValN(WindowSchedulingFlag::WS_On, "on", "Use window algorithm after SMS algorithm fails."), clEnumValN(WindowSchedulingFlag::WS_Force, "force", "Use window algorithm instead of SMS algorithm.")))
A command line argument to set the window scheduling option.
static bool pred_L(SetVector< SUnit * > &NodeOrder, SmallSetVector< SUnit *, 8 > &Preds, SwingSchedulerDDG *DDG, const NodeSet *S=nullptr)
Compute the Pred_L(O) set, as defined in the paper.
static cl::opt< bool > SwpShowResMask("pipeliner-show-mask", cl::Hidden, cl::init(false))
static cl::opt< int > SwpIISearchRange("pipeliner-ii-search-range", cl::desc("Range to search for II"), cl::Hidden, cl::init(10))
static bool computePath(SUnit *Cur, SetVector< SUnit * > &Path, SetVector< SUnit * > &DestNodes, SetVector< SUnit * > &Exclude, SmallPtrSet< SUnit *, 8 > &Visited, SwingSchedulerDDG *DDG)
Return true if there is a path from the specified node to any of the nodes in DestNodes.
static bool succ_L(SetVector< SUnit * > &NodeOrder, SmallSetVector< SUnit *, 8 > &Succs, SwingSchedulerDDG *DDG, const NodeSet *S=nullptr)
Compute the Succ_L(O) set, as defined in the paper.
static cl::opt< bool > LimitRegPressure("pipeliner-register-pressure", cl::Hidden, cl::init(false), cl::desc("Limit register pressure of scheduled loop"))
static cl::opt< bool > SwpPruneDeps("pipeliner-prune-deps", cl::desc("Prune dependences between unrelated Phi nodes."), cl::Hidden, cl::init(true))
A command line option to disable the pruning of chain dependences due to an unrelated Phi.
static SUnit * multipleIterations(SUnit *SU, SwingSchedulerDAG *DAG)
If an instruction has a use that spans multiple iterations, then return true.
static Register findUniqueOperandDefinedInLoop(const MachineInstr &MI)
static void getPhiRegs(const MachineInstr &Phi, const MachineBasicBlock *Loop, Register &InitVal, Register &LoopVal)
Return the register values for the operands of a Phi instruction.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
This file provides utility analysis objects describing memory locations.
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file defines the PriorityQueue class.
MachineRegisterInfo & MRI
Remove Loads Into Fake Uses
std::pair< BasicBlock *, BasicBlock * > Edge
This file defines generic set operations that may be used on set's of different types,...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Target-Independent Code Generator Pass Configuration Options pass.
Add loop-carried chain dependencies.
void computeDependencies()
The main function to compute loop-carried order-dependencies.
LoopCarriedOrderDepsTracker(SwingSchedulerDAG *SSD, BatchAAResults *BAA, const TargetInstrInfo *TII)
const BitVector & getLoopCarried(unsigned Idx) const
MachineOptimizationRemarkEmitter * ORE
const TargetInstrInfo * TII
bool run()
Run the software pipeliner over all loops in the function.
MachineDominatorTree * MDT
const MachineLoopInfo * MLI
MachinePipelinerImpl(MachineFunction &MF, const MachineLoopInfo &MLI, LiveIntervals &LIS, AAResults &AA, MachineOptimizationRemarkEmitter &ORE, RegisterClassInfo &RegClassInfo, MachineDominatorTree *MDT)
const InstrItineraryData * InstrItins
RegisterClassInfo * RegClassInfo
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
This class is a wrapper over an AAResults, and it is intended to be used only when there are no IR ch...
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
bool skipFunction(const Function &F) const
Optional passes call this function to check whether the pass should be skipped.
AttributeList getAttributes() const
Return the attribute list for this Function.
bool areMemAccessesTriviallyDisjoint(const MachineInstr &MIa, const MachineInstr &MIb) const override
bool isPostIncrement(const MachineInstr &MI) const override
Return true for post-incremented instructions.
bool getBaseAndOffsetPosition(const MachineInstr &MI, unsigned &BasePos, unsigned &OffsetPos) const override
For instructions with a base and offset, return the position of the base register and offset operands...
Itinerary data supplied by a subtarget to be used by a target.
const InstrStage * beginStage(unsigned ItinClassIndx) const
Return the first stage of the itinerary.
const InstrStage * endStage(unsigned ItinClassIndx) const
Return the last+1 stage of the itinerary.
bool isEmpty() const
Returns true if there are no itineraries.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
TypeSize getValue() const
Represents a single loop in the control flow graph.
unsigned getSchedClass() const
Return the scheduling class for this instruction.
const MCWriteProcResEntry * getWriteProcResEnd(const MCSchedClassDesc *SC) const
const MCWriteProcResEntry * getWriteProcResBegin(const MCSchedClassDesc *SC) const
Return an iterator at the first process resource consumed by the given scheduling class.
const MCSchedModel & getSchedModel() const
Get the machine model for this subtarget's CPU.
const MDOperand & getOperand(unsigned I) const
ArrayRef< MDOperand > operands() const
unsigned getNumOperands() const
Return number of MDNode operands.
LLVM_ABI StringRef getString() const
MachineInstrBundleIterator< const MachineInstr > const_iterator
iterator_range< iterator > phis()
Returns a range that iterates over the phis in the basic block.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
LLVM_ABI DebugLoc findDebugLoc(instr_iterator MBBI)
Find the next valid DebugLoc starting at MBBI, skipping any debug instructions.
instr_iterator instr_end()
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
filtered_mop_range all_defs()
Returns an iterator range over all operands that are (explicit or implicit) register defs.
bool memoperands_empty() const
Return true if we don't have any memory operands which described the memory access done by this instr...
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
bool isRegSequence() const
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
LLVM_ABI bool isIdenticalTo(const MachineInstr &Other, MICheckType Check=CheckDefs) const
Return true if this instruction is identical to Other.
LLVM_ABI void print(raw_ostream &OS, bool IsStandalone=true, bool SkipOpers=false, bool SkipDebugLoc=false, bool AddNewLine=true, const TargetInstrInfo *TII=nullptr) const
Print this MI to OS.
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
bool isPseudo(QueryType Type=IgnoreBundle) const
Return true if this is a pseudo instruction that doesn't correspond to a real machine instruction.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
Analysis pass that exposes the MachineLoopInfo for a machine function.
A description of a memory reference used in the backend.
AAMDNodes getAAInfo() const
Return the AA tags for the memory reference.
const Value * getValue() const
Return the base address of the memory access.
int64_t getOffset() const
For normal values, this is a byte offset added to the base address.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
void setImm(int64_t immVal)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
Register getReg() const
getReg - Returns the register number.
LLVM_ABI bool isIdenticalTo(const MachineOperand &Other) const
Returns true if this operand is identical to the specified operand except for liveness related flags ...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
defusechain_instr_iterator< true, false, false, true > use_instr_iterator
use_instr_iterator/use_instr_begin/use_instr_end - Walk all uses of the specified register,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
PSetIterator getPressureSets(VirtRegOrUnit VRegOrUnit) const
Get an iterator over the pressure sets affected by the virtual register or register unit.
MachineBasicBlock * getDefBlock(Register Reg) const
Return the machine basic block in which the specified virtual register is defined,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
static use_instr_iterator use_instr_end()
const MachineFunction & getMF() const
LLVM_ABI bool isReservedRegUnit(MCRegUnit Unit) const
Returns true when the given register unit is considered reserved.
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
static MemoryLocation getBeforeOrAfter(const Value *Ptr, const AAMDNodes &AATags=AAMDNodes())
Return a location that may access any location before or after Ptr, while remaining within the underl...
Expand the kernel using modulo variable expansion algorithm (MVE).
static LLVM_ABI bool canApply(MachineLoop &L)
Check if ModuloScheduleExpanderMVE can be applied to L.
The ModuloScheduleExpander takes a ModuloSchedule and expands it in-place, rewriting the old loop and...
LLVM_ABI void cleanup()
Performs final cleanup after expansion.
LLVM_ABI void expand()
Performs the actual expansion.
Expander that simply annotates each scheduled instruction with a post-instr symbol that can be consum...
LLVM_ABI void annotate()
Performs the annotation.
Represents a schedule for a single-block loop.
A NodeSet contains a set of SUnit DAG nodes with additional information that assigns a priority to th...
SUnit * getNode(unsigned i) const
LLVM_ABI void print(raw_ostream &os) const
void setRecMII(unsigned mii)
unsigned count(SUnit *SU) const
void setColocate(unsigned c)
int compareRecMII(NodeSet &RHS)
LLVM_DUMP_METHOD void dump() const
unsigned getWeight() const
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
AnalysisType * getAnalysisIfAvailable() const
getAnalysisIfAvailable<AnalysisType>() - Subclasses use this function to get analysis information tha...
A reimplementation of ModuloScheduleExpander.
PointerIntPair - This class implements a pair of a pointer and small integer.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Track the current register pressure at some position in the instruction stream, and remember the high...
LLVM_ABI void addLiveRegs(ArrayRef< VRegMaskOrUnit > Regs)
Force liveness of virtual registers or physical register units.
unsigned getRegPressureSetLimit(unsigned Idx) const
Get the register unit limit for the given pressure set index.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
LLVM_ABI int calculateResMII() const
LLVM_ABI void initProcResourceVectors(const MCSchedModel &SM, SmallVectorImpl< uint64_t > &Masks)
LLVM_ABI ResourceManager(const TargetSubtargetInfo *ST, ScheduleDAGInstrs *DAG)
LLVM_ABI void init(int II)
Initialize resources with the initiation interval II.
LLVM_ABI bool canReserveResources(SUnit &SU, int Cycle)
Check if the resources occupied by a machine instruction are available in the current state.
Kind
These are the different kinds of scheduling dependencies.
@ Order
Any other ordering dependency.
@ Anti
A register anti-dependence (aka WAR).
@ Data
Regular data dependence (aka true-dependence).
void setLatency(unsigned Lat)
Sets the latency for this edge.
@ Barrier
An unknown scheduling barrier.
@ Artificial
Arbitrary strong DAG edge (no real dependence).
This class represents the scheduled code.
LLVM_ABI std::deque< SUnit * > reorderInstructions(const SwingSchedulerDAG *SSD, const std::deque< SUnit * > &Instrs) const
void setInitiationInterval(int ii)
Set the initiation interval for this schedule.
LLVM_ABI void dump() const
Utility function used for debugging to print the schedule.
LLVM_ABI bool insert(SUnit *SU, int StartCycle, int EndCycle, int II)
Try to schedule the node at the specified StartCycle and continue until the node is schedule or the E...
unsigned getMaxStageCount()
Return the maximum stage count needed for this schedule.
LLVM_ABI void print(raw_ostream &os) const
Print the schedule information to the given output.
LLVM_ABI bool onlyHasLoopCarriedOutputOrOrderPreds(SUnit *SU, const SwingSchedulerDDG *DDG) const
Return true if all scheduled predecessors are loop-carried output/order dependencies.
int stageScheduled(SUnit *SU) const
Return the stage for a scheduled instruction.
LLVM_ABI void orderDependence(const SwingSchedulerDAG *SSD, SUnit *SU, std::deque< SUnit * > &Insts) const
Order the instructions within a cycle so that the definitions occur before the uses.
LLVM_ABI bool isValidSchedule(SwingSchedulerDAG *SSD)
int getInitiationInterval() const
Return the initiation interval for this schedule.
std::deque< SUnit * > & getInstructions(int cycle)
Return the instructions that are scheduled at the specified cycle.
int getFirstCycle() const
Return the first cycle in the completed schedule.
DenseMap< int, std::deque< SUnit * > >::const_iterator const_sched_iterator
LLVM_ABI bool isLoopCarriedDefOfUse(const SwingSchedulerDAG *SSD, MachineInstr *Def, MachineOperand &MO) const
Return true if the instruction is a definition that is loop carried and defines the use on the next i...
unsigned cycleScheduled(SUnit *SU) const
Return the cycle for a scheduled instruction.
LLVM_ABI SmallPtrSet< SUnit *, 8 > computeUnpipelineableNodes(SwingSchedulerDAG *SSD, TargetInstrInfo::PipelinerLoopInfo *PLI)
Determine transitive dependences of unpipelineable instructions.
LLVM_ABI void computeStart(SUnit *SU, int *MaxEarlyStart, int *MinLateStart, int II, SwingSchedulerDAG *DAG)
Compute the scheduling start slot for the instruction.
LLVM_ABI bool normalizeNonPipelinedInstructions(SwingSchedulerDAG *SSD, TargetInstrInfo::PipelinerLoopInfo *PLI)
LLVM_ABI bool isLoopCarried(const SwingSchedulerDAG *SSD, MachineInstr &Phi) const
Return true if the scheduled Phi has a loop carried operand.
int getFinalCycle() const
Return the last cycle in the finalized schedule.
LLVM_ABI void finalizeSchedule(SwingSchedulerDAG *SSD)
After the schedule has been formed, call this function to combine the instructions from the different...
Scheduling unit. This is a node in the scheduling DAG.
bool isInstr() const
Returns true if this SUnit refers to a machine instruction as opposed to an SDNode.
unsigned NodeNum
Entry # of node in the node vector.
void setInstr(MachineInstr *MI)
Assigns the instruction for the SUnit.
LLVM_ABI void removePred(const SDep &D)
Removes the specified edge as a pred of the current node if it exists.
bool isPred(const SUnit *N) const
Tests if node N is a predecessor of this node.
bool isBoundaryNode() const
Boundary nodes are placeholders for the boundary of the scheduling region.
bool hasPhysRegDefs
Has physreg defs that are being used.
SmallVector< SDep, 4 > Succs
All sunit successors.
SmallVector< SDep, 4 > Preds
All sunit predecessors.
LLVM_ABI bool addPred(const SDep &D, bool Required=true)
Adds the specified edge as a pred of the current node if not already.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
A ScheduleDAG for scheduling lists of MachineInstr.
DenseMap< MachineInstr *, SUnit * > MISUnitMap
After calling BuildSchedGraph, each machine instruction in the current scheduling region is mapped to...
virtual void finishBlock()
Cleans up after scheduling in the given block.
ScheduleDAGInstrs(MachineFunction &mf, const MachineLoopInfo *mli, bool RemoveKillFlags=false)
void buildSchedGraph(AAResults *AA, RegPressureTracker *RPTracker=nullptr, PressureDiffs *PDiffs=nullptr, LiveIntervals *LIS=nullptr, bool TrackLaneMasks=false)
Builds SUnits for the current region.
SUnit * getSUnit(MachineInstr *MI) const
Returns an existing SUnit for this MI, or nullptr.
const MachineLoopInfo * MLI
void dump() const override
LLVM_ABI void AddPred(SUnit *Y, SUnit *X)
Updates the topological ordering to accommodate an edge to be added from SUnit X to SUnit Y.
LLVM_ABI bool IsReachable(const SUnit *SU, const SUnit *TargetSU)
Checks if SU is reachable from TargetSU.
MachineRegisterInfo & MRI
Virtual/real register map.
const TargetInstrInfo * TII
Target instruction information.
std::vector< SUnit > SUnits
The scheduling units.
const TargetRegisterInfo * TRI
Target processor register info.
SUnit EntrySU
Special node for the region entry.
MachineFunction & MF
Machine function.
SUnit ExitSU
Special node for the region exit.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
void insert_range(Range &&R)
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
typename vector_type::const_iterator iterator
bool contains(const_arg_type key) const
Check if the SetVector contains the given key.
void clear()
Completely clear the SetVector.
bool empty() const
Determine if the SetVector is empty or not.
bool insert(const value_type &X)
Insert a new element into the SetVector.
SlotIndex insertMachineInstrInMaps(MachineInstr &MI, bool Late=false)
Insert the given machine instruction into the mapping.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
bool contains(const T &V) const
Check if the SmallSet contains the given element.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This class builds the dependence graph for the instructions in a loop, and attempts to schedule the i...
SwingSchedulerDAG(MachineFunction &MF, const MachineLoopInfo *MLI, MachineOptimizationRemarkEmitter *ORE, MachineLoop &L, LiveIntervals &lis, const RegisterClassInfo &rci, unsigned II, TargetInstrInfo::PipelinerLoopInfo *PLI, AliasAnalysis *AA, MachineDominatorTree *MDT=nullptr)
void applyInstrChange(MachineInstr *MI, SMSchedule &Schedule)
Apply changes to the instruction if needed.
const SwingSchedulerDDG * getDDG() const
void finishBlock() override
Clean up after the software pipeliner runs.
void fixupRegisterOverlaps(std::deque< SUnit * > &Instrs)
Attempt to fix the degenerate cases when the instruction serialization causes the register lifetimes ...
void schedule() override
We override the schedule function in ScheduleDAGInstrs to implement the scheduling part of the Swing ...
Register getInstrBaseReg(SUnit *SU) const
Return the new base register that was stored away for the changed instruction.
Represents a dependence between two instruction.
LLVM_ABI bool ignoreDependence(bool IgnoreAnti) const
Returns true for DDG nodes that we ignore when computing the cost functions.
This class provides APIs to retrieve edges from/to an SUnit node, with a particular focus on loop-car...
LLVM_ABI SwingSchedulerDDG(std::vector< SUnit > &SUnits, SUnit *EntrySU, SUnit *ExitSU, const LoopCarriedEdges &LCE)
LLVM_ABI ArrayRef< SUnit * > getExtraOutEdges(const SUnit *SU) const
LLVM_ABI const EdgesType & getInEdges(const SUnit *SU) const
LLVM_ABI bool isValidSchedule(const SMSchedule &Schedule) const
Check if Schedule doesn't violate the validation-only dependencies.
LLVM_ABI const EdgesType & getOutEdges(const SUnit *SU) const
Object returned by analyzeLoopForPipelining.
virtual bool shouldIgnoreForPipelining(const MachineInstr *MI) const =0
Return true if the given instruction should not be pipelined and should be ignored.
TargetInstrInfo - Interface to description of machine instruction set.
Primary interface to the complete machine description for the target machine.
Target-Independent Code Generator Pass Configuration Options.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual void overridePipelinerPolicy(MachinePipelinerPolicy &Policy) const
Override generic software pipelining policy.
virtual bool enableMachinePipeliner() const
True if the subtarget should run MachinePipeliner.
virtual bool useDFAforSMS() const
Default to DFA for resource management, return false when target will use ProcResource in InstrSchedM...
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const InstrItineraryData * getInstrItineraryData() const
getInstrItineraryData - Returns instruction itinerary data for the target or specific subtarget.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Wrapper class representing a virtual register or register unit.
constexpr bool isVirtualReg() const
constexpr MCRegUnit asMCRegUnit() const
constexpr Register asVirtualReg() const
The main class in the implementation of the target independent window scheduler.
int getNumOccurrences() const
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
@ BasicBlock
Various leaf nodes.
@ Valid
The data is already valid.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< DefNode * > Def
NodeAddr< PhiNode * > Phi
NodeAddr< UseNode * > Use
std::set< NodeId > NodeSet
friend class Instruction
Iterator for Instructions in a `BasicBlock.
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
void stable_sort(R &&Range)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
constexpr NextUseDistance min(NextUseDistance A, NextUseDistance B)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
bool set_is_subset(const S1Ty &S1, const S2Ty &S2)
set_is_subset(A, B) - Return true iff A in B
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
@ WS_Force
Use window algorithm after SMS algorithm fails.
@ WS_On
Turn off window algorithm.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
RegState getRegState(const MachineOperand &RegOp)
Get all register state flags from machine operand RegOp.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
LLVM_ABI bool mayOverlapInLaterIter(const MachineInstr *BaseMI, const MachineInstr *OtherMI, const MachineBasicBlock *LoopBB, const MachineRegisterInfo &MRI, const TargetInstrInfo &TII)
Return true if BaseMI and OtherMI may access overlapping memory in a later iteration of the loop Loop...
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
LLVM_ABI char & MachinePipelinerID
This pass performs software pipelining on machine instructions.
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
@ Increment
Incrementally increasing token ID.
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
LLVM_ABI void getUnderlyingObjects(const Value *V, SmallVectorImpl< const Value * > &Objects, const LoopInfo *LI=nullptr, unsigned MaxLookup=MaxLookupSearchDepth)
This method is similar to getUnderlyingObject except that it can look through phi and select instruct...
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
LLVM_ABI Printable printVRegOrUnit(VirtRegOrUnit VRegOrUnit, const TargetRegisterInfo *TRI)
Create Printable object to print virtual registers and physical registers on a raw_ostream.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Cache the target analysis information about the loop.
std::unique_ptr< TargetInstrInfo::PipelinerLoopInfo > LoopPipelinerInfo
SmallVector< MachineOperand, 4 > BrCond
MachineInstr * LoopCompare
MachineInstr * LoopInductionVar
This class holds an SUnit corresponding to a memory operation and other information related to the in...
const Value * MemOpValue
The value of a memory operand.
SmallVector< const Value *, 2 > UnderlyingObjs
bool isTriviallyDisjoint(const SUnitWithMemInfo &Other) const
int64_t MemOpOffset
The offset of a memory operand.
bool IsAllIdentified
True if all the underlying objects are identified.
SUnitWithMemInfo(SUnit *SU)
A collection of metadata nodes that might be associated with a memory access used by the alias-analys...
uint64_t FuncUnits
Bitmask representing a set of functional units.
static constexpr LaneBitmask getNone()
Represents loop-carried dependencies.
SmallSetVector< SUnit *, 8 > OrderDep
LLVM_ABI void dump(SUnit *SU, const TargetRegisterInfo *TRI, const MachineRegisterInfo *MRI) const
const OrderDep * getOrderDepOrNull(SUnit *Key) const
LLVM_ABI void modifySUnits(std::vector< SUnit > &SUnits, const TargetInstrInfo *TII)
Adds some edges to the original DAG that correspond to loop-carried dependencies.
Define a kind of processor resource that will be modeled by the scheduler.
Summarize the scheduling resources required for an instruction of a particular scheduling class.
Machine model for scheduling, bundling, and heuristics.
const MCSchedClassDesc * getSchedClassDesc(unsigned SchedClassIdx) const
bool hasInstrSchedModel() const
Does this machine model include instruction-level scheduling.
const MCProcResourceDesc * getProcResource(unsigned ProcResourceIdx) const
Identify one of the processor resource kinds consumed by a particular scheduling class for the specif...
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...
std::vector< unsigned > MaxSetPressure
Map of max reg pressure indexed by pressure set ID, not class ID.