71#include "llvm/Config/llvm-config.h"
100#define DEBUG_TYPE "pipeliner"
102STATISTIC(NumTrytoPipeline,
"Number of loops that we attempt to pipeline");
103STATISTIC(NumPipelined,
"Number of loops software pipelined");
104STATISTIC(NumNodeOrderIssues,
"Number of node order issues found");
105STATISTIC(NumFailBranch,
"Pipeliner abort due to unknown branch");
106STATISTIC(NumFailLoop,
"Pipeliner abort due to unsupported loop");
107STATISTIC(NumFailPreheader,
"Pipeliner abort due to missing preheader");
108STATISTIC(NumFailLargeMaxMII,
"Pipeliner abort due to MaxMII too large");
109STATISTIC(NumFailZeroMII,
"Pipeliner abort due to zero MII");
110STATISTIC(NumFailNoSchedule,
"Pipeliner abort due to no schedule found");
111STATISTIC(NumFailZeroStage,
"Pipeliner abort due to zero stage");
112STATISTIC(NumFailLargeMaxStage,
"Pipeliner abort due to too many stages");
113STATISTIC(NumFailTooManyStores,
"Pipeliner abort due to too many stores");
117 cl::desc(
"Enable Software Pipelining"));
126 cl::desc(
"Size limit for the MII."),
132 cl::desc(
"Force pipeliner to use specified II."),
138 cl::desc(
"Maximum stages allowed in the generated scheduled."),
145 cl::desc(
"Prune dependences between unrelated Phi nodes."),
152 cl::desc(
"Prune loop carried order dependences."),
170 cl::desc(
"Instead of emitting the pipelined code, annotate instructions "
171 "with the generated schedule for feeding into the "
172 "-modulo-schedule-test pass"));
177 "Use the experimental peeling code generator for software pipelining"));
185 cl::desc(
"Limit register pressure of scheduled loop"));
190 cl::desc(
"Margin representing the unused percentage of "
191 "the register pressure limit"));
195 cl::desc(
"Use the MVE code generator for software pipelining"));
200 "pipeliner-max-num-stores",
208 cl::desc(
"Enable CopyToPhi DAG Mutation"));
213 "pipeliner-force-issue-width",
220 cl::desc(
"Set how to use window scheduling algorithm."),
222 "Turn off window algorithm."),
224 "Use window algorithm after SMS algorithm fails."),
226 "Use window algorithm instead of SMS algorithm.")));
228unsigned SwingSchedulerDAG::Circuits::MaxPaths = 5;
236 "Modulo Software Pipelining",
false,
false)
278 enum class InstrTag {
287 TaggedSUnit(
SUnit *SU, InstrTag Tag)
290 InstrTag
getTag()
const {
return InstrTag(getInt()); }
295 struct NoBarrierInstsChunk {
300 void append(
SUnit *SU);
305 std::vector<SUnit> &SUnits;
311 std::vector<BitVector> LoopCarried;
324 std::vector<TaggedSUnit> TaggedSUnits;
338 return LoopCarried[Idx];
343 std::optional<InstrTag> getInstrTag(
SUnit *SU)
const;
345 void addLoopCarriedDepenenciesForChunks(
const NoBarrierInstsChunk &From,
346 const NoBarrierInstsChunk &To);
353 void computeDependenciesAux();
355 void setLoopCarriedDep(
const SUnit *Src,
const SUnit *Dst) {
356 LoopCarried[Src->NodeNum].set(Dst->NodeNum);
388 TII =
MF->getSubtarget().getInstrInfo();
390 for (
const auto &L : *
MLI)
400bool MachinePipeliner::scheduleLoop(
MachineLoop &L) {
402 for (
const auto &InnerLoop : L)
403 Changed |= scheduleLoop(*InnerLoop);
415 setPragmaPipelineOptions(L);
416 if (!canPipelineLoop(L)) {
420 L.getStartLoc(), L.getHeader())
421 <<
"Failed to pipeline loop";
424 LI.LoopPipelinerInfo.reset();
429 if (useSwingModuloScheduler())
430 Changed = swingModuloScheduler(L);
432 if (useWindowScheduler(
Changed))
433 Changed = runWindowScheduler(L);
435 LI.LoopPipelinerInfo.reset();
439void MachinePipeliner::setPragmaPipelineOptions(
MachineLoop &L) {
444 MachineBasicBlock *LBLK =
L.getTopBlock();
457 MDNode *LoopID = TI->
getMetadata(LLVMContext::MD_loop);
458 if (LoopID ==
nullptr)
475 if (S->
getString() ==
"llvm.loop.pipeline.initiationinterval") {
477 "Pipeline initiation interval hint metadata should have two operands.");
481 }
else if (S->
getString() ==
"llvm.loop.pipeline.disable") {
494 auto It = PhiDeps.find(
Reg);
495 if (It == PhiDeps.end())
506 for (
unsigned Dep : It->second) {
521 unsigned DefReg =
MI.getOperand(0).getReg();
525 for (
unsigned I = 1;
I <
MI.getNumOperands();
I += 2)
526 Ins->second.push_back(
MI.getOperand(
I).getReg());
533 for (
const auto &KV : PhiDeps) {
534 unsigned Reg = KV.first;
545bool MachinePipeliner::canPipelineLoop(
MachineLoop &L) {
546 if (
L.getNumBlocks() != 1) {
548 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
549 L.getStartLoc(),
L.getHeader())
550 <<
"Not a single basic block: "
551 <<
ore::NV(
"NumBlocks",
L.getNumBlocks());
563 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
564 L.getStartLoc(),
L.getHeader())
565 <<
"Disabled by Pragma.";
575 if (
TII->analyzeBranch(*
L.getHeader(),
LI.TBB,
LI.FBB,
LI.BrCond)) {
576 LLVM_DEBUG(
dbgs() <<
"Unable to analyzeBranch, can NOT pipeline Loop\n");
579 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
580 L.getStartLoc(),
L.getHeader())
581 <<
"The branch can't be understood";
586 LI.LoopInductionVar =
nullptr;
587 LI.LoopCompare =
nullptr;
588 LI.LoopPipelinerInfo =
TII->analyzeLoopForPipelining(
L.getTopBlock());
589 if (!
LI.LoopPipelinerInfo) {
590 LLVM_DEBUG(
dbgs() <<
"Unable to analyzeLoop, can NOT pipeline Loop\n");
593 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
594 L.getStartLoc(),
L.getHeader())
595 <<
"The loop structure is not supported";
600 if (!
L.getLoopPreheader()) {
601 LLVM_DEBUG(
dbgs() <<
"Preheader not found, can NOT pipeline Loop\n");
604 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
605 L.getStartLoc(),
L.getHeader())
606 <<
"No loop preheader found";
611 unsigned NumStores = 0;
612 for (MachineInstr &
MI : *
L.getHeader())
617 NumFailTooManyStores++;
619 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
620 L.getStartLoc(),
L.getHeader())
621 <<
"Too many store instructions in the loop: "
622 <<
ore::NV(
"NumStores", NumStores) <<
" > "
629 preprocessPhiNodes(*
L.getHeader());
634 MachineRegisterInfo &MRI =
MF->getRegInfo();
638 for (MachineInstr &PI :
B.phis()) {
639 MachineOperand &DefOp = PI.getOperand(0);
643 for (
unsigned i = 1, n = PI.getNumOperands(); i != n; i += 2) {
644 MachineOperand &RegOp = PI.getOperand(i);
651 MachineBasicBlock &PredB = *PI.getOperand(i+1).getMBB();
668bool MachinePipeliner::swingModuloScheduler(
MachineLoop &L) {
669 assert(
L.getBlocks().size() == 1 &&
"SMS works on single blocks only.");
672 SwingSchedulerDAG SMS(
676 MachineBasicBlock *
MBB =
L.getHeader();
694 return SMS.hasNewSchedule();
709bool MachinePipeliner::runWindowScheduler(
MachineLoop &L) {
716 Context.RegClassInfo =
722bool MachinePipeliner::useSwingModuloScheduler() {
727bool MachinePipeliner::useWindowScheduler(
bool Changed) {
734 "llvm.loop.pipeline.initiationinterval is set.\n");
742void SwingSchedulerDAG::setMII(
unsigned ResMII,
unsigned RecMII) {
745 else if (II_setByPragma > 0)
746 MII = II_setByPragma;
748 MII = std::max(ResMII, RecMII);
751void SwingSchedulerDAG::setMAX_II() {
754 else if (II_setByPragma > 0)
755 MAX_II = II_setByPragma;
765 updatePhiDependences();
766 Topo.InitDAGTopologicalSorting();
772 dbgs() <<
"===== Loop Carried Edges Begin =====\n";
775 dbgs() <<
"===== Loop Carried Edges End =====\n";
778 NodeSetType NodeSets;
779 findCircuits(NodeSets);
780 NodeSetType Circuits = NodeSets;
783 unsigned ResMII = calculateResMII();
784 unsigned RecMII = calculateRecMII(NodeSets);
792 setMII(ResMII, RecMII);
796 <<
" (rec=" << RecMII <<
", res=" << ResMII <<
")\n");
802 Pass.ORE->emit([&]() {
804 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
805 <<
"Invalid Minimal Initiation Interval: 0";
813 <<
", we don't pipeline large loops\n");
814 NumFailLargeMaxMII++;
815 Pass.ORE->emit([&]() {
817 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
818 <<
"Minimal Initiation Interval too large: "
819 <<
ore::NV(
"MII", (
int)MII) <<
" > "
821 <<
"Refer to -pipeliner-max-mii.";
826 computeNodeFunctions(NodeSets);
828 registerPressureFilter(NodeSets);
830 colocateNodeSets(NodeSets);
832 checkNodeSets(NodeSets);
835 for (
auto &
I : NodeSets) {
836 dbgs() <<
" Rec NodeSet ";
843 groupRemainingNodes(NodeSets);
845 removeDuplicateNodes(NodeSets);
848 for (
auto &
I : NodeSets) {
849 dbgs() <<
" NodeSet ";
854 computeNodeOrder(NodeSets);
857 checkValidNodeOrder(Circuits);
860 Scheduled = schedulePipeline(Schedule);
865 Pass.ORE->emit([&]() {
867 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
868 <<
"Unable to find schedule";
875 if (numStages == 0) {
878 Pass.ORE->emit([&]() {
880 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
881 <<
"No need to pipeline - no overlapped iterations in schedule.";
888 <<
" : too many stages, abort\n");
889 NumFailLargeMaxStage++;
890 Pass.ORE->emit([&]() {
892 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
893 <<
"Too many stages in schedule: "
894 <<
ore::NV(
"numStages", (
int)numStages) <<
" > "
896 <<
". Refer to -pipeliner-max-stages.";
901 Pass.ORE->emit([&]() {
904 <<
"Pipelined succesfully!";
909 std::vector<MachineInstr *> OrderedInsts;
913 OrderedInsts.push_back(SU->getInstr());
914 Cycles[SU->getInstr()] = Cycle;
919 for (
auto &KV : NewMIs) {
920 Cycles[KV.first] = Cycles[KV.second];
921 Stages[KV.first] = Stages[KV.second];
922 NewInstrChanges[KV.first] = InstrChanges[
getSUnit(KV.first)];
929 "Cannot serialize a schedule with InstrChanges!");
939 LoopPipelinerInfo->isMVEExpanderSupported() &&
953 for (
auto &KV : NewMIs)
954 MF.deleteMachineInstr(KV.second);
965 assert(Phi.isPHI() &&
"Expecting a Phi.");
969 for (
unsigned i = 1, e = Phi.getNumOperands(); i != e; i += 2)
970 if (Phi.getOperand(i + 1).getMBB() !=
Loop)
971 InitVal = Phi.getOperand(i).getReg();
973 LoopVal = Phi.getOperand(i).getReg();
975 assert(InitVal && LoopVal &&
"Unexpected Phi structure.");
981 for (
unsigned i = 1, e = Phi.getNumOperands(); i != e; i += 2)
982 if (Phi.getOperand(i + 1).getMBB() == LoopBB)
983 return Phi.getOperand(i).getReg();
992 while (!Worklist.
empty()) {
994 for (
const auto &
SI : SU->
Succs) {
997 if (Visited.
count(SuccSU))
1010 if (!getUnderlyingObjects())
1035bool SUnitWithMemInfo::getUnderlyingObjects() {
1037 if (!
MI->hasOneMemOperand())
1055 const SUnitWithMemInfo &Dst,
1060 if (Src.isTriviallyDisjoint(Dst))
1074 if (Src.isUnknown() || Dst.isUnknown())
1076 if (Src.MemOpValue == Dst.MemOpValue && Src.MemOpOffset <= Dst.MemOpOffset)
1087 for (
const Value *SrcObj : Src.UnderlyingObjs)
1088 for (
const Value *DstObj : Dst.UnderlyingObjs)
1096void LoopCarriedOrderDepsTracker::NoBarrierInstsChunk::append(SUnit *SU) {
1099 Stores.emplace_back(SU);
1100 else if (
MI->mayLoad())
1101 Loads.emplace_back(SU);
1102 else if (
MI->mayRaiseFPException())
1103 FPExceptions.emplace_back(SU);
1111 : DAG(SSD), BAA(BAA), SUnits(DAG->SUnits), N(SUnits.
size()),
1112 LoopCarried(N,
BitVector(N)), TII(TII), TRI(TRI) {}
1116 for (
auto &SU : SUnits) {
1117 auto Tagged = getInstrTag(&SU);
1122 TaggedSUnits.emplace_back(&SU, *Tagged);
1125 computeDependenciesAux();
1128std::optional<LoopCarriedOrderDepsTracker::InstrTag>
1129LoopCarriedOrderDepsTracker::getInstrTag(
SUnit *SU)
const {
1131 if (
TII->isGlobalMemoryObject(
MI))
1132 return InstrTag::Barrier;
1134 if (
MI->mayStore() ||
1135 (
MI->mayLoad() && !
MI->isDereferenceableInvariantLoad()))
1136 return InstrTag::LoadOrStore;
1138 if (
MI->mayRaiseFPException())
1139 return InstrTag::FPExceptions;
1141 return std::nullopt;
1144void LoopCarriedOrderDepsTracker::addDependenciesBetweenSUs(
1145 const SUnitWithMemInfo &Src,
const SUnitWithMemInfo &Dst) {
1147 if (Src.SU == Dst.SU)
1151 setLoopCarriedDep(Src.SU, Dst.SU);
1154void LoopCarriedOrderDepsTracker::addLoopCarriedDepenenciesForChunks(
1155 const NoBarrierInstsChunk &From,
const NoBarrierInstsChunk &To) {
1157 for (
const SUnitWithMemInfo &Src : From.Loads)
1158 for (
const SUnitWithMemInfo &Dst : To.Stores)
1159 addDependenciesBetweenSUs(Src, Dst);
1162 for (
const SUnitWithMemInfo &Src : From.Stores)
1163 for (
const SUnitWithMemInfo &Dst : To.Loads)
1164 addDependenciesBetweenSUs(Src, Dst);
1167 for (
const SUnitWithMemInfo &Src : From.Stores)
1168 for (
const SUnitWithMemInfo &Dst : To.Stores)
1169 addDependenciesBetweenSUs(Src, Dst);
1172void LoopCarriedOrderDepsTracker::computeDependenciesAux() {
1174 SUnit *FirstBarrier =
nullptr;
1175 SUnit *LastBarrier =
nullptr;
1176 for (
const auto &TSU : TaggedSUnits) {
1177 InstrTag
Tag = TSU.getTag();
1178 SUnit *SU = TSU.getPointer();
1180 case InstrTag::Barrier:
1184 Chunks.emplace_back();
1186 case InstrTag::LoadOrStore:
1187 case InstrTag::FPExceptions:
1188 Chunks.back().append(SU);
1196 for (
const NoBarrierInstsChunk &Chunk : Chunks)
1197 addLoopCarriedDepenenciesForChunks(Chunk, Chunk);
1226 assert(LastBarrier &&
"Both barriers should be set.");
1229 for (
const SUnitWithMemInfo &Dst : Chunks.front().Loads)
1230 setLoopCarriedDep(LastBarrier, Dst.SU);
1231 for (
const SUnitWithMemInfo &Dst : Chunks.front().Stores)
1232 setLoopCarriedDep(LastBarrier, Dst.SU);
1233 for (
const SUnitWithMemInfo &Dst : Chunks.front().FPExceptions)
1234 setLoopCarriedDep(LastBarrier, Dst.SU);
1237 for (
const SUnitWithMemInfo &Src : Chunks.back().Loads)
1238 setLoopCarriedDep(Src.SU, FirstBarrier);
1239 for (
const SUnitWithMemInfo &Src : Chunks.back().Stores)
1240 setLoopCarriedDep(Src.SU, FirstBarrier);
1241 for (
const SUnitWithMemInfo &Src : Chunks.back().FPExceptions)
1242 setLoopCarriedDep(Src.SU, FirstBarrier);
1245 if (FirstBarrier != LastBarrier)
1246 setLoopCarriedDep(LastBarrier, FirstBarrier);
1255LoopCarriedEdges SwingSchedulerDAG::addLoopCarriedDependences() {
1256 LoopCarriedEdges LCE;
1260 LCODTracker.computeDependencies();
1261 for (
unsigned I = 0;
I != SUnits.size();
I++)
1262 for (
const int Succ : LCODTracker.getLoopCarried(
I).set_bits())
1275void SwingSchedulerDAG::updatePhiDependences() {
1277 const TargetSubtargetInfo &
ST = MF.getSubtarget<TargetSubtargetInfo>();
1280 for (SUnit &
I : SUnits) {
1285 MachineInstr *
MI =
I.getInstr();
1287 for (
const MachineOperand &MO :
MI->operands()) {
1297 MachineInstr *
UseMI = &*UI;
1298 SUnit *SU = getSUnit(
UseMI);
1324 }
else if (MO.isUse()) {
1327 if (
DefMI ==
nullptr)
1329 SUnit *SU = getSUnit(
DefMI);
1334 ST.adjustSchedDependency(SU, 0, &
I, MO.getOperandNo(), Dep,
1341 if (SU->
NodeNum <
I.NodeNum && !
I.isPred(SU))
1350 for (
auto &PI :
I.Preds) {
1351 MachineInstr *PMI = PI.getSUnit()->getInstr();
1353 if (
I.getInstr()->isPHI()) {
1362 for (
const SDep &
D : RemoveDeps)
1369void SwingSchedulerDAG::changeDependences() {
1373 for (SUnit &
I : SUnits) {
1374 unsigned BasePos = 0, OffsetPos = 0;
1376 int64_t NewOffset = 0;
1377 if (!canUseLastOffsetValue(
I.getInstr(), BasePos, OffsetPos, NewBase,
1382 Register OrigBase =
I.getInstr()->getOperand(BasePos).getReg();
1386 SUnit *DefSU = getSUnit(
DefMI);
1393 SUnit *LastSU = getSUnit(LastMI);
1397 if (Topo.IsReachable(&
I, LastSU))
1402 for (
const SDep &
P :
I.Preds)
1403 if (
P.getSUnit() == DefSU)
1405 for (
const SDep &
D : Deps) {
1406 Topo.RemovePred(&
I,
D.getSUnit());
1411 for (
auto &
P : LastSU->
Preds)
1414 for (
const SDep &
D : Deps) {
1415 Topo.RemovePred(LastSU,
D.getSUnit());
1422 Topo.AddPred(LastSU, &
I);
1427 InstrChanges[&
I] = std::make_pair(NewBase, NewOffset);
1438 std::vector<MachineInstr *> &OrderedInsts,
1446 Stage <= LastStage; ++Stage) {
1449 Instrs[Cycle].push_front(SU);
1456 std::deque<SUnit *> &CycleInstrs = Instrs[Cycle];
1458 for (
SUnit *SU : CycleInstrs) {
1460 OrderedInsts.push_back(
MI);
1470struct FuncUnitSorter {
1471 const InstrItineraryData *InstrItins;
1472 const MCSubtargetInfo *STI;
1473 DenseMap<InstrStage::FuncUnits, unsigned>
Resources;
1475 FuncUnitSorter(
const TargetSubtargetInfo &TSI)
1476 : InstrItins(TSI.getInstrItineraryData()), STI(&TSI) {}
1481 unsigned minFuncUnits(
const MachineInstr *Inst,
1484 unsigned min = UINT_MAX;
1485 if (InstrItins && !InstrItins->
isEmpty()) {
1486 for (
const InstrStage &IS :
1488 InstrItins->
endStage(SchedClass))) {
1491 if (numAlternatives <
min) {
1492 min = numAlternatives;
1499 const MCSchedClassDesc *SCDesc =
1506 for (
const MCWriteProcResEntry &PRE :
1509 if (!PRE.ReleaseAtCycle)
1511 const MCProcResourceDesc *ProcResource =
1513 unsigned NumUnits = ProcResource->
NumUnits;
1514 if (NumUnits <
min) {
1516 F = PRE.ProcResourceIdx;
1521 llvm_unreachable(
"Should have non-empty InstrItins or hasInstrSchedModel!");
1529 void calcCriticalResources(MachineInstr &
MI) {
1530 unsigned SchedClass =
MI.getDesc().getSchedClass();
1531 if (InstrItins && !InstrItins->
isEmpty()) {
1532 for (
const InstrStage &IS :
1534 InstrItins->
endStage(SchedClass))) {
1542 const MCSchedClassDesc *SCDesc =
1549 for (
const MCWriteProcResEntry &PRE :
1552 if (!PRE.ReleaseAtCycle)
1558 llvm_unreachable(
"Should have non-empty InstrItins or hasInstrSchedModel!");
1562 bool operator()(
const MachineInstr *IS1,
const MachineInstr *IS2)
const {
1564 unsigned MFUs1 = minFuncUnits(IS1, F1);
1565 unsigned MFUs2 = minFuncUnits(IS2, F2);
1568 return MFUs1 > MFUs2;
1573class HighRegisterPressureDetector {
1574 MachineBasicBlock *OrigMBB;
1575 const MachineRegisterInfo &MRI;
1576 const TargetRegisterInfo *
TRI;
1578 const unsigned PSetNum;
1584 std::vector<unsigned> InitSetPressure;
1588 std::vector<unsigned> PressureSetLimit;
1590 DenseMap<MachineInstr *, RegisterOperands> ROMap;
1592 using Instr2LastUsesTy = DenseMap<MachineInstr *, SmallDenseSet<Register, 4>>;
1595 using OrderedInstsTy = std::vector<MachineInstr *>;
1596 using Instr2StageTy = DenseMap<MachineInstr *, unsigned>;
1599 static void dumpRegisterPressures(
const std::vector<unsigned> &Pressures) {
1600 if (Pressures.size() == 0) {
1604 for (
unsigned P : Pressures) {
1615 VirtRegOrUnit VRegOrUnit =
1617 : VirtRegOrUnit(static_cast<MCRegUnit>(
Reg.id()));
1620 dbgs() << *PSetIter <<
' ';
1625 void increaseRegisterPressure(std::vector<unsigned> &Pressure,
1628 VirtRegOrUnit VRegOrUnit =
1630 : VirtRegOrUnit(static_cast<MCRegUnit>(
Reg.id()));
1633 for (; PSetIter.isValid(); ++PSetIter)
1634 Pressure[*PSetIter] += Weight;
1637 void decreaseRegisterPressure(std::vector<unsigned> &Pressure,
1640 unsigned Weight = PSetIter.getWeight();
1641 for (; PSetIter.isValid(); ++PSetIter) {
1642 auto &
P = Pressure[*PSetIter];
1644 "register pressure must be greater than or equal weight");
1666 void computeLiveIn() {
1667 DenseSet<Register>
Used;
1668 for (
auto &
MI : *OrigMBB) {
1669 if (
MI.isDebugInstr())
1671 for (
auto &Use : ROMap[&
MI].
Uses) {
1674 Use.VRegOrUnit.isVirtualReg()
1675 ?
Use.VRegOrUnit.asVirtualReg()
1676 :
Register(
static_cast<unsigned>(
Use.VRegOrUnit.asMCRegUnit()));
1681 if (isReservedRegister(
Reg))
1683 if (isDefinedInThisLoop(
Reg))
1689 for (
auto LiveIn : Used)
1690 increaseRegisterPressure(InitSetPressure, LiveIn);
1694 void computePressureSetLimit(
const RegisterClassInfo &RCI) {
1695 for (
unsigned PSet = 0; PSet < PSetNum; PSet++)
1710 Instr2LastUsesTy computeLastUses(
const OrderedInstsTy &OrderedInsts,
1711 Instr2StageTy &Stages)
const {
1716 DenseSet<Register> TargetRegs;
1717 const auto UpdateTargetRegs = [
this, &TargetRegs](
Register Reg) {
1718 if (isDefinedInThisLoop(
Reg))
1721 for (MachineInstr *
MI : OrderedInsts) {
1724 UpdateTargetRegs(
Reg);
1726 for (
auto &Use : ROMap.
find(
MI)->getSecond().Uses) {
1729 ?
Use.VRegOrUnit.asVirtualReg()
1731 Use.VRegOrUnit.asMCRegUnit()));
1732 UpdateTargetRegs(
Reg);
1737 const auto InstrScore = [&Stages](MachineInstr *
MI) {
1738 return Stages[
MI] +
MI->isPHI();
1741 DenseMap<Register, MachineInstr *> LastUseMI;
1743 for (
auto &Use : ROMap.
find(
MI)->getSecond().Uses) {
1746 Use.VRegOrUnit.isVirtualReg()
1747 ?
Use.VRegOrUnit.asVirtualReg()
1748 :
Register(
static_cast<unsigned>(
Use.VRegOrUnit.asMCRegUnit()));
1753 MachineInstr *Orig = Ite->second;
1754 MachineInstr *
New =
MI;
1755 if (InstrScore(Orig) < InstrScore(New))
1761 Instr2LastUsesTy LastUses;
1762 for (
auto [
Reg,
MI] : LastUseMI)
1763 LastUses[
MI].insert(
Reg);
1779 std::vector<unsigned>
1780 computeMaxSetPressure(
const OrderedInstsTy &OrderedInsts,
1781 Instr2StageTy &Stages,
1782 const unsigned StageCount)
const {
1783 using RegSetTy = SmallDenseSet<Register, 16>;
1789 auto CurSetPressure = InitSetPressure;
1790 auto MaxSetPressure = InitSetPressure;
1791 auto LastUses = computeLastUses(OrderedInsts, Stages);
1794 dbgs() <<
"Ordered instructions:\n";
1795 for (MachineInstr *
MI : OrderedInsts) {
1796 dbgs() <<
"Stage " << Stages[
MI] <<
": ";
1801 const auto InsertReg = [
this, &CurSetPressure](RegSetTy &RegSet,
1802 VirtRegOrUnit VRegOrUnit) {
1816 increaseRegisterPressure(CurSetPressure,
Reg);
1820 const auto EraseReg = [
this, &CurSetPressure](RegSetTy &RegSet,
1826 if (!RegSet.contains(
Reg))
1831 decreaseRegisterPressure(CurSetPressure,
Reg);
1835 for (
unsigned I = 0;
I < StageCount;
I++) {
1836 for (MachineInstr *
MI : OrderedInsts) {
1837 const auto Stage = Stages[
MI];
1841 const unsigned Iter =
I - Stage;
1843 for (
auto &Def : ROMap.
find(
MI)->getSecond().Defs)
1844 InsertReg(LiveRegSets[Iter],
Def.VRegOrUnit);
1846 for (
auto LastUse : LastUses[
MI]) {
1849 EraseReg(LiveRegSets[Iter - 1], LastUse);
1851 EraseReg(LiveRegSets[Iter], LastUse);
1855 for (
unsigned PSet = 0; PSet < PSetNum; PSet++)
1856 MaxSetPressure[PSet] =
1857 std::max(MaxSetPressure[PSet], CurSetPressure[PSet]);
1860 dbgs() <<
"CurSetPressure=";
1861 dumpRegisterPressures(CurSetPressure);
1862 dbgs() <<
" iter=" << Iter <<
" stage=" << Stage <<
":";
1868 return MaxSetPressure;
1872 HighRegisterPressureDetector(MachineBasicBlock *OrigMBB,
1874 : OrigMBB(OrigMBB), MRI(MF.getRegInfo()),
1875 TRI(MF.getSubtarget().getRegisterInfo()),
1876 PSetNum(
TRI->getNumRegPressureSets()), InitSetPressure(PSetNum, 0),
1877 PressureSetLimit(PSetNum, 0) {}
1881 void init(
const RegisterClassInfo &RCI) {
1882 for (MachineInstr &
MI : *OrigMBB) {
1883 if (
MI.isDebugInstr())
1885 ROMap[&
MI].collect(
MI, *
TRI, MRI,
false,
true);
1889 computePressureSetLimit(RCI);
1894 bool detect(
const SwingSchedulerDAG *SSD, SMSchedule &Schedule,
1895 const unsigned MaxStage)
const {
1897 "the percentage of the margin must be between 0 to 100");
1899 OrderedInstsTy OrderedInsts;
1900 Instr2StageTy Stages;
1902 const auto MaxSetPressure =
1903 computeMaxSetPressure(OrderedInsts, Stages, MaxStage + 1);
1906 dbgs() <<
"Dump MaxSetPressure:\n";
1907 for (
unsigned I = 0;
I < MaxSetPressure.size();
I++) {
1908 dbgs() <<
format(
"MaxSetPressure[%d]=%d\n",
I, MaxSetPressure[
I]);
1913 for (
unsigned PSet = 0; PSet < PSetNum; PSet++) {
1914 unsigned Limit = PressureSetLimit[PSet];
1917 <<
" Margin=" << Margin <<
"\n");
1918 if (Limit < MaxSetPressure[PSet] + Margin) {
1921 <<
"Rejected the schedule because of too high register pressure\n");
1937unsigned SwingSchedulerDAG::calculateResMII() {
1939 ResourceManager
RM(&MF.getSubtarget(),
this);
1940 return RM.calculateResMII();
1949unsigned SwingSchedulerDAG::calculateRecMII(NodeSetType &NodeSets) {
1950 unsigned RecMII = 0;
1952 for (NodeSet &Nodes : NodeSets) {
1956 unsigned Delay = Nodes.getLatency();
1957 unsigned Distance = 1;
1960 unsigned CurMII = (Delay + Distance - 1) / Distance;
1961 Nodes.setRecMII(CurMII);
1962 if (CurMII > RecMII)
1970void SwingSchedulerDAG::Circuits::createAdjacencyStructure(
1971 SwingSchedulerDDG *DDG) {
1972 BitVector
Added(SUnits.size());
1973 DenseMap<int, int> OutputDeps;
1974 for (
int i = 0, e = SUnits.size(); i != e; ++i) {
1980 if (OE.isOutputDep()) {
1981 int N = OE.getDst()->NodeNum;
1983 auto Dep = OutputDeps.
find(BackEdge);
1984 if (Dep != OutputDeps.
end()) {
1985 BackEdge = Dep->second;
1986 OutputDeps.
erase(Dep);
1988 OutputDeps[
N] = BackEdge;
1991 if (OE.getDst()->isBoundaryNode() || OE.isArtificial())
2003 int N = OE.getDst()->NodeNum;
2005 AdjK[i].push_back(
N);
2012 int N = Dst->NodeNum;
2014 AdjK[i].push_back(
N);
2021 for (
auto &OD : OutputDeps)
2022 if (!
Added.test(OD.second)) {
2023 AdjK[OD.first].push_back(OD.second);
2024 Added.set(OD.second);
2030bool SwingSchedulerDAG::Circuits::circuit(
int V,
int S, NodeSetType &NodeSets,
2031 const SwingSchedulerDAG *DAG,
2033 SUnit *SV = &SUnits[
V];
2038 for (
auto W : AdjK[V]) {
2039 if (NumPaths > MaxPaths)
2050 if (!Blocked.test(W)) {
2051 if (circuit(W, S, NodeSets, DAG,
2052 Node2Idx->at(W) < Node2Idx->at(V) ?
true : HasBackedge))
2060 for (
auto W : AdjK[V]) {
2071void SwingSchedulerDAG::Circuits::unblock(
int U) {
2073 SmallPtrSet<SUnit *, 4> &BU =
B[
U];
2074 while (!BU.
empty()) {
2075 SmallPtrSet<SUnit *, 4>::iterator
SI = BU.
begin();
2076 assert(SI != BU.
end() &&
"Invalid B set.");
2079 if (Blocked.test(
W->NodeNum))
2080 unblock(
W->NodeNum);
2086void SwingSchedulerDAG::findCircuits(NodeSetType &NodeSets) {
2087 Circuits Cir(SUnits, Topo);
2089 Cir.createAdjacencyStructure(&*DDG);
2090 for (
int I = 0,
E = SUnits.size();
I !=
E; ++
I) {
2092 Cir.circuit(
I,
I, NodeSets,
this);
2114void SwingSchedulerDAG::CopyToPhiMutation::apply(ScheduleDAGInstrs *DAG) {
2115 for (SUnit &SU : DAG->
SUnits) {
2125 for (
auto &Dep : SU.
Preds) {
2126 SUnit *TmpSU = Dep.getSUnit();
2127 MachineInstr *TmpMI = TmpSU->
getInstr();
2138 if (PHISUs.
size() == 0 || SrcSUs.
size() == 0)
2146 for (
auto &Dep : PHISUs[Index]->Succs) {
2150 SUnit *TmpSU = Dep.getSUnit();
2151 MachineInstr *TmpMI = TmpSU->
getInstr();
2160 if (UseSUs.
size() == 0)
2165 for (
auto *
I : UseSUs) {
2166 for (
auto *Src : SrcSUs) {
2182void SwingSchedulerDAG::computeNodeFunctions(NodeSetType &NodeSets) {
2183 ScheduleInfo.resize(SUnits.size());
2186 for (
int I : Topo) {
2187 const SUnit &SU = SUnits[
I];
2194 for (
int I : Topo) {
2196 int zeroLatencyDepth = 0;
2197 SUnit *SU = &SUnits[
I];
2199 SUnit *Pred =
IE.getSrc();
2200 if (
IE.getLatency() == 0)
2202 std::max(zeroLatencyDepth, getZeroLatencyDepth(Pred) + 1);
2203 if (
IE.ignoreDependence(
true))
2205 asap = std::max(asap, (
int)(getASAP(Pred) +
IE.getLatency() -
2206 IE.getDistance() * MII));
2208 maxASAP = std::max(maxASAP, asap);
2209 ScheduleInfo[
I].ASAP = asap;
2210 ScheduleInfo[
I].ZeroLatencyDepth = zeroLatencyDepth;
2216 int zeroLatencyHeight = 0;
2217 SUnit *SU = &SUnits[
I];
2219 SUnit *Succ = OE.getDst();
2222 if (OE.getLatency() == 0)
2224 std::max(zeroLatencyHeight, getZeroLatencyHeight(Succ) + 1);
2225 if (OE.ignoreDependence(
true))
2227 alap = std::min(alap, (
int)(getALAP(Succ) - OE.getLatency() +
2228 OE.getDistance() * MII));
2231 ScheduleInfo[
I].ALAP = alap;
2232 ScheduleInfo[
I].ZeroLatencyHeight = zeroLatencyHeight;
2236 for (NodeSet &
I : NodeSets)
2237 I.computeNodeSetInfo(
this);
2240 for (
unsigned i = 0; i < SUnits.size(); i++) {
2241 dbgs() <<
"\tNode " << i <<
":\n";
2242 dbgs() <<
"\t ASAP = " << getASAP(&SUnits[i]) <<
"\n";
2243 dbgs() <<
"\t ALAP = " << getALAP(&SUnits[i]) <<
"\n";
2244 dbgs() <<
"\t MOV = " << getMOV(&SUnits[i]) <<
"\n";
2245 dbgs() <<
"\t D = " << getDepth(&SUnits[i]) <<
"\n";
2246 dbgs() <<
"\t H = " << getHeight(&SUnits[i]) <<
"\n";
2247 dbgs() <<
"\t ZLD = " << getZeroLatencyDepth(&SUnits[i]) <<
"\n";
2248 dbgs() <<
"\t ZLH = " << getZeroLatencyHeight(&SUnits[i]) <<
"\n";
2263 SUnit *PredSU = IE.getSrc();
2264 if (S && S->count(PredSU) == 0)
2266 if (IE.ignoreDependence(
true))
2277 SUnit *SuccSU = OE.getDst();
2278 if (!OE.isAntiDep())
2280 if (S && S->count(SuccSU) == 0)
2286 return !Preds.
empty();
2299 SUnit *SuccSU = OE.getDst();
2300 if (S && S->count(SuccSU) == 0)
2302 if (OE.ignoreDependence(
false))
2313 SUnit *PredSU = IE.getSrc();
2314 if (!IE.isAntiDep())
2316 if (S && S->count(PredSU) == 0)
2322 return !Succs.
empty();
2338 if (!Visited.
insert(Cur).second)
2339 return Path.contains(Cur);
2340 bool FoundPath =
false;
2342 if (!OE.ignoreDependence(
false))
2344 computePath(OE.getDst(), Path, DestNodes, Exclude, Visited, DDG);
2346 if (IE.isAntiDep() && IE.getDistance() == 0)
2348 computePath(IE.getSrc(), Path, DestNodes, Exclude, Visited, DDG);
2363 for (
SUnit *SU : NS) {
2369 if (
Reg.isVirtual())
2372 for (MCRegUnit Unit :
TRI->regunits(
Reg.asMCReg()))
2376 for (
SUnit *SU : NS)
2380 if (
Reg.isVirtual()) {
2385 for (MCRegUnit Unit :
TRI->regunits(
Reg.asMCReg()))
2396void SwingSchedulerDAG::registerPressureFilter(NodeSetType &NodeSets) {
2397 for (
auto &NS : NodeSets) {
2401 IntervalPressure RecRegPressure;
2402 RegPressureTracker RecRPTracker(RecRegPressure);
2403 RecRPTracker.init(&MF, &RegClassInfo, &LIS, BB, BB->end(),
false,
true);
2405 RecRPTracker.closeBottom();
2407 std::vector<SUnit *> SUnits(NS.begin(), NS.end());
2408 llvm::sort(SUnits, [](
const SUnit *
A,
const SUnit *
B) {
2409 return A->NodeNum >
B->NodeNum;
2412 for (
auto &SU : SUnits) {
2418 RecRPTracker.setPos(std::next(CurInstI));
2420 RegPressureDelta RPDelta;
2422 RecRPTracker.getMaxUpwardPressureDelta(SU->
getInstr(),
nullptr, RPDelta,
2427 dbgs() <<
"Excess register pressure: SU(" << SU->
NodeNum <<
") "
2430 NS.setExceedPressure(SU);
2433 RecRPTracker.recede();
2440void SwingSchedulerDAG::colocateNodeSets(NodeSetType &NodeSets) {
2441 unsigned Colocate = 0;
2442 for (
int i = 0, e = NodeSets.size(); i < e; ++i) {
2444 SmallSetVector<SUnit *, 8>
S1;
2447 for (
int j = i + 1;
j <
e; ++
j) {
2451 SmallSetVector<SUnit *, 8> S2;
2468void SwingSchedulerDAG::checkNodeSets(NodeSetType &NodeSets) {
2473 for (
auto &NS : NodeSets) {
2474 if (NS.getRecMII() > 2)
2476 if (NS.getMaxDepth() > MII)
2485void SwingSchedulerDAG::groupRemainingNodes(NodeSetType &NodeSets) {
2486 SetVector<SUnit *> NodesAdded;
2487 SmallPtrSet<SUnit *, 8> Visited;
2490 for (NodeSet &
I : NodeSets) {
2491 SmallSetVector<SUnit *, 8>
N;
2494 SetVector<SUnit *>
Path;
2495 for (SUnit *NI :
N) {
2497 computePath(NI, Path, NodesAdded,
I, Visited, DDG.get());
2504 if (
succ_L(NodesAdded,
N, DDG.get())) {
2505 SetVector<SUnit *>
Path;
2506 for (SUnit *NI :
N) {
2508 computePath(NI, Path,
I, NodesAdded, Visited, DDG.get());
2519 SmallSetVector<SUnit *, 8>
N;
2520 if (
succ_L(NodesAdded,
N, DDG.get()))
2522 addConnectedNodes(
I, NewSet, NodesAdded);
2523 if (!NewSet.
empty())
2524 NodeSets.push_back(NewSet);
2529 if (
pred_L(NodesAdded,
N, DDG.get()))
2531 addConnectedNodes(
I, NewSet, NodesAdded);
2532 if (!NewSet.
empty())
2533 NodeSets.push_back(NewSet);
2537 for (SUnit &SU : SUnits) {
2538 if (NodesAdded.
count(&SU) == 0) {
2540 addConnectedNodes(&SU, NewSet, NodesAdded);
2541 if (!NewSet.
empty())
2542 NodeSets.push_back(NewSet);
2548void SwingSchedulerDAG::addConnectedNodes(SUnit *SU, NodeSet &NewSet,
2549 SetVector<SUnit *> &NodesAdded) {
2554 if (!OE.isArtificial() && !
Successor->isBoundaryNode() &&
2556 addConnectedNodes(
Successor, NewSet, NodesAdded);
2559 SUnit *Predecessor =
IE.getSrc();
2560 if (!
IE.isArtificial() && NodesAdded.
count(Predecessor) == 0)
2561 addConnectedNodes(Predecessor, NewSet, NodesAdded);
2570 for (
SUnit *SU : Set1) {
2571 if (Set2.
count(SU) != 0)
2574 return !Result.empty();
2578void SwingSchedulerDAG::fuseRecs(NodeSetType &NodeSets) {
2579 for (NodeSetType::iterator
I = NodeSets.begin(),
E = NodeSets.end();
I !=
E;
2582 for (NodeSetType::iterator J =
I + 1; J !=
E;) {
2587 for (SUnit *SU : *J)
2599void SwingSchedulerDAG::removeDuplicateNodes(NodeSetType &NodeSets) {
2600 for (NodeSetType::iterator
I = NodeSets.begin(),
E = NodeSets.end();
I !=
E;
2602 for (NodeSetType::iterator J =
I + 1; J !=
E;) {
2603 J->remove_if([&](SUnit *SUJ) {
return I->count(SUJ); });
2618void SwingSchedulerDAG::computeNodeOrder(NodeSetType &NodeSets) {
2619 SmallSetVector<SUnit *, 8>
R;
2622 for (
auto &Nodes : NodeSets) {
2625 SmallSetVector<SUnit *, 8>
N;
2640 }
else if (NodeSets.size() == 1) {
2641 for (
const auto &
N : Nodes)
2642 if (
N->Succs.size() == 0)
2648 SUnit *maxASAP =
nullptr;
2649 for (SUnit *SU : Nodes) {
2650 if (maxASAP ==
nullptr || getASAP(SU) > getASAP(maxASAP) ||
2651 (getASAP(SU) == getASAP(maxASAP) && SU->
NodeNum > maxASAP->
NodeNum))
2659 while (!
R.empty()) {
2660 if (Order == TopDown) {
2664 while (!
R.empty()) {
2665 SUnit *maxHeight =
nullptr;
2666 for (SUnit *
I : R) {
2667 if (maxHeight ==
nullptr || getHeight(
I) > getHeight(maxHeight))
2669 else if (getHeight(
I) == getHeight(maxHeight) &&
2670 getZeroLatencyHeight(
I) > getZeroLatencyHeight(maxHeight))
2672 else if (getHeight(
I) == getHeight(maxHeight) &&
2673 getZeroLatencyHeight(
I) ==
2674 getZeroLatencyHeight(maxHeight) &&
2675 getMOV(
I) < getMOV(maxHeight))
2680 R.remove(maxHeight);
2681 for (
const auto &OE : DDG->
getOutEdges(maxHeight)) {
2682 SUnit *SU = OE.getDst();
2683 if (Nodes.count(SU) == 0)
2687 if (OE.ignoreDependence(
false))
2696 for (
const auto &IE : DDG->
getInEdges(maxHeight)) {
2697 SUnit *SU =
IE.getSrc();
2698 if (!
IE.isAntiDep())
2700 if (Nodes.count(SU) == 0)
2709 SmallSetVector<SUnit *, 8>
N;
2716 while (!
R.empty()) {
2717 SUnit *maxDepth =
nullptr;
2718 for (SUnit *
I : R) {
2719 if (maxDepth ==
nullptr || getDepth(
I) > getDepth(maxDepth))
2721 else if (getDepth(
I) == getDepth(maxDepth) &&
2722 getZeroLatencyDepth(
I) > getZeroLatencyDepth(maxDepth))
2724 else if (getDepth(
I) == getDepth(maxDepth) &&
2725 getZeroLatencyDepth(
I) == getZeroLatencyDepth(maxDepth) &&
2726 getMOV(
I) < getMOV(maxDepth))
2732 if (Nodes.isExceedSU(maxDepth)) {
2735 R.insert(Nodes.getNode(0));
2738 for (
const auto &IE : DDG->
getInEdges(maxDepth)) {
2739 SUnit *SU =
IE.getSrc();
2740 if (Nodes.count(SU) == 0)
2751 for (
const auto &OE : DDG->
getOutEdges(maxDepth)) {
2752 SUnit *SU = OE.getDst();
2753 if (!OE.isAntiDep())
2755 if (Nodes.count(SU) == 0)
2764 SmallSetVector<SUnit *, 8>
N;
2773 dbgs() <<
"Node order: ";
2775 dbgs() <<
" " <<
I->NodeNum <<
" ";
2781void SwingSchedulerDAG::initPolicy() {
2782 MF.getSubtarget().overridePipelinerPolicy(Policy);
2791bool SwingSchedulerDAG::schedulePipeline(SMSchedule &Schedule) {
2798 bool scheduleFound =
false;
2799 std::unique_ptr<HighRegisterPressureDetector> HRPDetector;
2800 if (Policy.ShouldLimitRegPressure) {
2802 std::make_unique<HighRegisterPressureDetector>(
Loop.getHeader(), MF);
2803 HRPDetector->init(RegClassInfo);
2806 for (
unsigned II = MII;
II <= MAX_II && !scheduleFound; ++
II) {
2818 int EarlyStart = INT_MIN;
2819 int LateStart = INT_MAX;
2828 dbgs() <<
format(
"\tes: %8x ls: %8x\n", EarlyStart, LateStart));
2830 if (EarlyStart > LateStart)
2831 scheduleFound =
false;
2832 else if (EarlyStart != INT_MIN && LateStart == INT_MAX)
2834 Schedule.
insert(SU, EarlyStart, EarlyStart + (
int)
II - 1,
II);
2835 else if (EarlyStart == INT_MIN && LateStart != INT_MAX)
2837 Schedule.
insert(SU, LateStart, LateStart - (
int)
II + 1,
II);
2838 else if (EarlyStart != INT_MIN && LateStart != INT_MAX) {
2839 LateStart = std::min(LateStart, EarlyStart + (
int)
II - 1);
2848 scheduleFound = Schedule.
insert(SU, LateStart, EarlyStart,
II);
2850 scheduleFound = Schedule.
insert(SU, EarlyStart, LateStart,
II);
2853 scheduleFound = Schedule.
insert(SU, FirstCycle + getASAP(SU),
2854 FirstCycle + getASAP(SU) +
II - 1,
II);
2862 scheduleFound =
false;
2866 dbgs() <<
"\tCan't schedule\n";
2868 }
while (++NI != NE && scheduleFound);
2886 if (scheduleFound && HRPDetector)
2895 if (scheduleFound) {
2896 scheduleFound = LoopPipelinerInfo->shouldUseSchedule(*
this, Schedule);
2901 if (scheduleFound) {
2903 Pass.ORE->emit([&]() {
2904 return MachineOptimizationRemarkAnalysis(
2906 <<
"Schedule found with Initiation Interval: "
2908 <<
", MaxStageCount: "
2922 if (!
Reg.isVirtual())
2936 if (!
Op.isReg() || !
Op.getReg().isVirtual())
2964 if (Def->getParent() != LoopBB)
2967 if (Def->isCopy()) {
2969 if (Def->getOperand(0).getSubReg() || Def->getOperand(1).getSubReg())
2971 CurReg = Def->getOperand(1).getReg();
2972 }
else if (Def->isPHI()) {
2978 }
else if (
TII->getIncrementValue(*Def,
Value)) {
2986 bool OffsetIsScalable;
2987 if (
TII->getMemOperandWithOffset(*Def, BaseOp,
Offset, OffsetIsScalable,
2990 CurReg = BaseOp->
getReg();
3002 if (CurReg == OrgReg)
3014bool SwingSchedulerDAG::computeDelta(
const MachineInstr &
MI,
int &Delta)
const {
3015 const TargetRegisterInfo *
TRI = MF.getSubtarget().getRegisterInfo();
3016 const MachineOperand *BaseOp;
3018 bool OffsetIsScalable;
3019 if (!
TII->getMemOperandWithOffset(
MI, BaseOp,
Offset, OffsetIsScalable,
TRI))
3023 if (OffsetIsScalable)
3026 if (!BaseOp->
isReg())
3039bool SwingSchedulerDAG::canUseLastOffsetValue(MachineInstr *
MI,
3041 unsigned &OffsetPos,
3047 unsigned BasePosLd, OffsetPosLd;
3055 if (!Phi || !
Phi->isPHI())
3063 MachineInstr *PrevDef = MRI.
getVRegDef(PrevReg);
3064 if (!PrevDef || PrevDef ==
MI)
3070 unsigned BasePos1 = 0, OffsetPos1 = 0;
3078 MachineInstr *NewMI = MF.CloneMachineInstr(
MI);
3081 MF.deleteMachineInstr(NewMI);
3086 BasePos = BasePosLd;
3087 OffsetPos = OffsetPosLd;
3099 InstrChanges.find(SU);
3100 if (It != InstrChanges.
end()) {
3101 std::pair<Register, int64_t> RegAndOffset = It->second;
3102 unsigned BasePos, OffsetPos;
3103 if (!
TII->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos))
3105 Register BaseReg =
MI->getOperand(BasePos).getReg();
3111 if (BaseStageNum < DefStageNum) {
3113 int OffsetDiff = DefStageNum - BaseStageNum;
3114 if (DefCycleNum < BaseCycleNum) {
3120 MI->getOperand(OffsetPos).getImm() + RegAndOffset.second * OffsetDiff;
3135 while (Def->isPHI()) {
3136 if (!Visited.
insert(Def).second)
3138 for (
unsigned i = 1, e = Def->getNumOperands(); i < e; i += 2)
3139 if (Def->getOperand(i + 1).getMBB() == BB) {
3140 Def = MRI.
getVRegDef(Def->getOperand(i).getReg());
3151 int DeltaB, DeltaO, Delta;
3158 int64_t OffsetB, OffsetO;
3159 bool OffsetBIsScalable, OffsetOIsScalable;
3161 if (!
TII->getMemOperandWithOffset(*BaseMI, BaseOpB, OffsetB,
3162 OffsetBIsScalable,
TRI) ||
3163 !
TII->getMemOperandWithOffset(*OtherMI, BaseOpO, OffsetO,
3164 OffsetOIsScalable,
TRI))
3167 if (OffsetBIsScalable || OffsetOIsScalable)
3177 if (!RegB.
isVirtual() || !RegO.isVirtual())
3182 if (!DefB || !DefO || !DefB->
isPHI() || !DefO->
isPHI())
3207 dbgs() <<
"Overlap check:\n";
3208 dbgs() <<
" BaseMI: ";
3210 dbgs() <<
" Base + " << OffsetB <<
" + I * " << Delta
3211 <<
", Len: " << AccessSizeB.
getValue() <<
"\n";
3212 dbgs() <<
" OtherMI: ";
3214 dbgs() <<
" Base + " << OffsetO <<
" + I * " << Delta
3215 <<
", Len: " << AccessSizeO.
getValue() <<
"\n";
3223 int64_t BaseMinAddr = OffsetB;
3224 int64_t OhterNextIterMaxAddr = OffsetO + Delta + AccessSizeO.
getValue() - 1;
3225 if (BaseMinAddr > OhterNextIterMaxAddr) {
3230 int64_t BaseMaxAddr = OffsetB + AccessSizeB.
getValue() - 1;
3231 int64_t OtherNextIterMinAddr = OffsetO + Delta;
3232 if (BaseMaxAddr < OtherNextIterMinAddr) {
3241void SwingSchedulerDAG::postProcessDAG() {
3242 for (
auto &M : Mutations)
3252 bool forward =
true;
3254 dbgs() <<
"Trying to insert node between " << StartCycle <<
" and "
3255 << EndCycle <<
" II: " <<
II <<
"\n";
3257 if (StartCycle > EndCycle)
3261 int termCycle = forward ? EndCycle + 1 : EndCycle - 1;
3262 for (
int curCycle = StartCycle; curCycle != termCycle;
3263 forward ? ++curCycle : --curCycle) {
3266 ProcItinResources.canReserveResources(*SU, curCycle)) {
3268 dbgs() <<
"\tinsert at cycle " << curCycle <<
" ";
3273 ProcItinResources.reserveResources(*SU, curCycle);
3274 ScheduledInstrs[curCycle].push_back(SU);
3275 InstrToCycle.insert(std::make_pair(SU, curCycle));
3276 if (curCycle > LastCycle)
3277 LastCycle = curCycle;
3278 if (curCycle < FirstCycle)
3279 FirstCycle = curCycle;
3283 dbgs() <<
"\tfailed to insert at cycle " << curCycle <<
" ";
3294 for (
auto &
P : SU->
Preds)
3295 if (
P.getKind() ==
SDep::Anti &&
P.getSUnit()->getInstr()->isPHI())
3296 for (
auto &S :
P.getSUnit()->Succs)
3297 if (S.getKind() ==
SDep::Data && S.getSUnit()->getInstr()->isPHI())
3298 return P.getSUnit();
3311 for (
int cycle =
getFirstCycle(); cycle <= LastCycle; ++cycle) {
3314 if (IE.getSrc() ==
I) {
3315 int EarlyStart = cycle + IE.getLatency() - IE.getDistance() *
II;
3316 *MaxEarlyStart = std::max(*MaxEarlyStart, EarlyStart);
3321 if (OE.getDst() ==
I) {
3322 int LateStart = cycle - OE.getLatency() + OE.getDistance() *
II;
3323 *MinLateStart = std::min(*MinLateStart, LateStart);
3328 for (
const auto &Dep : SU->
Preds) {
3331 if (BE && Dep.getSUnit() == BE && !SU->
getInstr()->
isPHI() &&
3333 *MinLateStart = std::min(*MinLateStart, cycle);
3343 std::deque<SUnit *> &Insts)
const {
3345 bool OrderBeforeUse =
false;
3346 bool OrderAfterDef =
false;
3347 bool OrderBeforeDef =
false;
3348 unsigned MoveDef = 0;
3349 unsigned MoveUse = 0;
3354 for (std::deque<SUnit *>::iterator
I = Insts.begin(), E = Insts.end();
I != E;
3357 if (!MO.isReg() || !MO.getReg().isVirtual())
3361 unsigned BasePos, OffsetPos;
3362 if (ST.getInstrInfo()->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos))
3363 if (
MI->getOperand(BasePos).getReg() == Reg)
3367 std::tie(Reads, Writes) =
3368 (*I)->getInstr()->readsWritesVirtualRegister(Reg);
3370 OrderBeforeUse =
true;
3375 OrderAfterDef =
true;
3377 }
else if (MO.isUse() && Writes &&
stageScheduled(*
I) == StageInst1) {
3379 OrderBeforeUse =
true;
3383 OrderAfterDef =
true;
3387 OrderBeforeUse =
true;
3391 OrderAfterDef =
true;
3396 OrderBeforeUse =
true;
3402 OrderBeforeDef =
true;
3410 if (OE.getDst() != *
I)
3413 OrderBeforeUse =
true;
3420 else if ((OE.isAntiDep() || OE.isOutputDep()) &&
3422 OrderBeforeUse =
true;
3423 if ((MoveUse == 0) || (Pos < MoveUse))
3428 if (IE.getSrc() != *
I)
3430 if ((IE.isAntiDep() || IE.isOutputDep() || IE.isOrderDep()) &&
3432 OrderAfterDef =
true;
3439 if (OrderAfterDef && OrderBeforeUse && MoveUse == MoveDef)
3440 OrderBeforeUse =
false;
3445 OrderBeforeUse = !OrderAfterDef || (MoveUse > MoveDef);
3449 if (OrderBeforeUse && OrderAfterDef) {
3450 SUnit *UseSU = Insts.at(MoveUse);
3451 SUnit *DefSU = Insts.at(MoveDef);
3452 if (MoveUse > MoveDef) {
3453 Insts.erase(Insts.begin() + MoveUse);
3454 Insts.erase(Insts.begin() + MoveDef);
3456 Insts.erase(Insts.begin() + MoveDef);
3457 Insts.erase(Insts.begin() + MoveUse);
3467 Insts.push_front(SU);
3469 Insts.push_back(SU);
3477 assert(Phi.isPHI() &&
"Expecting a Phi.");
3484 getPhiRegs(Phi, Phi.getParent(), InitVal, LoopVal);
3492 return (LoopCycle > DefCycle) || (LoopStage <= DefStage);
3510 if (!Phi || !Phi->isPHI() || Phi->getParent() != Def->getParent())
3516 if (DMO.getReg() == LoopReg)
3527 if (InstrToCycle.count(IE.getSrc()))
3538 for (
auto &SU : SSD->
SUnits)
3543 while (!Worklist.
empty()) {
3545 if (DoNotPipeline.
count(SU))
3548 DoNotPipeline.
insert(SU);
3555 if (OE.getDistance() == 1)
3558 return DoNotPipeline;
3567 int NewLastCycle = INT_MIN;
3572 NewLastCycle = std::max(NewLastCycle, InstrToCycle[&SU]);
3579 if (IE.getDistance() == 0)
3580 NewCycle = std::max(InstrToCycle[IE.getSrc()], NewCycle);
3585 if (OE.getDistance() == 1)
3586 NewCycle = std::max(InstrToCycle[OE.getDst()], NewCycle);
3588 int OldCycle = InstrToCycle[&SU];
3589 if (OldCycle != NewCycle) {
3590 InstrToCycle[&SU] = NewCycle;
3595 <<
") is not pipelined; moving from cycle " << OldCycle
3596 <<
" to " << NewCycle <<
" Instr:" << *SU.
getInstr());
3621 if (FirstCycle + InitiationInterval <= NewCycle)
3624 NewLastCycle = std::max(NewLastCycle, NewCycle);
3626 LastCycle = NewLastCycle;
3643 int CycleDef = InstrToCycle[&SU];
3644 assert(StageDef != -1 &&
"Instruction should have been scheduled.");
3646 SUnit *Dst = OE.getDst();
3647 if (OE.isAssignedRegDep() && !Dst->isBoundaryNode())
3648 if (OE.getReg().isPhysical()) {
3651 if (InstrToCycle[Dst] <= CycleDef)
3669void SwingSchedulerDAG::checkValidNodeOrder(
const NodeSetType &Circuits)
const {
3672 typedef std::pair<SUnit *, unsigned> UnitIndex;
3673 std::vector<UnitIndex> Indices(
NodeOrder.size(), std::make_pair(
nullptr, 0));
3675 for (
unsigned i = 0, s =
NodeOrder.size(); i < s; ++i)
3676 Indices.push_back(std::make_pair(
NodeOrder[i], i));
3678 auto CompareKey = [](UnitIndex i1, UnitIndex i2) {
3679 return std::get<0>(i1) < std::get<0>(i2);
3692 for (
unsigned i = 0, s =
NodeOrder.size(); i < s; ++i) {
3696 bool PredBefore =
false;
3697 bool SuccBefore =
false;
3705 SUnit *PredSU = IE.getSrc();
3706 unsigned PredIndex = std::get<1>(
3716 SUnit *SuccSU = OE.getDst();
3722 unsigned SuccIndex = std::get<1>(
3735 Circuits, [SU](
const NodeSet &Circuit) {
return Circuit.
count(SU); });
3740 NumNodeOrderIssues++;
3744 <<
" are scheduled before node " << SU->
NodeNum
3751 dbgs() <<
"Invalid node order found!\n";
3764 for (
SUnit *SU : Instrs) {
3766 for (
unsigned i = 0, e =
MI->getNumOperands(); i < e; ++i) {
3774 InstrChanges.find(SU);
3775 if (It != InstrChanges.
end()) {
3776 unsigned BasePos, OffsetPos;
3778 if (
TII->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos)) {
3782 MI->getOperand(OffsetPos).getImm() - It->second.second;
3795 unsigned TiedUseIdx = 0;
3796 if (
MI->isRegTiedToUseOperand(i, &TiedUseIdx)) {
3798 OverlapReg =
MI->getOperand(TiedUseIdx).getReg();
3800 NewBaseReg =
MI->getOperand(i).getReg();
3809 const std::deque<SUnit *> &Instrs)
const {
3810 std::deque<SUnit *> NewOrderPhi;
3811 for (
SUnit *SU : Instrs) {
3813 NewOrderPhi.push_back(SU);
3815 std::deque<SUnit *> NewOrderI;
3816 for (
SUnit *SU : Instrs) {
3832 std::deque<SUnit *> &cycleInstrs =
3833 ScheduledInstrs[cycle + (stage * InitiationInterval)];
3835 ScheduledInstrs[cycle].push_front(SU);
3841 for (
int cycle =
getFinalCycle() + 1; cycle <= LastCycle; ++cycle)
3842 ScheduledInstrs.erase(cycle);
3852 std::deque<SUnit *> &cycleInstrs = ScheduledInstrs[Cycle];
3861 os <<
"Num nodes " <<
size() <<
" rec " << RecMII <<
" mov " << MaxMOV
3862 <<
" depth " << MaxDepth <<
" col " << Colocate <<
"\n";
3863 for (
const auto &
I : Nodes)
3864 os <<
" SU(" <<
I->NodeNum <<
") " << *(
I->getInstr());
3868#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3875 for (
SUnit *CI : cycleInstrs->second) {
3877 os <<
"(" << CI->
NodeNum <<
") ";
3888void ResourceManager::dumpMRT()
const {
3892 std::stringstream SS;
3894 SS << std::setw(4) <<
"Slot";
3895 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I)
3896 SS << std::setw(3) <<
I;
3897 SS << std::setw(7) <<
"#Mops"
3899 for (
int Slot = 0; Slot < InitiationInterval; ++Slot) {
3900 SS << std::setw(4) << Slot;
3901 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I)
3902 SS << std::setw(3) << MRT[Slot][
I];
3903 SS << std::setw(7) << NumScheduledMops[Slot] <<
"\n";
3912 unsigned ProcResourceID = 0;
3916 assert(SM.getNumProcResourceKinds() < 64 &&
3917 "Too many kinds of resources, unsupported");
3920 Masks.
resize(SM.getNumProcResourceKinds());
3921 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
3923 if (
Desc.SubUnitsIdxBegin)
3925 Masks[
I] = 1ULL << ProcResourceID;
3929 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
3931 if (!
Desc.SubUnitsIdxBegin)
3933 Masks[
I] = 1ULL << ProcResourceID;
3934 for (
unsigned U = 0; U <
Desc.NumUnits; ++U)
3935 Masks[
I] |= Masks[
Desc.SubUnitsIdxBegin[U]];
3940 dbgs() <<
"ProcResourceDesc:\n";
3941 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
3943 dbgs() <<
format(
" %16s(%2d): Mask: 0x%08x, NumUnits:%2d\n",
3944 ProcResource->
Name,
I, Masks[
I],
3947 dbgs() <<
" -----------------\n";
3955 dbgs() <<
"canReserveResources:\n";
3958 return DFAResources[positiveModulo(Cycle, InitiationInterval)]
3964 dbgs() <<
"No valid Schedule Class Desc for schedClass!\n";
3970 reserveResources(SCDesc, Cycle);
3971 bool Result = !isOverbooked();
3972 unreserveResources(SCDesc, Cycle);
3978void ResourceManager::reserveResources(
SUnit &SU,
int Cycle) {
3981 dbgs() <<
"reserveResources:\n";
3984 return DFAResources[positiveModulo(Cycle, InitiationInterval)]
3990 dbgs() <<
"No valid Schedule Class Desc for schedClass!\n";
3996 reserveResources(SCDesc, Cycle);
4001 dbgs() <<
"reserveResources: done!\n\n";
4011 for (
int C = Cycle;
C < Cycle + PRE.ReleaseAtCycle; ++
C)
4012 ++MRT[positiveModulo(
C, InitiationInterval)][PRE.ProcResourceIdx];
4015 ++NumScheduledMops[positiveModulo(
C, InitiationInterval)];
4023 for (
int C = Cycle;
C < Cycle + PRE.ReleaseAtCycle; ++
C)
4024 --MRT[positiveModulo(
C, InitiationInterval)][PRE.ProcResourceIdx];
4027 --NumScheduledMops[positiveModulo(
C, InitiationInterval)];
4030bool ResourceManager::isOverbooked()
const {
4032 for (
int Slot = 0;
Slot < InitiationInterval; ++
Slot) {
4033 for (
unsigned I = 1,
E = SM.getNumProcResourceKinds();
I <
E; ++
I) {
4034 const MCProcResourceDesc *
Desc = SM.getProcResource(
I);
4035 if (MRT[Slot][
I] >
Desc->NumUnits)
4038 if (NumScheduledMops[Slot] > IssueWidth)
4044int ResourceManager::calculateResMIIDFA()
const {
4049 FuncUnitSorter FUS = FuncUnitSorter(*ST);
4050 for (SUnit &SU : DAG->
SUnits)
4051 FUS.calcCriticalResources(*SU.
getInstr());
4052 PriorityQueue<MachineInstr *, std::vector<MachineInstr *>, FuncUnitSorter>
4055 for (SUnit &SU : DAG->
SUnits)
4062 while (!FuncUnitOrder.empty()) {
4063 MachineInstr *
MI = FuncUnitOrder.top();
4064 FuncUnitOrder.pop();
4065 if (
TII->isZeroCost(
MI->getOpcode()))
4071 unsigned ReservedCycles = 0;
4075 dbgs() <<
"Trying to reserve resource for " << NumCycles
4076 <<
" cycles for \n";
4079 for (
unsigned C = 0;
C < NumCycles; ++
C)
4081 if ((*RI)->canReserveResources(*
MI)) {
4082 (*RI)->reserveResources(*
MI);
4089 <<
", NumCycles:" << NumCycles <<
"\n");
4091 for (
unsigned C = ReservedCycles;
C < NumCycles; ++
C) {
4093 <<
"NewResource created to reserve resources"
4096 assert(NewResource->canReserveResources(*
MI) &&
"Reserve error.");
4097 NewResource->reserveResources(*
MI);
4098 Resources.push_back(std::unique_ptr<DFAPacketizer>(NewResource));
4109 return calculateResMIIDFA();
4116 for (
SUnit &SU : DAG->SUnits) {
4128 <<
" WriteProcRes: ";
4133 make_range(STI->getWriteProcResBegin(SCDesc),
4134 STI->getWriteProcResEnd(SCDesc))) {
4138 SM.getProcResource(PRE.ProcResourceIdx);
4139 dbgs() <<
Desc->Name <<
": " << PRE.ReleaseAtCycle <<
", ";
4142 ResourceCount[PRE.ProcResourceIdx] += PRE.ReleaseAtCycle;
4147 int Result = (NumMops + IssueWidth - 1) / IssueWidth;
4150 dbgs() <<
"#Mops: " << NumMops <<
", "
4151 <<
"IssueWidth: " << IssueWidth <<
", "
4152 <<
"Cycles: " << Result <<
"\n";
4157 std::stringstream SS;
4158 SS << std::setw(2) <<
"ID" << std::setw(16) <<
"Name" << std::setw(10)
4159 <<
"Units" << std::setw(10) <<
"Consumed" << std::setw(10) <<
"Cycles"
4164 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4166 int Cycles = (ResourceCount[
I] +
Desc->NumUnits - 1) /
Desc->NumUnits;
4169 std::stringstream SS;
4170 SS << std::setw(2) <<
I << std::setw(16) <<
Desc->Name << std::setw(10)
4171 <<
Desc->NumUnits << std::setw(10) << ResourceCount[
I]
4172 << std::setw(10) << Cycles <<
"\n";
4176 if (Cycles > Result)
4183 InitiationInterval =
II;
4184 DFAResources.clear();
4185 DFAResources.resize(
II);
4186 for (
auto &
I : DFAResources)
4187 I.reset(ST->getInstrInfo()->CreateTargetScheduleState(*ST));
4190 NumScheduledMops.clear();
4191 NumScheduledMops.resize(
II);
4195 if (Pred.isArtificial() || Dst->isBoundaryNode())
4200 return IgnoreAnti && (Pred.getKind() ==
SDep::Kind::Anti || Distance != 0);
4203SwingSchedulerDDG::SwingSchedulerDDGEdges &
4204SwingSchedulerDDG::getEdges(
const SUnit *SU) {
4206 return EntrySUEdges;
4212const SwingSchedulerDDG::SwingSchedulerDDGEdges &
4213SwingSchedulerDDG::getEdges(
const SUnit *SU)
const {
4215 return EntrySUEdges;
4221void SwingSchedulerDDG::addEdge(
const SUnit *SU,
4222 const SwingSchedulerDDGEdge &
Edge) {
4224 "Validation-only edges are not expected here.");
4226 auto &Edges = getEdges(SU);
4227 if (
Edge.getSrc() == SU)
4228 Edges.Succs.push_back(
Edge);
4230 Edges.Preds.push_back(
Edge);
4233void SwingSchedulerDDG::initEdges(SUnit *SU) {
4234 for (
const auto &PI : SU->
Preds) {
4235 SwingSchedulerDDGEdge
Edge(SU, PI,
false,
4240 for (
const auto &SI : SU->
Succs) {
4241 SwingSchedulerDDGEdge
Edge(SU, SI,
true,
4249 : EntrySU(EntrySU), ExitSU(ExitSU) {
4250 EdgesVec.resize(SUnits.size());
4255 for (
auto &SU : SUnits)
4259 for (
SUnit &SU : SUnits) {
4264 for (
SUnit *Dst : *OD) {
4267 Edge.setDistance(1);
4268 ValidationOnlyEdges.push_back(Edge);
4280 bool UseAsExtraEdge = [&]() {
4281 if (Edge.getDistance() == 0 || !Edge.isOrderDep())
4284 SUnit *Src = Edge.getSrc();
4285 SUnit *Dst = Edge.getDst();
4286 if (Src->NodeNum < Dst->NodeNum)
4294 getEdges(Edge.getSrc()).ExtraSuccs.push_back(Edge.getDst());
4300const SwingSchedulerDDG::EdgesType &
4302 return getEdges(SU).Preds;
4305const SwingSchedulerDDG::EdgesType &
4307 return getEdges(SU).Succs;
4311 return getEdges(SU).ExtraSuccs;
4318 auto ExpandCycle = [&](
SUnit *SU) {
4321 return Cycle + (Stage *
II);
4325 SUnit *Src = Edge.getSrc();
4326 SUnit *Dst = Edge.getDst();
4327 if (!Src->isInstr() || !Dst->isInstr())
4329 int CycleSrc = ExpandCycle(Src);
4330 int CycleDst = ExpandCycle(Dst);
4331 int MaxLateStart = CycleDst + Edge.getDistance() *
II - Edge.getLatency();
4332 if (CycleSrc > MaxLateStart) {
4334 dbgs() <<
"Validation failed for edge from " << Src->NodeNum <<
" to "
4335 << Dst->NodeNum <<
"\n";
4345 for (
SUnit &SU : SUnits) {
4374 !
TII->isGlobalMemoryObject(FromMI) &&
4392 const auto DumpSU = [](
const SUnit *SU) {
4393 std::ostringstream OSS;
4394 OSS <<
"SU(" << SU->
NodeNum <<
")";
4398 dbgs() <<
" Loop carried edges from " << DumpSU(SU) <<
"\n"
4400 for (
SUnit *Dst : *Order)
4401 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 void addEdge(SmallVectorImpl< LazyCallGraph::Edge > &Edges, DenseMap< LazyCallGraph::Node *, int > &EdgeIndexMap, LazyCallGraph::Node &N, LazyCallGraph::Edge::Kind EK)
print mir2vec MIR2Vec Vocabulary Printer Pass
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 void getPhiRegs(MachineInstr &Phi, MachineBasicBlock *Loop, Register &InitVal, Register &LoopVal)
Return the register values for the operands of a Phi instruction.
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 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 Register getLoopPhiReg(const MachineInstr &Phi, const MachineBasicBlock *LoopBB)
Return the Phi register value that comes the loop block.
static bool isIntersect(SmallSetVector< SUnit *, 8 > &Set1, const NodeSet &Set2, SmallSetVector< SUnit *, 8 > &Result)
Return true if Set1 contains elements in Set2.
static bool findLoopIncrementValue(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 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 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 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 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 > EnableSWP("enable-pipeliner", cl::Hidden, cl::init(true), cl::desc("Enable Software Pipelining"))
A command line option to turn software pipelining on or off.
static bool hasLoopCarriedMemDep(const SUnitWithMemInfo &Src, const SUnitWithMemInfo &Dst, BatchAAResults &BAA, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, const SwingSchedulerDAG *SSD)
Returns true if there is a loop-carried order dependency from Src to Dst.
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)
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.
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.
const BitVector & getLoopCarried(unsigned Idx) const
LoopCarriedOrderDepsTracker(SwingSchedulerDAG *SSD, BatchAAResults *BAA, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI)
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
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)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
bool erase(const KeyT &Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
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.
DFAPacketizer * CreateTargetScheduleState(const TargetSubtargetInfo &STI) const override
Create machine specific model for scheduling.
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...
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
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 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
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 ...
The main class in the implementation of the target independent software pipeliner pass.
bool runOnMachineFunction(MachineFunction &MF) override
The "main" function for implementing Swing Modulo Scheduling.
const TargetInstrInfo * TII
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const MachineLoopInfo * MLI
const RegisterClassInfo * RegClassInfo
MachineOptimizationRemarkEmitter * ORE
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.
bool isReserved(MCRegister PhysReg) const
isReserved - Returns true when PhysReg is a reserved register.
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()
bool isAllocatable(MCRegister PhysReg) const
isAllocatable - Returns true when PhysReg belongs to an allocatable register class and it hasn't been...
const MachineFunction & getMF() const
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 ...
A reimplementation of ModuloScheduleExpander.
PointerIntPair - This class implements a pair of a pointer and small integer.
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.
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
LLVM_ABI int calculateResMII() const
LLVM_ABI void initProcResourceVectors(const MCSchedModel &SM, SmallVectorImpl< uint64_t > &Masks)
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.
unsigned short Latency
Node latency.
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.
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.
MachineBasicBlock * BB
The block in which to insert instructions.
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.
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.
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...
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 ...
bool mayOverlapInLaterIter(const MachineInstr *BaseMI, const MachineInstr *OtherMI) const
Return false if there is no overlap between the region accessed by BaseMI in an iteration and the reg...
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...
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
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
This class implements an extremely fast bulk output stream that can only output to a stream.
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.
@ 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.
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
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)
static int64_t computeDelta(SectionEntry *A, SectionEntry *B)
@ 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 cl::opt< bool > SwpEnableCopyToPhi
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.
LLVM_ABI cl::opt< int > SwpForceIssueWidth
A command line argument to force pipeliner to use specified issue width.
@ 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 printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
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
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.
LLVM_ABI void dump(SUnit *SU, const TargetRegisterInfo *TRI, const MachineRegisterInfo *MRI) const
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.