15321dcd6SQingShan Zhang //===- PPCMachineScheduler.cpp - MI Scheduler for PowerPC -------------===//
25321dcd6SQingShan Zhang //
35321dcd6SQingShan Zhang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45321dcd6SQingShan Zhang // See https://llvm.org/LICENSE.txt for license information.
55321dcd6SQingShan Zhang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65321dcd6SQingShan Zhang //
75321dcd6SQingShan Zhang //===----------------------------------------------------------------------===//
8067a17b5SDmitri Gribenko 
95321dcd6SQingShan Zhang #include "PPCMachineScheduler.h"
10067a17b5SDmitri Gribenko #include "MCTargetDesc/PPCMCTargetDesc.h"
11067a17b5SDmitri Gribenko 
125321dcd6SQingShan Zhang using namespace llvm;
135321dcd6SQingShan Zhang 
14449bfdd1SQingShan Zhang static cl::opt<bool>
15449bfdd1SQingShan Zhang DisableAddiLoadHeuristic("disable-ppc-sched-addi-load",
16449bfdd1SQingShan Zhang                          cl::desc("Disable scheduling addi instruction before"
17449bfdd1SQingShan Zhang                                   "load for ppc"), cl::Hidden);
18f8eabd6dSQingShan Zhang static cl::opt<bool>
19f8eabd6dSQingShan Zhang     EnableAddiHeuristic("ppc-postra-bias-addi",
20f8eabd6dSQingShan Zhang                         cl::desc("Enable scheduling addi instruction as early"
21f8eabd6dSQingShan Zhang                                  "as possible post ra"),
22f8eabd6dSQingShan Zhang                         cl::Hidden, cl::init(true));
23f8eabd6dSQingShan Zhang 
24f8eabd6dSQingShan Zhang static bool isADDIInstr(const GenericScheduler::SchedCandidate &Cand) {
25f8eabd6dSQingShan Zhang   return Cand.SU->getInstr()->getOpcode() == PPC::ADDI ||
26f8eabd6dSQingShan Zhang          Cand.SU->getInstr()->getOpcode() == PPC::ADDI8;
273f0cc7acSQingShan Zhang }
28449bfdd1SQingShan Zhang 
29449bfdd1SQingShan Zhang bool PPCPreRASchedStrategy::biasAddiLoadCandidate(SchedCandidate &Cand,
30449bfdd1SQingShan Zhang                                                   SchedCandidate &TryCand,
31449bfdd1SQingShan Zhang                                                   SchedBoundary &Zone) const {
32449bfdd1SQingShan Zhang   if (DisableAddiLoadHeuristic)
33449bfdd1SQingShan Zhang     return false;
34449bfdd1SQingShan Zhang 
35449bfdd1SQingShan Zhang   SchedCandidate &FirstCand = Zone.isTop() ? TryCand : Cand;
36449bfdd1SQingShan Zhang   SchedCandidate &SecondCand = Zone.isTop() ? Cand : TryCand;
37f8eabd6dSQingShan Zhang   if (isADDIInstr(FirstCand) && SecondCand.SU->getInstr()->mayLoad()) {
38449bfdd1SQingShan Zhang     TryCand.Reason = Stall;
39449bfdd1SQingShan Zhang     return true;
40449bfdd1SQingShan Zhang   }
41f8eabd6dSQingShan Zhang   if (FirstCand.SU->getInstr()->mayLoad() && isADDIInstr(SecondCand)) {
42449bfdd1SQingShan Zhang     TryCand.Reason = NoCand;
43449bfdd1SQingShan Zhang     return true;
44449bfdd1SQingShan Zhang   }
45449bfdd1SQingShan Zhang 
46449bfdd1SQingShan Zhang   return false;
47449bfdd1SQingShan Zhang }
48449bfdd1SQingShan Zhang 
49449bfdd1SQingShan Zhang void PPCPreRASchedStrategy::tryCandidate(SchedCandidate &Cand,
50449bfdd1SQingShan Zhang                                          SchedCandidate &TryCand,
51449bfdd1SQingShan Zhang                                          SchedBoundary *Zone) const {
52*449f2f71SQiu Chaofan   // From GenericScheduler::tryCandidate
53449bfdd1SQingShan Zhang 
54*449f2f71SQiu Chaofan   // Initialize the candidate if needed.
55*449f2f71SQiu Chaofan   if (!Cand.isValid()) {
56*449f2f71SQiu Chaofan     TryCand.Reason = NodeOrder;
57449bfdd1SQingShan Zhang     return;
58*449f2f71SQiu Chaofan   }
59*449f2f71SQiu Chaofan 
60*449f2f71SQiu Chaofan   // Bias PhysReg Defs and copies to their uses and defined respectively.
61*449f2f71SQiu Chaofan   if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
62*449f2f71SQiu Chaofan                  biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
63*449f2f71SQiu Chaofan     return;
64*449f2f71SQiu Chaofan 
65*449f2f71SQiu Chaofan   // Avoid exceeding the target's limit.
66*449f2f71SQiu Chaofan   if (DAG->isTrackingPressure() &&
67*449f2f71SQiu Chaofan       tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
68*449f2f71SQiu Chaofan                   RegExcess, TRI, DAG->MF))
69*449f2f71SQiu Chaofan     return;
70*449f2f71SQiu Chaofan 
71*449f2f71SQiu Chaofan   // Avoid increasing the max critical pressure in the scheduled region.
72*449f2f71SQiu Chaofan   if (DAG->isTrackingPressure() &&
73*449f2f71SQiu Chaofan       tryPressure(TryCand.RPDelta.CriticalMax, Cand.RPDelta.CriticalMax,
74*449f2f71SQiu Chaofan                   TryCand, Cand, RegCritical, TRI, DAG->MF))
75*449f2f71SQiu Chaofan     return;
76*449f2f71SQiu Chaofan 
77*449f2f71SQiu Chaofan   // We only compare a subset of features when comparing nodes between
78*449f2f71SQiu Chaofan   // Top and Bottom boundary. Some properties are simply incomparable, in many
79*449f2f71SQiu Chaofan   // other instances we should only override the other boundary if something
80*449f2f71SQiu Chaofan   // is a clear good pick on one boundary. Skip heuristics that are more
81*449f2f71SQiu Chaofan   // "tie-breaking" in nature.
82*449f2f71SQiu Chaofan   bool SameBoundary = Zone != nullptr;
83*449f2f71SQiu Chaofan   if (SameBoundary) {
84*449f2f71SQiu Chaofan     // For loops that are acyclic path limited, aggressively schedule for
85*449f2f71SQiu Chaofan     // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
86*449f2f71SQiu Chaofan     // heuristics to take precedence.
87*449f2f71SQiu Chaofan     if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
88*449f2f71SQiu Chaofan         tryLatency(TryCand, Cand, *Zone))
89*449f2f71SQiu Chaofan       return;
90*449f2f71SQiu Chaofan 
91*449f2f71SQiu Chaofan     // Prioritize instructions that read unbuffered resources by stall cycles.
92*449f2f71SQiu Chaofan     if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
93*449f2f71SQiu Chaofan                 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
94*449f2f71SQiu Chaofan       return;
95*449f2f71SQiu Chaofan   }
96*449f2f71SQiu Chaofan 
97*449f2f71SQiu Chaofan   // Keep clustered nodes together to encourage downstream peephole
98*449f2f71SQiu Chaofan   // optimizations which may reduce resource requirements.
99*449f2f71SQiu Chaofan   //
100*449f2f71SQiu Chaofan   // This is a best effort to set things up for a post-RA pass. Optimizations
101*449f2f71SQiu Chaofan   // like generating loads of multiple registers should ideally be done within
102*449f2f71SQiu Chaofan   // the scheduler pass by combining the loads during DAG postprocessing.
103*449f2f71SQiu Chaofan   const SUnit *CandNextClusterSU =
104*449f2f71SQiu Chaofan       Cand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
105*449f2f71SQiu Chaofan   const SUnit *TryCandNextClusterSU =
106*449f2f71SQiu Chaofan       TryCand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
107*449f2f71SQiu Chaofan   if (tryGreater(TryCand.SU == TryCandNextClusterSU,
108*449f2f71SQiu Chaofan                  Cand.SU == CandNextClusterSU, TryCand, Cand, Cluster))
109*449f2f71SQiu Chaofan     return;
110*449f2f71SQiu Chaofan 
111*449f2f71SQiu Chaofan   if (SameBoundary) {
112*449f2f71SQiu Chaofan     // Weak edges are for clustering and other constraints.
113*449f2f71SQiu Chaofan     if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
114*449f2f71SQiu Chaofan                 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
115*449f2f71SQiu Chaofan       return;
116*449f2f71SQiu Chaofan   }
117*449f2f71SQiu Chaofan 
118*449f2f71SQiu Chaofan   // Avoid increasing the max pressure of the entire region.
119*449f2f71SQiu Chaofan   if (DAG->isTrackingPressure() &&
120*449f2f71SQiu Chaofan       tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
121*449f2f71SQiu Chaofan                   Cand, RegMax, TRI, DAG->MF))
122*449f2f71SQiu Chaofan     return;
123*449f2f71SQiu Chaofan 
124*449f2f71SQiu Chaofan   if (SameBoundary) {
125*449f2f71SQiu Chaofan     // Avoid critical resource consumption and balance the schedule.
126*449f2f71SQiu Chaofan     TryCand.initResourceDelta(DAG, SchedModel);
127*449f2f71SQiu Chaofan     if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
128*449f2f71SQiu Chaofan                 TryCand, Cand, ResourceReduce))
129*449f2f71SQiu Chaofan       return;
130*449f2f71SQiu Chaofan     if (tryGreater(TryCand.ResDelta.DemandedResources,
131*449f2f71SQiu Chaofan                    Cand.ResDelta.DemandedResources, TryCand, Cand,
132*449f2f71SQiu Chaofan                    ResourceDemand))
133*449f2f71SQiu Chaofan       return;
134*449f2f71SQiu Chaofan 
135*449f2f71SQiu Chaofan     // Avoid serializing long latency dependence chains.
136*449f2f71SQiu Chaofan     // For acyclic path limited loops, latency was already checked above.
137*449f2f71SQiu Chaofan     if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
138*449f2f71SQiu Chaofan         !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
139*449f2f71SQiu Chaofan       return;
140*449f2f71SQiu Chaofan 
141*449f2f71SQiu Chaofan     // Fall through to original instruction order.
142*449f2f71SQiu Chaofan     if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
143*449f2f71SQiu Chaofan         (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
144*449f2f71SQiu Chaofan       TryCand.Reason = NodeOrder;
145*449f2f71SQiu Chaofan     }
146*449f2f71SQiu Chaofan   }
147*449f2f71SQiu Chaofan 
148*449f2f71SQiu Chaofan   // GenericScheduler::tryCandidate end
149449bfdd1SQingShan Zhang 
150449bfdd1SQingShan Zhang   // Add powerpc specific heuristic only when TryCand isn't selected or
151449bfdd1SQingShan Zhang   // selected as node order.
152449bfdd1SQingShan Zhang   if (TryCand.Reason != NodeOrder && TryCand.Reason != NoCand)
153449bfdd1SQingShan Zhang     return;
154449bfdd1SQingShan Zhang 
155449bfdd1SQingShan Zhang   // There are some benefits to schedule the ADDI before the load to hide the
156449bfdd1SQingShan Zhang   // latency, as RA may create a true dependency between the load and addi.
157*449f2f71SQiu Chaofan   if (SameBoundary) {
158449bfdd1SQingShan Zhang     if (biasAddiLoadCandidate(Cand, TryCand, *Zone))
159449bfdd1SQingShan Zhang       return;
160449bfdd1SQingShan Zhang   }
161*449f2f71SQiu Chaofan }
162449bfdd1SQingShan Zhang 
163f8eabd6dSQingShan Zhang bool PPCPostRASchedStrategy::biasAddiCandidate(SchedCandidate &Cand,
164f8eabd6dSQingShan Zhang                                                SchedCandidate &TryCand) const {
165f8eabd6dSQingShan Zhang   if (!EnableAddiHeuristic)
166f8eabd6dSQingShan Zhang     return false;
167f8eabd6dSQingShan Zhang 
168f8eabd6dSQingShan Zhang   if (isADDIInstr(TryCand) && !isADDIInstr(Cand)) {
169f8eabd6dSQingShan Zhang     TryCand.Reason = Stall;
170f8eabd6dSQingShan Zhang     return true;
171f8eabd6dSQingShan Zhang   }
172f8eabd6dSQingShan Zhang   return false;
173f8eabd6dSQingShan Zhang }
174f8eabd6dSQingShan Zhang 
175f8eabd6dSQingShan Zhang void PPCPostRASchedStrategy::tryCandidate(SchedCandidate &Cand,
176f8eabd6dSQingShan Zhang                                           SchedCandidate &TryCand) {
177*449f2f71SQiu Chaofan   // From PostGenericScheduler::tryCandidate
178f8eabd6dSQingShan Zhang 
179*449f2f71SQiu Chaofan   // Initialize the candidate if needed.
180*449f2f71SQiu Chaofan   if (!Cand.isValid()) {
181*449f2f71SQiu Chaofan     TryCand.Reason = NodeOrder;
182f8eabd6dSQingShan Zhang     return;
183*449f2f71SQiu Chaofan   }
184*449f2f71SQiu Chaofan 
185*449f2f71SQiu Chaofan   // Prioritize instructions that read unbuffered resources by stall cycles.
186*449f2f71SQiu Chaofan   if (tryLess(Top.getLatencyStallCycles(TryCand.SU),
187*449f2f71SQiu Chaofan               Top.getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
188*449f2f71SQiu Chaofan     return;
189*449f2f71SQiu Chaofan 
190*449f2f71SQiu Chaofan   // Keep clustered nodes together.
191*449f2f71SQiu Chaofan   if (tryGreater(TryCand.SU == DAG->getNextClusterSucc(),
192*449f2f71SQiu Chaofan                  Cand.SU == DAG->getNextClusterSucc(), TryCand, Cand, Cluster))
193*449f2f71SQiu Chaofan     return;
194*449f2f71SQiu Chaofan 
195*449f2f71SQiu Chaofan   // Avoid critical resource consumption and balance the schedule.
196*449f2f71SQiu Chaofan   if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
197*449f2f71SQiu Chaofan               TryCand, Cand, ResourceReduce))
198*449f2f71SQiu Chaofan     return;
199*449f2f71SQiu Chaofan   if (tryGreater(TryCand.ResDelta.DemandedResources,
200*449f2f71SQiu Chaofan                  Cand.ResDelta.DemandedResources, TryCand, Cand,
201*449f2f71SQiu Chaofan                  ResourceDemand))
202*449f2f71SQiu Chaofan     return;
203*449f2f71SQiu Chaofan 
204*449f2f71SQiu Chaofan   // Avoid serializing long latency dependence chains.
205*449f2f71SQiu Chaofan   if (Cand.Policy.ReduceLatency && tryLatency(TryCand, Cand, Top)) {
206*449f2f71SQiu Chaofan     return;
207*449f2f71SQiu Chaofan   }
208*449f2f71SQiu Chaofan 
209*449f2f71SQiu Chaofan   // Fall through to original instruction order.
210*449f2f71SQiu Chaofan   if (TryCand.SU->NodeNum < Cand.SU->NodeNum)
211*449f2f71SQiu Chaofan     TryCand.Reason = NodeOrder;
212*449f2f71SQiu Chaofan 
213*449f2f71SQiu Chaofan   // PostGenericScheduler::tryCandidate end
214f8eabd6dSQingShan Zhang 
215f8eabd6dSQingShan Zhang   // Add powerpc post ra specific heuristic only when TryCand isn't selected or
216f8eabd6dSQingShan Zhang   // selected as node order.
217f8eabd6dSQingShan Zhang   if (TryCand.Reason != NodeOrder && TryCand.Reason != NoCand)
218f8eabd6dSQingShan Zhang     return;
219f8eabd6dSQingShan Zhang 
220f8eabd6dSQingShan Zhang   // There are some benefits to schedule the ADDI as early as possible post ra
221f8eabd6dSQingShan Zhang   // to avoid stalled by vector instructions which take up all the hw units.
222f8eabd6dSQingShan Zhang   // And ADDI is usually used to post inc the loop indvar, which matters the
223f8eabd6dSQingShan Zhang   // performance.
224f8eabd6dSQingShan Zhang   if (biasAddiCandidate(Cand, TryCand))
225f8eabd6dSQingShan Zhang     return;
226f8eabd6dSQingShan Zhang }
227f8eabd6dSQingShan Zhang 
2285321dcd6SQingShan Zhang void PPCPostRASchedStrategy::enterMBB(MachineBasicBlock *MBB) {
2295321dcd6SQingShan Zhang   // Custom PPC PostRA specific behavior here.
2305321dcd6SQingShan Zhang   PostGenericScheduler::enterMBB(MBB);
2315321dcd6SQingShan Zhang }
2325321dcd6SQingShan Zhang 
2335321dcd6SQingShan Zhang void PPCPostRASchedStrategy::leaveMBB() {
2345321dcd6SQingShan Zhang   // Custom PPC PostRA specific behavior here.
2355321dcd6SQingShan Zhang   PostGenericScheduler::leaveMBB();
2365321dcd6SQingShan Zhang }
2375321dcd6SQingShan Zhang 
2385321dcd6SQingShan Zhang void PPCPostRASchedStrategy::initialize(ScheduleDAGMI *Dag) {
2395321dcd6SQingShan Zhang   // Custom PPC PostRA specific initialization here.
2405321dcd6SQingShan Zhang   PostGenericScheduler::initialize(Dag);
2415321dcd6SQingShan Zhang }
2425321dcd6SQingShan Zhang 
2435321dcd6SQingShan Zhang SUnit *PPCPostRASchedStrategy::pickNode(bool &IsTopNode) {
2445321dcd6SQingShan Zhang   // Custom PPC PostRA specific scheduling here.
2455321dcd6SQingShan Zhang   return PostGenericScheduler::pickNode(IsTopNode);
2465321dcd6SQingShan Zhang }
2475321dcd6SQingShan Zhang 
248