1e6d15924SDimitry Andric //===- PPCMachineScheduler.cpp - MI Scheduler for PowerPC -------------===//
2e6d15924SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e6d15924SDimitry Andric //
7e6d15924SDimitry Andric //===----------------------------------------------------------------------===//
8e6d15924SDimitry Andric
9e6d15924SDimitry Andric #include "PPCMachineScheduler.h"
10e6d15924SDimitry Andric #include "MCTargetDesc/PPCMCTargetDesc.h"
11e6d15924SDimitry Andric
12e6d15924SDimitry Andric using namespace llvm;
13e6d15924SDimitry Andric
14e6d15924SDimitry Andric static cl::opt<bool>
15e6d15924SDimitry Andric DisableAddiLoadHeuristic("disable-ppc-sched-addi-load",
16e6d15924SDimitry Andric cl::desc("Disable scheduling addi instruction before"
17e6d15924SDimitry Andric "load for ppc"), cl::Hidden);
18cfca06d7SDimitry Andric static cl::opt<bool>
19cfca06d7SDimitry Andric EnableAddiHeuristic("ppc-postra-bias-addi",
20cfca06d7SDimitry Andric cl::desc("Enable scheduling addi instruction as early"
21cfca06d7SDimitry Andric "as possible post ra"),
22cfca06d7SDimitry Andric cl::Hidden, cl::init(true));
23cfca06d7SDimitry Andric
isADDIInstr(const GenericScheduler::SchedCandidate & Cand)24cfca06d7SDimitry Andric static bool isADDIInstr(const GenericScheduler::SchedCandidate &Cand) {
25cfca06d7SDimitry Andric return Cand.SU->getInstr()->getOpcode() == PPC::ADDI ||
26cfca06d7SDimitry Andric Cand.SU->getInstr()->getOpcode() == PPC::ADDI8;
27cfca06d7SDimitry Andric }
28e6d15924SDimitry Andric
biasAddiLoadCandidate(SchedCandidate & Cand,SchedCandidate & TryCand,SchedBoundary & Zone) const29e6d15924SDimitry Andric bool PPCPreRASchedStrategy::biasAddiLoadCandidate(SchedCandidate &Cand,
30e6d15924SDimitry Andric SchedCandidate &TryCand,
31e6d15924SDimitry Andric SchedBoundary &Zone) const {
32e6d15924SDimitry Andric if (DisableAddiLoadHeuristic)
33e6d15924SDimitry Andric return false;
34e6d15924SDimitry Andric
35e6d15924SDimitry Andric SchedCandidate &FirstCand = Zone.isTop() ? TryCand : Cand;
36e6d15924SDimitry Andric SchedCandidate &SecondCand = Zone.isTop() ? Cand : TryCand;
37cfca06d7SDimitry Andric if (isADDIInstr(FirstCand) && SecondCand.SU->getInstr()->mayLoad()) {
38e6d15924SDimitry Andric TryCand.Reason = Stall;
39e6d15924SDimitry Andric return true;
40e6d15924SDimitry Andric }
41cfca06d7SDimitry Andric if (FirstCand.SU->getInstr()->mayLoad() && isADDIInstr(SecondCand)) {
42e6d15924SDimitry Andric TryCand.Reason = NoCand;
43e6d15924SDimitry Andric return true;
44e6d15924SDimitry Andric }
45e6d15924SDimitry Andric
46e6d15924SDimitry Andric return false;
47e6d15924SDimitry Andric }
48e6d15924SDimitry Andric
tryCandidate(SchedCandidate & Cand,SchedCandidate & TryCand,SchedBoundary * Zone) const49344a3780SDimitry Andric bool PPCPreRASchedStrategy::tryCandidate(SchedCandidate &Cand,
50e6d15924SDimitry Andric SchedCandidate &TryCand,
51e6d15924SDimitry Andric SchedBoundary *Zone) const {
52b60736ecSDimitry Andric // From GenericScheduler::tryCandidate
53e6d15924SDimitry Andric
54b60736ecSDimitry Andric // Initialize the candidate if needed.
55b60736ecSDimitry Andric if (!Cand.isValid()) {
56b60736ecSDimitry Andric TryCand.Reason = NodeOrder;
57344a3780SDimitry Andric return true;
58b60736ecSDimitry Andric }
59b60736ecSDimitry Andric
60b60736ecSDimitry Andric // Bias PhysReg Defs and copies to their uses and defined respectively.
61b60736ecSDimitry Andric if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
62b60736ecSDimitry Andric biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
63344a3780SDimitry Andric return TryCand.Reason != NoCand;
64b60736ecSDimitry Andric
65b60736ecSDimitry Andric // Avoid exceeding the target's limit.
66b60736ecSDimitry Andric if (DAG->isTrackingPressure() &&
67b60736ecSDimitry Andric tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
68b60736ecSDimitry Andric RegExcess, TRI, DAG->MF))
69344a3780SDimitry Andric return TryCand.Reason != NoCand;
70b60736ecSDimitry Andric
71b60736ecSDimitry Andric // Avoid increasing the max critical pressure in the scheduled region.
72b60736ecSDimitry Andric if (DAG->isTrackingPressure() &&
73b60736ecSDimitry Andric tryPressure(TryCand.RPDelta.CriticalMax, Cand.RPDelta.CriticalMax,
74b60736ecSDimitry Andric TryCand, Cand, RegCritical, TRI, DAG->MF))
75344a3780SDimitry Andric return TryCand.Reason != NoCand;
76b60736ecSDimitry Andric
77b60736ecSDimitry Andric // We only compare a subset of features when comparing nodes between
78b60736ecSDimitry Andric // Top and Bottom boundary. Some properties are simply incomparable, in many
79b60736ecSDimitry Andric // other instances we should only override the other boundary if something
80b60736ecSDimitry Andric // is a clear good pick on one boundary. Skip heuristics that are more
81b60736ecSDimitry Andric // "tie-breaking" in nature.
82b60736ecSDimitry Andric bool SameBoundary = Zone != nullptr;
83b60736ecSDimitry Andric if (SameBoundary) {
84b60736ecSDimitry Andric // For loops that are acyclic path limited, aggressively schedule for
85b60736ecSDimitry Andric // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
86b60736ecSDimitry Andric // heuristics to take precedence.
87b60736ecSDimitry Andric if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
88b60736ecSDimitry Andric tryLatency(TryCand, Cand, *Zone))
89344a3780SDimitry Andric return TryCand.Reason != NoCand;
90b60736ecSDimitry Andric
91b60736ecSDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles.
92b60736ecSDimitry Andric if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
93b60736ecSDimitry Andric Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
94344a3780SDimitry Andric return TryCand.Reason != NoCand;
95b60736ecSDimitry Andric }
96b60736ecSDimitry Andric
97b60736ecSDimitry Andric // Keep clustered nodes together to encourage downstream peephole
98b60736ecSDimitry Andric // optimizations which may reduce resource requirements.
99b60736ecSDimitry Andric //
100b60736ecSDimitry Andric // This is a best effort to set things up for a post-RA pass. Optimizations
101b60736ecSDimitry Andric // like generating loads of multiple registers should ideally be done within
102b60736ecSDimitry Andric // the scheduler pass by combining the loads during DAG postprocessing.
103b60736ecSDimitry Andric const SUnit *CandNextClusterSU =
104b60736ecSDimitry Andric Cand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
105b60736ecSDimitry Andric const SUnit *TryCandNextClusterSU =
106b60736ecSDimitry Andric TryCand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
107b60736ecSDimitry Andric if (tryGreater(TryCand.SU == TryCandNextClusterSU,
108b60736ecSDimitry Andric Cand.SU == CandNextClusterSU, TryCand, Cand, Cluster))
109344a3780SDimitry Andric return TryCand.Reason != NoCand;
110b60736ecSDimitry Andric
111b60736ecSDimitry Andric if (SameBoundary) {
112b60736ecSDimitry Andric // Weak edges are for clustering and other constraints.
113b60736ecSDimitry Andric if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
114b60736ecSDimitry Andric getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
115344a3780SDimitry Andric return TryCand.Reason != NoCand;
116b60736ecSDimitry Andric }
117b60736ecSDimitry Andric
118b60736ecSDimitry Andric // Avoid increasing the max pressure of the entire region.
119b60736ecSDimitry Andric if (DAG->isTrackingPressure() &&
120b60736ecSDimitry Andric tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
121b60736ecSDimitry Andric Cand, RegMax, TRI, DAG->MF))
122344a3780SDimitry Andric return TryCand.Reason != NoCand;
123b60736ecSDimitry Andric
124b60736ecSDimitry Andric if (SameBoundary) {
125b60736ecSDimitry Andric // Avoid critical resource consumption and balance the schedule.
126b60736ecSDimitry Andric TryCand.initResourceDelta(DAG, SchedModel);
127b60736ecSDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
128b60736ecSDimitry Andric TryCand, Cand, ResourceReduce))
129344a3780SDimitry Andric return TryCand.Reason != NoCand;
130b60736ecSDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources,
131b60736ecSDimitry Andric Cand.ResDelta.DemandedResources, TryCand, Cand,
132b60736ecSDimitry Andric ResourceDemand))
133344a3780SDimitry Andric return TryCand.Reason != NoCand;
134b60736ecSDimitry Andric
135b60736ecSDimitry Andric // Avoid serializing long latency dependence chains.
136b60736ecSDimitry Andric // For acyclic path limited loops, latency was already checked above.
137b60736ecSDimitry Andric if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
138b60736ecSDimitry Andric !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
139344a3780SDimitry Andric return TryCand.Reason != NoCand;
140b60736ecSDimitry Andric
141b60736ecSDimitry Andric // Fall through to original instruction order.
142b60736ecSDimitry Andric if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
143b60736ecSDimitry Andric (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
144b60736ecSDimitry Andric TryCand.Reason = NodeOrder;
145b60736ecSDimitry Andric }
146b60736ecSDimitry Andric }
147b60736ecSDimitry Andric
148b60736ecSDimitry Andric // GenericScheduler::tryCandidate end
149e6d15924SDimitry Andric
150e6d15924SDimitry Andric // Add powerpc specific heuristic only when TryCand isn't selected or
151e6d15924SDimitry Andric // selected as node order.
152e6d15924SDimitry Andric if (TryCand.Reason != NodeOrder && TryCand.Reason != NoCand)
153344a3780SDimitry Andric return true;
154e6d15924SDimitry Andric
155e6d15924SDimitry Andric // There are some benefits to schedule the ADDI before the load to hide the
156e6d15924SDimitry Andric // latency, as RA may create a true dependency between the load and addi.
157b60736ecSDimitry Andric if (SameBoundary) {
158e6d15924SDimitry Andric if (biasAddiLoadCandidate(Cand, TryCand, *Zone))
159344a3780SDimitry Andric return TryCand.Reason != NoCand;
160e6d15924SDimitry Andric }
161344a3780SDimitry Andric
162344a3780SDimitry Andric return TryCand.Reason != NoCand;
163b60736ecSDimitry Andric }
164e6d15924SDimitry Andric
biasAddiCandidate(SchedCandidate & Cand,SchedCandidate & TryCand) const165cfca06d7SDimitry Andric bool PPCPostRASchedStrategy::biasAddiCandidate(SchedCandidate &Cand,
166cfca06d7SDimitry Andric SchedCandidate &TryCand) const {
167cfca06d7SDimitry Andric if (!EnableAddiHeuristic)
168cfca06d7SDimitry Andric return false;
169cfca06d7SDimitry Andric
170cfca06d7SDimitry Andric if (isADDIInstr(TryCand) && !isADDIInstr(Cand)) {
171cfca06d7SDimitry Andric TryCand.Reason = Stall;
172cfca06d7SDimitry Andric return true;
173cfca06d7SDimitry Andric }
174cfca06d7SDimitry Andric return false;
175cfca06d7SDimitry Andric }
176cfca06d7SDimitry Andric
tryCandidate(SchedCandidate & Cand,SchedCandidate & TryCand)177344a3780SDimitry Andric bool PPCPostRASchedStrategy::tryCandidate(SchedCandidate &Cand,
178cfca06d7SDimitry Andric SchedCandidate &TryCand) {
179b60736ecSDimitry Andric // From PostGenericScheduler::tryCandidate
180cfca06d7SDimitry Andric
181b60736ecSDimitry Andric // Initialize the candidate if needed.
182b60736ecSDimitry Andric if (!Cand.isValid()) {
183b60736ecSDimitry Andric TryCand.Reason = NodeOrder;
184344a3780SDimitry Andric return true;
185b60736ecSDimitry Andric }
186b60736ecSDimitry Andric
187b60736ecSDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles.
188b60736ecSDimitry Andric if (tryLess(Top.getLatencyStallCycles(TryCand.SU),
189b60736ecSDimitry Andric Top.getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
190344a3780SDimitry Andric return TryCand.Reason != NoCand;
191b60736ecSDimitry Andric
192b60736ecSDimitry Andric // Keep clustered nodes together.
193b60736ecSDimitry Andric if (tryGreater(TryCand.SU == DAG->getNextClusterSucc(),
194b60736ecSDimitry Andric Cand.SU == DAG->getNextClusterSucc(), TryCand, Cand, Cluster))
195344a3780SDimitry Andric return TryCand.Reason != NoCand;
196b60736ecSDimitry Andric
197b60736ecSDimitry Andric // Avoid critical resource consumption and balance the schedule.
198b60736ecSDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
199b60736ecSDimitry Andric TryCand, Cand, ResourceReduce))
200344a3780SDimitry Andric return TryCand.Reason != NoCand;
201b60736ecSDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources,
202b60736ecSDimitry Andric Cand.ResDelta.DemandedResources, TryCand, Cand,
203b60736ecSDimitry Andric ResourceDemand))
204344a3780SDimitry Andric return TryCand.Reason != NoCand;
205b60736ecSDimitry Andric
206b60736ecSDimitry Andric // Avoid serializing long latency dependence chains.
207b60736ecSDimitry Andric if (Cand.Policy.ReduceLatency && tryLatency(TryCand, Cand, Top)) {
208344a3780SDimitry Andric return TryCand.Reason != NoCand;
209b60736ecSDimitry Andric }
210b60736ecSDimitry Andric
211b60736ecSDimitry Andric // Fall through to original instruction order.
212b60736ecSDimitry Andric if (TryCand.SU->NodeNum < Cand.SU->NodeNum)
213b60736ecSDimitry Andric TryCand.Reason = NodeOrder;
214b60736ecSDimitry Andric
215b60736ecSDimitry Andric // PostGenericScheduler::tryCandidate end
216cfca06d7SDimitry Andric
217cfca06d7SDimitry Andric // Add powerpc post ra specific heuristic only when TryCand isn't selected or
218cfca06d7SDimitry Andric // selected as node order.
219cfca06d7SDimitry Andric if (TryCand.Reason != NodeOrder && TryCand.Reason != NoCand)
220344a3780SDimitry Andric return true;
221cfca06d7SDimitry Andric
222cfca06d7SDimitry Andric // There are some benefits to schedule the ADDI as early as possible post ra
223cfca06d7SDimitry Andric // to avoid stalled by vector instructions which take up all the hw units.
224cfca06d7SDimitry Andric // And ADDI is usually used to post inc the loop indvar, which matters the
225cfca06d7SDimitry Andric // performance.
226cfca06d7SDimitry Andric if (biasAddiCandidate(Cand, TryCand))
227344a3780SDimitry Andric return TryCand.Reason != NoCand;
228344a3780SDimitry Andric
229344a3780SDimitry Andric return TryCand.Reason != NoCand;
230cfca06d7SDimitry Andric }
231cfca06d7SDimitry Andric
enterMBB(MachineBasicBlock * MBB)232e6d15924SDimitry Andric void PPCPostRASchedStrategy::enterMBB(MachineBasicBlock *MBB) {
233e6d15924SDimitry Andric // Custom PPC PostRA specific behavior here.
234e6d15924SDimitry Andric PostGenericScheduler::enterMBB(MBB);
235e6d15924SDimitry Andric }
236e6d15924SDimitry Andric
leaveMBB()237e6d15924SDimitry Andric void PPCPostRASchedStrategy::leaveMBB() {
238e6d15924SDimitry Andric // Custom PPC PostRA specific behavior here.
239e6d15924SDimitry Andric PostGenericScheduler::leaveMBB();
240e6d15924SDimitry Andric }
241e6d15924SDimitry Andric
initialize(ScheduleDAGMI * Dag)242e6d15924SDimitry Andric void PPCPostRASchedStrategy::initialize(ScheduleDAGMI *Dag) {
243e6d15924SDimitry Andric // Custom PPC PostRA specific initialization here.
244e6d15924SDimitry Andric PostGenericScheduler::initialize(Dag);
245e6d15924SDimitry Andric }
246e6d15924SDimitry Andric
pickNode(bool & IsTopNode)247e6d15924SDimitry Andric SUnit *PPCPostRASchedStrategy::pickNode(bool &IsTopNode) {
248e6d15924SDimitry Andric // Custom PPC PostRA specific scheduling here.
249e6d15924SDimitry Andric return PostGenericScheduler::pickNode(IsTopNode);
250e6d15924SDimitry Andric }
251e6d15924SDimitry Andric
252