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);
399 bool useSwingModuloScheduler();
400 bool useWindowScheduler(
bool Changed);
406int MachinePipelinerImpl::NumTries = 0;
419 for (
const auto &L : *
MLI)
444 MachinePipelinerImpl MP(MF, GetMLI(), GetLIS(), GetAA(), GetORE(), GetRCI());
505bool MachinePipelinerImpl::scheduleLoop(
MachineLoop &L) {
507 for (
const auto &InnerLoop : L)
508 Changed |= scheduleLoop(*InnerLoop);
520 setPragmaPipelineOptions(L);
521 if (!canPipelineLoop(L)) {
525 L.getStartLoc(), L.getHeader())
526 <<
"Failed to pipeline loop";
529 LI.LoopPipelinerInfo.reset();
534 if (useSwingModuloScheduler())
535 Changed = swingModuloScheduler(L);
537 if (useWindowScheduler(
Changed))
538 Changed = runWindowScheduler(L);
540 LI.LoopPipelinerInfo.reset();
544void MachinePipelinerImpl::setPragmaPipelineOptions(MachineLoop &L) {
549 MachineBasicBlock *LBLK =
L.getTopBlock();
559 MDNode *LoopID = TI->
getMetadata(LLVMContext::MD_loop);
560 if (LoopID ==
nullptr)
577 if (S->
getString() ==
"llvm.loop.pipeline.initiationinterval") {
579 "Pipeline initiation interval hint metadata should have two operands.");
583 }
else if (S->
getString() ==
"llvm.loop.pipeline.disable") {
596 auto It = PhiDeps.find(
Reg);
597 if (It == PhiDeps.end())
608 for (
unsigned Dep : It->second) {
623 unsigned DefReg =
MI.getOperand(0).getReg();
627 for (
unsigned I = 1;
I <
MI.getNumOperands();
I += 2)
628 Ins->second.push_back(
MI.getOperand(
I).getReg());
635 for (
const auto &KV : PhiDeps) {
636 unsigned Reg = KV.first;
647bool MachinePipelinerImpl::canPipelineLoop(MachineLoop &L) {
648 if (
L.getNumBlocks() != 1) {
650 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
651 L.getStartLoc(),
L.getHeader())
652 <<
"Not a single basic block: "
653 <<
ore::NV(
"NumBlocks",
L.getNumBlocks());
665 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
666 L.getStartLoc(),
L.getHeader())
667 <<
"Disabled by Pragma.";
677 if (
TII->analyzeBranch(*
L.getHeader(),
LI.TBB,
LI.FBB,
LI.BrCond)) {
678 LLVM_DEBUG(
dbgs() <<
"Unable to analyzeBranch, can NOT pipeline Loop\n");
681 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
682 L.getStartLoc(),
L.getHeader())
683 <<
"The branch can't be understood";
688 LI.LoopInductionVar =
nullptr;
689 LI.LoopCompare =
nullptr;
690 LI.LoopPipelinerInfo =
TII->analyzeLoopForPipelining(
L.getTopBlock());
691 if (!
LI.LoopPipelinerInfo) {
692 LLVM_DEBUG(
dbgs() <<
"Unable to analyzeLoop, can NOT pipeline Loop\n");
695 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
696 L.getStartLoc(),
L.getHeader())
697 <<
"The loop structure is not supported";
702 if (!
L.getLoopPreheader()) {
703 LLVM_DEBUG(
dbgs() <<
"Preheader not found, can NOT pipeline Loop\n");
706 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
707 L.getStartLoc(),
L.getHeader())
708 <<
"No loop preheader found";
713 unsigned NumStores = 0;
714 for (MachineInstr &
MI : *
L.getHeader())
719 NumFailTooManyStores++;
721 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
722 L.getStartLoc(),
L.getHeader())
723 <<
"Too many store instructions in the loop: "
724 <<
ore::NV(
"NumStores", NumStores) <<
" > "
731 preprocessPhiNodes(*
L.getHeader());
735void MachinePipelinerImpl::preprocessPhiNodes(MachineBasicBlock &
B) {
736 MachineRegisterInfo &MRI =
MF->getRegInfo();
737 SlotIndexes &Slots = *
LIS->getSlotIndexes();
739 for (MachineInstr &PI :
B.phis()) {
740 MachineOperand &DefOp = PI.getOperand(0);
744 for (
unsigned i = 1, n = PI.getNumOperands(); i != n; i += 2) {
745 MachineOperand &RegOp = PI.getOperand(i);
752 MachineBasicBlock &PredB = *PI.getOperand(i+1).getMBB();
769bool MachinePipelinerImpl::swingModuloScheduler(MachineLoop &L) {
770 assert(
L.getBlocks().size() == 1 &&
"SMS works on single blocks only.");
773 LI.LoopPipelinerInfo.get(),
AA);
775 MachineBasicBlock *
MBB =
L.getHeader();
793 return SMS.hasNewSchedule();
808bool MachinePipelinerImpl::runWindowScheduler(
MachineLoop &L) {
820bool MachinePipelinerImpl::useSwingModuloScheduler() {
825bool MachinePipelinerImpl::useWindowScheduler(
bool Changed) {
832 "llvm.loop.pipeline.initiationinterval is set.\n");
840void SwingSchedulerDAG::setMII(
unsigned ResMII,
unsigned RecMII) {
843 else if (II_setByPragma > 0)
844 MII = II_setByPragma;
846 MII = std::max(ResMII, RecMII);
849void SwingSchedulerDAG::setMAX_II() {
852 else if (II_setByPragma > 0)
853 MAX_II = II_setByPragma;
866 RegClassInfo(rci), II_setByPragma(
II), LoopPipelinerInfo(PLI),
869 MF.getSubtarget().getSMSMutations(Mutations);
871 Mutations.push_back(std::make_unique<CopyToPhiMutation>());
872 BAA.enableCrossIterationMode();
880 updatePhiDependences();
881 Topo.InitDAGTopologicalSorting();
887 dbgs() <<
"===== Loop Carried Edges Begin =====\n";
890 dbgs() <<
"===== Loop Carried Edges End =====\n";
893 NodeSetType NodeSets;
894 findCircuits(NodeSets);
895 NodeSetType Circuits = NodeSets;
898 unsigned ResMII = calculateResMII();
899 unsigned RecMII = calculateRecMII(NodeSets);
907 setMII(ResMII, RecMII);
911 <<
" (rec=" << RecMII <<
", res=" << ResMII <<
")\n");
919 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
920 <<
"Invalid Minimal Initiation Interval: 0";
928 <<
", we don't pipeline large loops\n");
929 NumFailLargeMaxMII++;
932 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
933 <<
"Minimal Initiation Interval too large: "
934 <<
ore::NV(
"MII", (
int)MII) <<
" > "
936 <<
"Refer to -pipeliner-max-mii.";
941 computeNodeFunctions(NodeSets);
943 registerPressureFilter(NodeSets);
945 colocateNodeSets(NodeSets);
947 checkNodeSets(NodeSets);
950 for (
auto &
I : NodeSets) {
951 dbgs() <<
" Rec NodeSet ";
958 groupRemainingNodes(NodeSets);
960 removeDuplicateNodes(NodeSets);
963 for (
auto &
I : NodeSets) {
964 dbgs() <<
" NodeSet ";
969 computeNodeOrder(NodeSets);
972 checkValidNodeOrder(Circuits);
975 Scheduled = schedulePipeline(Schedule);
982 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
983 <<
"Unable to find schedule";
990 if (numStages == 0) {
995 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
996 <<
"No need to pipeline - no overlapped iterations in schedule.";
1003 <<
" : too many stages, abort\n");
1004 NumFailLargeMaxStage++;
1007 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
1008 <<
"Too many stages in schedule: "
1009 <<
ore::NV(
"numStages", (
int)numStages) <<
" > "
1011 <<
". Refer to -pipeliner-max-stages.";
1019 <<
"Pipelined succesfully!";
1024 std::vector<MachineInstr *> OrderedInsts;
1028 OrderedInsts.push_back(SU->getInstr());
1029 Cycles[SU->getInstr()] = Cycle;
1034 for (
auto &KV : NewMIs) {
1035 Cycles[KV.first] = Cycles[KV.second];
1036 Stages[KV.first] = Stages[KV.second];
1037 NewInstrChanges[KV.first] = InstrChanges[
getSUnit(KV.first)];
1044 "Cannot serialize a schedule with InstrChanges!");
1054 LoopPipelinerInfo->isMVEExpanderSupported() &&
1068 for (
auto &KV : NewMIs)
1069 MF.deleteMachineInstr(KV.second);
1080 assert(Phi.isPHI() &&
"Expecting a Phi.");
1084 for (
unsigned i = 1, e = Phi.getNumOperands(); i != e; i += 2)
1085 if (Phi.getOperand(i + 1).getMBB() !=
Loop)
1086 InitVal = Phi.getOperand(i).getReg();
1088 LoopVal = Phi.getOperand(i).getReg();
1090 assert(InitVal && LoopVal &&
"Unexpected Phi structure.");
1096 for (
unsigned i = 1, e = Phi.getNumOperands(); i != e; i += 2)
1097 if (Phi.getOperand(i + 1).getMBB() == LoopBB)
1098 return Phi.getOperand(i).getReg();
1107 while (!Worklist.
empty()) {
1109 for (
const auto &
SI : SU->
Succs) {
1110 SUnit *SuccSU =
SI.getSUnit();
1112 if (Visited.
count(SuccSU))
1125 if (!getUnderlyingObjects())
1150bool SUnitWithMemInfo::getUnderlyingObjects() {
1152 if (!
MI->hasOneMemOperand())
1170 const SUnitWithMemInfo &Dst,
1173 if (Src.isTriviallyDisjoint(Dst))
1189 if (Src.isUnknown() || Dst.isUnknown())
1191 if (Src.MemOpValue == Dst.MemOpValue && Src.MemOpOffset <= Dst.MemOpOffset)
1202 for (
const Value *SrcObj : Src.UnderlyingObjs)
1203 for (
const Value *DstObj : Dst.UnderlyingObjs)
1211void LoopCarriedOrderDepsTracker::NoBarrierInstsChunk::append(SUnit *SU) {
1214 Stores.emplace_back(SU);
1215 else if (
MI->mayLoad())
1216 Loads.emplace_back(SU);
1217 else if (
MI->mayRaiseFPException())
1218 FPExceptions.emplace_back(SU);
1225 : DAG(SSD), BAA(BAA), SUnits(DAG->SUnits), N(SUnits.
size()),
1226 LoopCarried(N,
BitVector(N)), TII(TII) {}
1230 for (
auto &SU : SUnits) {
1231 auto Tagged = getInstrTag(&SU);
1236 TaggedSUnits.emplace_back(&SU, *Tagged);
1239 computeDependenciesAux();
1242std::optional<LoopCarriedOrderDepsTracker::InstrTag>
1243LoopCarriedOrderDepsTracker::getInstrTag(
SUnit *SU)
const {
1245 if (
TII->isGlobalMemoryObject(
MI))
1246 return InstrTag::Barrier;
1248 if (
MI->mayStore() ||
1249 (
MI->mayLoad() && !
MI->isDereferenceableInvariantLoad()))
1250 return InstrTag::LoadOrStore;
1252 if (
MI->mayRaiseFPException())
1253 return InstrTag::FPExceptions;
1255 return std::nullopt;
1258void LoopCarriedOrderDepsTracker::addDependenciesBetweenSUs(
1259 const SUnitWithMemInfo &Src,
const SUnitWithMemInfo &Dst) {
1261 if (Src.SU == Dst.SU)
1265 setLoopCarriedDep(Src.SU, Dst.SU);
1268void LoopCarriedOrderDepsTracker::addLoopCarriedDepenenciesForChunks(
1269 const NoBarrierInstsChunk &From,
const NoBarrierInstsChunk &To) {
1271 for (
const SUnitWithMemInfo &Src : From.Loads)
1272 for (
const SUnitWithMemInfo &Dst : To.Stores)
1273 addDependenciesBetweenSUs(Src, Dst);
1276 for (
const SUnitWithMemInfo &Src : From.Stores)
1277 for (
const SUnitWithMemInfo &Dst : To.Loads)
1278 addDependenciesBetweenSUs(Src, Dst);
1281 for (
const SUnitWithMemInfo &Src : From.Stores)
1282 for (
const SUnitWithMemInfo &Dst : To.Stores)
1283 addDependenciesBetweenSUs(Src, Dst);
1286void LoopCarriedOrderDepsTracker::computeDependenciesAux() {
1288 SUnit *FirstBarrier =
nullptr;
1289 SUnit *LastBarrier =
nullptr;
1290 for (
const auto &TSU : TaggedSUnits) {
1291 InstrTag
Tag = TSU.getTag();
1292 SUnit *SU = TSU.getPointer();
1294 case InstrTag::Barrier:
1298 Chunks.emplace_back();
1300 case InstrTag::LoadOrStore:
1301 case InstrTag::FPExceptions:
1302 Chunks.back().append(SU);
1310 for (
const NoBarrierInstsChunk &Chunk : Chunks)
1311 addLoopCarriedDepenenciesForChunks(Chunk, Chunk);
1340 assert(LastBarrier &&
"Both barriers should be set.");
1343 for (
const SUnitWithMemInfo &Dst : Chunks.front().Loads)
1344 setLoopCarriedDep(LastBarrier, Dst.SU);
1345 for (
const SUnitWithMemInfo &Dst : Chunks.front().Stores)
1346 setLoopCarriedDep(LastBarrier, Dst.SU);
1347 for (
const SUnitWithMemInfo &Dst : Chunks.front().FPExceptions)
1348 setLoopCarriedDep(LastBarrier, Dst.SU);
1351 for (
const SUnitWithMemInfo &Src : Chunks.back().Loads)
1352 setLoopCarriedDep(Src.SU, FirstBarrier);
1353 for (
const SUnitWithMemInfo &Src : Chunks.back().Stores)
1354 setLoopCarriedDep(Src.SU, FirstBarrier);
1355 for (
const SUnitWithMemInfo &Src : Chunks.back().FPExceptions)
1356 setLoopCarriedDep(Src.SU, FirstBarrier);
1359 if (FirstBarrier != LastBarrier)
1360 setLoopCarriedDep(LastBarrier, FirstBarrier);
1369LoopCarriedEdges SwingSchedulerDAG::addLoopCarriedDependences() {
1370 LoopCarriedEdges LCE;
1374 LCODTracker.computeDependencies();
1375 for (
unsigned I = 0;
I != SUnits.size();
I++)
1376 for (
const int Succ : LCODTracker.getLoopCarried(
I).set_bits())
1389void SwingSchedulerDAG::updatePhiDependences() {
1391 const TargetSubtargetInfo &
ST = MF.
getSubtarget<TargetSubtargetInfo>();
1394 for (SUnit &
I : SUnits) {
1399 MachineInstr *
MI =
I.getInstr();
1401 for (
const MachineOperand &MO :
MI->operands()) {
1414 MachineInstr *
UseMI = &*UI;
1415 SUnit *SU = getSUnit(
UseMI);
1441 }
else if (MO.isUse()) {
1444 if (
DefMI ==
nullptr)
1446 SUnit *SU = getSUnit(
DefMI);
1451 ST.adjustSchedDependency(SU, 0, &
I, MO.getOperandNo(), Dep,
1458 if (SU->
NodeNum <
I.NodeNum && !
I.isPred(SU))
1467 for (
auto &PI :
I.Preds) {
1468 MachineInstr *PMI = PI.getSUnit()->getInstr();
1470 if (
I.getInstr()->isPHI()) {
1479 for (
const SDep &
D : RemoveDeps)
1486void SwingSchedulerDAG::changeDependences() {
1490 for (SUnit &
I : SUnits) {
1491 unsigned BasePos = 0, OffsetPos = 0;
1493 int64_t NewOffset = 0;
1494 if (!canUseLastOffsetValue(
I.getInstr(), BasePos, OffsetPos, NewBase,
1499 Register OrigBase =
I.getInstr()->getOperand(BasePos).getReg();
1503 SUnit *DefSU = getSUnit(
DefMI);
1510 SUnit *LastSU = getSUnit(LastMI);
1514 if (Topo.IsReachable(&
I, LastSU))
1519 for (
const SDep &
P :
I.Preds)
1520 if (
P.getSUnit() == DefSU)
1522 for (
const SDep &
D : Deps) {
1523 Topo.RemovePred(&
I,
D.getSUnit());
1528 for (
auto &
P : LastSU->
Preds)
1531 for (
const SDep &
D : Deps) {
1532 Topo.RemovePred(LastSU,
D.getSUnit());
1539 Topo.AddPred(LastSU, &
I);
1544 InstrChanges[&
I] = std::make_pair(NewBase, NewOffset);
1555 std::vector<MachineInstr *> &OrderedInsts,
1563 Stage <= LastStage; ++Stage) {
1566 Instrs[Cycle].push_front(SU);
1573 std::deque<SUnit *> &CycleInstrs = Instrs[Cycle];
1575 for (
SUnit *SU : CycleInstrs) {
1577 OrderedInsts.push_back(
MI);
1587struct FuncUnitSorter {
1588 const InstrItineraryData *InstrItins;
1589 const MCSubtargetInfo *STI;
1590 DenseMap<InstrStage::FuncUnits, unsigned>
Resources;
1592 FuncUnitSorter(
const TargetSubtargetInfo &TSI)
1593 : InstrItins(TSI.getInstrItineraryData()), STI(&TSI) {}
1598 unsigned minFuncUnits(
const MachineInstr *Inst,
1601 unsigned min = UINT_MAX;
1602 if (InstrItins && !InstrItins->
isEmpty()) {
1603 for (
const InstrStage &IS :
1605 InstrItins->
endStage(SchedClass))) {
1608 if (numAlternatives <
min) {
1609 min = numAlternatives;
1616 const MCSchedClassDesc *SCDesc =
1623 for (
const MCWriteProcResEntry &PRE :
1626 if (!PRE.ReleaseAtCycle)
1628 const MCProcResourceDesc *ProcResource =
1630 unsigned NumUnits = ProcResource->
NumUnits;
1631 if (NumUnits <
min) {
1633 F = PRE.ProcResourceIdx;
1638 llvm_unreachable(
"Should have non-empty InstrItins or hasInstrSchedModel!");
1646 void calcCriticalResources(MachineInstr &
MI) {
1647 unsigned SchedClass =
MI.getDesc().getSchedClass();
1648 if (InstrItins && !InstrItins->
isEmpty()) {
1649 for (
const InstrStage &IS :
1651 InstrItins->
endStage(SchedClass))) {
1659 const MCSchedClassDesc *SCDesc =
1666 for (
const MCWriteProcResEntry &PRE :
1669 if (!PRE.ReleaseAtCycle)
1675 llvm_unreachable(
"Should have non-empty InstrItins or hasInstrSchedModel!");
1679 bool operator()(
const MachineInstr *IS1,
const MachineInstr *IS2)
const {
1681 unsigned MFUs1 = minFuncUnits(IS1, F1);
1682 unsigned MFUs2 = minFuncUnits(IS2, F2);
1685 return MFUs1 > MFUs2;
1690class HighRegisterPressureDetector {
1691 MachineBasicBlock *OrigMBB;
1692 const MachineRegisterInfo &MRI;
1693 const TargetRegisterInfo *
TRI;
1695 const unsigned PSetNum;
1701 std::vector<unsigned> InitSetPressure;
1705 std::vector<unsigned> PressureSetLimit;
1707 DenseMap<MachineInstr *, RegisterOperands> ROMap;
1709 using Instr2LastUsesTy = DenseMap<MachineInstr *, SmallSet<VirtRegOrUnit, 4>>;
1712 using OrderedInstsTy = std::vector<MachineInstr *>;
1713 using Instr2StageTy = DenseMap<MachineInstr *, unsigned>;
1716 static void dumpRegisterPressures(
const std::vector<unsigned> &Pressures) {
1717 if (Pressures.size() == 0) {
1721 for (
unsigned P : Pressures) {
1729 void dumpPSet(VirtRegOrUnit VRegOrUnit)
const {
1733 dbgs() << *PSetIter <<
' ';
1738 void increaseRegisterPressure(std::vector<unsigned> &Pressure,
1739 VirtRegOrUnit VRegOrUnit)
const {
1742 for (; PSetIter.isValid(); ++PSetIter)
1743 Pressure[*PSetIter] += Weight;
1746 void decreaseRegisterPressure(std::vector<unsigned> &Pressure,
1747 VirtRegOrUnit VRegOrUnit)
const {
1749 unsigned Weight = PSetIter.getWeight();
1750 for (; PSetIter.isValid(); ++PSetIter) {
1751 auto &
P = Pressure[*PSetIter];
1753 "register pressure must be greater than or equal weight");
1759 bool isReservedRegUnit(VirtRegOrUnit VRegOrUnit)
const {
1764 bool isDefinedInThisLoop(VirtRegOrUnit VRegOrUnit)
const {
1777 void computeLiveIn() {
1778 SmallSet<VirtRegOrUnit, 8>
Used;
1779 for (
auto &
MI : *OrigMBB) {
1780 if (
MI.isDebugInstr())
1782 for (
auto &Use : ROMap[&
MI].
Uses) {
1783 VirtRegOrUnit
Reg =
Use.VRegOrUnit;
1786 if (
MI.isPHI() &&
Reg.isVirtualReg() &&
1789 if (isReservedRegUnit(
Reg))
1791 if (isDefinedInThisLoop(
Reg))
1797 for (
auto LiveIn : Used)
1798 increaseRegisterPressure(InitSetPressure, LiveIn);
1802 void computePressureSetLimit(
const RegisterClassInfo &RCI) {
1803 for (
unsigned PSet = 0; PSet < PSetNum; PSet++)
1818 Instr2LastUsesTy computeLastUses(
const OrderedInstsTy &OrderedInsts,
1819 Instr2StageTy &Stages)
const {
1824 SmallSet<VirtRegOrUnit, 8> TargetRegs;
1825 const auto UpdateTargetRegs = [
this, &TargetRegs](VirtRegOrUnit
Reg) {
1826 if (isDefinedInThisLoop(
Reg))
1829 for (MachineInstr *
MI : OrderedInsts) {
1832 UpdateTargetRegs(VirtRegOrUnit(
Reg));
1834 for (
auto &Use : ROMap.
find(
MI)->getSecond().Uses)
1835 UpdateTargetRegs(
Use.VRegOrUnit);
1839 const auto InstrScore = [&Stages](MachineInstr *
MI) {
1840 return Stages[
MI] +
MI->isPHI();
1843 std::map<VirtRegOrUnit, MachineInstr *> LastUseMI;
1845 for (
auto &Use : ROMap.
find(
MI)->getSecond().Uses) {
1846 VirtRegOrUnit
Reg =
Use.VRegOrUnit;
1851 MachineInstr *Orig = Ite->second;
1852 MachineInstr *
New =
MI;
1853 if (InstrScore(Orig) < InstrScore(New))
1859 Instr2LastUsesTy LastUses;
1860 for (
auto [
Reg,
MI] : LastUseMI)
1861 LastUses[
MI].insert(
Reg);
1877 std::vector<unsigned>
1878 computeMaxSetPressure(
const OrderedInstsTy &OrderedInsts,
1879 Instr2StageTy &Stages,
1880 const unsigned StageCount)
const {
1881 using RegSetTy = SmallSet<VirtRegOrUnit, 16>;
1887 auto CurSetPressure = InitSetPressure;
1888 auto MaxSetPressure = InitSetPressure;
1889 auto LastUses = computeLastUses(OrderedInsts, Stages);
1892 dbgs() <<
"Ordered instructions:\n";
1893 for (MachineInstr *
MI : OrderedInsts) {
1894 dbgs() <<
"Stage " << Stages[
MI] <<
": ";
1899 const auto InsertReg = [
this, &CurSetPressure](RegSetTy &RegSet,
1900 VirtRegOrUnit
Reg) {
1901 if (isReservedRegUnit(
Reg))
1909 increaseRegisterPressure(CurSetPressure,
Reg);
1913 const auto EraseReg = [
this, &CurSetPressure](RegSetTy &RegSet,
1914 VirtRegOrUnit
Reg) {
1915 if (isReservedRegUnit(
Reg))
1919 if (!RegSet.contains(
Reg))
1924 decreaseRegisterPressure(CurSetPressure,
Reg);
1928 for (
unsigned I = 0;
I < StageCount;
I++) {
1929 for (MachineInstr *
MI : OrderedInsts) {
1930 const auto Stage = Stages[
MI];
1934 const unsigned Iter =
I - Stage;
1936 for (
auto &Def : ROMap.
find(
MI)->getSecond().Defs)
1937 InsertReg(LiveRegSets[Iter],
Def.VRegOrUnit);
1939 for (
auto LastUse : LastUses[
MI]) {
1942 EraseReg(LiveRegSets[Iter - 1], LastUse);
1944 EraseReg(LiveRegSets[Iter], LastUse);
1948 for (
unsigned PSet = 0; PSet < PSetNum; PSet++)
1949 MaxSetPressure[PSet] =
1950 std::max(MaxSetPressure[PSet], CurSetPressure[PSet]);
1953 dbgs() <<
"CurSetPressure=";
1954 dumpRegisterPressures(CurSetPressure);
1955 dbgs() <<
" iter=" << Iter <<
" stage=" << Stage <<
":";
1961 return MaxSetPressure;
1965 HighRegisterPressureDetector(MachineBasicBlock *OrigMBB,
1967 : OrigMBB(OrigMBB), MRI(MF.getRegInfo()),
1968 TRI(MF.getSubtarget().getRegisterInfo()),
1969 PSetNum(
TRI->getNumRegPressureSets()), InitSetPressure(PSetNum, 0),
1970 PressureSetLimit(PSetNum, 0) {}
1974 void init(
const RegisterClassInfo &RCI) {
1975 for (MachineInstr &
MI : *OrigMBB) {
1976 if (
MI.isDebugInstr())
1978 ROMap[&
MI].collect(
MI, *
TRI, MRI,
false,
true);
1982 computePressureSetLimit(RCI);
1987 bool detect(
const SwingSchedulerDAG *SSD, SMSchedule &Schedule,
1988 const unsigned MaxStage)
const {
1990 "the percentage of the margin must be between 0 to 100");
1992 OrderedInstsTy OrderedInsts;
1993 Instr2StageTy Stages;
1995 const auto MaxSetPressure =
1996 computeMaxSetPressure(OrderedInsts, Stages, MaxStage + 1);
1999 dbgs() <<
"Dump MaxSetPressure:\n";
2000 for (
unsigned I = 0;
I < MaxSetPressure.size();
I++) {
2001 dbgs() <<
format(
"MaxSetPressure[%d]=%d\n",
I, MaxSetPressure[
I]);
2006 for (
unsigned PSet = 0; PSet < PSetNum; PSet++) {
2007 unsigned Limit = PressureSetLimit[PSet];
2010 <<
" Margin=" << Margin <<
"\n");
2011 if (Limit < MaxSetPressure[PSet] + Margin) {
2014 <<
"Rejected the schedule because of too high register pressure\n");
2030unsigned SwingSchedulerDAG::calculateResMII() {
2033 return RM.calculateResMII();
2042unsigned SwingSchedulerDAG::calculateRecMII(NodeSetType &NodeSets) {
2043 unsigned RecMII = 0;
2045 for (NodeSet &Nodes : NodeSets) {
2049 unsigned Delay = Nodes.getLatency();
2050 unsigned Distance = 1;
2053 unsigned CurMII = (Delay + Distance - 1) / Distance;
2054 Nodes.setRecMII(CurMII);
2055 if (CurMII > RecMII)
2063void SwingSchedulerDAG::Circuits::createAdjacencyStructure(
2064 SwingSchedulerDDG *DDG) {
2065 BitVector
Added(SUnits.size());
2066 DenseMap<int, int> OutputDeps;
2067 for (
int i = 0, e = SUnits.size(); i != e; ++i) {
2073 if (OE.isOutputDep()) {
2074 int N = OE.getDst()->NodeNum;
2076 auto Dep = OutputDeps.
find(BackEdge);
2077 if (Dep != OutputDeps.
end()) {
2078 BackEdge = Dep->second;
2079 OutputDeps.
erase(Dep);
2081 OutputDeps[
N] = BackEdge;
2084 if (OE.getDst()->isBoundaryNode() || OE.isArtificial())
2096 int N = OE.getDst()->NodeNum;
2098 AdjK[i].push_back(
N);
2105 int N = Dst->NodeNum;
2107 AdjK[i].push_back(
N);
2114 for (
auto &OD : OutputDeps)
2115 if (!
Added.test(OD.second)) {
2116 AdjK[OD.first].push_back(OD.second);
2117 Added.set(OD.second);
2123bool SwingSchedulerDAG::Circuits::circuit(
int V,
int S, NodeSetType &NodeSets,
2124 const SwingSchedulerDAG *DAG,
2126 SUnit *
SV = &SUnits[
V];
2131 for (
auto W : AdjK[V]) {
2132 if (NumPaths > MaxPaths)
2143 if (!Blocked.test(W)) {
2144 if (circuit(W, S, NodeSets, DAG,
2145 Node2Idx->at(W) < Node2Idx->at(V) ?
true : HasBackedge))
2153 for (
auto W : AdjK[V]) {
2164void SwingSchedulerDAG::Circuits::unblock(
int U) {
2166 SmallPtrSet<SUnit *, 4> &BU =
B[
U];
2167 while (!BU.
empty()) {
2168 SmallPtrSet<SUnit *, 4>::iterator
SI = BU.
begin();
2169 assert(SI != BU.
end() &&
"Invalid B set.");
2172 if (Blocked.test(
W->NodeNum))
2173 unblock(
W->NodeNum);
2179void SwingSchedulerDAG::findCircuits(NodeSetType &NodeSets) {
2180 Circuits Cir(SUnits, Topo);
2182 Cir.createAdjacencyStructure(&*DDG);
2183 for (
int I = 0,
E = SUnits.size();
I !=
E; ++
I) {
2185 Cir.circuit(
I,
I, NodeSets,
this);
2207void SwingSchedulerDAG::CopyToPhiMutation::apply(ScheduleDAGInstrs *DAG) {
2208 for (SUnit &SU : DAG->
SUnits) {
2218 for (
auto &Dep : SU.
Preds) {
2219 SUnit *TmpSU = Dep.getSUnit();
2220 MachineInstr *TmpMI = TmpSU->
getInstr();
2231 if (PHISUs.
size() == 0 || SrcSUs.
size() == 0)
2239 for (
auto &Dep : PHISUs[Index]->Succs) {
2243 SUnit *TmpSU = Dep.getSUnit();
2244 MachineInstr *TmpMI = TmpSU->
getInstr();
2253 if (UseSUs.
size() == 0)
2258 for (
auto *
I : UseSUs) {
2259 for (
auto *Src : SrcSUs) {
2275void SwingSchedulerDAG::computeNodeFunctions(NodeSetType &NodeSets) {
2276 ScheduleInfo.resize(SUnits.size());
2279 for (
int I : Topo) {
2280 const SUnit &SU = SUnits[
I];
2287 for (
int I : Topo) {
2289 int zeroLatencyDepth = 0;
2290 SUnit *SU = &SUnits[
I];
2292 SUnit *Pred =
IE.getSrc();
2293 if (
IE.getLatency() == 0)
2295 std::max(zeroLatencyDepth, getZeroLatencyDepth(Pred) + 1);
2296 if (
IE.ignoreDependence(
true))
2298 asap = std::max(asap, (
int)(getASAP(Pred) +
IE.getLatency() -
2299 IE.getDistance() * MII));
2301 maxASAP = std::max(maxASAP, asap);
2302 ScheduleInfo[
I].ASAP = asap;
2303 ScheduleInfo[
I].ZeroLatencyDepth = zeroLatencyDepth;
2309 int zeroLatencyHeight = 0;
2310 SUnit *SU = &SUnits[
I];
2312 SUnit *Succ = OE.getDst();
2315 if (OE.getLatency() == 0)
2317 std::max(zeroLatencyHeight, getZeroLatencyHeight(Succ) + 1);
2318 if (OE.ignoreDependence(
true))
2320 alap = std::min(alap, (
int)(getALAP(Succ) - OE.getLatency() +
2321 OE.getDistance() * MII));
2324 ScheduleInfo[
I].ALAP = alap;
2325 ScheduleInfo[
I].ZeroLatencyHeight = zeroLatencyHeight;
2329 for (NodeSet &
I : NodeSets)
2330 I.computeNodeSetInfo(
this);
2333 for (
unsigned i = 0; i < SUnits.size(); i++) {
2334 dbgs() <<
"\tNode " << i <<
":\n";
2335 dbgs() <<
"\t ASAP = " << getASAP(&SUnits[i]) <<
"\n";
2336 dbgs() <<
"\t ALAP = " << getALAP(&SUnits[i]) <<
"\n";
2337 dbgs() <<
"\t MOV = " << getMOV(&SUnits[i]) <<
"\n";
2338 dbgs() <<
"\t D = " << getDepth(&SUnits[i]) <<
"\n";
2339 dbgs() <<
"\t H = " << getHeight(&SUnits[i]) <<
"\n";
2340 dbgs() <<
"\t ZLD = " << getZeroLatencyDepth(&SUnits[i]) <<
"\n";
2341 dbgs() <<
"\t ZLH = " << getZeroLatencyHeight(&SUnits[i]) <<
"\n";
2356 SUnit *PredSU = IE.getSrc();
2357 if (S && S->count(PredSU) == 0)
2359 if (IE.ignoreDependence(
true))
2370 SUnit *SuccSU = OE.getDst();
2371 if (!OE.isAntiDep())
2373 if (S && S->count(SuccSU) == 0)
2379 return !Preds.
empty();
2392 SUnit *SuccSU = OE.getDst();
2393 if (S && S->count(SuccSU) == 0)
2395 if (OE.ignoreDependence(
false))
2406 SUnit *PredSU = IE.getSrc();
2407 if (!IE.isAntiDep())
2409 if (S && S->count(PredSU) == 0)
2415 return !Succs.
empty();
2431 if (!Visited.
insert(Cur).second)
2432 return Path.contains(Cur);
2433 bool FoundPath =
false;
2435 if (!OE.ignoreDependence(
false))
2437 computePath(OE.getDst(), Path, DestNodes, Exclude, Visited, DDG);
2439 if (IE.isAntiDep() && IE.getDistance() == 0)
2441 computePath(IE.getSrc(), Path, DestNodes, Exclude, Visited, DDG);
2456 for (
SUnit *SU : NS) {
2462 if (
Reg.isVirtual())
2465 for (MCRegUnit Unit :
TRI->regunits(
Reg.asMCReg()))
2469 for (
SUnit *SU : NS)
2473 if (
Reg.isVirtual()) {
2478 for (MCRegUnit Unit :
TRI->regunits(
Reg.asMCReg()))
2489void SwingSchedulerDAG::registerPressureFilter(NodeSetType &NodeSets) {
2490 for (
auto &NS : NodeSets) {
2494 IntervalPressure RecRegPressure;
2495 RegPressureTracker RecRPTracker(RecRegPressure);
2496 RecRPTracker.init(&MF, &RegClassInfo, &LIS, BB, BB->end(),
false,
true);
2498 RecRPTracker.closeBottom();
2500 std::vector<SUnit *> SUnits(NS.begin(), NS.end());
2501 llvm::sort(SUnits, [](
const SUnit *
A,
const SUnit *
B) {
2502 return A->NodeNum >
B->NodeNum;
2505 for (
auto &SU : SUnits) {
2511 RecRPTracker.setPos(std::next(CurInstI));
2513 RegPressureDelta RPDelta;
2515 RecRPTracker.getMaxUpwardPressureDelta(SU->
getInstr(),
nullptr, RPDelta,
2520 dbgs() <<
"Excess register pressure: " << *SU <<
" "
2523 NS.setExceedPressure(SU);
2526 RecRPTracker.recede();
2533void SwingSchedulerDAG::colocateNodeSets(NodeSetType &NodeSets) {
2534 unsigned Colocate = 0;
2535 for (
int i = 0, e = NodeSets.size(); i < e; ++i) {
2537 SmallSetVector<SUnit *, 8>
S1;
2540 for (
int j = i + 1;
j <
e; ++
j) {
2544 SmallSetVector<SUnit *, 8> S2;
2561void SwingSchedulerDAG::checkNodeSets(NodeSetType &NodeSets) {
2566 for (
auto &NS : NodeSets) {
2567 if (NS.getRecMII() > 2)
2569 if (NS.getMaxDepth() > MII)
2578void SwingSchedulerDAG::groupRemainingNodes(NodeSetType &NodeSets) {
2579 SetVector<SUnit *> NodesAdded;
2580 SmallPtrSet<SUnit *, 8> Visited;
2583 for (NodeSet &
I : NodeSets) {
2584 SmallSetVector<SUnit *, 8>
N;
2587 SetVector<SUnit *>
Path;
2588 for (SUnit *NI :
N) {
2590 computePath(NI, Path, NodesAdded,
I, Visited, DDG.get());
2597 if (
succ_L(NodesAdded,
N, DDG.get())) {
2598 SetVector<SUnit *>
Path;
2599 for (SUnit *NI :
N) {
2601 computePath(NI, Path,
I, NodesAdded, Visited, DDG.get());
2612 SmallSetVector<SUnit *, 8>
N;
2613 if (
succ_L(NodesAdded,
N, DDG.get()))
2615 addConnectedNodes(
I, NewSet, NodesAdded);
2616 if (!NewSet.
empty())
2617 NodeSets.push_back(NewSet);
2622 if (
pred_L(NodesAdded,
N, DDG.get()))
2624 addConnectedNodes(
I, NewSet, NodesAdded);
2625 if (!NewSet.
empty())
2626 NodeSets.push_back(NewSet);
2630 for (SUnit &SU : SUnits) {
2631 if (NodesAdded.
count(&SU) == 0) {
2633 addConnectedNodes(&SU, NewSet, NodesAdded);
2634 if (!NewSet.
empty())
2635 NodeSets.push_back(NewSet);
2641void SwingSchedulerDAG::addConnectedNodes(SUnit *SU, NodeSet &NewSet,
2642 SetVector<SUnit *> &NodesAdded) {
2647 if (!OE.isArtificial() && !
Successor->isBoundaryNode() &&
2649 addConnectedNodes(
Successor, NewSet, NodesAdded);
2652 SUnit *Predecessor =
IE.getSrc();
2653 if (!
IE.isArtificial() && NodesAdded.
count(Predecessor) == 0)
2654 addConnectedNodes(Predecessor, NewSet, NodesAdded);
2663 for (
SUnit *SU : Set1) {
2664 if (Set2.
count(SU) != 0)
2667 return !Result.empty();
2671void SwingSchedulerDAG::fuseRecs(NodeSetType &NodeSets) {
2672 for (NodeSetType::iterator
I = NodeSets.begin(),
E = NodeSets.end();
I !=
E;
2675 for (NodeSetType::iterator J =
I + 1; J !=
E;) {
2680 for (SUnit *SU : *J)
2692void SwingSchedulerDAG::removeDuplicateNodes(NodeSetType &NodeSets) {
2693 for (NodeSetType::iterator
I = NodeSets.begin(),
E = NodeSets.end();
I !=
E;
2695 for (NodeSetType::iterator J =
I + 1; J !=
E;) {
2696 J->remove_if([&](SUnit *SUJ) {
return I->count(SUJ); });
2711void SwingSchedulerDAG::computeNodeOrder(NodeSetType &NodeSets) {
2712 SmallSetVector<SUnit *, 8>
R;
2715 for (
auto &Nodes : NodeSets) {
2718 SmallSetVector<SUnit *, 8>
N;
2733 }
else if (NodeSets.size() == 1) {
2734 for (
const auto &
N : Nodes)
2735 if (
N->Succs.size() == 0)
2741 SUnit *maxASAP =
nullptr;
2742 for (SUnit *SU : Nodes) {
2743 if (maxASAP ==
nullptr || getASAP(SU) > getASAP(maxASAP) ||
2744 (getASAP(SU) == getASAP(maxASAP) && SU->
NodeNum > maxASAP->
NodeNum))
2752 while (!
R.empty()) {
2753 if (Order == TopDown) {
2757 while (!
R.empty()) {
2758 SUnit *maxHeight =
nullptr;
2759 for (SUnit *
I : R) {
2760 if (maxHeight ==
nullptr || getHeight(
I) > getHeight(maxHeight))
2762 else if (getHeight(
I) == getHeight(maxHeight) &&
2763 getZeroLatencyHeight(
I) > getZeroLatencyHeight(maxHeight))
2765 else if (getHeight(
I) == getHeight(maxHeight) &&
2766 getZeroLatencyHeight(
I) ==
2767 getZeroLatencyHeight(maxHeight) &&
2768 getMOV(
I) < getMOV(maxHeight))
2773 R.remove(maxHeight);
2774 for (
const auto &OE : DDG->
getOutEdges(maxHeight)) {
2775 SUnit *SU = OE.getDst();
2776 if (Nodes.count(SU) == 0)
2780 if (OE.ignoreDependence(
false))
2789 for (
const auto &IE : DDG->
getInEdges(maxHeight)) {
2790 SUnit *SU =
IE.getSrc();
2791 if (!
IE.isAntiDep())
2793 if (Nodes.count(SU) == 0)
2802 SmallSetVector<SUnit *, 8>
N;
2809 while (!
R.empty()) {
2810 SUnit *maxDepth =
nullptr;
2811 for (SUnit *
I : R) {
2812 if (maxDepth ==
nullptr || getDepth(
I) > getDepth(maxDepth))
2814 else if (getDepth(
I) == getDepth(maxDepth) &&
2815 getZeroLatencyDepth(
I) > getZeroLatencyDepth(maxDepth))
2817 else if (getDepth(
I) == getDepth(maxDepth) &&
2818 getZeroLatencyDepth(
I) == getZeroLatencyDepth(maxDepth) &&
2819 getMOV(
I) < getMOV(maxDepth))
2825 if (Nodes.isExceedSU(maxDepth)) {
2828 R.insert(Nodes.getNode(0));
2831 for (
const auto &IE : DDG->
getInEdges(maxDepth)) {
2832 SUnit *SU =
IE.getSrc();
2833 if (Nodes.count(SU) == 0)
2844 for (
const auto &OE : DDG->
getOutEdges(maxDepth)) {
2845 SUnit *SU = OE.getDst();
2846 if (!OE.isAntiDep())
2848 if (Nodes.count(SU) == 0)
2857 SmallSetVector<SUnit *, 8>
N;
2866 dbgs() <<
"Node order: ";
2868 dbgs() <<
" " << *
I <<
" ";
2874void SwingSchedulerDAG::initPolicy() {
2884bool SwingSchedulerDAG::schedulePipeline(SMSchedule &Schedule) {
2891 bool scheduleFound =
false;
2892 std::unique_ptr<HighRegisterPressureDetector> HRPDetector;
2893 if (Policy.ShouldLimitRegPressure) {
2895 std::make_unique<HighRegisterPressureDetector>(
Loop.getHeader(), MF);
2896 HRPDetector->init(RegClassInfo);
2899 for (
unsigned II = MII;
II <= MAX_II && !scheduleFound; ++
II) {
2911 int EarlyStart = INT_MIN;
2912 int LateStart = INT_MAX;
2916 dbgs() << *SU <<
" ";
2921 dbgs() <<
format(
"\tes: %8x ls: %8x\n", EarlyStart, LateStart));
2923 if (EarlyStart > LateStart)
2924 scheduleFound =
false;
2925 else if (EarlyStart != INT_MIN && LateStart == INT_MAX)
2927 Schedule.
insert(SU, EarlyStart, EarlyStart + (
int)
II - 1,
II);
2928 else if (EarlyStart == INT_MIN && LateStart != INT_MAX)
2930 Schedule.
insert(SU, LateStart, LateStart - (
int)
II + 1,
II);
2931 else if (EarlyStart != INT_MIN && LateStart != INT_MAX) {
2932 LateStart = std::min(LateStart, EarlyStart + (
int)
II - 1);
2941 scheduleFound = Schedule.
insert(SU, LateStart, EarlyStart,
II);
2943 scheduleFound = Schedule.
insert(SU, EarlyStart, LateStart,
II);
2946 scheduleFound = Schedule.
insert(SU, FirstCycle + getASAP(SU),
2947 FirstCycle + getASAP(SU) +
II - 1,
II);
2955 scheduleFound =
false;
2959 dbgs() <<
"\tCan't schedule\n";
2961 }
while (++NI != NE && scheduleFound);
2979 if (scheduleFound && HRPDetector)
2988 if (scheduleFound) {
2989 scheduleFound = LoopPipelinerInfo->shouldUseSchedule(*
this, Schedule);
2994 if (scheduleFound) {
2997 return MachineOptimizationRemarkAnalysis(
2999 <<
"Schedule found with Initiation Interval: "
3001 <<
", MaxStageCount: "
3015 if (!
Reg.isVirtual())
3030 if (!
Op.isReg() || !
Op.getReg().isVirtual())
3055 if (!Def || Def->getParent() != LoopBB)
3058 if (Def->isCopy()) {
3060 if (Def->getOperand(0).getSubReg() || Def->getOperand(1).getSubReg())
3062 CurReg = Def->getOperand(1).getReg();
3063 }
else if (Def->isPHI()) {
3069 }
else if (
TII->getIncrementValue(*Def,
Value)) {
3077 bool OffsetIsScalable;
3078 if (
TII->getMemOperandWithOffset(*Def, BaseOp,
Offset,
3079 OffsetIsScalable)) {
3081 CurReg = BaseOp->
getReg();
3093 if (CurReg == OrgReg)
3109 bool OffsetIsScalable;
3110 if (!
TII.getMemOperandWithOffset(
MI, BaseOp,
Offset, OffsetIsScalable))
3114 if (OffsetIsScalable)
3117 if (!BaseOp->
isReg())
3130bool SwingSchedulerDAG::canUseLastOffsetValue(MachineInstr *
MI,
3132 unsigned &OffsetPos,
3138 unsigned BasePosLd, OffsetPosLd;
3146 if (!Phi || !
Phi->isPHI())
3154 MachineInstr *PrevDef = MRI.
getVRegDef(PrevReg);
3155 if (!PrevDef || PrevDef ==
MI)
3161 unsigned BasePos1 = 0, OffsetPos1 = 0;
3169 MachineInstr *NewMI = MF.CloneMachineInstr(
MI);
3172 MF.deleteMachineInstr(NewMI);
3177 BasePos = BasePosLd;
3178 OffsetPos = OffsetPosLd;
3190 InstrChanges.find(SU);
3191 if (It != InstrChanges.
end()) {
3192 std::pair<Register, int64_t> RegAndOffset = It->second;
3193 unsigned BasePos, OffsetPos;
3194 if (!
TII->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos))
3196 Register BaseReg =
MI->getOperand(BasePos).getReg();
3202 if (BaseStageNum < DefStageNum) {
3204 int OffsetDiff = DefStageNum - BaseStageNum;
3205 if (DefCycleNum < BaseCycleNum) {
3211 MI->getOperand(OffsetPos).getImm() + RegAndOffset.second * OffsetDiff;
3226 while (Def->isPHI()) {
3227 if (!Visited.
insert(Def).second)
3229 for (
unsigned i = 1, e = Def->getNumOperands(); i < e; i += 2)
3230 if (Def->getOperand(i + 1).getMBB() == BB) {
3231 Def = MRI.
getVRegDef(Def->getOperand(i).getReg());
3245 int DeltaB, DeltaO, Delta;
3252 int64_t OffsetB, OffsetO;
3253 bool OffsetBIsScalable, OffsetOIsScalable;
3254 if (!
TII.getMemOperandWithOffset(*BaseMI, BaseOpB, OffsetB,
3255 OffsetBIsScalable) ||
3256 !
TII.getMemOperandWithOffset(*OtherMI, BaseOpO, OffsetO,
3260 if (OffsetBIsScalable || OffsetOIsScalable)
3270 if (!RegB.
isVirtual() || !RegO.isVirtual())
3275 if (!DefB || !DefO || !DefB->
isPHI() || !DefO->
isPHI())
3278 Register InitValB, LoopValB, InitValO, LoopValO;
3279 getPhiRegs(*DefB, LoopBB, InitValB, LoopValB);
3280 getPhiRegs(*DefO, LoopBB, InitValO, LoopValO);
3285 if (!InitDefB || !InitDefO || !InitDefB->
isIdenticalTo(*InitDefO))
3300 dbgs() <<
"Overlap check:\n";
3301 dbgs() <<
" BaseMI: ";
3303 dbgs() <<
" Base + " << OffsetB <<
" + I * " << Delta
3304 <<
", Len: " << AccessSizeB.
getValue() <<
"\n";
3305 dbgs() <<
" OtherMI: ";
3307 dbgs() <<
" Base + " << OffsetO <<
" + I * " << Delta
3308 <<
", Len: " << AccessSizeO.
getValue() <<
"\n";
3316 int64_t BaseMinAddr = OffsetB;
3317 int64_t OhterNextIterMaxAddr = OffsetO + Delta + AccessSizeO.
getValue() - 1;
3318 if (BaseMinAddr > OhterNextIterMaxAddr) {
3323 int64_t BaseMaxAddr = OffsetB + AccessSizeB.
getValue() - 1;
3324 int64_t OtherNextIterMinAddr = OffsetO + Delta;
3325 if (BaseMaxAddr < OtherNextIterMinAddr) {
3334void SwingSchedulerDAG::postProcessDAG() {
3335 for (
auto &M : Mutations)
3345 bool forward =
true;
3347 dbgs() <<
"Trying to insert node between " << StartCycle <<
" and "
3348 << EndCycle <<
" II: " <<
II <<
"\n";
3350 if (StartCycle > EndCycle)
3354 int termCycle = forward ? EndCycle + 1 : EndCycle - 1;
3355 for (
int curCycle = StartCycle; curCycle != termCycle;
3356 forward ? ++curCycle : --curCycle) {
3359 ProcItinResources.canReserveResources(*SU, curCycle)) {
3361 dbgs() <<
"\tinsert at cycle " << curCycle <<
" ";
3366 ProcItinResources.reserveResources(*SU, curCycle);
3367 ScheduledInstrs[curCycle].push_back(SU);
3368 InstrToCycle.insert(std::make_pair(SU, curCycle));
3369 if (curCycle > LastCycle)
3370 LastCycle = curCycle;
3371 if (curCycle < FirstCycle)
3372 FirstCycle = curCycle;
3376 dbgs() <<
"\tfailed to insert at cycle " << curCycle <<
" ";
3387 for (
auto &
P : SU->
Preds)
3388 if (
P.getKind() ==
SDep::Anti &&
P.getSUnit()->getInstr()->isPHI())
3389 for (
auto &S :
P.getSUnit()->Succs)
3390 if (S.getKind() ==
SDep::Data && S.getSUnit()->getInstr()->isPHI())
3391 return P.getSUnit();
3404 for (
int cycle =
getFirstCycle(); cycle <= LastCycle; ++cycle) {
3407 if (IE.getSrc() ==
I) {
3408 int EarlyStart = cycle + IE.getLatency() - IE.getDistance() *
II;
3409 *MaxEarlyStart = std::max(*MaxEarlyStart, EarlyStart);
3414 if (OE.getDst() ==
I) {
3415 int LateStart = cycle - OE.getLatency() + OE.getDistance() *
II;
3416 *MinLateStart = std::min(*MinLateStart, LateStart);
3421 for (
const auto &Dep : SU->
Preds) {
3424 if (BE && Dep.getSUnit() == BE && !SU->
getInstr()->
isPHI() &&
3426 *MinLateStart = std::min(*MinLateStart, cycle);
3436 std::deque<SUnit *> &Insts)
const {
3438 bool OrderBeforeUse =
false;
3439 bool OrderAfterDef =
false;
3440 bool OrderBeforeDef =
false;
3441 unsigned MoveDef = 0;
3442 unsigned MoveUse = 0;
3447 for (std::deque<SUnit *>::iterator
I = Insts.begin(), E = Insts.end();
I != E;
3450 if (!MO.isReg() || !MO.getReg().isVirtual())
3454 unsigned BasePos, OffsetPos;
3455 if (ST.getInstrInfo()->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos))
3456 if (
MI->getOperand(BasePos).getReg() == Reg)
3460 std::tie(Reads, Writes) =
3461 (*I)->getInstr()->readsWritesVirtualRegister(Reg);
3463 OrderBeforeUse =
true;
3468 OrderAfterDef =
true;
3470 }
else if (MO.isUse() && Writes &&
stageScheduled(*
I) == StageInst1) {
3472 OrderBeforeUse =
true;
3476 OrderAfterDef =
true;
3480 OrderBeforeUse =
true;
3484 OrderAfterDef =
true;
3489 OrderBeforeUse =
true;
3495 OrderBeforeDef =
true;
3503 if (OE.getDst() != *
I)
3506 OrderBeforeUse =
true;
3513 else if ((OE.isAntiDep() || OE.isOutputDep()) &&
3515 OrderBeforeUse =
true;
3516 if ((MoveUse == 0) || (Pos < MoveUse))
3521 if (IE.getSrc() != *
I)
3523 if ((IE.isAntiDep() || IE.isOutputDep() || IE.isOrderDep()) &&
3525 OrderAfterDef =
true;
3532 if (OrderAfterDef && OrderBeforeUse && MoveUse == MoveDef)
3533 OrderBeforeUse =
false;
3538 OrderBeforeUse = !OrderAfterDef || (MoveUse > MoveDef);
3542 if (OrderBeforeUse && OrderAfterDef) {
3543 SUnit *UseSU = Insts.at(MoveUse);
3544 SUnit *DefSU = Insts.at(MoveDef);
3545 if (MoveUse > MoveDef) {
3546 Insts.erase(Insts.begin() + MoveUse);
3547 Insts.erase(Insts.begin() + MoveDef);
3549 Insts.erase(Insts.begin() + MoveDef);
3550 Insts.erase(Insts.begin() + MoveUse);
3560 Insts.push_front(SU);
3562 Insts.push_back(SU);
3570 assert(Phi.isPHI() &&
"Expecting a Phi.");
3577 getPhiRegs(Phi, Phi.getParent(), InitVal, LoopVal);
3585 return (LoopCycle > DefCycle) || (LoopStage <= DefStage);
3603 if (!Phi || !Phi->isPHI() || Phi->getParent() != Def->getParent())
3609 if (DMO.getReg() == LoopReg)
3620 if (InstrToCycle.count(IE.getSrc()))
3631 for (
auto &SU : SSD->
SUnits)
3636 while (!Worklist.
empty()) {
3638 if (DoNotPipeline.
count(SU))
3641 DoNotPipeline.
insert(SU);
3648 if (OE.getDistance() == 1)
3651 return DoNotPipeline;
3660 int NewLastCycle = INT_MIN;
3665 NewLastCycle = std::max(NewLastCycle, InstrToCycle[&SU]);
3672 if (IE.getDistance() == 0)
3673 NewCycle = std::max(InstrToCycle[IE.getSrc()], NewCycle);
3678 if (OE.getDistance() == 1)
3679 NewCycle = std::max(InstrToCycle[OE.getDst()], NewCycle);
3681 int OldCycle = InstrToCycle[&SU];
3682 if (OldCycle != NewCycle) {
3683 InstrToCycle[&SU] = NewCycle;
3687 LLVM_DEBUG(
dbgs() << SU <<
" is not pipelined; moving from cycle "
3688 << OldCycle <<
" to " << NewCycle
3714 if (FirstCycle + InitiationInterval <= NewCycle)
3717 NewLastCycle = std::max(NewLastCycle, NewCycle);
3719 LastCycle = NewLastCycle;
3736 int CycleDef = InstrToCycle[&SU];
3737 assert(StageDef != -1 &&
"Instruction should have been scheduled.");
3739 SUnit *Dst = OE.getDst();
3740 if (OE.isAssignedRegDep() && !Dst->isBoundaryNode())
3741 if (OE.getReg().isPhysical()) {
3744 if (InstrToCycle[Dst] <= CycleDef)
3762void SwingSchedulerDAG::checkValidNodeOrder(
const NodeSetType &Circuits)
const {
3765 typedef std::pair<SUnit *, unsigned> UnitIndex;
3766 std::vector<UnitIndex> Indices(
NodeOrder.size(), std::make_pair(
nullptr, 0));
3768 for (
unsigned i = 0, s =
NodeOrder.size(); i < s; ++i)
3769 Indices.push_back(std::make_pair(
NodeOrder[i], i));
3771 auto CompareKey = [](UnitIndex i1, UnitIndex i2) {
3772 return std::get<0>(i1) < std::get<0>(i2);
3785 for (
unsigned i = 0, s =
NodeOrder.size(); i < s; ++i) {
3789 bool PredBefore =
false;
3790 bool SuccBefore =
false;
3798 SUnit *PredSU = IE.getSrc();
3799 unsigned PredIndex = std::get<1>(
3809 SUnit *SuccSU = OE.getDst();
3815 unsigned SuccIndex = std::get<1>(
3828 Circuits, [SU](
const NodeSet &Circuit) {
return Circuit.
count(SU); });
3833 NumNodeOrderIssues++;
3837 <<
" are scheduled before node " << *SU <<
"\n");
3843 dbgs() <<
"Invalid node order found!\n";
3856 for (
SUnit *SU : Instrs) {
3858 for (
unsigned i = 0, e =
MI->getNumOperands(); i < e; ++i) {
3866 InstrChanges.find(SU);
3867 if (It != InstrChanges.
end()) {
3868 unsigned BasePos, OffsetPos;
3870 if (
TII->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos)) {
3874 MI->getOperand(OffsetPos).getImm() - It->second.second;
3887 unsigned TiedUseIdx = 0;
3888 if (
MI->isRegTiedToUseOperand(i, &TiedUseIdx)) {
3890 OverlapReg =
MI->getOperand(TiedUseIdx).getReg();
3892 NewBaseReg =
MI->getOperand(i).getReg();
3901 const std::deque<SUnit *> &Instrs)
const {
3902 std::deque<SUnit *> NewOrderPhi;
3903 for (
SUnit *SU : Instrs) {
3905 NewOrderPhi.push_back(SU);
3907 std::deque<SUnit *> NewOrderI;
3908 for (
SUnit *SU : Instrs) {
3924 std::deque<SUnit *> &cycleInstrs =
3925 ScheduledInstrs[cycle + (stage * InitiationInterval)];
3927 ScheduledInstrs[cycle].push_front(SU);
3933 for (
int cycle =
getFinalCycle() + 1; cycle <= LastCycle; ++cycle)
3934 ScheduledInstrs.erase(cycle);
3944 std::deque<SUnit *> &cycleInstrs = ScheduledInstrs[Cycle];
3952#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3954 os <<
"Num nodes " <<
size() <<
" rec " << RecMII <<
" mov " << MaxMOV
3955 <<
" depth " << MaxDepth <<
" col " << Colocate <<
"\n";
3956 for (
const auto &
I : Nodes)
3957 os <<
" " << *
I <<
" " << *(
I->getInstr());
3967 for (
SUnit *CI : cycleInstrs->second) {
3980void ResourceManager::dumpMRT()
const {
3984 std::stringstream SS;
3986 SS << std::setw(4) <<
"Slot";
3987 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I)
3988 SS << std::setw(3) <<
I;
3989 SS << std::setw(7) <<
"#Mops"
3991 for (
int Slot = 0; Slot < InitiationInterval; ++Slot) {
3992 SS << std::setw(4) << Slot;
3993 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I)
3994 SS << std::setw(3) << MRT[Slot][
I];
3995 SS << std::setw(7) << NumScheduledMops[Slot] <<
"\n";
4004 : STI(ST), SM(ST->getSchedModel()), ST(ST), TII(ST->getInstrInfo()),
4005 DAG(DAG), UseDFA(ST->useDFAforSMS()),
4006 ProcResourceMasks(SM.getNumProcResourceKinds(), 0),
4007 IssueWidth(SM.IssueWidth) {
4009 if (IssueWidth <= 0)
4018 unsigned ProcResourceID = 0;
4022 assert(SM.getNumProcResourceKinds() < 64 &&
4023 "Too many kinds of resources, unsupported");
4026 Masks.
resize(SM.getNumProcResourceKinds());
4027 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4029 if (
Desc.SubUnitsIdxBegin)
4031 Masks[
I] = 1ULL << ProcResourceID;
4035 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4037 if (!
Desc.SubUnitsIdxBegin)
4039 Masks[
I] = 1ULL << ProcResourceID;
4040 for (
unsigned U = 0; U <
Desc.NumUnits; ++U)
4041 Masks[
I] |= Masks[
Desc.SubUnitsIdxBegin[U]];
4046 dbgs() <<
"ProcResourceDesc:\n";
4047 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4049 dbgs() <<
format(
" %16s(%2d): Mask: 0x%08x, NumUnits:%2d\n",
4050 ProcResource->
Name,
I, Masks[
I],
4053 dbgs() <<
" -----------------\n";
4061 dbgs() <<
"canReserveResources:\n";
4064 return DFAResources[positiveModulo(Cycle, InitiationInterval)]
4070 dbgs() <<
"No valid Schedule Class Desc for schedClass!\n";
4076 reserveResources(SCDesc, Cycle);
4077 bool Result = !isOverbooked();
4078 unreserveResources(SCDesc, Cycle);
4084void ResourceManager::reserveResources(
SUnit &SU,
int Cycle) {
4087 dbgs() <<
"reserveResources:\n";
4090 return DFAResources[positiveModulo(Cycle, InitiationInterval)]
4096 dbgs() <<
"No valid Schedule Class Desc for schedClass!\n";
4102 reserveResources(SCDesc, Cycle);
4107 dbgs() <<
"reserveResources: done!\n\n";
4117 for (
int C = Cycle;
C < Cycle + PRE.ReleaseAtCycle; ++
C)
4118 ++MRT[positiveModulo(
C, InitiationInterval)][PRE.ProcResourceIdx];
4121 ++NumScheduledMops[positiveModulo(
C, InitiationInterval)];
4129 for (
int C = Cycle;
C < Cycle + PRE.ReleaseAtCycle; ++
C)
4130 --MRT[positiveModulo(
C, InitiationInterval)][PRE.ProcResourceIdx];
4133 --NumScheduledMops[positiveModulo(
C, InitiationInterval)];
4136bool ResourceManager::isOverbooked()
const {
4138 for (
int Slot = 0;
Slot < InitiationInterval; ++
Slot) {
4139 for (
unsigned I = 1,
E = SM.getNumProcResourceKinds();
I <
E; ++
I) {
4140 const MCProcResourceDesc *
Desc = SM.getProcResource(
I);
4141 if (MRT[Slot][
I] >
Desc->NumUnits)
4144 if (NumScheduledMops[Slot] > IssueWidth)
4150int ResourceManager::calculateResMIIDFA()
const {
4155 FuncUnitSorter FUS = FuncUnitSorter(*ST);
4156 for (SUnit &SU : DAG->SUnits)
4157 FUS.calcCriticalResources(*SU.
getInstr());
4158 PriorityQueue<MachineInstr *, std::vector<MachineInstr *>, FuncUnitSorter>
4161 for (SUnit &SU : DAG->SUnits)
4166 std::unique_ptr<DFAPacketizer>(TII->CreateTargetScheduleState(*ST)));
4168 while (!FuncUnitOrder.empty()) {
4169 MachineInstr *
MI = FuncUnitOrder.top();
4170 FuncUnitOrder.pop();
4171 if (TII->isZeroCost(
MI->getOpcode()))
4176 unsigned NumCycles = DAG->getSUnit(
MI)->Latency;
4177 unsigned ReservedCycles = 0;
4181 dbgs() <<
"Trying to reserve resource for " << NumCycles
4182 <<
" cycles for \n";
4185 for (
unsigned C = 0;
C < NumCycles; ++
C)
4187 if ((*RI)->canReserveResources(*
MI)) {
4188 (*RI)->reserveResources(*
MI);
4195 <<
", NumCycles:" << NumCycles <<
"\n");
4197 for (
unsigned C = ReservedCycles;
C < NumCycles; ++
C) {
4199 <<
"NewResource created to reserve resources"
4201 auto *NewResource = TII->CreateTargetScheduleState(*ST);
4202 assert(NewResource->canReserveResources(*
MI) &&
"Reserve error.");
4203 NewResource->reserveResources(*
MI);
4204 Resources.push_back(std::unique_ptr<DFAPacketizer>(NewResource));
4215 return calculateResMIIDFA();
4222 for (
SUnit &SU : DAG->SUnits) {
4234 <<
" WriteProcRes: ";
4239 make_range(STI->getWriteProcResBegin(SCDesc),
4240 STI->getWriteProcResEnd(SCDesc))) {
4244 SM.getProcResource(PRE.ProcResourceIdx);
4245 dbgs() <<
Desc->Name <<
": " << PRE.ReleaseAtCycle <<
", ";
4248 ResourceCount[PRE.ProcResourceIdx] += PRE.ReleaseAtCycle;
4253 int Result = (NumMops + IssueWidth - 1) / IssueWidth;
4256 dbgs() <<
"#Mops: " << NumMops <<
", "
4257 <<
"IssueWidth: " << IssueWidth <<
", "
4258 <<
"Cycles: " << Result <<
"\n";
4263 std::stringstream SS;
4264 SS << std::setw(2) <<
"ID" << std::setw(16) <<
"Name" << std::setw(10)
4265 <<
"Units" << std::setw(10) <<
"Consumed" << std::setw(10) <<
"Cycles"
4270 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4272 int Cycles = (ResourceCount[
I] +
Desc->NumUnits - 1) /
Desc->NumUnits;
4275 std::stringstream SS;
4276 SS << std::setw(2) <<
I << std::setw(16) <<
Desc->Name << std::setw(10)
4277 <<
Desc->NumUnits << std::setw(10) << ResourceCount[
I]
4278 << std::setw(10) << Cycles <<
"\n";
4282 if (Cycles > Result)
4289 InitiationInterval =
II;
4290 DFAResources.clear();
4291 DFAResources.resize(
II);
4292 for (
auto &
I : DFAResources)
4293 I.reset(ST->getInstrInfo()->CreateTargetScheduleState(*ST));
4296 NumScheduledMops.clear();
4297 NumScheduledMops.resize(
II);
4301 if (Pred.isArtificial() || Dst->isBoundaryNode())
4306 return IgnoreAnti && (Pred.getKind() ==
SDep::Kind::Anti || Distance != 0);
4309SwingSchedulerDDG::SwingSchedulerDDGEdges &
4310SwingSchedulerDDG::getEdges(
const SUnit *SU) {
4312 return EntrySUEdges;
4318const SwingSchedulerDDG::SwingSchedulerDDGEdges &
4319SwingSchedulerDDG::getEdges(
const SUnit *SU)
const {
4321 return EntrySUEdges;
4327void SwingSchedulerDDG::addEdge(
const SUnit *SU,
4330 "Validation-only edges are not expected here.");
4332 auto &Edges = getEdges(SU);
4333 if (
Edge.getSrc() == SU)
4334 Edges.Succs.push_back(
Edge);
4336 Edges.Preds.push_back(
Edge);
4339void SwingSchedulerDDG::initEdges(
SUnit *SU) {
4340 for (
const auto &PI : SU->
Preds) {
4341 SwingSchedulerDDGEdge
Edge(SU, PI,
false,
4346 for (
const auto &SI : SU->
Succs) {
4347 SwingSchedulerDDGEdge
Edge(SU, SI,
true,
4355 : EntrySU(EntrySU), ExitSU(ExitSU) {
4356 EdgesVec.resize(SUnits.size());
4361 for (
auto &SU : SUnits)
4365 for (
SUnit &SU : SUnits) {
4370 for (
SUnit *Dst : *OD) {
4373 Edge.setDistance(1);
4374 ValidationOnlyEdges.push_back(Edge);
4386 bool UseAsExtraEdge = [&]() {
4387 if (Edge.getDistance() == 0 || !Edge.isOrderDep())
4390 SUnit *Src = Edge.getSrc();
4391 SUnit *Dst = Edge.getDst();
4392 if (Src->NodeNum < Dst->NodeNum)
4400 getEdges(Edge.getSrc()).ExtraSuccs.push_back(Edge.getDst());
4406const SwingSchedulerDDG::EdgesType &
4408 return getEdges(SU).Preds;
4411const SwingSchedulerDDG::EdgesType &
4413 return getEdges(SU).Succs;
4417 return getEdges(SU).ExtraSuccs;
4424 auto ExpandCycle = [&](
SUnit *SU) {
4427 return Cycle + (Stage *
II);
4431 SUnit *Src = Edge.getSrc();
4432 SUnit *Dst = Edge.getDst();
4433 if (!Src->isInstr() || !Dst->isInstr())
4435 int CycleSrc = ExpandCycle(Src);
4436 int CycleDst = ExpandCycle(Dst);
4437 int MaxLateStart = CycleDst + Edge.getDistance() *
II - Edge.getLatency();
4438 if (CycleSrc > MaxLateStart) {
4440 dbgs() <<
"Validation failed for edge from " << *Src <<
" to " << *Dst
4451 for (
SUnit &SU : SUnits) {
4480 !
TII->isGlobalMemoryObject(FromMI) &&
4491#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
4500 const auto DumpSU = [](
const SUnit *SU) {
4507 dbgs() <<
" Loop carried edges from " << DumpSU(SU) <<
"\n"
4509 for (
SUnit *Dst : *Order)
4510 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 runMachinePipeliner(MachineFunction &MF, function_ref< const MachineLoopInfo &()> GetMLI, function_ref< LiveIntervals &()> GetLIS, function_ref< AAResults &()> GetAA, function_ref< MachineOptimizationRemarkEmitter &()> GetORE, function_ref< RegisterClassInfo &()> GetRCI)
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 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.
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.
const MachineLoopInfo * MLI
const InstrItineraryData * InstrItins
MachinePipelinerImpl(MachineFunction &MF, const MachineLoopInfo &MLI, LiveIntervals &LIS, AAResults &AA, MachineOptimizationRemarkEmitter &ORE, RegisterClassInfo &RegClassInfo)
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 & 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
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()
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 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 ...
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...
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 ...
SwingSchedulerDAG(MachineFunction &MF, const MachineLoopInfo *MLI, MachineOptimizationRemarkEmitter *ORE, MachineLoop &L, LiveIntervals &lis, const RegisterClassInfo &rci, unsigned II, TargetInstrInfo::PipelinerLoopInfo *PLI, AliasAnalysis *AA)
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.