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");
118 cl::desc(
"Enable Software Pipelining"));
127 cl::desc(
"Size limit for the MII."),
133 cl::desc(
"Force pipeliner to use specified II."),
139 cl::desc(
"Maximum stages allowed in the generated scheduled."),
146 cl::desc(
"Prune dependences between unrelated Phi nodes."),
153 cl::desc(
"Prune loop carried order dependences."),
171 cl::desc(
"Instead of emitting the pipelined code, annotate instructions "
172 "with the generated schedule for feeding into the "
173 "-modulo-schedule-test pass"));
178 "Use the experimental peeling code generator for software pipelining"));
186 cl::desc(
"Limit register pressure of scheduled loop"));
191 cl::desc(
"Margin representing the unused percentage of "
192 "the register pressure limit"));
196 cl::desc(
"Use the MVE code generator for software pipelining"));
201 "pipeliner-max-num-stores",
209 cl::desc(
"Enable CopyToPhi DAG Mutation"));
214 "pipeliner-force-issue-width",
221 cl::desc(
"Set how to use window scheduling algorithm."),
223 "Turn off window algorithm."),
225 "Use window algorithm after SMS algorithm fails."),
227 "Use window algorithm instead of SMS algorithm.")));
229unsigned SwingSchedulerDAG::Circuits::MaxPaths = 5;
234 "Modulo Software Pipelining",
false,
false)
276 enum class InstrTag {
285 TaggedSUnit(
SUnit *SU, InstrTag Tag)
288 InstrTag
getTag()
const {
return InstrTag(getInt()); }
293 struct NoBarrierInstsChunk {
298 void append(
SUnit *SU);
303 std::vector<SUnit> &SUnits;
309 std::vector<BitVector> LoopCarried;
322 std::vector<TaggedSUnit> TaggedSUnits;
336 return LoopCarried[Idx];
341 std::optional<InstrTag> getInstrTag(
SUnit *SU)
const;
343 void addLoopCarriedDepenenciesForChunks(
const NoBarrierInstsChunk &From,
344 const NoBarrierInstsChunk &To);
351 void computeDependenciesAux();
353 void setLoopCarriedDep(
const SUnit *Src,
const SUnit *Dst) {
354 LoopCarried[Src->NodeNum].set(Dst->NodeNum);
405 bool useSwingModuloScheduler();
406 bool useWindowScheduler(
bool Changed);
412int MachinePipelinerImpl::NumTries = 0;
425 for (
const auto &L : *
MLI)
453 MachinePipelinerImpl MP(MF, GetMLI(), GetLIS(), GetAA(), GetORE(), GetRCI());
514bool MachinePipelinerImpl::scheduleLoop(
MachineLoop &L) {
516 for (
const auto &InnerLoop : L)
517 Changed |= scheduleLoop(*InnerLoop);
529 setPragmaPipelineOptions(L);
530 if (!canPipelineLoop(L)) {
534 L.getStartLoc(), L.getHeader())
535 <<
"Failed to pipeline loop";
538 LI.LoopPipelinerInfo.reset();
543 if (useSwingModuloScheduler())
544 Changed = swingModuloScheduler(L);
546 if (useWindowScheduler(
Changed))
547 Changed = runWindowScheduler(L);
549 LI.LoopPipelinerInfo.reset();
553void MachinePipelinerImpl::setPragmaPipelineOptions(MachineLoop &L) {
558 MachineBasicBlock *LBLK =
L.getTopBlock();
571 MDNode *LoopID = TI->
getMetadata(LLVMContext::MD_loop);
572 if (LoopID ==
nullptr)
589 if (S->
getString() ==
"llvm.loop.pipeline.initiationinterval") {
591 "Pipeline initiation interval hint metadata should have two operands.");
595 }
else if (S->
getString() ==
"llvm.loop.pipeline.disable") {
608 auto It = PhiDeps.find(
Reg);
609 if (It == PhiDeps.end())
620 for (
unsigned Dep : It->second) {
635 unsigned DefReg =
MI.getOperand(0).getReg();
639 for (
unsigned I = 1;
I <
MI.getNumOperands();
I += 2)
640 Ins->second.push_back(
MI.getOperand(
I).getReg());
647 for (
const auto &KV : PhiDeps) {
648 unsigned Reg = KV.first;
659bool MachinePipelinerImpl::canPipelineLoop(MachineLoop &L) {
660 if (
L.getNumBlocks() != 1) {
662 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
663 L.getStartLoc(),
L.getHeader())
664 <<
"Not a single basic block: "
665 <<
ore::NV(
"NumBlocks",
L.getNumBlocks());
677 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
678 L.getStartLoc(),
L.getHeader())
679 <<
"Disabled by Pragma.";
689 if (
TII->analyzeBranch(*
L.getHeader(),
LI.TBB,
LI.FBB,
LI.BrCond)) {
690 LLVM_DEBUG(
dbgs() <<
"Unable to analyzeBranch, can NOT pipeline Loop\n");
693 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
694 L.getStartLoc(),
L.getHeader())
695 <<
"The branch can't be understood";
700 LI.LoopInductionVar =
nullptr;
701 LI.LoopCompare =
nullptr;
702 LI.LoopPipelinerInfo =
TII->analyzeLoopForPipelining(
L.getTopBlock());
703 if (!
LI.LoopPipelinerInfo) {
704 LLVM_DEBUG(
dbgs() <<
"Unable to analyzeLoop, can NOT pipeline Loop\n");
707 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
708 L.getStartLoc(),
L.getHeader())
709 <<
"The loop structure is not supported";
714 if (!
L.getLoopPreheader()) {
715 LLVM_DEBUG(
dbgs() <<
"Preheader not found, can NOT pipeline Loop\n");
718 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
719 L.getStartLoc(),
L.getHeader())
720 <<
"No loop preheader found";
725 unsigned NumStores = 0;
726 for (MachineInstr &
MI : *
L.getHeader())
731 NumFailTooManyStores++;
733 return MachineOptimizationRemarkAnalysis(
DEBUG_TYPE,
"canPipelineLoop",
734 L.getStartLoc(),
L.getHeader())
735 <<
"Too many store instructions in the loop: "
736 <<
ore::NV(
"NumStores", NumStores) <<
" > "
743 preprocessPhiNodes(*
L.getHeader());
747void MachinePipelinerImpl::preprocessPhiNodes(MachineBasicBlock &
B) {
748 MachineRegisterInfo &MRI =
MF->getRegInfo();
749 SlotIndexes &Slots = *
LIS->getSlotIndexes();
751 for (MachineInstr &PI :
B.phis()) {
752 MachineOperand &DefOp = PI.getOperand(0);
756 for (
unsigned i = 1, n = PI.getNumOperands(); i != n; i += 2) {
757 MachineOperand &RegOp = PI.getOperand(i);
764 MachineBasicBlock &PredB = *PI.getOperand(i+1).getMBB();
781bool MachinePipelinerImpl::swingModuloScheduler(MachineLoop &L) {
782 assert(
L.getBlocks().size() == 1 &&
"SMS works on single blocks only.");
785 LI.LoopPipelinerInfo.get(),
AA);
787 MachineBasicBlock *
MBB =
L.getHeader();
805 return SMS.hasNewSchedule();
820bool MachinePipelinerImpl::runWindowScheduler(
MachineLoop &L) {
832bool MachinePipelinerImpl::useSwingModuloScheduler() {
837bool MachinePipelinerImpl::useWindowScheduler(
bool Changed) {
844 "llvm.loop.pipeline.initiationinterval is set.\n");
852void SwingSchedulerDAG::setMII(
unsigned ResMII,
unsigned RecMII) {
855 else if (II_setByPragma > 0)
856 MII = II_setByPragma;
858 MII = std::max(ResMII, RecMII);
861void SwingSchedulerDAG::setMAX_II() {
864 else if (II_setByPragma > 0)
865 MAX_II = II_setByPragma;
878 RegClassInfo(rci), II_setByPragma(
II), LoopPipelinerInfo(PLI),
881 MF.getSubtarget().getSMSMutations(Mutations);
883 Mutations.push_back(std::make_unique<CopyToPhiMutation>());
884 BAA.enableCrossIterationMode();
892 updatePhiDependences();
893 Topo.InitDAGTopologicalSorting();
899 dbgs() <<
"===== Loop Carried Edges Begin =====\n";
902 dbgs() <<
"===== Loop Carried Edges End =====\n";
905 NodeSetType NodeSets;
906 findCircuits(NodeSets);
907 NodeSetType Circuits = NodeSets;
910 unsigned ResMII = calculateResMII();
911 unsigned RecMII = calculateRecMII(NodeSets);
919 setMII(ResMII, RecMII);
923 <<
" (rec=" << RecMII <<
", res=" << ResMII <<
")\n");
931 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
932 <<
"Invalid Minimal Initiation Interval: 0";
940 <<
", we don't pipeline large loops\n");
941 NumFailLargeMaxMII++;
944 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
945 <<
"Minimal Initiation Interval too large: "
946 <<
ore::NV(
"MII", (
int)MII) <<
" > "
948 <<
"Refer to -pipeliner-max-mii.";
953 computeNodeFunctions(NodeSets);
955 registerPressureFilter(NodeSets);
957 colocateNodeSets(NodeSets);
959 checkNodeSets(NodeSets);
962 for (
auto &
I : NodeSets) {
963 dbgs() <<
" Rec NodeSet ";
970 groupRemainingNodes(NodeSets);
972 removeDuplicateNodes(NodeSets);
975 for (
auto &
I : NodeSets) {
976 dbgs() <<
" NodeSet ";
981 computeNodeOrder(NodeSets);
984 checkValidNodeOrder(Circuits);
987 Scheduled = schedulePipeline(Schedule);
994 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
995 <<
"Unable to find schedule";
1002 if (numStages == 0) {
1007 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
1008 <<
"No need to pipeline - no overlapped iterations in schedule.";
1015 <<
" : too many stages, abort\n");
1016 NumFailLargeMaxStage++;
1019 DEBUG_TYPE,
"schedule", Loop.getStartLoc(), Loop.getHeader())
1020 <<
"Too many stages in schedule: "
1021 <<
ore::NV(
"numStages", (
int)numStages) <<
" > "
1023 <<
". Refer to -pipeliner-max-stages.";
1031 <<
"Pipelined succesfully!";
1036 std::vector<MachineInstr *> OrderedInsts;
1040 OrderedInsts.push_back(SU->getInstr());
1041 Cycles[SU->getInstr()] = Cycle;
1046 for (
auto &KV : NewMIs) {
1047 Cycles[KV.first] = Cycles[KV.second];
1048 Stages[KV.first] = Stages[KV.second];
1049 NewInstrChanges[KV.first] = InstrChanges[
getSUnit(KV.first)];
1056 "Cannot serialize a schedule with InstrChanges!");
1066 LoopPipelinerInfo->isMVEExpanderSupported() &&
1080 for (
auto &KV : NewMIs)
1081 MF.deleteMachineInstr(KV.second);
1092 assert(Phi.isPHI() &&
"Expecting a Phi.");
1096 for (
unsigned i = 1, e = Phi.getNumOperands(); i != e; i += 2)
1097 if (Phi.getOperand(i + 1).getMBB() !=
Loop)
1098 InitVal = Phi.getOperand(i).getReg();
1100 LoopVal = Phi.getOperand(i).getReg();
1102 assert(InitVal && LoopVal &&
"Unexpected Phi structure.");
1108 for (
unsigned i = 1, e = Phi.getNumOperands(); i != e; i += 2)
1109 if (Phi.getOperand(i + 1).getMBB() == LoopBB)
1110 return Phi.getOperand(i).getReg();
1119 while (!Worklist.
empty()) {
1121 for (
const auto &
SI : SU->
Succs) {
1122 SUnit *SuccSU =
SI.getSUnit();
1124 if (Visited.
count(SuccSU))
1137 if (!getUnderlyingObjects())
1162bool SUnitWithMemInfo::getUnderlyingObjects() {
1164 if (!
MI->hasOneMemOperand())
1182 const SUnitWithMemInfo &Dst,
1187 if (Src.isTriviallyDisjoint(Dst))
1201 if (Src.isUnknown() || Dst.isUnknown())
1203 if (Src.MemOpValue == Dst.MemOpValue && Src.MemOpOffset <= Dst.MemOpOffset)
1214 for (
const Value *SrcObj : Src.UnderlyingObjs)
1215 for (
const Value *DstObj : Dst.UnderlyingObjs)
1223void LoopCarriedOrderDepsTracker::NoBarrierInstsChunk::append(SUnit *SU) {
1226 Stores.emplace_back(SU);
1227 else if (
MI->mayLoad())
1228 Loads.emplace_back(SU);
1229 else if (
MI->mayRaiseFPException())
1230 FPExceptions.emplace_back(SU);
1238 : DAG(SSD), BAA(BAA), SUnits(DAG->SUnits), N(SUnits.
size()),
1239 LoopCarried(N,
BitVector(N)), TII(TII), TRI(TRI) {}
1243 for (
auto &SU : SUnits) {
1244 auto Tagged = getInstrTag(&SU);
1249 TaggedSUnits.emplace_back(&SU, *Tagged);
1252 computeDependenciesAux();
1255std::optional<LoopCarriedOrderDepsTracker::InstrTag>
1256LoopCarriedOrderDepsTracker::getInstrTag(
SUnit *SU)
const {
1258 if (
TII->isGlobalMemoryObject(
MI))
1259 return InstrTag::Barrier;
1261 if (
MI->mayStore() ||
1262 (
MI->mayLoad() && !
MI->isDereferenceableInvariantLoad()))
1263 return InstrTag::LoadOrStore;
1265 if (
MI->mayRaiseFPException())
1266 return InstrTag::FPExceptions;
1268 return std::nullopt;
1271void LoopCarriedOrderDepsTracker::addDependenciesBetweenSUs(
1272 const SUnitWithMemInfo &Src,
const SUnitWithMemInfo &Dst) {
1274 if (Src.SU == Dst.SU)
1278 setLoopCarriedDep(Src.SU, Dst.SU);
1281void LoopCarriedOrderDepsTracker::addLoopCarriedDepenenciesForChunks(
1282 const NoBarrierInstsChunk &From,
const NoBarrierInstsChunk &To) {
1284 for (
const SUnitWithMemInfo &Src : From.Loads)
1285 for (
const SUnitWithMemInfo &Dst : To.Stores)
1286 addDependenciesBetweenSUs(Src, Dst);
1289 for (
const SUnitWithMemInfo &Src : From.Stores)
1290 for (
const SUnitWithMemInfo &Dst : To.Loads)
1291 addDependenciesBetweenSUs(Src, Dst);
1294 for (
const SUnitWithMemInfo &Src : From.Stores)
1295 for (
const SUnitWithMemInfo &Dst : To.Stores)
1296 addDependenciesBetweenSUs(Src, Dst);
1299void LoopCarriedOrderDepsTracker::computeDependenciesAux() {
1301 SUnit *FirstBarrier =
nullptr;
1302 SUnit *LastBarrier =
nullptr;
1303 for (
const auto &TSU : TaggedSUnits) {
1304 InstrTag
Tag = TSU.getTag();
1305 SUnit *SU = TSU.getPointer();
1307 case InstrTag::Barrier:
1311 Chunks.emplace_back();
1313 case InstrTag::LoadOrStore:
1314 case InstrTag::FPExceptions:
1315 Chunks.back().append(SU);
1323 for (
const NoBarrierInstsChunk &Chunk : Chunks)
1324 addLoopCarriedDepenenciesForChunks(Chunk, Chunk);
1353 assert(LastBarrier &&
"Both barriers should be set.");
1356 for (
const SUnitWithMemInfo &Dst : Chunks.front().Loads)
1357 setLoopCarriedDep(LastBarrier, Dst.SU);
1358 for (
const SUnitWithMemInfo &Dst : Chunks.front().Stores)
1359 setLoopCarriedDep(LastBarrier, Dst.SU);
1360 for (
const SUnitWithMemInfo &Dst : Chunks.front().FPExceptions)
1361 setLoopCarriedDep(LastBarrier, Dst.SU);
1364 for (
const SUnitWithMemInfo &Src : Chunks.back().Loads)
1365 setLoopCarriedDep(Src.SU, FirstBarrier);
1366 for (
const SUnitWithMemInfo &Src : Chunks.back().Stores)
1367 setLoopCarriedDep(Src.SU, FirstBarrier);
1368 for (
const SUnitWithMemInfo &Src : Chunks.back().FPExceptions)
1369 setLoopCarriedDep(Src.SU, FirstBarrier);
1372 if (FirstBarrier != LastBarrier)
1373 setLoopCarriedDep(LastBarrier, FirstBarrier);
1382LoopCarriedEdges SwingSchedulerDAG::addLoopCarriedDependences() {
1383 LoopCarriedEdges LCE;
1387 LCODTracker.computeDependencies();
1388 for (
unsigned I = 0;
I != SUnits.size();
I++)
1389 for (
const int Succ : LCODTracker.getLoopCarried(
I).set_bits())
1402void SwingSchedulerDAG::updatePhiDependences() {
1404 const TargetSubtargetInfo &
ST = MF.
getSubtarget<TargetSubtargetInfo>();
1407 for (SUnit &
I : SUnits) {
1412 MachineInstr *
MI =
I.getInstr();
1414 for (
const MachineOperand &MO :
MI->operands()) {
1427 MachineInstr *
UseMI = &*UI;
1428 SUnit *SU = getSUnit(
UseMI);
1454 }
else if (MO.isUse()) {
1457 if (
DefMI ==
nullptr)
1459 SUnit *SU = getSUnit(
DefMI);
1464 ST.adjustSchedDependency(SU, 0, &
I, MO.getOperandNo(), Dep,
1471 if (SU->
NodeNum <
I.NodeNum && !
I.isPred(SU))
1480 for (
auto &PI :
I.Preds) {
1481 MachineInstr *PMI = PI.getSUnit()->getInstr();
1483 if (
I.getInstr()->isPHI()) {
1492 for (
const SDep &
D : RemoveDeps)
1499void SwingSchedulerDAG::changeDependences() {
1503 for (SUnit &
I : SUnits) {
1504 unsigned BasePos = 0, OffsetPos = 0;
1506 int64_t NewOffset = 0;
1507 if (!canUseLastOffsetValue(
I.getInstr(), BasePos, OffsetPos, NewBase,
1512 Register OrigBase =
I.getInstr()->getOperand(BasePos).getReg();
1516 SUnit *DefSU = getSUnit(
DefMI);
1523 SUnit *LastSU = getSUnit(LastMI);
1527 if (Topo.IsReachable(&
I, LastSU))
1532 for (
const SDep &
P :
I.Preds)
1533 if (
P.getSUnit() == DefSU)
1535 for (
const SDep &
D : Deps) {
1536 Topo.RemovePred(&
I,
D.getSUnit());
1541 for (
auto &
P : LastSU->
Preds)
1544 for (
const SDep &
D : Deps) {
1545 Topo.RemovePred(LastSU,
D.getSUnit());
1552 Topo.AddPred(LastSU, &
I);
1557 InstrChanges[&
I] = std::make_pair(NewBase, NewOffset);
1568 std::vector<MachineInstr *> &OrderedInsts,
1576 Stage <= LastStage; ++Stage) {
1579 Instrs[Cycle].push_front(SU);
1586 std::deque<SUnit *> &CycleInstrs = Instrs[Cycle];
1588 for (
SUnit *SU : CycleInstrs) {
1590 OrderedInsts.push_back(
MI);
1600struct FuncUnitSorter {
1601 const InstrItineraryData *InstrItins;
1602 const MCSubtargetInfo *STI;
1603 DenseMap<InstrStage::FuncUnits, unsigned>
Resources;
1605 FuncUnitSorter(
const TargetSubtargetInfo &TSI)
1606 : InstrItins(TSI.getInstrItineraryData()), STI(&TSI) {}
1611 unsigned minFuncUnits(
const MachineInstr *Inst,
1614 unsigned min = UINT_MAX;
1615 if (InstrItins && !InstrItins->
isEmpty()) {
1616 for (
const InstrStage &IS :
1618 InstrItins->
endStage(SchedClass))) {
1621 if (numAlternatives <
min) {
1622 min = numAlternatives;
1629 const MCSchedClassDesc *SCDesc =
1636 for (
const MCWriteProcResEntry &PRE :
1639 if (!PRE.ReleaseAtCycle)
1641 const MCProcResourceDesc *ProcResource =
1643 unsigned NumUnits = ProcResource->
NumUnits;
1644 if (NumUnits <
min) {
1646 F = PRE.ProcResourceIdx;
1651 llvm_unreachable(
"Should have non-empty InstrItins or hasInstrSchedModel!");
1659 void calcCriticalResources(MachineInstr &
MI) {
1660 unsigned SchedClass =
MI.getDesc().getSchedClass();
1661 if (InstrItins && !InstrItins->
isEmpty()) {
1662 for (
const InstrStage &IS :
1664 InstrItins->
endStage(SchedClass))) {
1672 const MCSchedClassDesc *SCDesc =
1679 for (
const MCWriteProcResEntry &PRE :
1682 if (!PRE.ReleaseAtCycle)
1688 llvm_unreachable(
"Should have non-empty InstrItins or hasInstrSchedModel!");
1692 bool operator()(
const MachineInstr *IS1,
const MachineInstr *IS2)
const {
1694 unsigned MFUs1 = minFuncUnits(IS1, F1);
1695 unsigned MFUs2 = minFuncUnits(IS2, F2);
1698 return MFUs1 > MFUs2;
1703class HighRegisterPressureDetector {
1704 MachineBasicBlock *OrigMBB;
1705 const MachineRegisterInfo &MRI;
1706 const TargetRegisterInfo *
TRI;
1708 const unsigned PSetNum;
1714 std::vector<unsigned> InitSetPressure;
1718 std::vector<unsigned> PressureSetLimit;
1720 DenseMap<MachineInstr *, RegisterOperands> ROMap;
1722 using Instr2LastUsesTy = DenseMap<MachineInstr *, SmallSet<VirtRegOrUnit, 4>>;
1725 using OrderedInstsTy = std::vector<MachineInstr *>;
1726 using Instr2StageTy = DenseMap<MachineInstr *, unsigned>;
1729 static void dumpRegisterPressures(
const std::vector<unsigned> &Pressures) {
1730 if (Pressures.size() == 0) {
1734 for (
unsigned P : Pressures) {
1742 void dumpPSet(VirtRegOrUnit VRegOrUnit)
const {
1746 dbgs() << *PSetIter <<
' ';
1751 void increaseRegisterPressure(std::vector<unsigned> &Pressure,
1752 VirtRegOrUnit VRegOrUnit)
const {
1755 for (; PSetIter.isValid(); ++PSetIter)
1756 Pressure[*PSetIter] += Weight;
1759 void decreaseRegisterPressure(std::vector<unsigned> &Pressure,
1760 VirtRegOrUnit VRegOrUnit)
const {
1762 unsigned Weight = PSetIter.getWeight();
1763 for (; PSetIter.isValid(); ++PSetIter) {
1764 auto &
P = Pressure[*PSetIter];
1766 "register pressure must be greater than or equal weight");
1772 bool isReservedRegUnit(VirtRegOrUnit VRegOrUnit)
const {
1777 bool isDefinedInThisLoop(VirtRegOrUnit VRegOrUnit)
const {
1790 void computeLiveIn() {
1791 SmallSet<VirtRegOrUnit, 8>
Used;
1792 for (
auto &
MI : *OrigMBB) {
1793 if (
MI.isDebugInstr())
1795 for (
auto &Use : ROMap[&
MI].
Uses) {
1796 VirtRegOrUnit
Reg =
Use.VRegOrUnit;
1799 if (
MI.isPHI() &&
Reg.isVirtualReg() &&
1802 if (isReservedRegUnit(
Reg))
1804 if (isDefinedInThisLoop(
Reg))
1810 for (
auto LiveIn : Used)
1811 increaseRegisterPressure(InitSetPressure, LiveIn);
1815 void computePressureSetLimit(
const RegisterClassInfo &RCI) {
1816 for (
unsigned PSet = 0; PSet < PSetNum; PSet++)
1831 Instr2LastUsesTy computeLastUses(
const OrderedInstsTy &OrderedInsts,
1832 Instr2StageTy &Stages)
const {
1837 SmallSet<VirtRegOrUnit, 8> TargetRegs;
1838 const auto UpdateTargetRegs = [
this, &TargetRegs](VirtRegOrUnit
Reg) {
1839 if (isDefinedInThisLoop(
Reg))
1842 for (MachineInstr *
MI : OrderedInsts) {
1845 UpdateTargetRegs(VirtRegOrUnit(
Reg));
1847 for (
auto &Use : ROMap.
find(
MI)->getSecond().Uses)
1848 UpdateTargetRegs(
Use.VRegOrUnit);
1852 const auto InstrScore = [&Stages](MachineInstr *
MI) {
1853 return Stages[
MI] +
MI->isPHI();
1856 std::map<VirtRegOrUnit, MachineInstr *> LastUseMI;
1858 for (
auto &Use : ROMap.
find(
MI)->getSecond().Uses) {
1859 VirtRegOrUnit
Reg =
Use.VRegOrUnit;
1864 MachineInstr *Orig = Ite->second;
1865 MachineInstr *
New =
MI;
1866 if (InstrScore(Orig) < InstrScore(New))
1872 Instr2LastUsesTy LastUses;
1873 for (
auto [
Reg,
MI] : LastUseMI)
1874 LastUses[
MI].insert(
Reg);
1890 std::vector<unsigned>
1891 computeMaxSetPressure(
const OrderedInstsTy &OrderedInsts,
1892 Instr2StageTy &Stages,
1893 const unsigned StageCount)
const {
1894 using RegSetTy = SmallSet<VirtRegOrUnit, 16>;
1900 auto CurSetPressure = InitSetPressure;
1901 auto MaxSetPressure = InitSetPressure;
1902 auto LastUses = computeLastUses(OrderedInsts, Stages);
1905 dbgs() <<
"Ordered instructions:\n";
1906 for (MachineInstr *
MI : OrderedInsts) {
1907 dbgs() <<
"Stage " << Stages[
MI] <<
": ";
1912 const auto InsertReg = [
this, &CurSetPressure](RegSetTy &RegSet,
1913 VirtRegOrUnit
Reg) {
1914 if (isReservedRegUnit(
Reg))
1922 increaseRegisterPressure(CurSetPressure,
Reg);
1926 const auto EraseReg = [
this, &CurSetPressure](RegSetTy &RegSet,
1927 VirtRegOrUnit
Reg) {
1928 if (isReservedRegUnit(
Reg))
1932 if (!RegSet.contains(
Reg))
1937 decreaseRegisterPressure(CurSetPressure,
Reg);
1941 for (
unsigned I = 0;
I < StageCount;
I++) {
1942 for (MachineInstr *
MI : OrderedInsts) {
1943 const auto Stage = Stages[
MI];
1947 const unsigned Iter =
I - Stage;
1949 for (
auto &Def : ROMap.
find(
MI)->getSecond().Defs)
1950 InsertReg(LiveRegSets[Iter],
Def.VRegOrUnit);
1952 for (
auto LastUse : LastUses[
MI]) {
1955 EraseReg(LiveRegSets[Iter - 1], LastUse);
1957 EraseReg(LiveRegSets[Iter], LastUse);
1961 for (
unsigned PSet = 0; PSet < PSetNum; PSet++)
1962 MaxSetPressure[PSet] =
1963 std::max(MaxSetPressure[PSet], CurSetPressure[PSet]);
1966 dbgs() <<
"CurSetPressure=";
1967 dumpRegisterPressures(CurSetPressure);
1968 dbgs() <<
" iter=" << Iter <<
" stage=" << Stage <<
":";
1974 return MaxSetPressure;
1978 HighRegisterPressureDetector(MachineBasicBlock *OrigMBB,
1980 : OrigMBB(OrigMBB), MRI(MF.getRegInfo()),
1981 TRI(MF.getSubtarget().getRegisterInfo()),
1982 PSetNum(
TRI->getNumRegPressureSets()), InitSetPressure(PSetNum, 0),
1983 PressureSetLimit(PSetNum, 0) {}
1987 void init(
const RegisterClassInfo &RCI) {
1988 for (MachineInstr &
MI : *OrigMBB) {
1989 if (
MI.isDebugInstr())
1991 ROMap[&
MI].collect(
MI, *
TRI, MRI,
false,
true);
1995 computePressureSetLimit(RCI);
2000 bool detect(
const SwingSchedulerDAG *SSD, SMSchedule &Schedule,
2001 const unsigned MaxStage)
const {
2003 "the percentage of the margin must be between 0 to 100");
2005 OrderedInstsTy OrderedInsts;
2006 Instr2StageTy Stages;
2008 const auto MaxSetPressure =
2009 computeMaxSetPressure(OrderedInsts, Stages, MaxStage + 1);
2012 dbgs() <<
"Dump MaxSetPressure:\n";
2013 for (
unsigned I = 0;
I < MaxSetPressure.size();
I++) {
2014 dbgs() <<
format(
"MaxSetPressure[%d]=%d\n",
I, MaxSetPressure[
I]);
2019 for (
unsigned PSet = 0; PSet < PSetNum; PSet++) {
2020 unsigned Limit = PressureSetLimit[PSet];
2023 <<
" Margin=" << Margin <<
"\n");
2024 if (Limit < MaxSetPressure[PSet] + Margin) {
2027 <<
"Rejected the schedule because of too high register pressure\n");
2043unsigned SwingSchedulerDAG::calculateResMII() {
2046 return RM.calculateResMII();
2055unsigned SwingSchedulerDAG::calculateRecMII(NodeSetType &NodeSets) {
2056 unsigned RecMII = 0;
2058 for (NodeSet &Nodes : NodeSets) {
2062 unsigned Delay = Nodes.getLatency();
2063 unsigned Distance = 1;
2066 unsigned CurMII = (Delay + Distance - 1) / Distance;
2067 Nodes.setRecMII(CurMII);
2068 if (CurMII > RecMII)
2076void SwingSchedulerDAG::Circuits::createAdjacencyStructure(
2077 SwingSchedulerDDG *DDG) {
2078 BitVector
Added(SUnits.size());
2079 DenseMap<int, int> OutputDeps;
2080 for (
int i = 0, e = SUnits.size(); i != e; ++i) {
2086 if (OE.isOutputDep()) {
2087 int N = OE.getDst()->NodeNum;
2089 auto Dep = OutputDeps.
find(BackEdge);
2090 if (Dep != OutputDeps.
end()) {
2091 BackEdge = Dep->second;
2092 OutputDeps.
erase(Dep);
2094 OutputDeps[
N] = BackEdge;
2097 if (OE.getDst()->isBoundaryNode() || OE.isArtificial())
2109 int N = OE.getDst()->NodeNum;
2111 AdjK[i].push_back(
N);
2118 int N = Dst->NodeNum;
2120 AdjK[i].push_back(
N);
2127 for (
auto &OD : OutputDeps)
2128 if (!
Added.test(OD.second)) {
2129 AdjK[OD.first].push_back(OD.second);
2130 Added.set(OD.second);
2136bool SwingSchedulerDAG::Circuits::circuit(
int V,
int S, NodeSetType &NodeSets,
2137 const SwingSchedulerDAG *DAG,
2139 SUnit *
SV = &SUnits[
V];
2144 for (
auto W : AdjK[V]) {
2145 if (NumPaths > MaxPaths)
2156 if (!Blocked.test(W)) {
2157 if (circuit(W, S, NodeSets, DAG,
2158 Node2Idx->at(W) < Node2Idx->at(V) ?
true : HasBackedge))
2166 for (
auto W : AdjK[V]) {
2177void SwingSchedulerDAG::Circuits::unblock(
int U) {
2179 SmallPtrSet<SUnit *, 4> &BU =
B[
U];
2180 while (!BU.
empty()) {
2181 SmallPtrSet<SUnit *, 4>::iterator
SI = BU.
begin();
2182 assert(SI != BU.
end() &&
"Invalid B set.");
2185 if (Blocked.test(
W->NodeNum))
2186 unblock(
W->NodeNum);
2192void SwingSchedulerDAG::findCircuits(NodeSetType &NodeSets) {
2193 Circuits Cir(SUnits, Topo);
2195 Cir.createAdjacencyStructure(&*DDG);
2196 for (
int I = 0,
E = SUnits.size();
I !=
E; ++
I) {
2198 Cir.circuit(
I,
I, NodeSets,
this);
2220void SwingSchedulerDAG::CopyToPhiMutation::apply(ScheduleDAGInstrs *DAG) {
2221 for (SUnit &SU : DAG->
SUnits) {
2231 for (
auto &Dep : SU.
Preds) {
2232 SUnit *TmpSU = Dep.getSUnit();
2233 MachineInstr *TmpMI = TmpSU->
getInstr();
2244 if (PHISUs.
size() == 0 || SrcSUs.
size() == 0)
2252 for (
auto &Dep : PHISUs[Index]->Succs) {
2256 SUnit *TmpSU = Dep.getSUnit();
2257 MachineInstr *TmpMI = TmpSU->
getInstr();
2266 if (UseSUs.
size() == 0)
2271 for (
auto *
I : UseSUs) {
2272 for (
auto *Src : SrcSUs) {
2288void SwingSchedulerDAG::computeNodeFunctions(NodeSetType &NodeSets) {
2289 ScheduleInfo.resize(SUnits.size());
2292 for (
int I : Topo) {
2293 const SUnit &SU = SUnits[
I];
2300 for (
int I : Topo) {
2302 int zeroLatencyDepth = 0;
2303 SUnit *SU = &SUnits[
I];
2305 SUnit *Pred =
IE.getSrc();
2306 if (
IE.getLatency() == 0)
2308 std::max(zeroLatencyDepth, getZeroLatencyDepth(Pred) + 1);
2309 if (
IE.ignoreDependence(
true))
2311 asap = std::max(asap, (
int)(getASAP(Pred) +
IE.getLatency() -
2312 IE.getDistance() * MII));
2314 maxASAP = std::max(maxASAP, asap);
2315 ScheduleInfo[
I].ASAP = asap;
2316 ScheduleInfo[
I].ZeroLatencyDepth = zeroLatencyDepth;
2322 int zeroLatencyHeight = 0;
2323 SUnit *SU = &SUnits[
I];
2325 SUnit *Succ = OE.getDst();
2328 if (OE.getLatency() == 0)
2330 std::max(zeroLatencyHeight, getZeroLatencyHeight(Succ) + 1);
2331 if (OE.ignoreDependence(
true))
2333 alap = std::min(alap, (
int)(getALAP(Succ) - OE.getLatency() +
2334 OE.getDistance() * MII));
2337 ScheduleInfo[
I].ALAP = alap;
2338 ScheduleInfo[
I].ZeroLatencyHeight = zeroLatencyHeight;
2342 for (NodeSet &
I : NodeSets)
2343 I.computeNodeSetInfo(
this);
2346 for (
unsigned i = 0; i < SUnits.size(); i++) {
2347 dbgs() <<
"\tNode " << i <<
":\n";
2348 dbgs() <<
"\t ASAP = " << getASAP(&SUnits[i]) <<
"\n";
2349 dbgs() <<
"\t ALAP = " << getALAP(&SUnits[i]) <<
"\n";
2350 dbgs() <<
"\t MOV = " << getMOV(&SUnits[i]) <<
"\n";
2351 dbgs() <<
"\t D = " << getDepth(&SUnits[i]) <<
"\n";
2352 dbgs() <<
"\t H = " << getHeight(&SUnits[i]) <<
"\n";
2353 dbgs() <<
"\t ZLD = " << getZeroLatencyDepth(&SUnits[i]) <<
"\n";
2354 dbgs() <<
"\t ZLH = " << getZeroLatencyHeight(&SUnits[i]) <<
"\n";
2369 SUnit *PredSU = IE.getSrc();
2370 if (S && S->count(PredSU) == 0)
2372 if (IE.ignoreDependence(
true))
2383 SUnit *SuccSU = OE.getDst();
2384 if (!OE.isAntiDep())
2386 if (S && S->count(SuccSU) == 0)
2392 return !Preds.
empty();
2405 SUnit *SuccSU = OE.getDst();
2406 if (S && S->count(SuccSU) == 0)
2408 if (OE.ignoreDependence(
false))
2419 SUnit *PredSU = IE.getSrc();
2420 if (!IE.isAntiDep())
2422 if (S && S->count(PredSU) == 0)
2428 return !Succs.
empty();
2444 if (!Visited.
insert(Cur).second)
2445 return Path.contains(Cur);
2446 bool FoundPath =
false;
2448 if (!OE.ignoreDependence(
false))
2450 computePath(OE.getDst(), Path, DestNodes, Exclude, Visited, DDG);
2452 if (IE.isAntiDep() && IE.getDistance() == 0)
2454 computePath(IE.getSrc(), Path, DestNodes, Exclude, Visited, DDG);
2469 for (
SUnit *SU : NS) {
2475 if (
Reg.isVirtual())
2478 for (MCRegUnit Unit :
TRI->regunits(
Reg.asMCReg()))
2482 for (
SUnit *SU : NS)
2486 if (
Reg.isVirtual()) {
2491 for (MCRegUnit Unit :
TRI->regunits(
Reg.asMCReg()))
2502void SwingSchedulerDAG::registerPressureFilter(NodeSetType &NodeSets) {
2503 for (
auto &NS : NodeSets) {
2507 IntervalPressure RecRegPressure;
2508 RegPressureTracker RecRPTracker(RecRegPressure);
2509 RecRPTracker.init(&MF, &RegClassInfo, &LIS, BB, BB->end(),
false,
true);
2511 RecRPTracker.closeBottom();
2513 std::vector<SUnit *> SUnits(NS.begin(), NS.end());
2514 llvm::sort(SUnits, [](
const SUnit *
A,
const SUnit *
B) {
2515 return A->NodeNum >
B->NodeNum;
2518 for (
auto &SU : SUnits) {
2524 RecRPTracker.setPos(std::next(CurInstI));
2526 RegPressureDelta RPDelta;
2528 RecRPTracker.getMaxUpwardPressureDelta(SU->
getInstr(),
nullptr, RPDelta,
2533 dbgs() <<
"Excess register pressure: " << *SU <<
" "
2536 NS.setExceedPressure(SU);
2539 RecRPTracker.recede();
2546void SwingSchedulerDAG::colocateNodeSets(NodeSetType &NodeSets) {
2547 unsigned Colocate = 0;
2548 for (
int i = 0, e = NodeSets.size(); i < e; ++i) {
2550 SmallSetVector<SUnit *, 8>
S1;
2553 for (
int j = i + 1;
j <
e; ++
j) {
2557 SmallSetVector<SUnit *, 8> S2;
2574void SwingSchedulerDAG::checkNodeSets(NodeSetType &NodeSets) {
2579 for (
auto &NS : NodeSets) {
2580 if (NS.getRecMII() > 2)
2582 if (NS.getMaxDepth() > MII)
2591void SwingSchedulerDAG::groupRemainingNodes(NodeSetType &NodeSets) {
2592 SetVector<SUnit *> NodesAdded;
2593 SmallPtrSet<SUnit *, 8> Visited;
2596 for (NodeSet &
I : NodeSets) {
2597 SmallSetVector<SUnit *, 8>
N;
2600 SetVector<SUnit *>
Path;
2601 for (SUnit *NI :
N) {
2603 computePath(NI, Path, NodesAdded,
I, Visited, DDG.get());
2610 if (
succ_L(NodesAdded,
N, DDG.get())) {
2611 SetVector<SUnit *>
Path;
2612 for (SUnit *NI :
N) {
2614 computePath(NI, Path,
I, NodesAdded, Visited, DDG.get());
2625 SmallSetVector<SUnit *, 8>
N;
2626 if (
succ_L(NodesAdded,
N, DDG.get()))
2628 addConnectedNodes(
I, NewSet, NodesAdded);
2629 if (!NewSet.
empty())
2630 NodeSets.push_back(NewSet);
2635 if (
pred_L(NodesAdded,
N, DDG.get()))
2637 addConnectedNodes(
I, NewSet, NodesAdded);
2638 if (!NewSet.
empty())
2639 NodeSets.push_back(NewSet);
2643 for (SUnit &SU : SUnits) {
2644 if (NodesAdded.
count(&SU) == 0) {
2646 addConnectedNodes(&SU, NewSet, NodesAdded);
2647 if (!NewSet.
empty())
2648 NodeSets.push_back(NewSet);
2654void SwingSchedulerDAG::addConnectedNodes(SUnit *SU, NodeSet &NewSet,
2655 SetVector<SUnit *> &NodesAdded) {
2660 if (!OE.isArtificial() && !
Successor->isBoundaryNode() &&
2662 addConnectedNodes(
Successor, NewSet, NodesAdded);
2665 SUnit *Predecessor =
IE.getSrc();
2666 if (!
IE.isArtificial() && NodesAdded.
count(Predecessor) == 0)
2667 addConnectedNodes(Predecessor, NewSet, NodesAdded);
2676 for (
SUnit *SU : Set1) {
2677 if (Set2.
count(SU) != 0)
2680 return !Result.empty();
2684void SwingSchedulerDAG::fuseRecs(NodeSetType &NodeSets) {
2685 for (NodeSetType::iterator
I = NodeSets.begin(),
E = NodeSets.end();
I !=
E;
2688 for (NodeSetType::iterator J =
I + 1; J !=
E;) {
2693 for (SUnit *SU : *J)
2705void SwingSchedulerDAG::removeDuplicateNodes(NodeSetType &NodeSets) {
2706 for (NodeSetType::iterator
I = NodeSets.begin(),
E = NodeSets.end();
I !=
E;
2708 for (NodeSetType::iterator J =
I + 1; J !=
E;) {
2709 J->remove_if([&](SUnit *SUJ) {
return I->count(SUJ); });
2724void SwingSchedulerDAG::computeNodeOrder(NodeSetType &NodeSets) {
2725 SmallSetVector<SUnit *, 8>
R;
2728 for (
auto &Nodes : NodeSets) {
2731 SmallSetVector<SUnit *, 8>
N;
2746 }
else if (NodeSets.size() == 1) {
2747 for (
const auto &
N : Nodes)
2748 if (
N->Succs.size() == 0)
2754 SUnit *maxASAP =
nullptr;
2755 for (SUnit *SU : Nodes) {
2756 if (maxASAP ==
nullptr || getASAP(SU) > getASAP(maxASAP) ||
2757 (getASAP(SU) == getASAP(maxASAP) && SU->
NodeNum > maxASAP->
NodeNum))
2765 while (!
R.empty()) {
2766 if (Order == TopDown) {
2770 while (!
R.empty()) {
2771 SUnit *maxHeight =
nullptr;
2772 for (SUnit *
I : R) {
2773 if (maxHeight ==
nullptr || getHeight(
I) > getHeight(maxHeight))
2775 else if (getHeight(
I) == getHeight(maxHeight) &&
2776 getZeroLatencyHeight(
I) > getZeroLatencyHeight(maxHeight))
2778 else if (getHeight(
I) == getHeight(maxHeight) &&
2779 getZeroLatencyHeight(
I) ==
2780 getZeroLatencyHeight(maxHeight) &&
2781 getMOV(
I) < getMOV(maxHeight))
2786 R.remove(maxHeight);
2787 for (
const auto &OE : DDG->
getOutEdges(maxHeight)) {
2788 SUnit *SU = OE.getDst();
2789 if (Nodes.count(SU) == 0)
2793 if (OE.ignoreDependence(
false))
2802 for (
const auto &IE : DDG->
getInEdges(maxHeight)) {
2803 SUnit *SU =
IE.getSrc();
2804 if (!
IE.isAntiDep())
2806 if (Nodes.count(SU) == 0)
2815 SmallSetVector<SUnit *, 8>
N;
2822 while (!
R.empty()) {
2823 SUnit *maxDepth =
nullptr;
2824 for (SUnit *
I : R) {
2825 if (maxDepth ==
nullptr || getDepth(
I) > getDepth(maxDepth))
2827 else if (getDepth(
I) == getDepth(maxDepth) &&
2828 getZeroLatencyDepth(
I) > getZeroLatencyDepth(maxDepth))
2830 else if (getDepth(
I) == getDepth(maxDepth) &&
2831 getZeroLatencyDepth(
I) == getZeroLatencyDepth(maxDepth) &&
2832 getMOV(
I) < getMOV(maxDepth))
2838 if (Nodes.isExceedSU(maxDepth)) {
2841 R.insert(Nodes.getNode(0));
2844 for (
const auto &IE : DDG->
getInEdges(maxDepth)) {
2845 SUnit *SU =
IE.getSrc();
2846 if (Nodes.count(SU) == 0)
2857 for (
const auto &OE : DDG->
getOutEdges(maxDepth)) {
2858 SUnit *SU = OE.getDst();
2859 if (!OE.isAntiDep())
2861 if (Nodes.count(SU) == 0)
2870 SmallSetVector<SUnit *, 8>
N;
2879 dbgs() <<
"Node order: ";
2881 dbgs() <<
" " << *
I <<
" ";
2887void SwingSchedulerDAG::initPolicy() {
2897bool SwingSchedulerDAG::schedulePipeline(SMSchedule &Schedule) {
2904 bool scheduleFound =
false;
2905 std::unique_ptr<HighRegisterPressureDetector> HRPDetector;
2906 if (Policy.ShouldLimitRegPressure) {
2908 std::make_unique<HighRegisterPressureDetector>(
Loop.getHeader(), MF);
2909 HRPDetector->init(RegClassInfo);
2912 for (
unsigned II = MII;
II <= MAX_II && !scheduleFound; ++
II) {
2924 int EarlyStart = INT_MIN;
2925 int LateStart = INT_MAX;
2929 dbgs() << *SU <<
" ";
2934 dbgs() <<
format(
"\tes: %8x ls: %8x\n", EarlyStart, LateStart));
2936 if (EarlyStart > LateStart)
2937 scheduleFound =
false;
2938 else if (EarlyStart != INT_MIN && LateStart == INT_MAX)
2940 Schedule.
insert(SU, EarlyStart, EarlyStart + (
int)
II - 1,
II);
2941 else if (EarlyStart == INT_MIN && LateStart != INT_MAX)
2943 Schedule.
insert(SU, LateStart, LateStart - (
int)
II + 1,
II);
2944 else if (EarlyStart != INT_MIN && LateStart != INT_MAX) {
2945 LateStart = std::min(LateStart, EarlyStart + (
int)
II - 1);
2954 scheduleFound = Schedule.
insert(SU, LateStart, EarlyStart,
II);
2956 scheduleFound = Schedule.
insert(SU, EarlyStart, LateStart,
II);
2959 scheduleFound = Schedule.
insert(SU, FirstCycle + getASAP(SU),
2960 FirstCycle + getASAP(SU) +
II - 1,
II);
2968 scheduleFound =
false;
2972 dbgs() <<
"\tCan't schedule\n";
2974 }
while (++NI != NE && scheduleFound);
2992 if (scheduleFound && HRPDetector)
3001 if (scheduleFound) {
3002 scheduleFound = LoopPipelinerInfo->shouldUseSchedule(*
this, Schedule);
3007 if (scheduleFound) {
3010 return MachineOptimizationRemarkAnalysis(
3012 <<
"Schedule found with Initiation Interval: "
3014 <<
", MaxStageCount: "
3028 if (!
Reg.isVirtual())
3043 if (!
Op.isReg() || !
Op.getReg().isVirtual())
3068 if (Def->getParent() != LoopBB)
3071 if (Def->isCopy()) {
3073 if (Def->getOperand(0).getSubReg() || Def->getOperand(1).getSubReg())
3075 CurReg = Def->getOperand(1).getReg();
3076 }
else if (Def->isPHI()) {
3082 }
else if (
TII->getIncrementValue(*Def,
Value)) {
3090 bool OffsetIsScalable;
3091 if (
TII->getMemOperandWithOffset(*Def, BaseOp,
Offset,
3092 OffsetIsScalable)) {
3094 CurReg = BaseOp->
getReg();
3106 if (CurReg == OrgReg)
3118bool SwingSchedulerDAG::computeDelta(
const MachineInstr &
MI,
int &Delta)
const {
3119 const MachineOperand *BaseOp;
3121 bool OffsetIsScalable;
3122 if (!
TII->getMemOperandWithOffset(
MI, BaseOp,
Offset, OffsetIsScalable))
3126 if (OffsetIsScalable)
3129 if (!BaseOp->
isReg())
3142bool SwingSchedulerDAG::canUseLastOffsetValue(MachineInstr *
MI,
3144 unsigned &OffsetPos,
3150 unsigned BasePosLd, OffsetPosLd;
3158 if (!Phi || !
Phi->isPHI())
3166 MachineInstr *PrevDef = MRI.
getVRegDef(PrevReg);
3167 if (!PrevDef || PrevDef ==
MI)
3173 unsigned BasePos1 = 0, OffsetPos1 = 0;
3181 MachineInstr *NewMI = MF.CloneMachineInstr(
MI);
3184 MF.deleteMachineInstr(NewMI);
3189 BasePos = BasePosLd;
3190 OffsetPos = OffsetPosLd;
3202 InstrChanges.find(SU);
3203 if (It != InstrChanges.
end()) {
3204 std::pair<Register, int64_t> RegAndOffset = It->second;
3205 unsigned BasePos, OffsetPos;
3206 if (!
TII->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos))
3208 Register BaseReg =
MI->getOperand(BasePos).getReg();
3214 if (BaseStageNum < DefStageNum) {
3216 int OffsetDiff = DefStageNum - BaseStageNum;
3217 if (DefCycleNum < BaseCycleNum) {
3223 MI->getOperand(OffsetPos).getImm() + RegAndOffset.second * OffsetDiff;
3238 while (Def->isPHI()) {
3239 if (!Visited.
insert(Def).second)
3241 for (
unsigned i = 1, e = Def->getNumOperands(); i < e; i += 2)
3242 if (Def->getOperand(i + 1).getMBB() == BB) {
3243 Def = MRI.
getVRegDef(Def->getOperand(i).getReg());
3254 int DeltaB, DeltaO, Delta;
3261 int64_t OffsetB, OffsetO;
3262 bool OffsetBIsScalable, OffsetOIsScalable;
3263 if (!
TII->getMemOperandWithOffset(*BaseMI, BaseOpB, OffsetB,
3264 OffsetBIsScalable) ||
3265 !
TII->getMemOperandWithOffset(*OtherMI, BaseOpO, OffsetO,
3269 if (OffsetBIsScalable || OffsetOIsScalable)
3279 if (!RegB.
isVirtual() || !RegO.isVirtual())
3284 if (!DefB || !DefO || !DefB->
isPHI() || !DefO->
isPHI())
3309 dbgs() <<
"Overlap check:\n";
3310 dbgs() <<
" BaseMI: ";
3312 dbgs() <<
" Base + " << OffsetB <<
" + I * " << Delta
3313 <<
", Len: " << AccessSizeB.
getValue() <<
"\n";
3314 dbgs() <<
" OtherMI: ";
3316 dbgs() <<
" Base + " << OffsetO <<
" + I * " << Delta
3317 <<
", Len: " << AccessSizeO.
getValue() <<
"\n";
3325 int64_t BaseMinAddr = OffsetB;
3326 int64_t OhterNextIterMaxAddr = OffsetO + Delta + AccessSizeO.
getValue() - 1;
3327 if (BaseMinAddr > OhterNextIterMaxAddr) {
3332 int64_t BaseMaxAddr = OffsetB + AccessSizeB.
getValue() - 1;
3333 int64_t OtherNextIterMinAddr = OffsetO + Delta;
3334 if (BaseMaxAddr < OtherNextIterMinAddr) {
3343void SwingSchedulerDAG::postProcessDAG() {
3344 for (
auto &M : Mutations)
3354 bool forward =
true;
3356 dbgs() <<
"Trying to insert node between " << StartCycle <<
" and "
3357 << EndCycle <<
" II: " <<
II <<
"\n";
3359 if (StartCycle > EndCycle)
3363 int termCycle = forward ? EndCycle + 1 : EndCycle - 1;
3364 for (
int curCycle = StartCycle; curCycle != termCycle;
3365 forward ? ++curCycle : --curCycle) {
3368 ProcItinResources.canReserveResources(*SU, curCycle)) {
3370 dbgs() <<
"\tinsert at cycle " << curCycle <<
" ";
3375 ProcItinResources.reserveResources(*SU, curCycle);
3376 ScheduledInstrs[curCycle].push_back(SU);
3377 InstrToCycle.insert(std::make_pair(SU, curCycle));
3378 if (curCycle > LastCycle)
3379 LastCycle = curCycle;
3380 if (curCycle < FirstCycle)
3381 FirstCycle = curCycle;
3385 dbgs() <<
"\tfailed to insert at cycle " << curCycle <<
" ";
3396 for (
auto &
P : SU->
Preds)
3397 if (
P.getKind() ==
SDep::Anti &&
P.getSUnit()->getInstr()->isPHI())
3398 for (
auto &S :
P.getSUnit()->Succs)
3399 if (S.getKind() ==
SDep::Data && S.getSUnit()->getInstr()->isPHI())
3400 return P.getSUnit();
3413 for (
int cycle =
getFirstCycle(); cycle <= LastCycle; ++cycle) {
3416 if (IE.getSrc() ==
I) {
3417 int EarlyStart = cycle + IE.getLatency() - IE.getDistance() *
II;
3418 *MaxEarlyStart = std::max(*MaxEarlyStart, EarlyStart);
3423 if (OE.getDst() ==
I) {
3424 int LateStart = cycle - OE.getLatency() + OE.getDistance() *
II;
3425 *MinLateStart = std::min(*MinLateStart, LateStart);
3430 for (
const auto &Dep : SU->
Preds) {
3433 if (BE && Dep.getSUnit() == BE && !SU->
getInstr()->
isPHI() &&
3435 *MinLateStart = std::min(*MinLateStart, cycle);
3445 std::deque<SUnit *> &Insts)
const {
3447 bool OrderBeforeUse =
false;
3448 bool OrderAfterDef =
false;
3449 bool OrderBeforeDef =
false;
3450 unsigned MoveDef = 0;
3451 unsigned MoveUse = 0;
3456 for (std::deque<SUnit *>::iterator
I = Insts.begin(), E = Insts.end();
I != E;
3459 if (!MO.isReg() || !MO.getReg().isVirtual())
3463 unsigned BasePos, OffsetPos;
3464 if (ST.getInstrInfo()->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos))
3465 if (
MI->getOperand(BasePos).getReg() == Reg)
3469 std::tie(Reads, Writes) =
3470 (*I)->getInstr()->readsWritesVirtualRegister(Reg);
3472 OrderBeforeUse =
true;
3477 OrderAfterDef =
true;
3479 }
else if (MO.isUse() && Writes &&
stageScheduled(*
I) == StageInst1) {
3481 OrderBeforeUse =
true;
3485 OrderAfterDef =
true;
3489 OrderBeforeUse =
true;
3493 OrderAfterDef =
true;
3498 OrderBeforeUse =
true;
3504 OrderBeforeDef =
true;
3512 if (OE.getDst() != *
I)
3515 OrderBeforeUse =
true;
3522 else if ((OE.isAntiDep() || OE.isOutputDep()) &&
3524 OrderBeforeUse =
true;
3525 if ((MoveUse == 0) || (Pos < MoveUse))
3530 if (IE.getSrc() != *
I)
3532 if ((IE.isAntiDep() || IE.isOutputDep() || IE.isOrderDep()) &&
3534 OrderAfterDef =
true;
3541 if (OrderAfterDef && OrderBeforeUse && MoveUse == MoveDef)
3542 OrderBeforeUse =
false;
3547 OrderBeforeUse = !OrderAfterDef || (MoveUse > MoveDef);
3551 if (OrderBeforeUse && OrderAfterDef) {
3552 SUnit *UseSU = Insts.at(MoveUse);
3553 SUnit *DefSU = Insts.at(MoveDef);
3554 if (MoveUse > MoveDef) {
3555 Insts.erase(Insts.begin() + MoveUse);
3556 Insts.erase(Insts.begin() + MoveDef);
3558 Insts.erase(Insts.begin() + MoveDef);
3559 Insts.erase(Insts.begin() + MoveUse);
3569 Insts.push_front(SU);
3571 Insts.push_back(SU);
3579 assert(Phi.isPHI() &&
"Expecting a Phi.");
3586 getPhiRegs(Phi, Phi.getParent(), InitVal, LoopVal);
3594 return (LoopCycle > DefCycle) || (LoopStage <= DefStage);
3612 if (!Phi || !Phi->isPHI() || Phi->getParent() != Def->getParent())
3618 if (DMO.getReg() == LoopReg)
3629 if (InstrToCycle.count(IE.getSrc()))
3640 for (
auto &SU : SSD->
SUnits)
3645 while (!Worklist.
empty()) {
3647 if (DoNotPipeline.
count(SU))
3650 DoNotPipeline.
insert(SU);
3657 if (OE.getDistance() == 1)
3660 return DoNotPipeline;
3669 int NewLastCycle = INT_MIN;
3674 NewLastCycle = std::max(NewLastCycle, InstrToCycle[&SU]);
3681 if (IE.getDistance() == 0)
3682 NewCycle = std::max(InstrToCycle[IE.getSrc()], NewCycle);
3687 if (OE.getDistance() == 1)
3688 NewCycle = std::max(InstrToCycle[OE.getDst()], NewCycle);
3690 int OldCycle = InstrToCycle[&SU];
3691 if (OldCycle != NewCycle) {
3692 InstrToCycle[&SU] = NewCycle;
3696 LLVM_DEBUG(
dbgs() << SU <<
" is not pipelined; moving from cycle "
3697 << OldCycle <<
" to " << NewCycle
3723 if (FirstCycle + InitiationInterval <= NewCycle)
3726 NewLastCycle = std::max(NewLastCycle, NewCycle);
3728 LastCycle = NewLastCycle;
3745 int CycleDef = InstrToCycle[&SU];
3746 assert(StageDef != -1 &&
"Instruction should have been scheduled.");
3748 SUnit *Dst = OE.getDst();
3749 if (OE.isAssignedRegDep() && !Dst->isBoundaryNode())
3750 if (OE.getReg().isPhysical()) {
3753 if (InstrToCycle[Dst] <= CycleDef)
3771void SwingSchedulerDAG::checkValidNodeOrder(
const NodeSetType &Circuits)
const {
3774 typedef std::pair<SUnit *, unsigned> UnitIndex;
3775 std::vector<UnitIndex> Indices(
NodeOrder.size(), std::make_pair(
nullptr, 0));
3777 for (
unsigned i = 0, s =
NodeOrder.size(); i < s; ++i)
3778 Indices.push_back(std::make_pair(
NodeOrder[i], i));
3780 auto CompareKey = [](UnitIndex i1, UnitIndex i2) {
3781 return std::get<0>(i1) < std::get<0>(i2);
3794 for (
unsigned i = 0, s =
NodeOrder.size(); i < s; ++i) {
3798 bool PredBefore =
false;
3799 bool SuccBefore =
false;
3807 SUnit *PredSU = IE.getSrc();
3808 unsigned PredIndex = std::get<1>(
3818 SUnit *SuccSU = OE.getDst();
3824 unsigned SuccIndex = std::get<1>(
3837 Circuits, [SU](
const NodeSet &Circuit) {
return Circuit.
count(SU); });
3842 NumNodeOrderIssues++;
3846 <<
" are scheduled before node " << *SU <<
"\n");
3852 dbgs() <<
"Invalid node order found!\n";
3865 for (
SUnit *SU : Instrs) {
3867 for (
unsigned i = 0, e =
MI->getNumOperands(); i < e; ++i) {
3875 InstrChanges.find(SU);
3876 if (It != InstrChanges.
end()) {
3877 unsigned BasePos, OffsetPos;
3879 if (
TII->getBaseAndOffsetPosition(*
MI, BasePos, OffsetPos)) {
3883 MI->getOperand(OffsetPos).getImm() - It->second.second;
3896 unsigned TiedUseIdx = 0;
3897 if (
MI->isRegTiedToUseOperand(i, &TiedUseIdx)) {
3899 OverlapReg =
MI->getOperand(TiedUseIdx).getReg();
3901 NewBaseReg =
MI->getOperand(i).getReg();
3910 const std::deque<SUnit *> &Instrs)
const {
3911 std::deque<SUnit *> NewOrderPhi;
3912 for (
SUnit *SU : Instrs) {
3914 NewOrderPhi.push_back(SU);
3916 std::deque<SUnit *> NewOrderI;
3917 for (
SUnit *SU : Instrs) {
3933 std::deque<SUnit *> &cycleInstrs =
3934 ScheduledInstrs[cycle + (stage * InitiationInterval)];
3936 ScheduledInstrs[cycle].push_front(SU);
3942 for (
int cycle =
getFinalCycle() + 1; cycle <= LastCycle; ++cycle)
3943 ScheduledInstrs.erase(cycle);
3953 std::deque<SUnit *> &cycleInstrs = ScheduledInstrs[Cycle];
3961#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3963 os <<
"Num nodes " <<
size() <<
" rec " << RecMII <<
" mov " << MaxMOV
3964 <<
" depth " << MaxDepth <<
" col " << Colocate <<
"\n";
3965 for (
const auto &
I : Nodes)
3966 os <<
" " << *
I <<
" " << *(
I->getInstr());
3976 for (
SUnit *CI : cycleInstrs->second) {
3989void ResourceManager::dumpMRT()
const {
3993 std::stringstream SS;
3995 SS << std::setw(4) <<
"Slot";
3996 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I)
3997 SS << std::setw(3) <<
I;
3998 SS << std::setw(7) <<
"#Mops"
4000 for (
int Slot = 0; Slot < InitiationInterval; ++Slot) {
4001 SS << std::setw(4) << Slot;
4002 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I)
4003 SS << std::setw(3) << MRT[Slot][
I];
4004 SS << std::setw(7) << NumScheduledMops[Slot] <<
"\n";
4013 : STI(ST), SM(ST->getSchedModel()), ST(ST), TII(ST->getInstrInfo()),
4014 DAG(DAG), UseDFA(ST->useDFAforSMS()),
4015 ProcResourceMasks(SM.getNumProcResourceKinds(), 0),
4016 IssueWidth(SM.IssueWidth) {
4018 if (IssueWidth <= 0)
4027 unsigned ProcResourceID = 0;
4031 assert(SM.getNumProcResourceKinds() < 64 &&
4032 "Too many kinds of resources, unsupported");
4035 Masks.
resize(SM.getNumProcResourceKinds());
4036 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4038 if (
Desc.SubUnitsIdxBegin)
4040 Masks[
I] = 1ULL << ProcResourceID;
4044 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4046 if (!
Desc.SubUnitsIdxBegin)
4048 Masks[
I] = 1ULL << ProcResourceID;
4049 for (
unsigned U = 0; U <
Desc.NumUnits; ++U)
4050 Masks[
I] |= Masks[
Desc.SubUnitsIdxBegin[U]];
4055 dbgs() <<
"ProcResourceDesc:\n";
4056 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4058 dbgs() <<
format(
" %16s(%2d): Mask: 0x%08x, NumUnits:%2d\n",
4059 ProcResource->
Name,
I, Masks[
I],
4062 dbgs() <<
" -----------------\n";
4070 dbgs() <<
"canReserveResources:\n";
4073 return DFAResources[positiveModulo(Cycle, InitiationInterval)]
4079 dbgs() <<
"No valid Schedule Class Desc for schedClass!\n";
4085 reserveResources(SCDesc, Cycle);
4086 bool Result = !isOverbooked();
4087 unreserveResources(SCDesc, Cycle);
4093void ResourceManager::reserveResources(
SUnit &SU,
int Cycle) {
4096 dbgs() <<
"reserveResources:\n";
4099 return DFAResources[positiveModulo(Cycle, InitiationInterval)]
4105 dbgs() <<
"No valid Schedule Class Desc for schedClass!\n";
4111 reserveResources(SCDesc, Cycle);
4116 dbgs() <<
"reserveResources: done!\n\n";
4126 for (
int C = Cycle;
C < Cycle + PRE.ReleaseAtCycle; ++
C)
4127 ++MRT[positiveModulo(
C, InitiationInterval)][PRE.ProcResourceIdx];
4130 ++NumScheduledMops[positiveModulo(
C, InitiationInterval)];
4138 for (
int C = Cycle;
C < Cycle + PRE.ReleaseAtCycle; ++
C)
4139 --MRT[positiveModulo(
C, InitiationInterval)][PRE.ProcResourceIdx];
4142 --NumScheduledMops[positiveModulo(
C, InitiationInterval)];
4145bool ResourceManager::isOverbooked()
const {
4147 for (
int Slot = 0;
Slot < InitiationInterval; ++
Slot) {
4148 for (
unsigned I = 1,
E = SM.getNumProcResourceKinds();
I <
E; ++
I) {
4149 const MCProcResourceDesc *
Desc = SM.getProcResource(
I);
4150 if (MRT[Slot][
I] >
Desc->NumUnits)
4153 if (NumScheduledMops[Slot] > IssueWidth)
4159int ResourceManager::calculateResMIIDFA()
const {
4164 FuncUnitSorter FUS = FuncUnitSorter(*ST);
4165 for (SUnit &SU : DAG->SUnits)
4166 FUS.calcCriticalResources(*SU.
getInstr());
4167 PriorityQueue<MachineInstr *, std::vector<MachineInstr *>, FuncUnitSorter>
4170 for (SUnit &SU : DAG->SUnits)
4175 std::unique_ptr<DFAPacketizer>(TII->CreateTargetScheduleState(*ST)));
4177 while (!FuncUnitOrder.empty()) {
4178 MachineInstr *
MI = FuncUnitOrder.top();
4179 FuncUnitOrder.pop();
4180 if (TII->isZeroCost(
MI->getOpcode()))
4185 unsigned NumCycles = DAG->getSUnit(
MI)->Latency;
4186 unsigned ReservedCycles = 0;
4190 dbgs() <<
"Trying to reserve resource for " << NumCycles
4191 <<
" cycles for \n";
4194 for (
unsigned C = 0;
C < NumCycles; ++
C)
4196 if ((*RI)->canReserveResources(*
MI)) {
4197 (*RI)->reserveResources(*
MI);
4204 <<
", NumCycles:" << NumCycles <<
"\n");
4206 for (
unsigned C = ReservedCycles;
C < NumCycles; ++
C) {
4208 <<
"NewResource created to reserve resources"
4210 auto *NewResource = TII->CreateTargetScheduleState(*ST);
4211 assert(NewResource->canReserveResources(*
MI) &&
"Reserve error.");
4212 NewResource->reserveResources(*
MI);
4213 Resources.push_back(std::unique_ptr<DFAPacketizer>(NewResource));
4224 return calculateResMIIDFA();
4231 for (
SUnit &SU : DAG->SUnits) {
4243 <<
" WriteProcRes: ";
4248 make_range(STI->getWriteProcResBegin(SCDesc),
4249 STI->getWriteProcResEnd(SCDesc))) {
4253 SM.getProcResource(PRE.ProcResourceIdx);
4254 dbgs() <<
Desc->Name <<
": " << PRE.ReleaseAtCycle <<
", ";
4257 ResourceCount[PRE.ProcResourceIdx] += PRE.ReleaseAtCycle;
4262 int Result = (NumMops + IssueWidth - 1) / IssueWidth;
4265 dbgs() <<
"#Mops: " << NumMops <<
", "
4266 <<
"IssueWidth: " << IssueWidth <<
", "
4267 <<
"Cycles: " << Result <<
"\n";
4272 std::stringstream SS;
4273 SS << std::setw(2) <<
"ID" << std::setw(16) <<
"Name" << std::setw(10)
4274 <<
"Units" << std::setw(10) <<
"Consumed" << std::setw(10) <<
"Cycles"
4279 for (
unsigned I = 1, E = SM.getNumProcResourceKinds();
I < E; ++
I) {
4281 int Cycles = (ResourceCount[
I] +
Desc->NumUnits - 1) /
Desc->NumUnits;
4284 std::stringstream SS;
4285 SS << std::setw(2) <<
I << std::setw(16) <<
Desc->Name << std::setw(10)
4286 <<
Desc->NumUnits << std::setw(10) << ResourceCount[
I]
4287 << std::setw(10) << Cycles <<
"\n";
4291 if (Cycles > Result)
4298 InitiationInterval =
II;
4299 DFAResources.clear();
4300 DFAResources.resize(
II);
4301 for (
auto &
I : DFAResources)
4302 I.reset(ST->getInstrInfo()->CreateTargetScheduleState(*ST));
4305 NumScheduledMops.clear();
4306 NumScheduledMops.resize(
II);
4310 if (Pred.isArtificial() || Dst->isBoundaryNode())
4315 return IgnoreAnti && (Pred.getKind() ==
SDep::Kind::Anti || Distance != 0);
4318SwingSchedulerDDG::SwingSchedulerDDGEdges &
4319SwingSchedulerDDG::getEdges(
const SUnit *SU) {
4321 return EntrySUEdges;
4327const SwingSchedulerDDG::SwingSchedulerDDGEdges &
4328SwingSchedulerDDG::getEdges(
const SUnit *SU)
const {
4330 return EntrySUEdges;
4336void SwingSchedulerDDG::addEdge(
const SUnit *SU,
4339 "Validation-only edges are not expected here.");
4341 auto &Edges = getEdges(SU);
4342 if (
Edge.getSrc() == SU)
4343 Edges.Succs.push_back(
Edge);
4345 Edges.Preds.push_back(
Edge);
4348void SwingSchedulerDDG::initEdges(
SUnit *SU) {
4349 for (
const auto &PI : SU->
Preds) {
4350 SwingSchedulerDDGEdge
Edge(SU, PI,
false,
4355 for (
const auto &SI : SU->
Succs) {
4356 SwingSchedulerDDGEdge
Edge(SU, SI,
true,
4364 : EntrySU(EntrySU), ExitSU(ExitSU) {
4365 EdgesVec.resize(SUnits.size());
4370 for (
auto &SU : SUnits)
4374 for (
SUnit &SU : SUnits) {
4379 for (
SUnit *Dst : *OD) {
4382 Edge.setDistance(1);
4383 ValidationOnlyEdges.push_back(Edge);
4395 bool UseAsExtraEdge = [&]() {
4396 if (Edge.getDistance() == 0 || !Edge.isOrderDep())
4399 SUnit *Src = Edge.getSrc();
4400 SUnit *Dst = Edge.getDst();
4401 if (Src->NodeNum < Dst->NodeNum)
4409 getEdges(Edge.getSrc()).ExtraSuccs.push_back(Edge.getDst());
4415const SwingSchedulerDDG::EdgesType &
4417 return getEdges(SU).Preds;
4420const SwingSchedulerDDG::EdgesType &
4422 return getEdges(SU).Succs;
4426 return getEdges(SU).ExtraSuccs;
4433 auto ExpandCycle = [&](
SUnit *SU) {
4436 return Cycle + (Stage *
II);
4440 SUnit *Src = Edge.getSrc();
4441 SUnit *Dst = Edge.getDst();
4442 if (!Src->isInstr() || !Dst->isInstr())
4444 int CycleSrc = ExpandCycle(Src);
4445 int CycleDst = ExpandCycle(Dst);
4446 int MaxLateStart = CycleDst + Edge.getDistance() *
II - Edge.getLatency();
4447 if (CycleSrc > MaxLateStart) {
4449 dbgs() <<
"Validation failed for edge from " << *Src <<
" to " << *Dst
4460 for (
SUnit &SU : SUnits) {
4489 !
TII->isGlobalMemoryObject(FromMI) &&
4500#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
4509 const auto DumpSU = [](
const SUnit *SU) {
4516 dbgs() <<
" Loop carried edges from " << DumpSU(SU) <<
"\n"
4518 for (
SUnit *Dst : *Order)
4519 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 void getPhiRegs(MachineInstr &Phi, MachineBasicBlock *Loop, Register &InitVal, Register &LoopVal)
Return the register values for the operands of a Phi instruction.
static cl::opt< bool > SwpDebugResource("pipeliner-dbg-res", cl::Hidden, cl::init(false))
static void computeLiveOuts(MachineFunction &MF, RegPressureTracker &RPTracker, NodeSet &NS)
Compute the live-out registers for the instructions in a node-set.
static 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 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 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 > EnableSWP("enable-pipeliner", cl::Hidden, cl::init(true), cl::desc("Enable Software Pipelining"))
A command line option to turn software pipelining on or off.
static bool hasLoopCarriedMemDep(const SUnitWithMemInfo &Src, const SUnitWithMemInfo &Dst, BatchAAResults &BAA, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, const SwingSchedulerDAG *SSD)
Returns true if there is a loop-carried order dependency from Src to Dst.
static cl::opt< bool > SwpPruneDeps("pipeliner-prune-deps", cl::desc("Prune dependences between unrelated Phi nodes."), cl::Hidden, cl::init(true))
A command line option to disable the pruning of chain dependences due to an unrelated Phi.
static SUnit * multipleIterations(SUnit *SU, SwingSchedulerDAG *DAG)
If an instruction has a use that spans multiple iterations, then return true.
static Register findUniqueOperandDefinedInLoop(const MachineInstr &MI)
Register const TargetRegisterInfo * TRI
Promote Memory to Register
This file provides utility analysis objects describing memory locations.
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file defines the PriorityQueue class.
Remove Loads Into Fake Uses
std::pair< BasicBlock *, BasicBlock * > Edge
This file defines generic set operations that may be used on set's of different types,...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Target-Independent Code Generator Pass Configuration Options pass.
Add loop-carried chain dependencies.
void computeDependencies()
The main function to compute loop-carried order-dependencies.
const BitVector & getLoopCarried(unsigned Idx) const
LoopCarriedOrderDepsTracker(SwingSchedulerDAG *SSD, BatchAAResults *BAA, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI)
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 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.
MachineBasicBlock * BB
The block in which to insert instructions.
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 ...
bool mayOverlapInLaterIter(const MachineInstr *BaseMI, const MachineInstr *OtherMI) const
Return false if there is no overlap between the region accessed by BaseMI in an iteration and the reg...
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)
static int64_t computeDelta(SectionEntry *A, SectionEntry *B)
@ WS_Force
Use window algorithm after SMS algorithm fails.
@ WS_On
Turn off window algorithm.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
RegState getRegState(const MachineOperand &RegOp)
Get all register state flags from machine operand RegOp.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
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.