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 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 290b57cec5SDimitry 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 490b57cec5SDimitry Andric void PPCPreRASchedStrategy::tryCandidate(SchedCandidate &Cand, 500b57cec5SDimitry Andric SchedCandidate &TryCand, 510b57cec5SDimitry Andric SchedBoundary *Zone) const { 52*e8d8bef9SDimitry Andric // From GenericScheduler::tryCandidate 530b57cec5SDimitry Andric 54*e8d8bef9SDimitry Andric // Initialize the candidate if needed. 55*e8d8bef9SDimitry Andric if (!Cand.isValid()) { 56*e8d8bef9SDimitry Andric TryCand.Reason = NodeOrder; 570b57cec5SDimitry Andric return; 58*e8d8bef9SDimitry Andric } 59*e8d8bef9SDimitry Andric 60*e8d8bef9SDimitry Andric // Bias PhysReg Defs and copies to their uses and defined respectively. 61*e8d8bef9SDimitry Andric if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop), 62*e8d8bef9SDimitry Andric biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg)) 63*e8d8bef9SDimitry Andric return; 64*e8d8bef9SDimitry Andric 65*e8d8bef9SDimitry Andric // Avoid exceeding the target's limit. 66*e8d8bef9SDimitry Andric if (DAG->isTrackingPressure() && 67*e8d8bef9SDimitry Andric tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand, 68*e8d8bef9SDimitry Andric RegExcess, TRI, DAG->MF)) 69*e8d8bef9SDimitry Andric return; 70*e8d8bef9SDimitry Andric 71*e8d8bef9SDimitry Andric // Avoid increasing the max critical pressure in the scheduled region. 72*e8d8bef9SDimitry Andric if (DAG->isTrackingPressure() && 73*e8d8bef9SDimitry Andric tryPressure(TryCand.RPDelta.CriticalMax, Cand.RPDelta.CriticalMax, 74*e8d8bef9SDimitry Andric TryCand, Cand, RegCritical, TRI, DAG->MF)) 75*e8d8bef9SDimitry Andric return; 76*e8d8bef9SDimitry Andric 77*e8d8bef9SDimitry Andric // We only compare a subset of features when comparing nodes between 78*e8d8bef9SDimitry Andric // Top and Bottom boundary. Some properties are simply incomparable, in many 79*e8d8bef9SDimitry Andric // other instances we should only override the other boundary if something 80*e8d8bef9SDimitry Andric // is a clear good pick on one boundary. Skip heuristics that are more 81*e8d8bef9SDimitry Andric // "tie-breaking" in nature. 82*e8d8bef9SDimitry Andric bool SameBoundary = Zone != nullptr; 83*e8d8bef9SDimitry Andric if (SameBoundary) { 84*e8d8bef9SDimitry Andric // For loops that are acyclic path limited, aggressively schedule for 85*e8d8bef9SDimitry Andric // latency. Within an single cycle, whenever CurrMOps > 0, allow normal 86*e8d8bef9SDimitry Andric // heuristics to take precedence. 87*e8d8bef9SDimitry Andric if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() && 88*e8d8bef9SDimitry Andric tryLatency(TryCand, Cand, *Zone)) 89*e8d8bef9SDimitry Andric return; 90*e8d8bef9SDimitry Andric 91*e8d8bef9SDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles. 92*e8d8bef9SDimitry Andric if (tryLess(Zone->getLatencyStallCycles(TryCand.SU), 93*e8d8bef9SDimitry Andric Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall)) 94*e8d8bef9SDimitry Andric return; 95*e8d8bef9SDimitry Andric } 96*e8d8bef9SDimitry Andric 97*e8d8bef9SDimitry Andric // Keep clustered nodes together to encourage downstream peephole 98*e8d8bef9SDimitry Andric // optimizations which may reduce resource requirements. 99*e8d8bef9SDimitry Andric // 100*e8d8bef9SDimitry Andric // This is a best effort to set things up for a post-RA pass. Optimizations 101*e8d8bef9SDimitry Andric // like generating loads of multiple registers should ideally be done within 102*e8d8bef9SDimitry Andric // the scheduler pass by combining the loads during DAG postprocessing. 103*e8d8bef9SDimitry Andric const SUnit *CandNextClusterSU = 104*e8d8bef9SDimitry Andric Cand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred(); 105*e8d8bef9SDimitry Andric const SUnit *TryCandNextClusterSU = 106*e8d8bef9SDimitry Andric TryCand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred(); 107*e8d8bef9SDimitry Andric if (tryGreater(TryCand.SU == TryCandNextClusterSU, 108*e8d8bef9SDimitry Andric Cand.SU == CandNextClusterSU, TryCand, Cand, Cluster)) 109*e8d8bef9SDimitry Andric return; 110*e8d8bef9SDimitry Andric 111*e8d8bef9SDimitry Andric if (SameBoundary) { 112*e8d8bef9SDimitry Andric // Weak edges are for clustering and other constraints. 113*e8d8bef9SDimitry Andric if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop), 114*e8d8bef9SDimitry Andric getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak)) 115*e8d8bef9SDimitry Andric return; 116*e8d8bef9SDimitry Andric } 117*e8d8bef9SDimitry Andric 118*e8d8bef9SDimitry Andric // Avoid increasing the max pressure of the entire region. 119*e8d8bef9SDimitry Andric if (DAG->isTrackingPressure() && 120*e8d8bef9SDimitry Andric tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand, 121*e8d8bef9SDimitry Andric Cand, RegMax, TRI, DAG->MF)) 122*e8d8bef9SDimitry Andric return; 123*e8d8bef9SDimitry Andric 124*e8d8bef9SDimitry Andric if (SameBoundary) { 125*e8d8bef9SDimitry Andric // Avoid critical resource consumption and balance the schedule. 126*e8d8bef9SDimitry Andric TryCand.initResourceDelta(DAG, SchedModel); 127*e8d8bef9SDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources, 128*e8d8bef9SDimitry Andric TryCand, Cand, ResourceReduce)) 129*e8d8bef9SDimitry Andric return; 130*e8d8bef9SDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources, 131*e8d8bef9SDimitry Andric Cand.ResDelta.DemandedResources, TryCand, Cand, 132*e8d8bef9SDimitry Andric ResourceDemand)) 133*e8d8bef9SDimitry Andric return; 134*e8d8bef9SDimitry Andric 135*e8d8bef9SDimitry Andric // Avoid serializing long latency dependence chains. 136*e8d8bef9SDimitry Andric // For acyclic path limited loops, latency was already checked above. 137*e8d8bef9SDimitry Andric if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency && 138*e8d8bef9SDimitry Andric !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone)) 139*e8d8bef9SDimitry Andric return; 140*e8d8bef9SDimitry Andric 141*e8d8bef9SDimitry Andric // Fall through to original instruction order. 142*e8d8bef9SDimitry Andric if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) || 143*e8d8bef9SDimitry Andric (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) { 144*e8d8bef9SDimitry Andric TryCand.Reason = NodeOrder; 145*e8d8bef9SDimitry Andric } 146*e8d8bef9SDimitry Andric } 147*e8d8bef9SDimitry Andric 148*e8d8bef9SDimitry 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) 1530b57cec5SDimitry Andric return; 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. 157*e8d8bef9SDimitry Andric if (SameBoundary) { 1580b57cec5SDimitry Andric if (biasAddiLoadCandidate(Cand, TryCand, *Zone)) 1590b57cec5SDimitry Andric return; 1600b57cec5SDimitry Andric } 161*e8d8bef9SDimitry Andric } 1620b57cec5SDimitry Andric 1635ffd83dbSDimitry Andric bool PPCPostRASchedStrategy::biasAddiCandidate(SchedCandidate &Cand, 1645ffd83dbSDimitry Andric SchedCandidate &TryCand) const { 1655ffd83dbSDimitry Andric if (!EnableAddiHeuristic) 1665ffd83dbSDimitry Andric return false; 1675ffd83dbSDimitry Andric 1685ffd83dbSDimitry Andric if (isADDIInstr(TryCand) && !isADDIInstr(Cand)) { 1695ffd83dbSDimitry Andric TryCand.Reason = Stall; 1705ffd83dbSDimitry Andric return true; 1715ffd83dbSDimitry Andric } 1725ffd83dbSDimitry Andric return false; 1735ffd83dbSDimitry Andric } 1745ffd83dbSDimitry Andric 1755ffd83dbSDimitry Andric void PPCPostRASchedStrategy::tryCandidate(SchedCandidate &Cand, 1765ffd83dbSDimitry Andric SchedCandidate &TryCand) { 177*e8d8bef9SDimitry Andric // From PostGenericScheduler::tryCandidate 1785ffd83dbSDimitry Andric 179*e8d8bef9SDimitry Andric // Initialize the candidate if needed. 180*e8d8bef9SDimitry Andric if (!Cand.isValid()) { 181*e8d8bef9SDimitry Andric TryCand.Reason = NodeOrder; 1825ffd83dbSDimitry Andric return; 183*e8d8bef9SDimitry Andric } 184*e8d8bef9SDimitry Andric 185*e8d8bef9SDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles. 186*e8d8bef9SDimitry Andric if (tryLess(Top.getLatencyStallCycles(TryCand.SU), 187*e8d8bef9SDimitry Andric Top.getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall)) 188*e8d8bef9SDimitry Andric return; 189*e8d8bef9SDimitry Andric 190*e8d8bef9SDimitry Andric // Keep clustered nodes together. 191*e8d8bef9SDimitry Andric if (tryGreater(TryCand.SU == DAG->getNextClusterSucc(), 192*e8d8bef9SDimitry Andric Cand.SU == DAG->getNextClusterSucc(), TryCand, Cand, Cluster)) 193*e8d8bef9SDimitry Andric return; 194*e8d8bef9SDimitry Andric 195*e8d8bef9SDimitry Andric // Avoid critical resource consumption and balance the schedule. 196*e8d8bef9SDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources, 197*e8d8bef9SDimitry Andric TryCand, Cand, ResourceReduce)) 198*e8d8bef9SDimitry Andric return; 199*e8d8bef9SDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources, 200*e8d8bef9SDimitry Andric Cand.ResDelta.DemandedResources, TryCand, Cand, 201*e8d8bef9SDimitry Andric ResourceDemand)) 202*e8d8bef9SDimitry Andric return; 203*e8d8bef9SDimitry Andric 204*e8d8bef9SDimitry Andric // Avoid serializing long latency dependence chains. 205*e8d8bef9SDimitry Andric if (Cand.Policy.ReduceLatency && tryLatency(TryCand, Cand, Top)) { 206*e8d8bef9SDimitry Andric return; 207*e8d8bef9SDimitry Andric } 208*e8d8bef9SDimitry Andric 209*e8d8bef9SDimitry Andric // Fall through to original instruction order. 210*e8d8bef9SDimitry Andric if (TryCand.SU->NodeNum < Cand.SU->NodeNum) 211*e8d8bef9SDimitry Andric TryCand.Reason = NodeOrder; 212*e8d8bef9SDimitry Andric 213*e8d8bef9SDimitry Andric // PostGenericScheduler::tryCandidate end 2145ffd83dbSDimitry Andric 2155ffd83dbSDimitry Andric // Add powerpc post ra specific heuristic only when TryCand isn't selected or 2165ffd83dbSDimitry Andric // selected as node order. 2175ffd83dbSDimitry Andric if (TryCand.Reason != NodeOrder && TryCand.Reason != NoCand) 2185ffd83dbSDimitry Andric return; 2195ffd83dbSDimitry Andric 2205ffd83dbSDimitry Andric // There are some benefits to schedule the ADDI as early as possible post ra 2215ffd83dbSDimitry Andric // to avoid stalled by vector instructions which take up all the hw units. 2225ffd83dbSDimitry Andric // And ADDI is usually used to post inc the loop indvar, which matters the 2235ffd83dbSDimitry Andric // performance. 2245ffd83dbSDimitry Andric if (biasAddiCandidate(Cand, TryCand)) 2255ffd83dbSDimitry Andric return; 2265ffd83dbSDimitry Andric } 2275ffd83dbSDimitry Andric 2280b57cec5SDimitry Andric void PPCPostRASchedStrategy::enterMBB(MachineBasicBlock *MBB) { 2290b57cec5SDimitry Andric // Custom PPC PostRA specific behavior here. 2300b57cec5SDimitry Andric PostGenericScheduler::enterMBB(MBB); 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric void PPCPostRASchedStrategy::leaveMBB() { 2340b57cec5SDimitry Andric // Custom PPC PostRA specific behavior here. 2350b57cec5SDimitry Andric PostGenericScheduler::leaveMBB(); 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric void PPCPostRASchedStrategy::initialize(ScheduleDAGMI *Dag) { 2390b57cec5SDimitry Andric // Custom PPC PostRA specific initialization here. 2400b57cec5SDimitry Andric PostGenericScheduler::initialize(Dag); 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric SUnit *PPCPostRASchedStrategy::pickNode(bool &IsTopNode) { 2440b57cec5SDimitry Andric // Custom PPC PostRA specific scheduling here. 2450b57cec5SDimitry Andric return PostGenericScheduler::pickNode(IsTopNode); 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 248