10b57cec5SDimitry Andric //===-- GCNSchedStrategy.cpp - GCN Scheduler Strategy ---------------------===// 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 /// \file 100b57cec5SDimitry Andric /// This contains a MachineSchedStrategy implementation for maximizing wave 110b57cec5SDimitry Andric /// occupancy on GCN hardware. 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "GCNSchedStrategy.h" 150b57cec5SDimitry Andric #include "SIMachineFunctionInfo.h" 1681ad6265SDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric using namespace llvm; 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric GCNMaxOccupancySchedStrategy::GCNMaxOccupancySchedStrategy( 230b57cec5SDimitry Andric const MachineSchedContext *C) : 24fe6060f1SDimitry Andric GenericScheduler(C), TargetOccupancy(0), HasClusteredNodes(false), 25fe6060f1SDimitry Andric HasExcessPressure(false), MF(nullptr) { } 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric void GCNMaxOccupancySchedStrategy::initialize(ScheduleDAGMI *DAG) { 280b57cec5SDimitry Andric GenericScheduler::initialize(DAG); 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric MF = &DAG->MF; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>(); 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric // FIXME: This is also necessary, because some passes that run after 350b57cec5SDimitry Andric // scheduling and before regalloc increase register pressure. 36349cc55cSDimitry Andric const unsigned ErrorMargin = 3; 370b57cec5SDimitry Andric 38349cc55cSDimitry Andric SGPRExcessLimit = 39349cc55cSDimitry Andric Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass); 40349cc55cSDimitry Andric VGPRExcessLimit = 41349cc55cSDimitry Andric Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass); 420b57cec5SDimitry Andric 43349cc55cSDimitry Andric SIMachineFunctionInfo &MFI = *MF->getInfo<SIMachineFunctionInfo>(); 44349cc55cSDimitry Andric // Set the initial TargetOccupnacy to the maximum occupancy that we can 45349cc55cSDimitry Andric // achieve for this function. This effectively sets a lower bound on the 46349cc55cSDimitry Andric // 'Critical' register limits in the scheduler. 47349cc55cSDimitry Andric TargetOccupancy = MFI.getOccupancy(); 48349cc55cSDimitry Andric SGPRCriticalLimit = 49349cc55cSDimitry Andric std::min(ST.getMaxNumSGPRs(TargetOccupancy, true), SGPRExcessLimit); 50349cc55cSDimitry Andric VGPRCriticalLimit = 51349cc55cSDimitry Andric std::min(ST.getMaxNumVGPRs(TargetOccupancy), VGPRExcessLimit); 52349cc55cSDimitry Andric 53349cc55cSDimitry Andric // Subtract error margin from register limits and avoid overflow. 54349cc55cSDimitry Andric SGPRCriticalLimit = 55349cc55cSDimitry Andric std::min(SGPRCriticalLimit - ErrorMargin, SGPRCriticalLimit); 56349cc55cSDimitry Andric VGPRCriticalLimit = 57349cc55cSDimitry Andric std::min(VGPRCriticalLimit - ErrorMargin, VGPRCriticalLimit); 58349cc55cSDimitry Andric SGPRExcessLimit = std::min(SGPRExcessLimit - ErrorMargin, SGPRExcessLimit); 59349cc55cSDimitry Andric VGPRExcessLimit = std::min(VGPRExcessLimit - ErrorMargin, VGPRExcessLimit); 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric void GCNMaxOccupancySchedStrategy::initCandidate(SchedCandidate &Cand, SUnit *SU, 630b57cec5SDimitry Andric bool AtTop, const RegPressureTracker &RPTracker, 640b57cec5SDimitry Andric const SIRegisterInfo *SRI, 650b57cec5SDimitry Andric unsigned SGPRPressure, 660b57cec5SDimitry Andric unsigned VGPRPressure) { 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric Cand.SU = SU; 690b57cec5SDimitry Andric Cand.AtTop = AtTop; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // getDownwardPressure() and getUpwardPressure() make temporary changes to 720b57cec5SDimitry Andric // the tracker, so we need to pass those function a non-const copy. 730b57cec5SDimitry Andric RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker); 740b57cec5SDimitry Andric 758bcb0991SDimitry Andric Pressure.clear(); 768bcb0991SDimitry Andric MaxPressure.clear(); 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric if (AtTop) 790b57cec5SDimitry Andric TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure); 800b57cec5SDimitry Andric else { 810b57cec5SDimitry Andric // FIXME: I think for bottom up scheduling, the register pressure is cached 820b57cec5SDimitry Andric // and can be retrieved by DAG->getPressureDif(SU). 830b57cec5SDimitry Andric TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure); 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 865ffd83dbSDimitry Andric unsigned NewSGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32]; 875ffd83dbSDimitry Andric unsigned NewVGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32]; 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric // If two instructions increase the pressure of different register sets 900b57cec5SDimitry Andric // by the same amount, the generic scheduler will prefer to schedule the 910b57cec5SDimitry Andric // instruction that increases the set with the least amount of registers, 920b57cec5SDimitry Andric // which in our case would be SGPRs. This is rarely what we want, so 930b57cec5SDimitry Andric // when we report excess/critical register pressure, we do it either 940b57cec5SDimitry Andric // only for VGPRs or only for SGPRs. 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs. 970b57cec5SDimitry Andric const unsigned MaxVGPRPressureInc = 16; 980b57cec5SDimitry Andric bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit; 990b57cec5SDimitry Andric bool ShouldTrackSGPRs = !ShouldTrackVGPRs && SGPRPressure >= SGPRExcessLimit; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // FIXME: We have to enter REG-EXCESS before we reach the actual threshold 1030b57cec5SDimitry Andric // to increase the likelihood we don't go over the limits. We should improve 1040b57cec5SDimitry Andric // the analysis to look through dependencies to find the path with the least 1050b57cec5SDimitry Andric // register pressure. 1060b57cec5SDimitry Andric 1078bcb0991SDimitry Andric // We only need to update the RPDelta for instructions that increase register 1088bcb0991SDimitry Andric // pressure. Instructions that decrease or keep reg pressure the same will be 1098bcb0991SDimitry Andric // marked as RegExcess in tryCandidate() when they are compared with 1108bcb0991SDimitry Andric // instructions that increase the register pressure. 1110b57cec5SDimitry Andric if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) { 112fe6060f1SDimitry Andric HasExcessPressure = true; 1135ffd83dbSDimitry Andric Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::VGPR_32); 1140b57cec5SDimitry Andric Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) { 118fe6060f1SDimitry Andric HasExcessPressure = true; 1195ffd83dbSDimitry Andric Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::SReg_32); 1200b57cec5SDimitry Andric Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure - SGPRExcessLimit); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // Register pressure is considered 'CRITICAL' if it is approaching a value 1240b57cec5SDimitry Andric // that would reduce the wave occupancy for the execution unit. When 125349cc55cSDimitry Andric // register pressure is 'CRITICAL', increasing SGPR and VGPR pressure both 1260b57cec5SDimitry Andric // has the same cost, so we don't need to prefer one over the other. 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit; 1290b57cec5SDimitry Andric int VGPRDelta = NewVGPRPressure - VGPRCriticalLimit; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric if (SGPRDelta >= 0 || VGPRDelta >= 0) { 132fe6060f1SDimitry Andric HasExcessPressure = true; 1330b57cec5SDimitry Andric if (SGPRDelta > VGPRDelta) { 1345ffd83dbSDimitry Andric Cand.RPDelta.CriticalMax = 1355ffd83dbSDimitry Andric PressureChange(AMDGPU::RegisterPressureSets::SReg_32); 1360b57cec5SDimitry Andric Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta); 1370b57cec5SDimitry Andric } else { 1385ffd83dbSDimitry Andric Cand.RPDelta.CriticalMax = 1395ffd83dbSDimitry Andric PressureChange(AMDGPU::RegisterPressureSets::VGPR_32); 1400b57cec5SDimitry Andric Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta); 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric // This function is mostly cut and pasted from 1460b57cec5SDimitry Andric // GenericScheduler::pickNodeFromQueue() 1470b57cec5SDimitry Andric void GCNMaxOccupancySchedStrategy::pickNodeFromQueue(SchedBoundary &Zone, 1480b57cec5SDimitry Andric const CandPolicy &ZonePolicy, 1490b57cec5SDimitry Andric const RegPressureTracker &RPTracker, 1500b57cec5SDimitry Andric SchedCandidate &Cand) { 1510b57cec5SDimitry Andric const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo*>(TRI); 1520b57cec5SDimitry Andric ArrayRef<unsigned> Pressure = RPTracker.getRegSetPressureAtPos(); 1535ffd83dbSDimitry Andric unsigned SGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32]; 1545ffd83dbSDimitry Andric unsigned VGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32]; 1550b57cec5SDimitry Andric ReadyQueue &Q = Zone.Available; 1560b57cec5SDimitry Andric for (SUnit *SU : Q) { 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric SchedCandidate TryCand(ZonePolicy); 1590b57cec5SDimitry Andric initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, 1600b57cec5SDimitry Andric SGPRPressure, VGPRPressure); 1610b57cec5SDimitry Andric // Pass SchedBoundary only when comparing nodes from the same boundary. 1620b57cec5SDimitry Andric SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr; 1630b57cec5SDimitry Andric GenericScheduler::tryCandidate(Cand, TryCand, ZoneArg); 1640b57cec5SDimitry Andric if (TryCand.Reason != NoCand) { 1650b57cec5SDimitry Andric // Initialize resource delta if needed in case future heuristics query it. 1660b57cec5SDimitry Andric if (TryCand.ResDelta == SchedResourceDelta()) 1670b57cec5SDimitry Andric TryCand.initResourceDelta(Zone.DAG, SchedModel); 1680b57cec5SDimitry Andric Cand.setBest(TryCand); 1698bcb0991SDimitry Andric LLVM_DEBUG(traceCandidate(Cand)); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric // This function is mostly cut and pasted from 1750b57cec5SDimitry Andric // GenericScheduler::pickNodeBidirectional() 1760b57cec5SDimitry Andric SUnit *GCNMaxOccupancySchedStrategy::pickNodeBidirectional(bool &IsTopNode) { 1770b57cec5SDimitry Andric // Schedule as far as possible in the direction of no choice. This is most 1780b57cec5SDimitry Andric // efficient, but also provides the best heuristics for CriticalPSets. 1790b57cec5SDimitry Andric if (SUnit *SU = Bot.pickOnlyChoice()) { 1800b57cec5SDimitry Andric IsTopNode = false; 1810b57cec5SDimitry Andric return SU; 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric if (SUnit *SU = Top.pickOnlyChoice()) { 1840b57cec5SDimitry Andric IsTopNode = true; 1850b57cec5SDimitry Andric return SU; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric // Set the bottom-up policy based on the state of the current bottom zone and 1880b57cec5SDimitry Andric // the instructions outside the zone, including the top zone. 1890b57cec5SDimitry Andric CandPolicy BotPolicy; 1900b57cec5SDimitry Andric setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top); 1910b57cec5SDimitry Andric // Set the top-down policy based on the state of the current top zone and 1920b57cec5SDimitry Andric // the instructions outside the zone, including the bottom zone. 1930b57cec5SDimitry Andric CandPolicy TopPolicy; 1940b57cec5SDimitry Andric setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot); 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric // See if BotCand is still valid (because we previously scheduled from Top). 1970b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Picking from Bot:\n"); 1980b57cec5SDimitry Andric if (!BotCand.isValid() || BotCand.SU->isScheduled || 1990b57cec5SDimitry Andric BotCand.Policy != BotPolicy) { 2000b57cec5SDimitry Andric BotCand.reset(CandPolicy()); 2010b57cec5SDimitry Andric pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand); 2020b57cec5SDimitry Andric assert(BotCand.Reason != NoCand && "failed to find the first candidate"); 2030b57cec5SDimitry Andric } else { 2040b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(BotCand)); 2058bcb0991SDimitry Andric #ifndef NDEBUG 2068bcb0991SDimitry Andric if (VerifyScheduling) { 2078bcb0991SDimitry Andric SchedCandidate TCand; 2088bcb0991SDimitry Andric TCand.reset(CandPolicy()); 2098bcb0991SDimitry Andric pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand); 2108bcb0991SDimitry Andric assert(TCand.SU == BotCand.SU && 2118bcb0991SDimitry Andric "Last pick result should correspond to re-picking right now"); 2128bcb0991SDimitry Andric } 2138bcb0991SDimitry Andric #endif 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // Check if the top Q has a better candidate. 2170b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Picking from Top:\n"); 2180b57cec5SDimitry Andric if (!TopCand.isValid() || TopCand.SU->isScheduled || 2190b57cec5SDimitry Andric TopCand.Policy != TopPolicy) { 2200b57cec5SDimitry Andric TopCand.reset(CandPolicy()); 2210b57cec5SDimitry Andric pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand); 2220b57cec5SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find the first candidate"); 2230b57cec5SDimitry Andric } else { 2240b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(TopCand)); 2258bcb0991SDimitry Andric #ifndef NDEBUG 2268bcb0991SDimitry Andric if (VerifyScheduling) { 2278bcb0991SDimitry Andric SchedCandidate TCand; 2288bcb0991SDimitry Andric TCand.reset(CandPolicy()); 2298bcb0991SDimitry Andric pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand); 2308bcb0991SDimitry Andric assert(TCand.SU == TopCand.SU && 2318bcb0991SDimitry Andric "Last pick result should correspond to re-picking right now"); 2328bcb0991SDimitry Andric } 2338bcb0991SDimitry Andric #endif 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric // Pick best from BotCand and TopCand. 2370b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Top Cand: "; traceCandidate(TopCand); 2380b57cec5SDimitry Andric dbgs() << "Bot Cand: "; traceCandidate(BotCand);); 2395ffd83dbSDimitry Andric SchedCandidate Cand = BotCand; 2400b57cec5SDimitry Andric TopCand.Reason = NoCand; 2410b57cec5SDimitry Andric GenericScheduler::tryCandidate(Cand, TopCand, nullptr); 2420b57cec5SDimitry Andric if (TopCand.Reason != NoCand) { 2430b57cec5SDimitry Andric Cand.setBest(TopCand); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Picking: "; traceCandidate(Cand);); 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric IsTopNode = Cand.AtTop; 2480b57cec5SDimitry Andric return Cand.SU; 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric // This function is mostly cut and pasted from 2520b57cec5SDimitry Andric // GenericScheduler::pickNode() 2530b57cec5SDimitry Andric SUnit *GCNMaxOccupancySchedStrategy::pickNode(bool &IsTopNode) { 2540b57cec5SDimitry Andric if (DAG->top() == DAG->bottom()) { 2550b57cec5SDimitry Andric assert(Top.Available.empty() && Top.Pending.empty() && 2560b57cec5SDimitry Andric Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage"); 2570b57cec5SDimitry Andric return nullptr; 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric SUnit *SU; 2600b57cec5SDimitry Andric do { 2610b57cec5SDimitry Andric if (RegionPolicy.OnlyTopDown) { 2620b57cec5SDimitry Andric SU = Top.pickOnlyChoice(); 2630b57cec5SDimitry Andric if (!SU) { 2640b57cec5SDimitry Andric CandPolicy NoPolicy; 2650b57cec5SDimitry Andric TopCand.reset(NoPolicy); 2660b57cec5SDimitry Andric pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand); 2670b57cec5SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find a candidate"); 2680b57cec5SDimitry Andric SU = TopCand.SU; 2690b57cec5SDimitry Andric } 2700b57cec5SDimitry Andric IsTopNode = true; 2710b57cec5SDimitry Andric } else if (RegionPolicy.OnlyBottomUp) { 2720b57cec5SDimitry Andric SU = Bot.pickOnlyChoice(); 2730b57cec5SDimitry Andric if (!SU) { 2740b57cec5SDimitry Andric CandPolicy NoPolicy; 2750b57cec5SDimitry Andric BotCand.reset(NoPolicy); 2760b57cec5SDimitry Andric pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand); 2770b57cec5SDimitry Andric assert(BotCand.Reason != NoCand && "failed to find a candidate"); 2780b57cec5SDimitry Andric SU = BotCand.SU; 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric IsTopNode = false; 2810b57cec5SDimitry Andric } else { 2820b57cec5SDimitry Andric SU = pickNodeBidirectional(IsTopNode); 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric } while (SU->isScheduled); 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric if (SU->isTopReady()) 2870b57cec5SDimitry Andric Top.removeReady(SU); 2880b57cec5SDimitry Andric if (SU->isBottomReady()) 2890b57cec5SDimitry Andric Bot.removeReady(SU); 2900b57cec5SDimitry Andric 291fe6060f1SDimitry Andric if (!HasClusteredNodes && SU->getInstr()->mayLoadOrStore()) { 292fe6060f1SDimitry Andric for (SDep &Dep : SU->Preds) { 293fe6060f1SDimitry Andric if (Dep.isCluster()) { 294fe6060f1SDimitry Andric HasClusteredNodes = true; 295fe6060f1SDimitry Andric break; 296fe6060f1SDimitry Andric } 297fe6060f1SDimitry Andric } 298fe6060f1SDimitry Andric } 299fe6060f1SDimitry Andric 3000b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " 3010b57cec5SDimitry Andric << *SU->getInstr()); 3020b57cec5SDimitry Andric return SU; 3030b57cec5SDimitry Andric } 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric GCNScheduleDAGMILive::GCNScheduleDAGMILive(MachineSchedContext *C, 3060b57cec5SDimitry Andric std::unique_ptr<MachineSchedStrategy> S) : 3070b57cec5SDimitry Andric ScheduleDAGMILive(C, std::move(S)), 3080b57cec5SDimitry Andric ST(MF.getSubtarget<GCNSubtarget>()), 3090b57cec5SDimitry Andric MFI(*MF.getInfo<SIMachineFunctionInfo>()), 3100b57cec5SDimitry Andric StartingOccupancy(MFI.getOccupancy()), 3115ffd83dbSDimitry Andric MinOccupancy(StartingOccupancy), Stage(Collect), RegionIdx(0) { 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Starting occupancy is " << StartingOccupancy << ".\n"); 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric void GCNScheduleDAGMILive::schedule() { 3175ffd83dbSDimitry Andric if (Stage == Collect) { 3180b57cec5SDimitry Andric // Just record regions at the first pass. 3190b57cec5SDimitry Andric Regions.push_back(std::make_pair(RegionBegin, RegionEnd)); 3200b57cec5SDimitry Andric return; 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric std::vector<MachineInstr*> Unsched; 3240b57cec5SDimitry Andric Unsched.reserve(NumRegionInstrs); 3250b57cec5SDimitry Andric for (auto &I : *this) { 3260b57cec5SDimitry Andric Unsched.push_back(&I); 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric 3290b57cec5SDimitry Andric GCNRegPressure PressureBefore; 3300b57cec5SDimitry Andric if (LIS) { 3310b57cec5SDimitry Andric PressureBefore = Pressure[RegionIdx]; 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Pressure before scheduling:\nRegion live-ins:"; 3340b57cec5SDimitry Andric GCNRPTracker::printLiveRegs(dbgs(), LiveIns[RegionIdx], MRI); 3350b57cec5SDimitry Andric dbgs() << "Region live-in pressure: "; 3360b57cec5SDimitry Andric llvm::getRegPressure(MRI, LiveIns[RegionIdx]).print(dbgs()); 3370b57cec5SDimitry Andric dbgs() << "Region register pressure: "; 3380b57cec5SDimitry Andric PressureBefore.print(dbgs())); 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric 341fe6060f1SDimitry Andric GCNMaxOccupancySchedStrategy &S = (GCNMaxOccupancySchedStrategy&)*SchedImpl; 342fe6060f1SDimitry Andric // Set HasClusteredNodes to true for late stages where we have already 343fe6060f1SDimitry Andric // collected it. That way pickNode() will not scan SDep's when not needed. 344fe6060f1SDimitry Andric S.HasClusteredNodes = Stage > InitialSchedule; 345fe6060f1SDimitry Andric S.HasExcessPressure = false; 3460b57cec5SDimitry Andric ScheduleDAGMILive::schedule(); 3470b57cec5SDimitry Andric Regions[RegionIdx] = std::make_pair(RegionBegin, RegionEnd); 3485ffd83dbSDimitry Andric RescheduleRegions[RegionIdx] = false; 349fe6060f1SDimitry Andric if (Stage == InitialSchedule && S.HasClusteredNodes) 350fe6060f1SDimitry Andric RegionsWithClusters[RegionIdx] = true; 351fe6060f1SDimitry Andric if (S.HasExcessPressure) 352fe6060f1SDimitry Andric RegionsWithHighRP[RegionIdx] = true; 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric if (!LIS) 3550b57cec5SDimitry Andric return; 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric // Check the results of scheduling. 3580b57cec5SDimitry Andric auto PressureAfter = getRealRegPressure(); 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Pressure after scheduling: "; 3610b57cec5SDimitry Andric PressureAfter.print(dbgs())); 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit && 364fe6060f1SDimitry Andric PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) <= S.VGPRCriticalLimit) { 3650b57cec5SDimitry Andric Pressure[RegionIdx] = PressureAfter; 36681ad6265SDimitry Andric RegionsWithMinOcc[RegionIdx] = 36781ad6265SDimitry Andric PressureAfter.getOccupancy(ST) == MinOccupancy; 36881ad6265SDimitry Andric 3690b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n"); 3700b57cec5SDimitry Andric return; 3710b57cec5SDimitry Andric } 372349cc55cSDimitry Andric 373349cc55cSDimitry Andric unsigned WavesAfter = 374349cc55cSDimitry Andric std::min(S.TargetOccupancy, PressureAfter.getOccupancy(ST)); 375349cc55cSDimitry Andric unsigned WavesBefore = 376349cc55cSDimitry Andric std::min(S.TargetOccupancy, PressureBefore.getOccupancy(ST)); 3770b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore 3780b57cec5SDimitry Andric << ", after " << WavesAfter << ".\n"); 3790b57cec5SDimitry Andric 380349cc55cSDimitry Andric // We may not be able to keep the current target occupancy because of the just 381349cc55cSDimitry Andric // scheduled region. We might still be able to revert scheduling if the 382349cc55cSDimitry Andric // occupancy before was higher, or if the current schedule has register 383349cc55cSDimitry Andric // pressure higher than the excess limits which could lead to more spilling. 3840b57cec5SDimitry Andric unsigned NewOccupancy = std::max(WavesAfter, WavesBefore); 38581ad6265SDimitry Andric 3860b57cec5SDimitry Andric // Allow memory bound functions to drop to 4 waves if not limited by an 3870b57cec5SDimitry Andric // attribute. 3880b57cec5SDimitry Andric if (WavesAfter < WavesBefore && WavesAfter < MinOccupancy && 3890b57cec5SDimitry Andric WavesAfter >= MFI.getMinAllowedOccupancy()) { 3900b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to " 3910b57cec5SDimitry Andric << MFI.getMinAllowedOccupancy() << " waves\n"); 3920b57cec5SDimitry Andric NewOccupancy = WavesAfter; 3930b57cec5SDimitry Andric } 394349cc55cSDimitry Andric 3950b57cec5SDimitry Andric if (NewOccupancy < MinOccupancy) { 3960b57cec5SDimitry Andric MinOccupancy = NewOccupancy; 3970b57cec5SDimitry Andric MFI.limitOccupancy(MinOccupancy); 39881ad6265SDimitry Andric RegionsWithMinOcc.reset(); 3990b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to " 4000b57cec5SDimitry Andric << MinOccupancy << ".\n"); 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric 4035ffd83dbSDimitry Andric unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF); 4045ffd83dbSDimitry Andric unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF); 405fe6060f1SDimitry Andric if (PressureAfter.getVGPRNum(false) > MaxVGPRs || 406fe6060f1SDimitry Andric PressureAfter.getAGPRNum() > MaxVGPRs || 407fe6060f1SDimitry Andric PressureAfter.getSGPRNum() > MaxSGPRs) { 4085ffd83dbSDimitry Andric RescheduleRegions[RegionIdx] = true; 409fe6060f1SDimitry Andric RegionsWithHighRP[RegionIdx] = true; 410fe6060f1SDimitry Andric } 4115ffd83dbSDimitry Andric 412349cc55cSDimitry Andric // If this condition is true, then either the occupancy before and after 413349cc55cSDimitry Andric // scheduling is the same, or we are allowing the occupancy to drop because 414349cc55cSDimitry Andric // the function is memory bound. Even if we are OK with the current occupancy, 415349cc55cSDimitry Andric // we still need to verify that we will not introduce any extra chance of 416349cc55cSDimitry Andric // spilling. 4170b57cec5SDimitry Andric if (WavesAfter >= MinOccupancy) { 4185ffd83dbSDimitry Andric if (Stage == UnclusteredReschedule && 4195ffd83dbSDimitry Andric !PressureAfter.less(ST, PressureBefore)) { 4205ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n"); 4215ffd83dbSDimitry Andric } else if (WavesAfter > MFI.getMinWavesPerEU() || 422480093f4SDimitry Andric PressureAfter.less(ST, PressureBefore) || 4235ffd83dbSDimitry Andric !RescheduleRegions[RegionIdx]) { 4240b57cec5SDimitry Andric Pressure[RegionIdx] = PressureAfter; 42581ad6265SDimitry Andric RegionsWithMinOcc[RegionIdx] = 42681ad6265SDimitry Andric PressureAfter.getOccupancy(ST) == MinOccupancy; 427fe6060f1SDimitry Andric if (!RegionsWithClusters[RegionIdx] && 428fe6060f1SDimitry Andric (Stage + 1) == UnclusteredReschedule) 429fe6060f1SDimitry Andric RescheduleRegions[RegionIdx] = false; 4300b57cec5SDimitry Andric return; 4315ffd83dbSDimitry Andric } else { 432480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n"); 433480093f4SDimitry Andric } 4345ffd83dbSDimitry Andric } 4350b57cec5SDimitry Andric 43681ad6265SDimitry Andric RegionsWithMinOcc[RegionIdx] = 43781ad6265SDimitry Andric PressureBefore.getOccupancy(ST) == MinOccupancy; 4380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Attempting to revert scheduling.\n"); 439fe6060f1SDimitry Andric RescheduleRegions[RegionIdx] = RegionsWithClusters[RegionIdx] || 440fe6060f1SDimitry Andric (Stage + 1) != UnclusteredReschedule; 4410b57cec5SDimitry Andric RegionEnd = RegionBegin; 44281ad6265SDimitry Andric int SkippedDebugInstr = 0; 4430b57cec5SDimitry Andric for (MachineInstr *MI : Unsched) { 44481ad6265SDimitry Andric if (MI->isDebugInstr()) { 44581ad6265SDimitry Andric ++SkippedDebugInstr; 4460b57cec5SDimitry Andric continue; 44781ad6265SDimitry Andric } 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric if (MI->getIterator() != RegionEnd) { 4500b57cec5SDimitry Andric BB->remove(MI); 4510b57cec5SDimitry Andric BB->insert(RegionEnd, MI); 4520b57cec5SDimitry Andric if (!MI->isDebugInstr()) 4530b57cec5SDimitry Andric LIS->handleMove(*MI, true); 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric // Reset read-undef flags and update them later. 4560b57cec5SDimitry Andric for (auto &Op : MI->operands()) 4570b57cec5SDimitry Andric if (Op.isReg() && Op.isDef()) 4580b57cec5SDimitry Andric Op.setIsUndef(false); 4590b57cec5SDimitry Andric RegisterOperands RegOpers; 4600b57cec5SDimitry Andric RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, false); 4610b57cec5SDimitry Andric if (!MI->isDebugInstr()) { 4620b57cec5SDimitry Andric if (ShouldTrackLaneMasks) { 4630b57cec5SDimitry Andric // Adjust liveness and add missing dead+read-undef flags. 4640b57cec5SDimitry Andric SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot(); 4650b57cec5SDimitry Andric RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI); 4660b57cec5SDimitry Andric } else { 4670b57cec5SDimitry Andric // Adjust for missing dead-def flags. 4680b57cec5SDimitry Andric RegOpers.detectDeadDefs(*MI, *LIS); 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric RegionEnd = MI->getIterator(); 4720b57cec5SDimitry Andric ++RegionEnd; 4730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Scheduling " << *MI); 4740b57cec5SDimitry Andric } 4750b57cec5SDimitry Andric 47681ad6265SDimitry Andric // After reverting schedule, debug instrs will now be at the end of the block 47781ad6265SDimitry Andric // and RegionEnd will point to the first debug instr. Increment RegionEnd 47881ad6265SDimitry Andric // pass debug instrs to the actual end of the scheduling region. 47981ad6265SDimitry Andric while (SkippedDebugInstr-- > 0) 48081ad6265SDimitry Andric ++RegionEnd; 48181ad6265SDimitry Andric 48281ad6265SDimitry Andric // If Unsched.front() instruction is a debug instruction, this will actually 48381ad6265SDimitry Andric // shrink the region since we moved all debug instructions to the end of the 48481ad6265SDimitry Andric // block. Find the first instruction that is not a debug instruction. 48581ad6265SDimitry Andric RegionBegin = Unsched.front()->getIterator(); 48681ad6265SDimitry Andric if (RegionBegin->isDebugInstr()) { 48781ad6265SDimitry Andric for (MachineInstr *MI : Unsched) { 48881ad6265SDimitry Andric if (MI->isDebugInstr()) 48981ad6265SDimitry Andric continue; 49081ad6265SDimitry Andric RegionBegin = MI->getIterator(); 49181ad6265SDimitry Andric break; 49281ad6265SDimitry Andric } 49381ad6265SDimitry Andric } 49481ad6265SDimitry Andric 49581ad6265SDimitry Andric // Then move the debug instructions back into their correct place and set 49681ad6265SDimitry Andric // RegionBegin and RegionEnd if needed. 4970b57cec5SDimitry Andric placeDebugValues(); 49881ad6265SDimitry Andric 49981ad6265SDimitry Andric Regions[RegionIdx] = std::make_pair(RegionBegin, RegionEnd); 5000b57cec5SDimitry Andric } 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric GCNRegPressure GCNScheduleDAGMILive::getRealRegPressure() const { 5030b57cec5SDimitry Andric GCNDownwardRPTracker RPTracker(*LIS); 5040b57cec5SDimitry Andric RPTracker.advance(begin(), end(), &LiveIns[RegionIdx]); 5050b57cec5SDimitry Andric return RPTracker.moveMaxPressure(); 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric void GCNScheduleDAGMILive::computeBlockPressure(const MachineBasicBlock *MBB) { 5090b57cec5SDimitry Andric GCNDownwardRPTracker RPTracker(*LIS); 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric // If the block has the only successor then live-ins of that successor are 5120b57cec5SDimitry Andric // live-outs of the current block. We can reuse calculated live set if the 5130b57cec5SDimitry Andric // successor will be sent to scheduling past current block. 5140b57cec5SDimitry Andric const MachineBasicBlock *OnlySucc = nullptr; 5150b57cec5SDimitry Andric if (MBB->succ_size() == 1 && !(*MBB->succ_begin())->empty()) { 5160b57cec5SDimitry Andric SlotIndexes *Ind = LIS->getSlotIndexes(); 5170b57cec5SDimitry Andric if (Ind->getMBBStartIdx(MBB) < Ind->getMBBStartIdx(*MBB->succ_begin())) 5180b57cec5SDimitry Andric OnlySucc = *MBB->succ_begin(); 5190b57cec5SDimitry Andric } 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric // Scheduler sends regions from the end of the block upwards. 5220b57cec5SDimitry Andric size_t CurRegion = RegionIdx; 5230b57cec5SDimitry Andric for (size_t E = Regions.size(); CurRegion != E; ++CurRegion) 5240b57cec5SDimitry Andric if (Regions[CurRegion].first->getParent() != MBB) 5250b57cec5SDimitry Andric break; 5260b57cec5SDimitry Andric --CurRegion; 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric auto I = MBB->begin(); 5290b57cec5SDimitry Andric auto LiveInIt = MBBLiveIns.find(MBB); 53081ad6265SDimitry Andric auto &Rgn = Regions[CurRegion]; 53181ad6265SDimitry Andric auto *NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second); 5320b57cec5SDimitry Andric if (LiveInIt != MBBLiveIns.end()) { 5330b57cec5SDimitry Andric auto LiveIn = std::move(LiveInIt->second); 5340b57cec5SDimitry Andric RPTracker.reset(*MBB->begin(), &LiveIn); 5350b57cec5SDimitry Andric MBBLiveIns.erase(LiveInIt); 5360b57cec5SDimitry Andric } else { 5370b57cec5SDimitry Andric I = Rgn.first; 5380b57cec5SDimitry Andric auto LRS = BBLiveInMap.lookup(NonDbgMI); 539fe6060f1SDimitry Andric #ifdef EXPENSIVE_CHECKS 5400b57cec5SDimitry Andric assert(isEqual(getLiveRegsBefore(*NonDbgMI, *LIS), LRS)); 541fe6060f1SDimitry Andric #endif 5420b57cec5SDimitry Andric RPTracker.reset(*I, &LRS); 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric for ( ; ; ) { 5460b57cec5SDimitry Andric I = RPTracker.getNext(); 5470b57cec5SDimitry Andric 54881ad6265SDimitry Andric if (Regions[CurRegion].first == I || NonDbgMI == I) { 5490b57cec5SDimitry Andric LiveIns[CurRegion] = RPTracker.getLiveRegs(); 5500b57cec5SDimitry Andric RPTracker.clearMaxPressure(); 5510b57cec5SDimitry Andric } 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric if (Regions[CurRegion].second == I) { 5540b57cec5SDimitry Andric Pressure[CurRegion] = RPTracker.moveMaxPressure(); 5550b57cec5SDimitry Andric if (CurRegion-- == RegionIdx) 5560b57cec5SDimitry Andric break; 5570b57cec5SDimitry Andric } 5580b57cec5SDimitry Andric RPTracker.advanceToNext(); 5590b57cec5SDimitry Andric RPTracker.advanceBeforeNext(); 5600b57cec5SDimitry Andric } 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric if (OnlySucc) { 5630b57cec5SDimitry Andric if (I != MBB->end()) { 5640b57cec5SDimitry Andric RPTracker.advanceToNext(); 5650b57cec5SDimitry Andric RPTracker.advance(MBB->end()); 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric RPTracker.reset(*OnlySucc->begin(), &RPTracker.getLiveRegs()); 5680b57cec5SDimitry Andric RPTracker.advanceBeforeNext(); 5690b57cec5SDimitry Andric MBBLiveIns[OnlySucc] = RPTracker.moveLiveRegs(); 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric } 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> 5740b57cec5SDimitry Andric GCNScheduleDAGMILive::getBBLiveInMap() const { 5750b57cec5SDimitry Andric assert(!Regions.empty()); 5760b57cec5SDimitry Andric std::vector<MachineInstr *> BBStarters; 5770b57cec5SDimitry Andric BBStarters.reserve(Regions.size()); 5780b57cec5SDimitry Andric auto I = Regions.rbegin(), E = Regions.rend(); 5790b57cec5SDimitry Andric auto *BB = I->first->getParent(); 5800b57cec5SDimitry Andric do { 5810b57cec5SDimitry Andric auto *MI = &*skipDebugInstructionsForward(I->first, I->second); 5820b57cec5SDimitry Andric BBStarters.push_back(MI); 5830b57cec5SDimitry Andric do { 5840b57cec5SDimitry Andric ++I; 5850b57cec5SDimitry Andric } while (I != E && I->first->getParent() == BB); 5860b57cec5SDimitry Andric } while (I != E); 5870b57cec5SDimitry Andric return getLiveRegMap(BBStarters, false /*After*/, *LIS); 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric void GCNScheduleDAGMILive::finalizeSchedule() { 5910b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "All regions recorded, starting actual scheduling.\n"); 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric LiveIns.resize(Regions.size()); 5940b57cec5SDimitry Andric Pressure.resize(Regions.size()); 5955ffd83dbSDimitry Andric RescheduleRegions.resize(Regions.size()); 596fe6060f1SDimitry Andric RegionsWithClusters.resize(Regions.size()); 597fe6060f1SDimitry Andric RegionsWithHighRP.resize(Regions.size()); 59881ad6265SDimitry Andric RegionsWithMinOcc.resize(Regions.size()); 5995ffd83dbSDimitry Andric RescheduleRegions.set(); 600fe6060f1SDimitry Andric RegionsWithClusters.reset(); 601fe6060f1SDimitry Andric RegionsWithHighRP.reset(); 60281ad6265SDimitry Andric RegionsWithMinOcc.reset(); 6030b57cec5SDimitry Andric 6040b57cec5SDimitry Andric if (!Regions.empty()) 6050b57cec5SDimitry Andric BBLiveInMap = getBBLiveInMap(); 6060b57cec5SDimitry Andric 6075ffd83dbSDimitry Andric std::vector<std::unique_ptr<ScheduleDAGMutation>> SavedMutations; 6085ffd83dbSDimitry Andric 6090b57cec5SDimitry Andric do { 6100b57cec5SDimitry Andric Stage++; 6110b57cec5SDimitry Andric RegionIdx = 0; 6120b57cec5SDimitry Andric MachineBasicBlock *MBB = nullptr; 6130b57cec5SDimitry Andric 6145ffd83dbSDimitry Andric if (Stage > InitialSchedule) { 6155ffd83dbSDimitry Andric if (!LIS) 6165ffd83dbSDimitry Andric break; 6175ffd83dbSDimitry Andric 6180b57cec5SDimitry Andric // Retry function scheduling if we found resulting occupancy and it is 6190b57cec5SDimitry Andric // lower than used for first pass scheduling. This will give more freedom 6200b57cec5SDimitry Andric // to schedule low register pressure blocks. 6210b57cec5SDimitry Andric // Code is partially copied from MachineSchedulerBase::scheduleRegions(). 6220b57cec5SDimitry Andric 6235ffd83dbSDimitry Andric if (Stage == UnclusteredReschedule) { 6245ffd83dbSDimitry Andric if (RescheduleRegions.none()) 6255ffd83dbSDimitry Andric continue; 6265ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << 6275ffd83dbSDimitry Andric "Retrying function scheduling without clustering.\n"); 6285ffd83dbSDimitry Andric } 6295ffd83dbSDimitry Andric 6305ffd83dbSDimitry Andric if (Stage == ClusteredLowOccupancyReschedule) { 6315ffd83dbSDimitry Andric if (StartingOccupancy <= MinOccupancy) 6320b57cec5SDimitry Andric break; 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric LLVM_DEBUG( 6350b57cec5SDimitry Andric dbgs() 6360b57cec5SDimitry Andric << "Retrying function scheduling with lowest recorded occupancy " 6370b57cec5SDimitry Andric << MinOccupancy << ".\n"); 6380b57cec5SDimitry Andric } 63981ad6265SDimitry Andric 64081ad6265SDimitry Andric if (Stage == PreRARematerialize) { 64181ad6265SDimitry Andric if (RegionsWithMinOcc.none() || Regions.size() == 1) 64281ad6265SDimitry Andric break; 64381ad6265SDimitry Andric 64481ad6265SDimitry Andric const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 64581ad6265SDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 64681ad6265SDimitry Andric // Check maximum occupancy 64781ad6265SDimitry Andric if (ST.computeOccupancy(MF.getFunction(), MFI.getLDSSize()) == 64881ad6265SDimitry Andric MinOccupancy) 64981ad6265SDimitry Andric break; 65081ad6265SDimitry Andric 65181ad6265SDimitry Andric // FIXME: This pass will invalidate cached MBBLiveIns for regions 65281ad6265SDimitry Andric // inbetween the defs and region we sinked the def to. Cached pressure 65381ad6265SDimitry Andric // for regions where a def is sinked from will also be invalidated. Will 65481ad6265SDimitry Andric // need to be fixed if there is another pass after this pass. 65581ad6265SDimitry Andric static_assert(LastStage == PreRARematerialize, 65681ad6265SDimitry Andric "Passes after PreRARematerialize are not supported"); 65781ad6265SDimitry Andric 65881ad6265SDimitry Andric collectRematerializableInstructions(); 65981ad6265SDimitry Andric if (RematerializableInsts.empty() || !sinkTriviallyRematInsts(ST, TII)) 66081ad6265SDimitry Andric break; 66181ad6265SDimitry Andric 66281ad6265SDimitry Andric LLVM_DEBUG( 66381ad6265SDimitry Andric dbgs() << "Retrying function scheduling with improved occupancy of " 66481ad6265SDimitry Andric << MinOccupancy << " from rematerializing\n"); 66581ad6265SDimitry Andric } 6665ffd83dbSDimitry Andric } 6675ffd83dbSDimitry Andric 6685ffd83dbSDimitry Andric if (Stage == UnclusteredReschedule) 6695ffd83dbSDimitry Andric SavedMutations.swap(Mutations); 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric for (auto Region : Regions) { 67281ad6265SDimitry Andric if (((Stage == UnclusteredReschedule || Stage == PreRARematerialize) && 67381ad6265SDimitry Andric !RescheduleRegions[RegionIdx]) || 674fe6060f1SDimitry Andric (Stage == ClusteredLowOccupancyReschedule && 675fe6060f1SDimitry Andric !RegionsWithClusters[RegionIdx] && !RegionsWithHighRP[RegionIdx])) { 676fe6060f1SDimitry Andric 677e8d8bef9SDimitry Andric ++RegionIdx; 6785ffd83dbSDimitry Andric continue; 679e8d8bef9SDimitry Andric } 6805ffd83dbSDimitry Andric 6810b57cec5SDimitry Andric RegionBegin = Region.first; 6820b57cec5SDimitry Andric RegionEnd = Region.second; 6830b57cec5SDimitry Andric 6840b57cec5SDimitry Andric if (RegionBegin->getParent() != MBB) { 6850b57cec5SDimitry Andric if (MBB) finishBlock(); 6860b57cec5SDimitry Andric MBB = RegionBegin->getParent(); 6870b57cec5SDimitry Andric startBlock(MBB); 6885ffd83dbSDimitry Andric if (Stage == InitialSchedule) 6890b57cec5SDimitry Andric computeBlockPressure(MBB); 6900b57cec5SDimitry Andric } 6910b57cec5SDimitry Andric 6920b57cec5SDimitry Andric unsigned NumRegionInstrs = std::distance(begin(), end()); 6930b57cec5SDimitry Andric enterRegion(MBB, begin(), end(), NumRegionInstrs); 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric // Skip empty scheduling regions (0 or 1 schedulable instructions). 6960b57cec5SDimitry Andric if (begin() == end() || begin() == std::prev(end())) { 6970b57cec5SDimitry Andric exitRegion(); 69881ad6265SDimitry Andric ++RegionIdx; 6990b57cec5SDimitry Andric continue; 7000b57cec5SDimitry Andric } 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n"); 7030b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << MF.getName() << ":" << printMBBReference(*MBB) << " " 7040b57cec5SDimitry Andric << MBB->getName() << "\n From: " << *begin() 7050b57cec5SDimitry Andric << " To: "; 7060b57cec5SDimitry Andric if (RegionEnd != MBB->end()) dbgs() << *RegionEnd; 7070b57cec5SDimitry Andric else dbgs() << "End"; 7080b57cec5SDimitry Andric dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n'); 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric schedule(); 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric exitRegion(); 7130b57cec5SDimitry Andric ++RegionIdx; 7140b57cec5SDimitry Andric } 7150b57cec5SDimitry Andric finishBlock(); 7160b57cec5SDimitry Andric 7175ffd83dbSDimitry Andric if (Stage == UnclusteredReschedule) 7185ffd83dbSDimitry Andric SavedMutations.swap(Mutations); 7195ffd83dbSDimitry Andric } while (Stage != LastStage); 7200b57cec5SDimitry Andric } 72181ad6265SDimitry Andric 72281ad6265SDimitry Andric void GCNScheduleDAGMILive::collectRematerializableInstructions() { 72381ad6265SDimitry Andric const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo *>(TRI); 72481ad6265SDimitry Andric for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { 72581ad6265SDimitry Andric Register Reg = Register::index2VirtReg(I); 72681ad6265SDimitry Andric if (!LIS->hasInterval(Reg)) 72781ad6265SDimitry Andric continue; 72881ad6265SDimitry Andric 72981ad6265SDimitry Andric // TODO: Handle AGPR and SGPR rematerialization 73081ad6265SDimitry Andric if (!SRI->isVGPRClass(MRI.getRegClass(Reg)) || !MRI.hasOneDef(Reg) || 73181ad6265SDimitry Andric !MRI.hasOneNonDBGUse(Reg)) 73281ad6265SDimitry Andric continue; 73381ad6265SDimitry Andric 73481ad6265SDimitry Andric MachineOperand *Op = MRI.getOneDef(Reg); 73581ad6265SDimitry Andric MachineInstr *Def = Op->getParent(); 736*fcaf7f86SDimitry Andric if (Op->getSubReg() != 0 || !isTriviallyReMaterializable(*Def)) 73781ad6265SDimitry Andric continue; 73881ad6265SDimitry Andric 73981ad6265SDimitry Andric MachineInstr *UseI = &*MRI.use_instr_nodbg_begin(Reg); 74081ad6265SDimitry Andric if (Def->getParent() == UseI->getParent()) 74181ad6265SDimitry Andric continue; 74281ad6265SDimitry Andric 74381ad6265SDimitry Andric // We are only collecting defs that are defined in another block and are 74481ad6265SDimitry Andric // live-through or used inside regions at MinOccupancy. This means that the 74581ad6265SDimitry Andric // register must be in the live-in set for the region. 74681ad6265SDimitry Andric bool AddedToRematList = false; 74781ad6265SDimitry Andric for (unsigned I = 0, E = Regions.size(); I != E; ++I) { 74881ad6265SDimitry Andric auto It = LiveIns[I].find(Reg); 74981ad6265SDimitry Andric if (It != LiveIns[I].end() && !It->second.none()) { 75081ad6265SDimitry Andric if (RegionsWithMinOcc[I]) { 75181ad6265SDimitry Andric RematerializableInsts[I][Def] = UseI; 75281ad6265SDimitry Andric AddedToRematList = true; 75381ad6265SDimitry Andric } 75481ad6265SDimitry Andric 75581ad6265SDimitry Andric // Collect regions with rematerializable reg as live-in to avoid 75681ad6265SDimitry Andric // searching later when updating RP. 75781ad6265SDimitry Andric RematDefToLiveInRegions[Def].push_back(I); 75881ad6265SDimitry Andric } 75981ad6265SDimitry Andric } 76081ad6265SDimitry Andric if (!AddedToRematList) 76181ad6265SDimitry Andric RematDefToLiveInRegions.erase(Def); 76281ad6265SDimitry Andric } 76381ad6265SDimitry Andric } 76481ad6265SDimitry Andric 76581ad6265SDimitry Andric bool GCNScheduleDAGMILive::sinkTriviallyRematInsts(const GCNSubtarget &ST, 76681ad6265SDimitry Andric const TargetInstrInfo *TII) { 76781ad6265SDimitry Andric // Temporary copies of cached variables we will be modifying and replacing if 76881ad6265SDimitry Andric // sinking succeeds. 76981ad6265SDimitry Andric SmallVector< 77081ad6265SDimitry Andric std::pair<MachineBasicBlock::iterator, MachineBasicBlock::iterator>, 32> 77181ad6265SDimitry Andric NewRegions; 77281ad6265SDimitry Andric DenseMap<unsigned, GCNRPTracker::LiveRegSet> NewLiveIns; 77381ad6265SDimitry Andric DenseMap<unsigned, GCNRegPressure> NewPressure; 77481ad6265SDimitry Andric BitVector NewRescheduleRegions; 77581ad6265SDimitry Andric 77681ad6265SDimitry Andric NewRegions.resize(Regions.size()); 77781ad6265SDimitry Andric NewRescheduleRegions.resize(Regions.size()); 77881ad6265SDimitry Andric 77981ad6265SDimitry Andric // Collect only regions that has a rematerializable def as a live-in. 78081ad6265SDimitry Andric SmallSet<unsigned, 16> ImpactedRegions; 78181ad6265SDimitry Andric for (const auto &It : RematDefToLiveInRegions) 78281ad6265SDimitry Andric ImpactedRegions.insert(It.second.begin(), It.second.end()); 78381ad6265SDimitry Andric 78481ad6265SDimitry Andric // Make copies of register pressure and live-ins cache that will be updated 78581ad6265SDimitry Andric // as we rematerialize. 78681ad6265SDimitry Andric for (auto Idx : ImpactedRegions) { 78781ad6265SDimitry Andric NewPressure[Idx] = Pressure[Idx]; 78881ad6265SDimitry Andric NewLiveIns[Idx] = LiveIns[Idx]; 78981ad6265SDimitry Andric } 79081ad6265SDimitry Andric NewRegions = Regions; 79181ad6265SDimitry Andric NewRescheduleRegions.reset(); 79281ad6265SDimitry Andric 79381ad6265SDimitry Andric DenseMap<MachineInstr *, MachineInstr *> InsertedMIToOldDef; 79481ad6265SDimitry Andric bool Improved = false; 79581ad6265SDimitry Andric for (auto I : ImpactedRegions) { 79681ad6265SDimitry Andric if (!RegionsWithMinOcc[I]) 79781ad6265SDimitry Andric continue; 79881ad6265SDimitry Andric 79981ad6265SDimitry Andric Improved = false; 80081ad6265SDimitry Andric int VGPRUsage = NewPressure[I].getVGPRNum(ST.hasGFX90AInsts()); 80181ad6265SDimitry Andric int SGPRUsage = NewPressure[I].getSGPRNum(); 80281ad6265SDimitry Andric 80381ad6265SDimitry Andric // TODO: Handle occupancy drop due to AGPR and SGPR. 80481ad6265SDimitry Andric // Check if cause of occupancy drop is due to VGPR usage and not SGPR. 80581ad6265SDimitry Andric if (ST.getOccupancyWithNumSGPRs(SGPRUsage) == MinOccupancy) 80681ad6265SDimitry Andric break; 80781ad6265SDimitry Andric 80881ad6265SDimitry Andric // The occupancy of this region could have been improved by a previous 80981ad6265SDimitry Andric // iteration's sinking of defs. 81081ad6265SDimitry Andric if (NewPressure[I].getOccupancy(ST) > MinOccupancy) { 81181ad6265SDimitry Andric NewRescheduleRegions[I] = true; 81281ad6265SDimitry Andric Improved = true; 81381ad6265SDimitry Andric continue; 81481ad6265SDimitry Andric } 81581ad6265SDimitry Andric 81681ad6265SDimitry Andric // First check if we have enough trivially rematerializable instructions to 81781ad6265SDimitry Andric // improve occupancy. Optimistically assume all instructions we are able to 81881ad6265SDimitry Andric // sink decreased RP. 81981ad6265SDimitry Andric int TotalSinkableRegs = 0; 82081ad6265SDimitry Andric for (const auto &It : RematerializableInsts[I]) { 82181ad6265SDimitry Andric MachineInstr *Def = It.first; 82281ad6265SDimitry Andric Register DefReg = Def->getOperand(0).getReg(); 82381ad6265SDimitry Andric TotalSinkableRegs += 82481ad6265SDimitry Andric SIRegisterInfo::getNumCoveredRegs(NewLiveIns[I][DefReg]); 82581ad6265SDimitry Andric } 82681ad6265SDimitry Andric int VGPRsAfterSink = VGPRUsage - TotalSinkableRegs; 82781ad6265SDimitry Andric unsigned OptimisticOccupancy = ST.getOccupancyWithNumVGPRs(VGPRsAfterSink); 82881ad6265SDimitry Andric // If in the most optimistic scenario, we cannot improve occupancy, then do 82981ad6265SDimitry Andric // not attempt to sink any instructions. 83081ad6265SDimitry Andric if (OptimisticOccupancy <= MinOccupancy) 83181ad6265SDimitry Andric break; 83281ad6265SDimitry Andric 83381ad6265SDimitry Andric unsigned ImproveOccupancy = 0; 83481ad6265SDimitry Andric SmallVector<MachineInstr *, 4> SinkedDefs; 83581ad6265SDimitry Andric for (auto &It : RematerializableInsts[I]) { 83681ad6265SDimitry Andric MachineInstr *Def = It.first; 83781ad6265SDimitry Andric MachineBasicBlock::iterator InsertPos = 83881ad6265SDimitry Andric MachineBasicBlock::iterator(It.second); 83981ad6265SDimitry Andric Register Reg = Def->getOperand(0).getReg(); 84081ad6265SDimitry Andric // Rematerialize MI to its use block. Since we are only rematerializing 84181ad6265SDimitry Andric // instructions that do not have any virtual reg uses, we do not need to 84281ad6265SDimitry Andric // call LiveRangeEdit::allUsesAvailableAt() and 84381ad6265SDimitry Andric // LiveRangeEdit::canRematerializeAt(). 84481ad6265SDimitry Andric TII->reMaterialize(*InsertPos->getParent(), InsertPos, Reg, 84581ad6265SDimitry Andric Def->getOperand(0).getSubReg(), *Def, *TRI); 84681ad6265SDimitry Andric MachineInstr *NewMI = &*(--InsertPos); 84781ad6265SDimitry Andric LIS->InsertMachineInstrInMaps(*NewMI); 84881ad6265SDimitry Andric LIS->removeInterval(Reg); 84981ad6265SDimitry Andric LIS->createAndComputeVirtRegInterval(Reg); 85081ad6265SDimitry Andric InsertedMIToOldDef[NewMI] = Def; 85181ad6265SDimitry Andric 85281ad6265SDimitry Andric // Update region boundaries in scheduling region we sinked from since we 85381ad6265SDimitry Andric // may sink an instruction that was at the beginning or end of its region 85481ad6265SDimitry Andric updateRegionBoundaries(NewRegions, Def, /*NewMI =*/nullptr, 85581ad6265SDimitry Andric /*Removing =*/true); 85681ad6265SDimitry Andric 85781ad6265SDimitry Andric // Update region boundaries in region we sinked to. 85881ad6265SDimitry Andric updateRegionBoundaries(NewRegions, InsertPos, NewMI); 85981ad6265SDimitry Andric 86081ad6265SDimitry Andric LaneBitmask PrevMask = NewLiveIns[I][Reg]; 86181ad6265SDimitry Andric // FIXME: Also update cached pressure for where the def was sinked from. 86281ad6265SDimitry Andric // Update RP for all regions that has this reg as a live-in and remove 86381ad6265SDimitry Andric // the reg from all regions as a live-in. 86481ad6265SDimitry Andric for (auto Idx : RematDefToLiveInRegions[Def]) { 86581ad6265SDimitry Andric NewLiveIns[Idx].erase(Reg); 86681ad6265SDimitry Andric if (InsertPos->getParent() != Regions[Idx].first->getParent()) { 86781ad6265SDimitry Andric // Def is live-through and not used in this block. 86881ad6265SDimitry Andric NewPressure[Idx].inc(Reg, PrevMask, LaneBitmask::getNone(), MRI); 86981ad6265SDimitry Andric } else { 87081ad6265SDimitry Andric // Def is used and rematerialized into this block. 87181ad6265SDimitry Andric GCNDownwardRPTracker RPT(*LIS); 87281ad6265SDimitry Andric auto *NonDbgMI = &*skipDebugInstructionsForward( 87381ad6265SDimitry Andric NewRegions[Idx].first, NewRegions[Idx].second); 87481ad6265SDimitry Andric RPT.reset(*NonDbgMI, &NewLiveIns[Idx]); 87581ad6265SDimitry Andric RPT.advance(NewRegions[Idx].second); 87681ad6265SDimitry Andric NewPressure[Idx] = RPT.moveMaxPressure(); 87781ad6265SDimitry Andric } 87881ad6265SDimitry Andric } 87981ad6265SDimitry Andric 88081ad6265SDimitry Andric SinkedDefs.push_back(Def); 88181ad6265SDimitry Andric ImproveOccupancy = NewPressure[I].getOccupancy(ST); 88281ad6265SDimitry Andric if (ImproveOccupancy > MinOccupancy) 88381ad6265SDimitry Andric break; 88481ad6265SDimitry Andric } 88581ad6265SDimitry Andric 88681ad6265SDimitry Andric // Remove defs we just sinked from all regions' list of sinkable defs 88781ad6265SDimitry Andric for (auto &Def : SinkedDefs) 88881ad6265SDimitry Andric for (auto TrackedIdx : RematDefToLiveInRegions[Def]) 88981ad6265SDimitry Andric RematerializableInsts[TrackedIdx].erase(Def); 89081ad6265SDimitry Andric 89181ad6265SDimitry Andric if (ImproveOccupancy <= MinOccupancy) 89281ad6265SDimitry Andric break; 89381ad6265SDimitry Andric 89481ad6265SDimitry Andric NewRescheduleRegions[I] = true; 89581ad6265SDimitry Andric Improved = true; 89681ad6265SDimitry Andric } 89781ad6265SDimitry Andric 89881ad6265SDimitry Andric if (!Improved) { 89981ad6265SDimitry Andric // Occupancy was not improved for all regions that were at MinOccupancy. 90081ad6265SDimitry Andric // Undo sinking and remove newly rematerialized instructions. 90181ad6265SDimitry Andric for (auto &Entry : InsertedMIToOldDef) { 90281ad6265SDimitry Andric MachineInstr *MI = Entry.first; 90381ad6265SDimitry Andric MachineInstr *OldMI = Entry.second; 90481ad6265SDimitry Andric Register Reg = MI->getOperand(0).getReg(); 90581ad6265SDimitry Andric LIS->RemoveMachineInstrFromMaps(*MI); 90681ad6265SDimitry Andric MI->eraseFromParent(); 90781ad6265SDimitry Andric OldMI->clearRegisterDeads(Reg); 90881ad6265SDimitry Andric LIS->removeInterval(Reg); 90981ad6265SDimitry Andric LIS->createAndComputeVirtRegInterval(Reg); 91081ad6265SDimitry Andric } 91181ad6265SDimitry Andric return false; 91281ad6265SDimitry Andric } 91381ad6265SDimitry Andric 91481ad6265SDimitry Andric // Occupancy was improved for all regions. 91581ad6265SDimitry Andric for (auto &Entry : InsertedMIToOldDef) { 91681ad6265SDimitry Andric MachineInstr *MI = Entry.first; 91781ad6265SDimitry Andric MachineInstr *OldMI = Entry.second; 91881ad6265SDimitry Andric 91981ad6265SDimitry Andric // Remove OldMI from BBLiveInMap since we are sinking it from its MBB. 92081ad6265SDimitry Andric BBLiveInMap.erase(OldMI); 92181ad6265SDimitry Andric 92281ad6265SDimitry Andric // Remove OldMI and update LIS 92381ad6265SDimitry Andric Register Reg = MI->getOperand(0).getReg(); 92481ad6265SDimitry Andric LIS->RemoveMachineInstrFromMaps(*OldMI); 92581ad6265SDimitry Andric OldMI->eraseFromParent(); 92681ad6265SDimitry Andric LIS->removeInterval(Reg); 92781ad6265SDimitry Andric LIS->createAndComputeVirtRegInterval(Reg); 92881ad6265SDimitry Andric } 92981ad6265SDimitry Andric 93081ad6265SDimitry Andric // Update live-ins, register pressure, and regions caches. 93181ad6265SDimitry Andric for (auto Idx : ImpactedRegions) { 93281ad6265SDimitry Andric LiveIns[Idx] = NewLiveIns[Idx]; 93381ad6265SDimitry Andric Pressure[Idx] = NewPressure[Idx]; 93481ad6265SDimitry Andric MBBLiveIns.erase(Regions[Idx].first->getParent()); 93581ad6265SDimitry Andric } 93681ad6265SDimitry Andric Regions = NewRegions; 93781ad6265SDimitry Andric RescheduleRegions = NewRescheduleRegions; 93881ad6265SDimitry Andric 93981ad6265SDimitry Andric SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>(); 94081ad6265SDimitry Andric MFI.increaseOccupancy(MF, ++MinOccupancy); 94181ad6265SDimitry Andric 94281ad6265SDimitry Andric return true; 94381ad6265SDimitry Andric } 94481ad6265SDimitry Andric 94581ad6265SDimitry Andric // Copied from MachineLICM 946*fcaf7f86SDimitry Andric bool GCNScheduleDAGMILive::isTriviallyReMaterializable(const MachineInstr &MI) { 947*fcaf7f86SDimitry Andric if (!TII->isTriviallyReMaterializable(MI)) 94881ad6265SDimitry Andric return false; 94981ad6265SDimitry Andric 95081ad6265SDimitry Andric for (const MachineOperand &MO : MI.operands()) 95181ad6265SDimitry Andric if (MO.isReg() && MO.isUse() && MO.getReg().isVirtual()) 95281ad6265SDimitry Andric return false; 95381ad6265SDimitry Andric 95481ad6265SDimitry Andric return true; 95581ad6265SDimitry Andric } 95681ad6265SDimitry Andric 95781ad6265SDimitry Andric // When removing, we will have to check both beginning and ending of the region. 95881ad6265SDimitry Andric // When inserting, we will only have to check if we are inserting NewMI in front 95981ad6265SDimitry Andric // of a scheduling region and do not need to check the ending since we will only 96081ad6265SDimitry Andric // ever be inserting before an already existing MI. 96181ad6265SDimitry Andric void GCNScheduleDAGMILive::updateRegionBoundaries( 96281ad6265SDimitry Andric SmallVectorImpl<std::pair<MachineBasicBlock::iterator, 96381ad6265SDimitry Andric MachineBasicBlock::iterator>> &RegionBoundaries, 96481ad6265SDimitry Andric MachineBasicBlock::iterator MI, MachineInstr *NewMI, bool Removing) { 96581ad6265SDimitry Andric unsigned I = 0, E = RegionBoundaries.size(); 96681ad6265SDimitry Andric // Search for first region of the block where MI is located 96781ad6265SDimitry Andric while (I != E && MI->getParent() != RegionBoundaries[I].first->getParent()) 96881ad6265SDimitry Andric ++I; 96981ad6265SDimitry Andric 97081ad6265SDimitry Andric for (; I != E; ++I) { 97181ad6265SDimitry Andric if (MI->getParent() != RegionBoundaries[I].first->getParent()) 97281ad6265SDimitry Andric return; 97381ad6265SDimitry Andric 97481ad6265SDimitry Andric if (Removing && MI == RegionBoundaries[I].first && 97581ad6265SDimitry Andric MI == RegionBoundaries[I].second) { 97681ad6265SDimitry Andric // MI is in a region with size 1, after removing, the region will be 97781ad6265SDimitry Andric // size 0, set RegionBegin and RegionEnd to pass end of block iterator. 97881ad6265SDimitry Andric RegionBoundaries[I] = 97981ad6265SDimitry Andric std::make_pair(MI->getParent()->end(), MI->getParent()->end()); 98081ad6265SDimitry Andric return; 98181ad6265SDimitry Andric } 98281ad6265SDimitry Andric if (MI == RegionBoundaries[I].first) { 98381ad6265SDimitry Andric if (Removing) 98481ad6265SDimitry Andric RegionBoundaries[I] = 98581ad6265SDimitry Andric std::make_pair(std::next(MI), RegionBoundaries[I].second); 98681ad6265SDimitry Andric else 98781ad6265SDimitry Andric // Inserted NewMI in front of region, set new RegionBegin to NewMI 98881ad6265SDimitry Andric RegionBoundaries[I] = std::make_pair(MachineBasicBlock::iterator(NewMI), 98981ad6265SDimitry Andric RegionBoundaries[I].second); 99081ad6265SDimitry Andric return; 99181ad6265SDimitry Andric } 99281ad6265SDimitry Andric if (Removing && MI == RegionBoundaries[I].second) { 99381ad6265SDimitry Andric RegionBoundaries[I] = 99481ad6265SDimitry Andric std::make_pair(RegionBoundaries[I].first, std::prev(MI)); 99581ad6265SDimitry Andric return; 99681ad6265SDimitry Andric } 99781ad6265SDimitry Andric } 99881ad6265SDimitry Andric } 999