10b57cec5SDimitry Andric //===- PPCMachineScheduler.cpp - MI Scheduler for PowerPC -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "PPCMachineScheduler.h"
100b57cec5SDimitry Andric #include "MCTargetDesc/PPCMCTargetDesc.h"
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric using namespace llvm;
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric static cl::opt<bool>
150b57cec5SDimitry Andric DisableAddiLoadHeuristic("disable-ppc-sched-addi-load",
160b57cec5SDimitry Andric cl::desc("Disable scheduling addi instruction before"
170b57cec5SDimitry Andric "load for ppc"), cl::Hidden);
185ffd83dbSDimitry Andric static cl::opt<bool>
195ffd83dbSDimitry Andric EnableAddiHeuristic("ppc-postra-bias-addi",
205ffd83dbSDimitry Andric cl::desc("Enable scheduling addi instruction as early"
215ffd83dbSDimitry Andric "as possible post ra"),
225ffd83dbSDimitry Andric cl::Hidden, cl::init(true));
235ffd83dbSDimitry Andric
isADDIInstr(const GenericScheduler::SchedCandidate & Cand)245ffd83dbSDimitry Andric static bool isADDIInstr(const GenericScheduler::SchedCandidate &Cand) {
255ffd83dbSDimitry Andric return Cand.SU->getInstr()->getOpcode() == PPC::ADDI ||
265ffd83dbSDimitry Andric Cand.SU->getInstr()->getOpcode() == PPC::ADDI8;
275ffd83dbSDimitry Andric }
280b57cec5SDimitry Andric
biasAddiLoadCandidate(SchedCandidate & Cand,SchedCandidate & TryCand,SchedBoundary & Zone) const290b57cec5SDimitry Andric bool PPCPreRASchedStrategy::biasAddiLoadCandidate(SchedCandidate &Cand,
300b57cec5SDimitry Andric SchedCandidate &TryCand,
310b57cec5SDimitry Andric SchedBoundary &Zone) const {
320b57cec5SDimitry Andric if (DisableAddiLoadHeuristic)
330b57cec5SDimitry Andric return false;
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric SchedCandidate &FirstCand = Zone.isTop() ? TryCand : Cand;
360b57cec5SDimitry Andric SchedCandidate &SecondCand = Zone.isTop() ? Cand : TryCand;
375ffd83dbSDimitry Andric if (isADDIInstr(FirstCand) && SecondCand.SU->getInstr()->mayLoad()) {
380b57cec5SDimitry Andric TryCand.Reason = Stall;
390b57cec5SDimitry Andric return true;
400b57cec5SDimitry Andric }
415ffd83dbSDimitry Andric if (FirstCand.SU->getInstr()->mayLoad() && isADDIInstr(SecondCand)) {
420b57cec5SDimitry Andric TryCand.Reason = NoCand;
430b57cec5SDimitry Andric return true;
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric return false;
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric
tryCandidate(SchedCandidate & Cand,SchedCandidate & TryCand,SchedBoundary * Zone) const49*5f7ddb14SDimitry Andric bool PPCPreRASchedStrategy::tryCandidate(SchedCandidate &Cand,
500b57cec5SDimitry Andric SchedCandidate &TryCand,
510b57cec5SDimitry Andric SchedBoundary *Zone) const {
52af732203SDimitry Andric // From GenericScheduler::tryCandidate
530b57cec5SDimitry Andric
54af732203SDimitry Andric // Initialize the candidate if needed.
55af732203SDimitry Andric if (!Cand.isValid()) {
56af732203SDimitry Andric TryCand.Reason = NodeOrder;
57*5f7ddb14SDimitry Andric return true;
58af732203SDimitry Andric }
59af732203SDimitry Andric
60af732203SDimitry Andric // Bias PhysReg Defs and copies to their uses and defined respectively.
61af732203SDimitry Andric if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
62af732203SDimitry Andric biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
63*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
64af732203SDimitry Andric
65af732203SDimitry Andric // Avoid exceeding the target's limit.
66af732203SDimitry Andric if (DAG->isTrackingPressure() &&
67af732203SDimitry Andric tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
68af732203SDimitry Andric RegExcess, TRI, DAG->MF))
69*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
70af732203SDimitry Andric
71af732203SDimitry Andric // Avoid increasing the max critical pressure in the scheduled region.
72af732203SDimitry Andric if (DAG->isTrackingPressure() &&
73af732203SDimitry Andric tryPressure(TryCand.RPDelta.CriticalMax, Cand.RPDelta.CriticalMax,
74af732203SDimitry Andric TryCand, Cand, RegCritical, TRI, DAG->MF))
75*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
76af732203SDimitry Andric
77af732203SDimitry Andric // We only compare a subset of features when comparing nodes between
78af732203SDimitry Andric // Top and Bottom boundary. Some properties are simply incomparable, in many
79af732203SDimitry Andric // other instances we should only override the other boundary if something
80af732203SDimitry Andric // is a clear good pick on one boundary. Skip heuristics that are more
81af732203SDimitry Andric // "tie-breaking" in nature.
82af732203SDimitry Andric bool SameBoundary = Zone != nullptr;
83af732203SDimitry Andric if (SameBoundary) {
84af732203SDimitry Andric // For loops that are acyclic path limited, aggressively schedule for
85af732203SDimitry Andric // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
86af732203SDimitry Andric // heuristics to take precedence.
87af732203SDimitry Andric if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
88af732203SDimitry Andric tryLatency(TryCand, Cand, *Zone))
89*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
90af732203SDimitry Andric
91af732203SDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles.
92af732203SDimitry Andric if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
93af732203SDimitry Andric Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
94*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
95af732203SDimitry Andric }
96af732203SDimitry Andric
97af732203SDimitry Andric // Keep clustered nodes together to encourage downstream peephole
98af732203SDimitry Andric // optimizations which may reduce resource requirements.
99af732203SDimitry Andric //
100af732203SDimitry Andric // This is a best effort to set things up for a post-RA pass. Optimizations
101af732203SDimitry Andric // like generating loads of multiple registers should ideally be done within
102af732203SDimitry Andric // the scheduler pass by combining the loads during DAG postprocessing.
103af732203SDimitry Andric const SUnit *CandNextClusterSU =
104af732203SDimitry Andric Cand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
105af732203SDimitry Andric const SUnit *TryCandNextClusterSU =
106af732203SDimitry Andric TryCand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
107af732203SDimitry Andric if (tryGreater(TryCand.SU == TryCandNextClusterSU,
108af732203SDimitry Andric Cand.SU == CandNextClusterSU, TryCand, Cand, Cluster))
109*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
110af732203SDimitry Andric
111af732203SDimitry Andric if (SameBoundary) {
112af732203SDimitry Andric // Weak edges are for clustering and other constraints.
113af732203SDimitry Andric if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
114af732203SDimitry Andric getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
115*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
116af732203SDimitry Andric }
117af732203SDimitry Andric
118af732203SDimitry Andric // Avoid increasing the max pressure of the entire region.
119af732203SDimitry Andric if (DAG->isTrackingPressure() &&
120af732203SDimitry Andric tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
121af732203SDimitry Andric Cand, RegMax, TRI, DAG->MF))
122*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
123af732203SDimitry Andric
124af732203SDimitry Andric if (SameBoundary) {
125af732203SDimitry Andric // Avoid critical resource consumption and balance the schedule.
126af732203SDimitry Andric TryCand.initResourceDelta(DAG, SchedModel);
127af732203SDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
128af732203SDimitry Andric TryCand, Cand, ResourceReduce))
129*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
130af732203SDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources,
131af732203SDimitry Andric Cand.ResDelta.DemandedResources, TryCand, Cand,
132af732203SDimitry Andric ResourceDemand))
133*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
134af732203SDimitry Andric
135af732203SDimitry Andric // Avoid serializing long latency dependence chains.
136af732203SDimitry Andric // For acyclic path limited loops, latency was already checked above.
137af732203SDimitry Andric if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
138af732203SDimitry Andric !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
139*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
140af732203SDimitry Andric
141af732203SDimitry Andric // Fall through to original instruction order.
142af732203SDimitry Andric if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
143af732203SDimitry Andric (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
144af732203SDimitry Andric TryCand.Reason = NodeOrder;
145af732203SDimitry Andric }
146af732203SDimitry Andric }
147af732203SDimitry Andric
148af732203SDimitry Andric // GenericScheduler::tryCandidate end
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric // Add powerpc specific heuristic only when TryCand isn't selected or
1510b57cec5SDimitry Andric // selected as node order.
1520b57cec5SDimitry Andric if (TryCand.Reason != NodeOrder && TryCand.Reason != NoCand)
153*5f7ddb14SDimitry Andric return true;
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric // There are some benefits to schedule the ADDI before the load to hide the
1560b57cec5SDimitry Andric // latency, as RA may create a true dependency between the load and addi.
157af732203SDimitry Andric if (SameBoundary) {
1580b57cec5SDimitry Andric if (biasAddiLoadCandidate(Cand, TryCand, *Zone))
159*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
1600b57cec5SDimitry Andric }
161*5f7ddb14SDimitry Andric
162*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
163af732203SDimitry Andric }
1640b57cec5SDimitry Andric
biasAddiCandidate(SchedCandidate & Cand,SchedCandidate & TryCand) const1655ffd83dbSDimitry Andric bool PPCPostRASchedStrategy::biasAddiCandidate(SchedCandidate &Cand,
1665ffd83dbSDimitry Andric SchedCandidate &TryCand) const {
1675ffd83dbSDimitry Andric if (!EnableAddiHeuristic)
1685ffd83dbSDimitry Andric return false;
1695ffd83dbSDimitry Andric
1705ffd83dbSDimitry Andric if (isADDIInstr(TryCand) && !isADDIInstr(Cand)) {
1715ffd83dbSDimitry Andric TryCand.Reason = Stall;
1725ffd83dbSDimitry Andric return true;
1735ffd83dbSDimitry Andric }
1745ffd83dbSDimitry Andric return false;
1755ffd83dbSDimitry Andric }
1765ffd83dbSDimitry Andric
tryCandidate(SchedCandidate & Cand,SchedCandidate & TryCand)177*5f7ddb14SDimitry Andric bool PPCPostRASchedStrategy::tryCandidate(SchedCandidate &Cand,
1785ffd83dbSDimitry Andric SchedCandidate &TryCand) {
179af732203SDimitry Andric // From PostGenericScheduler::tryCandidate
1805ffd83dbSDimitry Andric
181af732203SDimitry Andric // Initialize the candidate if needed.
182af732203SDimitry Andric if (!Cand.isValid()) {
183af732203SDimitry Andric TryCand.Reason = NodeOrder;
184*5f7ddb14SDimitry Andric return true;
185af732203SDimitry Andric }
186af732203SDimitry Andric
187af732203SDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles.
188af732203SDimitry Andric if (tryLess(Top.getLatencyStallCycles(TryCand.SU),
189af732203SDimitry Andric Top.getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
190*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
191af732203SDimitry Andric
192af732203SDimitry Andric // Keep clustered nodes together.
193af732203SDimitry Andric if (tryGreater(TryCand.SU == DAG->getNextClusterSucc(),
194af732203SDimitry Andric Cand.SU == DAG->getNextClusterSucc(), TryCand, Cand, Cluster))
195*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
196af732203SDimitry Andric
197af732203SDimitry Andric // Avoid critical resource consumption and balance the schedule.
198af732203SDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
199af732203SDimitry Andric TryCand, Cand, ResourceReduce))
200*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
201af732203SDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources,
202af732203SDimitry Andric Cand.ResDelta.DemandedResources, TryCand, Cand,
203af732203SDimitry Andric ResourceDemand))
204*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
205af732203SDimitry Andric
206af732203SDimitry Andric // Avoid serializing long latency dependence chains.
207af732203SDimitry Andric if (Cand.Policy.ReduceLatency && tryLatency(TryCand, Cand, Top)) {
208*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
209af732203SDimitry Andric }
210af732203SDimitry Andric
211af732203SDimitry Andric // Fall through to original instruction order.
212af732203SDimitry Andric if (TryCand.SU->NodeNum < Cand.SU->NodeNum)
213af732203SDimitry Andric TryCand.Reason = NodeOrder;
214af732203SDimitry Andric
215af732203SDimitry Andric // PostGenericScheduler::tryCandidate end
2165ffd83dbSDimitry Andric
2175ffd83dbSDimitry Andric // Add powerpc post ra specific heuristic only when TryCand isn't selected or
2185ffd83dbSDimitry Andric // selected as node order.
2195ffd83dbSDimitry Andric if (TryCand.Reason != NodeOrder && TryCand.Reason != NoCand)
220*5f7ddb14SDimitry Andric return true;
2215ffd83dbSDimitry Andric
2225ffd83dbSDimitry Andric // There are some benefits to schedule the ADDI as early as possible post ra
2235ffd83dbSDimitry Andric // to avoid stalled by vector instructions which take up all the hw units.
2245ffd83dbSDimitry Andric // And ADDI is usually used to post inc the loop indvar, which matters the
2255ffd83dbSDimitry Andric // performance.
2265ffd83dbSDimitry Andric if (biasAddiCandidate(Cand, TryCand))
227*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
228*5f7ddb14SDimitry Andric
229*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
2305ffd83dbSDimitry Andric }
2315ffd83dbSDimitry Andric
enterMBB(MachineBasicBlock * MBB)2320b57cec5SDimitry Andric void PPCPostRASchedStrategy::enterMBB(MachineBasicBlock *MBB) {
2330b57cec5SDimitry Andric // Custom PPC PostRA specific behavior here.
2340b57cec5SDimitry Andric PostGenericScheduler::enterMBB(MBB);
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric
leaveMBB()2370b57cec5SDimitry Andric void PPCPostRASchedStrategy::leaveMBB() {
2380b57cec5SDimitry Andric // Custom PPC PostRA specific behavior here.
2390b57cec5SDimitry Andric PostGenericScheduler::leaveMBB();
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
initialize(ScheduleDAGMI * Dag)2420b57cec5SDimitry Andric void PPCPostRASchedStrategy::initialize(ScheduleDAGMI *Dag) {
2430b57cec5SDimitry Andric // Custom PPC PostRA specific initialization here.
2440b57cec5SDimitry Andric PostGenericScheduler::initialize(Dag);
2450b57cec5SDimitry Andric }
2460b57cec5SDimitry Andric
pickNode(bool & IsTopNode)2470b57cec5SDimitry Andric SUnit *PPCPostRASchedStrategy::pickNode(bool &IsTopNode) {
2480b57cec5SDimitry Andric // Custom PPC PostRA specific scheduling here.
2490b57cec5SDimitry Andric return PostGenericScheduler::pickNode(IsTopNode);
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric
252