10b57cec5SDimitry Andric //===- GCNRegPressure.cpp -------------------------------------------------===// 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 //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric /// 95ffd83dbSDimitry Andric /// \file 105ffd83dbSDimitry Andric /// This file implements the GCNRegPressure class. 115ffd83dbSDimitry Andric /// 125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "GCNRegPressure.h" 15*5f757f3fSDimitry Andric #include "AMDGPU.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric using namespace llvm; 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric bool llvm::isEqual(const GCNRPTracker::LiveRegSet &S1, 230b57cec5SDimitry Andric const GCNRPTracker::LiveRegSet &S2) { 240b57cec5SDimitry Andric if (S1.size() != S2.size()) 250b57cec5SDimitry Andric return false; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric for (const auto &P : S1) { 280b57cec5SDimitry Andric auto I = S2.find(P.first); 290b57cec5SDimitry Andric if (I == S2.end() || I->second != P.second) 300b57cec5SDimitry Andric return false; 310b57cec5SDimitry Andric } 320b57cec5SDimitry Andric return true; 330b57cec5SDimitry Andric } 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric /////////////////////////////////////////////////////////////////////////////// 360b57cec5SDimitry Andric // GCNRegPressure 370b57cec5SDimitry Andric 38e8d8bef9SDimitry Andric unsigned GCNRegPressure::getRegKind(Register Reg, 390b57cec5SDimitry Andric const MachineRegisterInfo &MRI) { 40e8d8bef9SDimitry Andric assert(Reg.isVirtual()); 410b57cec5SDimitry Andric const auto RC = MRI.getRegClass(Reg); 420b57cec5SDimitry Andric auto STI = static_cast<const SIRegisterInfo*>(MRI.getTargetRegisterInfo()); 434824e7fdSDimitry Andric return STI->isSGPRClass(RC) 444824e7fdSDimitry Andric ? (STI->getRegSizeInBits(*RC) == 32 ? SGPR32 : SGPR_TUPLE) 454824e7fdSDimitry Andric : STI->isAGPRClass(RC) 464824e7fdSDimitry Andric ? (STI->getRegSizeInBits(*RC) == 32 ? AGPR32 : AGPR_TUPLE) 474824e7fdSDimitry Andric : (STI->getRegSizeInBits(*RC) == 32 ? VGPR32 : VGPR_TUPLE); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric void GCNRegPressure::inc(unsigned Reg, 510b57cec5SDimitry Andric LaneBitmask PrevMask, 520b57cec5SDimitry Andric LaneBitmask NewMask, 530b57cec5SDimitry Andric const MachineRegisterInfo &MRI) { 545ffd83dbSDimitry Andric if (SIRegisterInfo::getNumCoveredRegs(NewMask) == 555ffd83dbSDimitry Andric SIRegisterInfo::getNumCoveredRegs(PrevMask)) 560b57cec5SDimitry Andric return; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric int Sign = 1; 590b57cec5SDimitry Andric if (NewMask < PrevMask) { 600b57cec5SDimitry Andric std::swap(NewMask, PrevMask); 610b57cec5SDimitry Andric Sign = -1; 620b57cec5SDimitry Andric } 635ffd83dbSDimitry Andric 640b57cec5SDimitry Andric switch (auto Kind = getRegKind(Reg, MRI)) { 650b57cec5SDimitry Andric case SGPR32: 660b57cec5SDimitry Andric case VGPR32: 670b57cec5SDimitry Andric case AGPR32: 680b57cec5SDimitry Andric Value[Kind] += Sign; 690b57cec5SDimitry Andric break; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric case SGPR_TUPLE: 720b57cec5SDimitry Andric case VGPR_TUPLE: 730b57cec5SDimitry Andric case AGPR_TUPLE: 740b57cec5SDimitry Andric assert(PrevMask < NewMask); 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric Value[Kind == SGPR_TUPLE ? SGPR32 : Kind == AGPR_TUPLE ? AGPR32 : VGPR32] += 775ffd83dbSDimitry Andric Sign * SIRegisterInfo::getNumCoveredRegs(~PrevMask & NewMask); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric if (PrevMask.none()) { 800b57cec5SDimitry Andric assert(NewMask.any()); 81*5f757f3fSDimitry Andric const TargetRegisterInfo *TRI = MRI.getTargetRegisterInfo(); 82*5f757f3fSDimitry Andric Value[Kind] += 83*5f757f3fSDimitry Andric Sign * TRI->getRegClassWeight(MRI.getRegClass(Reg)).RegWeight; 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric break; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric default: llvm_unreachable("Unknown register kind"); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric bool GCNRegPressure::less(const GCNSubtarget &ST, 920b57cec5SDimitry Andric const GCNRegPressure& O, 930b57cec5SDimitry Andric unsigned MaxOccupancy) const { 940b57cec5SDimitry Andric const auto SGPROcc = std::min(MaxOccupancy, 950b57cec5SDimitry Andric ST.getOccupancyWithNumSGPRs(getSGPRNum())); 96fe6060f1SDimitry Andric const auto VGPROcc = 97fe6060f1SDimitry Andric std::min(MaxOccupancy, 98fe6060f1SDimitry Andric ST.getOccupancyWithNumVGPRs(getVGPRNum(ST.hasGFX90AInsts()))); 990b57cec5SDimitry Andric const auto OtherSGPROcc = std::min(MaxOccupancy, 1000b57cec5SDimitry Andric ST.getOccupancyWithNumSGPRs(O.getSGPRNum())); 101fe6060f1SDimitry Andric const auto OtherVGPROcc = 102fe6060f1SDimitry Andric std::min(MaxOccupancy, 103fe6060f1SDimitry Andric ST.getOccupancyWithNumVGPRs(O.getVGPRNum(ST.hasGFX90AInsts()))); 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric const auto Occ = std::min(SGPROcc, VGPROcc); 1060b57cec5SDimitry Andric const auto OtherOcc = std::min(OtherSGPROcc, OtherVGPROcc); 1070b57cec5SDimitry Andric if (Occ != OtherOcc) 1080b57cec5SDimitry Andric return Occ > OtherOcc; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric bool SGPRImportant = SGPROcc < VGPROcc; 1110b57cec5SDimitry Andric const bool OtherSGPRImportant = OtherSGPROcc < OtherVGPROcc; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric // if both pressures disagree on what is more important compare vgprs 1140b57cec5SDimitry Andric if (SGPRImportant != OtherSGPRImportant) { 1150b57cec5SDimitry Andric SGPRImportant = false; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric // compare large regs pressure 1190b57cec5SDimitry Andric bool SGPRFirst = SGPRImportant; 1200b57cec5SDimitry Andric for (int I = 2; I > 0; --I, SGPRFirst = !SGPRFirst) { 1210b57cec5SDimitry Andric if (SGPRFirst) { 1220b57cec5SDimitry Andric auto SW = getSGPRTuplesWeight(); 1230b57cec5SDimitry Andric auto OtherSW = O.getSGPRTuplesWeight(); 1240b57cec5SDimitry Andric if (SW != OtherSW) 1250b57cec5SDimitry Andric return SW < OtherSW; 1260b57cec5SDimitry Andric } else { 1270b57cec5SDimitry Andric auto VW = getVGPRTuplesWeight(); 1280b57cec5SDimitry Andric auto OtherVW = O.getVGPRTuplesWeight(); 1290b57cec5SDimitry Andric if (VW != OtherVW) 1300b57cec5SDimitry Andric return VW < OtherVW; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric return SGPRImportant ? (getSGPRNum() < O.getSGPRNum()): 134fe6060f1SDimitry Andric (getVGPRNum(ST.hasGFX90AInsts()) < 135fe6060f1SDimitry Andric O.getVGPRNum(ST.hasGFX90AInsts())); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 138bdd1243dSDimitry Andric Printable llvm::print(const GCNRegPressure &RP, const GCNSubtarget *ST) { 139bdd1243dSDimitry Andric return Printable([&RP, ST](raw_ostream &OS) { 140bdd1243dSDimitry Andric OS << "VGPRs: " << RP.Value[GCNRegPressure::VGPR32] << ' ' 141bdd1243dSDimitry Andric << "AGPRs: " << RP.getAGPRNum(); 142bdd1243dSDimitry Andric if (ST) 143bdd1243dSDimitry Andric OS << "(O" 144bdd1243dSDimitry Andric << ST->getOccupancyWithNumVGPRs(RP.getVGPRNum(ST->hasGFX90AInsts())) 145fe6060f1SDimitry Andric << ')'; 146bdd1243dSDimitry Andric OS << ", SGPRs: " << RP.getSGPRNum(); 147bdd1243dSDimitry Andric if (ST) 148bdd1243dSDimitry Andric OS << "(O" << ST->getOccupancyWithNumSGPRs(RP.getSGPRNum()) << ')'; 149bdd1243dSDimitry Andric OS << ", LVGPR WT: " << RP.getVGPRTuplesWeight() 150bdd1243dSDimitry Andric << ", LSGPR WT: " << RP.getSGPRTuplesWeight(); 151bdd1243dSDimitry Andric if (ST) 152bdd1243dSDimitry Andric OS << " -> Occ: " << RP.getOccupancy(*ST); 1530b57cec5SDimitry Andric OS << '\n'; 154bdd1243dSDimitry Andric }); 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric static LaneBitmask getDefRegMask(const MachineOperand &MO, 1580b57cec5SDimitry Andric const MachineRegisterInfo &MRI) { 159e8d8bef9SDimitry Andric assert(MO.isDef() && MO.isReg() && MO.getReg().isVirtual()); 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric // We don't rely on read-undef flag because in case of tentative schedule 1620b57cec5SDimitry Andric // tracking it isn't set correctly yet. This works correctly however since 1630b57cec5SDimitry Andric // use mask has been tracked before using LIS. 1640b57cec5SDimitry Andric return MO.getSubReg() == 0 ? 1650b57cec5SDimitry Andric MRI.getMaxLaneMaskForVReg(MO.getReg()) : 1660b57cec5SDimitry Andric MRI.getTargetRegisterInfo()->getSubRegIndexLaneMask(MO.getSubReg()); 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 169*5f757f3fSDimitry Andric static void 170*5f757f3fSDimitry Andric collectVirtualRegUses(SmallVectorImpl<RegisterMaskPair> &RegMaskPairs, 171*5f757f3fSDimitry Andric const MachineInstr &MI, const LiveIntervals &LIS, 1720b57cec5SDimitry Andric const MachineRegisterInfo &MRI) { 173*5f757f3fSDimitry Andric SlotIndex InstrSI; 1740b57cec5SDimitry Andric for (const auto &MO : MI.operands()) { 175e8d8bef9SDimitry Andric if (!MO.isReg() || !MO.getReg().isVirtual()) 1760b57cec5SDimitry Andric continue; 1770b57cec5SDimitry Andric if (!MO.isUse() || !MO.readsReg()) 1780b57cec5SDimitry Andric continue; 1790b57cec5SDimitry Andric 180*5f757f3fSDimitry Andric Register Reg = MO.getReg(); 181*5f757f3fSDimitry Andric if (llvm::any_of(RegMaskPairs, [Reg](const RegisterMaskPair &RM) { 182*5f757f3fSDimitry Andric return RM.RegUnit == Reg; 183*5f757f3fSDimitry Andric })) 184*5f757f3fSDimitry Andric continue; 1850b57cec5SDimitry Andric 186*5f757f3fSDimitry Andric LaneBitmask UseMask; 187*5f757f3fSDimitry Andric auto &LI = LIS.getInterval(Reg); 188*5f757f3fSDimitry Andric if (!LI.hasSubRanges()) 189*5f757f3fSDimitry Andric UseMask = MRI.getMaxLaneMaskForVReg(Reg); 190*5f757f3fSDimitry Andric else { 191*5f757f3fSDimitry Andric // For a tentative schedule LIS isn't updated yet but livemask should 192*5f757f3fSDimitry Andric // remain the same on any schedule. Subreg defs can be reordered but they 193*5f757f3fSDimitry Andric // all must dominate uses anyway. 194*5f757f3fSDimitry Andric if (!InstrSI) 195*5f757f3fSDimitry Andric InstrSI = LIS.getInstructionIndex(*MO.getParent()).getBaseIndex(); 196*5f757f3fSDimitry Andric UseMask = getLiveLaneMask(LI, InstrSI, MRI); 1970b57cec5SDimitry Andric } 198*5f757f3fSDimitry Andric 199*5f757f3fSDimitry Andric RegMaskPairs.emplace_back(Reg, UseMask); 200*5f757f3fSDimitry Andric } 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric /////////////////////////////////////////////////////////////////////////////// 2040b57cec5SDimitry Andric // GCNRPTracker 2050b57cec5SDimitry Andric 206*5f757f3fSDimitry Andric LaneBitmask llvm::getLiveLaneMask(unsigned Reg, SlotIndex SI, 2070b57cec5SDimitry Andric const LiveIntervals &LIS, 2080b57cec5SDimitry Andric const MachineRegisterInfo &MRI) { 209*5f757f3fSDimitry Andric return getLiveLaneMask(LIS.getInterval(Reg), SI, MRI); 210*5f757f3fSDimitry Andric } 211*5f757f3fSDimitry Andric 212*5f757f3fSDimitry Andric LaneBitmask llvm::getLiveLaneMask(const LiveInterval &LI, SlotIndex SI, 213*5f757f3fSDimitry Andric const MachineRegisterInfo &MRI) { 2140b57cec5SDimitry Andric LaneBitmask LiveMask; 2150b57cec5SDimitry Andric if (LI.hasSubRanges()) { 2160b57cec5SDimitry Andric for (const auto &S : LI.subranges()) 2170b57cec5SDimitry Andric if (S.liveAt(SI)) { 2180b57cec5SDimitry Andric LiveMask |= S.LaneMask; 219*5f757f3fSDimitry Andric assert(LiveMask == (LiveMask & MRI.getMaxLaneMaskForVReg(LI.reg()))); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric } else if (LI.liveAt(SI)) { 222*5f757f3fSDimitry Andric LiveMask = MRI.getMaxLaneMaskForVReg(LI.reg()); 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric return LiveMask; 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric GCNRPTracker::LiveRegSet llvm::getLiveRegs(SlotIndex SI, 2280b57cec5SDimitry Andric const LiveIntervals &LIS, 2290b57cec5SDimitry Andric const MachineRegisterInfo &MRI) { 2300b57cec5SDimitry Andric GCNRPTracker::LiveRegSet LiveRegs; 2310b57cec5SDimitry Andric for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { 2328bcb0991SDimitry Andric auto Reg = Register::index2VirtReg(I); 2330b57cec5SDimitry Andric if (!LIS.hasInterval(Reg)) 2340b57cec5SDimitry Andric continue; 2350b57cec5SDimitry Andric auto LiveMask = getLiveLaneMask(Reg, SI, LIS, MRI); 2360b57cec5SDimitry Andric if (LiveMask.any()) 2370b57cec5SDimitry Andric LiveRegs[Reg] = LiveMask; 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric return LiveRegs; 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric void GCNRPTracker::reset(const MachineInstr &MI, 2430b57cec5SDimitry Andric const LiveRegSet *LiveRegsCopy, 2440b57cec5SDimitry Andric bool After) { 2450b57cec5SDimitry Andric const MachineFunction &MF = *MI.getMF(); 2460b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 2470b57cec5SDimitry Andric if (LiveRegsCopy) { 2480b57cec5SDimitry Andric if (&LiveRegs != LiveRegsCopy) 2490b57cec5SDimitry Andric LiveRegs = *LiveRegsCopy; 2500b57cec5SDimitry Andric } else { 2510b57cec5SDimitry Andric LiveRegs = After ? getLiveRegsAfter(MI, LIS) 2520b57cec5SDimitry Andric : getLiveRegsBefore(MI, LIS); 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric MaxPressure = CurPressure = getRegPressure(*MRI, LiveRegs); 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 258*5f757f3fSDimitry Andric //////////////////////////////////////////////////////////////////////////////// 259*5f757f3fSDimitry Andric // GCNUpwardRPTracker 260*5f757f3fSDimitry Andric 261*5f757f3fSDimitry Andric void GCNUpwardRPTracker::reset(const MachineRegisterInfo &MRI_, 262*5f757f3fSDimitry Andric const LiveRegSet &LiveRegs_) { 263*5f757f3fSDimitry Andric MRI = &MRI_; 264*5f757f3fSDimitry Andric LiveRegs = LiveRegs_; 265*5f757f3fSDimitry Andric LastTrackedMI = nullptr; 266*5f757f3fSDimitry Andric MaxPressure = CurPressure = getRegPressure(MRI_, LiveRegs_); 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric void GCNUpwardRPTracker::recede(const MachineInstr &MI) { 2700b57cec5SDimitry Andric assert(MRI && "call reset first"); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric LastTrackedMI = &MI; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric if (MI.isDebugInstr()) 2750b57cec5SDimitry Andric return; 2760b57cec5SDimitry Andric 277*5f757f3fSDimitry Andric // Kill all defs. 278*5f757f3fSDimitry Andric GCNRegPressure DefPressure, ECDefPressure; 279*5f757f3fSDimitry Andric bool HasECDefs = false; 280*5f757f3fSDimitry Andric for (const MachineOperand &MO : MI.all_defs()) { 281*5f757f3fSDimitry Andric if (!MO.getReg().isVirtual()) 2820b57cec5SDimitry Andric continue; 2830b57cec5SDimitry Andric 284*5f757f3fSDimitry Andric Register Reg = MO.getReg(); 285*5f757f3fSDimitry Andric LaneBitmask DefMask = getDefRegMask(MO, *MRI); 286*5f757f3fSDimitry Andric 287*5f757f3fSDimitry Andric // Treat a def as fully live at the moment of definition: keep a record. 288*5f757f3fSDimitry Andric if (MO.isEarlyClobber()) { 289*5f757f3fSDimitry Andric ECDefPressure.inc(Reg, LaneBitmask::getNone(), DefMask, *MRI); 290*5f757f3fSDimitry Andric HasECDefs = true; 291*5f757f3fSDimitry Andric } else 292*5f757f3fSDimitry Andric DefPressure.inc(Reg, LaneBitmask::getNone(), DefMask, *MRI); 293*5f757f3fSDimitry Andric 2940b57cec5SDimitry Andric auto I = LiveRegs.find(Reg); 2950b57cec5SDimitry Andric if (I == LiveRegs.end()) 2960b57cec5SDimitry Andric continue; 297*5f757f3fSDimitry Andric 298*5f757f3fSDimitry Andric LaneBitmask &LiveMask = I->second; 299*5f757f3fSDimitry Andric LaneBitmask PrevMask = LiveMask; 300*5f757f3fSDimitry Andric LiveMask &= ~DefMask; 3010b57cec5SDimitry Andric CurPressure.inc(Reg, PrevMask, LiveMask, *MRI); 3020b57cec5SDimitry Andric if (LiveMask.none()) 3030b57cec5SDimitry Andric LiveRegs.erase(I); 3040b57cec5SDimitry Andric } 305*5f757f3fSDimitry Andric 306*5f757f3fSDimitry Andric // Update MaxPressure with defs pressure. 307*5f757f3fSDimitry Andric DefPressure += CurPressure; 308*5f757f3fSDimitry Andric if (HasECDefs) 309*5f757f3fSDimitry Andric DefPressure += ECDefPressure; 310*5f757f3fSDimitry Andric MaxPressure = max(DefPressure, MaxPressure); 311*5f757f3fSDimitry Andric 312*5f757f3fSDimitry Andric // Make uses alive. 313*5f757f3fSDimitry Andric SmallVector<RegisterMaskPair, 8> RegUses; 314*5f757f3fSDimitry Andric collectVirtualRegUses(RegUses, MI, LIS, *MRI); 315*5f757f3fSDimitry Andric for (const RegisterMaskPair &U : RegUses) { 316*5f757f3fSDimitry Andric LaneBitmask &LiveMask = LiveRegs[U.RegUnit]; 317*5f757f3fSDimitry Andric LaneBitmask PrevMask = LiveMask; 3180b57cec5SDimitry Andric LiveMask |= U.LaneMask; 3190b57cec5SDimitry Andric CurPressure.inc(U.RegUnit, PrevMask, LiveMask, *MRI); 3200b57cec5SDimitry Andric } 321*5f757f3fSDimitry Andric 322*5f757f3fSDimitry Andric // Update MaxPressure with uses plus early-clobber defs pressure. 323*5f757f3fSDimitry Andric MaxPressure = HasECDefs ? max(CurPressure + ECDefPressure, MaxPressure) 324*5f757f3fSDimitry Andric : max(CurPressure, MaxPressure); 325*5f757f3fSDimitry Andric 3260b57cec5SDimitry Andric assert(CurPressure == getRegPressure(*MRI, LiveRegs)); 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric 329*5f757f3fSDimitry Andric //////////////////////////////////////////////////////////////////////////////// 330*5f757f3fSDimitry Andric // GCNDownwardRPTracker 331*5f757f3fSDimitry Andric 3320b57cec5SDimitry Andric bool GCNDownwardRPTracker::reset(const MachineInstr &MI, 3330b57cec5SDimitry Andric const LiveRegSet *LiveRegsCopy) { 3340b57cec5SDimitry Andric MRI = &MI.getParent()->getParent()->getRegInfo(); 3350b57cec5SDimitry Andric LastTrackedMI = nullptr; 3360b57cec5SDimitry Andric MBBEnd = MI.getParent()->end(); 3370b57cec5SDimitry Andric NextMI = &MI; 3380b57cec5SDimitry Andric NextMI = skipDebugInstructionsForward(NextMI, MBBEnd); 3390b57cec5SDimitry Andric if (NextMI == MBBEnd) 3400b57cec5SDimitry Andric return false; 3410b57cec5SDimitry Andric GCNRPTracker::reset(*NextMI, LiveRegsCopy, false); 3420b57cec5SDimitry Andric return true; 3430b57cec5SDimitry Andric } 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric bool GCNDownwardRPTracker::advanceBeforeNext() { 3460b57cec5SDimitry Andric assert(MRI && "call reset first"); 347bdd1243dSDimitry Andric if (!LastTrackedMI) 348bdd1243dSDimitry Andric return NextMI == MBBEnd; 3490b57cec5SDimitry Andric 350bdd1243dSDimitry Andric assert(NextMI == MBBEnd || !NextMI->isDebugInstr()); 3510b57cec5SDimitry Andric 352bdd1243dSDimitry Andric SlotIndex SI = NextMI == MBBEnd 353bdd1243dSDimitry Andric ? LIS.getInstructionIndex(*LastTrackedMI).getDeadSlot() 354bdd1243dSDimitry Andric : LIS.getInstructionIndex(*NextMI).getBaseIndex(); 3550b57cec5SDimitry Andric assert(SI.isValid()); 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric // Remove dead registers or mask bits. 35806c3fb27SDimitry Andric SmallSet<Register, 8> SeenRegs; 35906c3fb27SDimitry Andric for (auto &MO : LastTrackedMI->operands()) { 36006c3fb27SDimitry Andric if (!MO.isReg() || !MO.getReg().isVirtual()) 36106c3fb27SDimitry Andric continue; 36206c3fb27SDimitry Andric if (MO.isUse() && !MO.readsReg()) 36306c3fb27SDimitry Andric continue; 36406c3fb27SDimitry Andric if (!SeenRegs.insert(MO.getReg()).second) 36506c3fb27SDimitry Andric continue; 36606c3fb27SDimitry Andric const LiveInterval &LI = LIS.getInterval(MO.getReg()); 3670b57cec5SDimitry Andric if (LI.hasSubRanges()) { 36806c3fb27SDimitry Andric auto It = LiveRegs.end(); 3690b57cec5SDimitry Andric for (const auto &S : LI.subranges()) { 3700b57cec5SDimitry Andric if (!S.liveAt(SI)) { 37106c3fb27SDimitry Andric if (It == LiveRegs.end()) { 37206c3fb27SDimitry Andric It = LiveRegs.find(MO.getReg()); 37306c3fb27SDimitry Andric if (It == LiveRegs.end()) 37406c3fb27SDimitry Andric llvm_unreachable("register isn't live"); 37506c3fb27SDimitry Andric } 37606c3fb27SDimitry Andric auto PrevMask = It->second; 37706c3fb27SDimitry Andric It->second &= ~S.LaneMask; 37806c3fb27SDimitry Andric CurPressure.inc(MO.getReg(), PrevMask, It->second, *MRI); 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric } 38106c3fb27SDimitry Andric if (It != LiveRegs.end() && It->second.none()) 38206c3fb27SDimitry Andric LiveRegs.erase(It); 3830b57cec5SDimitry Andric } else if (!LI.liveAt(SI)) { 38406c3fb27SDimitry Andric auto It = LiveRegs.find(MO.getReg()); 38506c3fb27SDimitry Andric if (It == LiveRegs.end()) 38606c3fb27SDimitry Andric llvm_unreachable("register isn't live"); 38706c3fb27SDimitry Andric CurPressure.inc(MO.getReg(), It->second, LaneBitmask::getNone(), *MRI); 38806c3fb27SDimitry Andric LiveRegs.erase(It); 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric MaxPressure = max(MaxPressure, CurPressure); 3930b57cec5SDimitry Andric 394bdd1243dSDimitry Andric LastTrackedMI = nullptr; 395bdd1243dSDimitry Andric 396bdd1243dSDimitry Andric return NextMI == MBBEnd; 3970b57cec5SDimitry Andric } 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric void GCNDownwardRPTracker::advanceToNext() { 4000b57cec5SDimitry Andric LastTrackedMI = &*NextMI++; 401fe6060f1SDimitry Andric NextMI = skipDebugInstructionsForward(NextMI, MBBEnd); 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric // Add new registers or mask bits. 40406c3fb27SDimitry Andric for (const auto &MO : LastTrackedMI->all_defs()) { 4058bcb0991SDimitry Andric Register Reg = MO.getReg(); 406e8d8bef9SDimitry Andric if (!Reg.isVirtual()) 4070b57cec5SDimitry Andric continue; 4080b57cec5SDimitry Andric auto &LiveMask = LiveRegs[Reg]; 4090b57cec5SDimitry Andric auto PrevMask = LiveMask; 4100b57cec5SDimitry Andric LiveMask |= getDefRegMask(MO, *MRI); 4110b57cec5SDimitry Andric CurPressure.inc(Reg, PrevMask, LiveMask, *MRI); 4120b57cec5SDimitry Andric } 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric MaxPressure = max(MaxPressure, CurPressure); 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric bool GCNDownwardRPTracker::advance() { 418bdd1243dSDimitry Andric if (NextMI == MBBEnd) 4190b57cec5SDimitry Andric return false; 420bdd1243dSDimitry Andric advanceBeforeNext(); 4210b57cec5SDimitry Andric advanceToNext(); 4220b57cec5SDimitry Andric return true; 4230b57cec5SDimitry Andric } 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric bool GCNDownwardRPTracker::advance(MachineBasicBlock::const_iterator End) { 4260b57cec5SDimitry Andric while (NextMI != End) 4270b57cec5SDimitry Andric if (!advance()) return false; 4280b57cec5SDimitry Andric return true; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric bool GCNDownwardRPTracker::advance(MachineBasicBlock::const_iterator Begin, 4320b57cec5SDimitry Andric MachineBasicBlock::const_iterator End, 4330b57cec5SDimitry Andric const LiveRegSet *LiveRegsCopy) { 4340b57cec5SDimitry Andric reset(*Begin, LiveRegsCopy); 4350b57cec5SDimitry Andric return advance(End); 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric 438bdd1243dSDimitry Andric Printable llvm::reportMismatch(const GCNRPTracker::LiveRegSet &LISLR, 4390b57cec5SDimitry Andric const GCNRPTracker::LiveRegSet &TrackedLR, 440*5f757f3fSDimitry Andric const TargetRegisterInfo *TRI, StringRef Pfx) { 441*5f757f3fSDimitry Andric return Printable([&LISLR, &TrackedLR, TRI, Pfx](raw_ostream &OS) { 4420b57cec5SDimitry Andric for (auto const &P : TrackedLR) { 4430b57cec5SDimitry Andric auto I = LISLR.find(P.first); 4440b57cec5SDimitry Andric if (I == LISLR.end()) { 445*5f757f3fSDimitry Andric OS << Pfx << printReg(P.first, TRI) << ":L" << PrintLaneMask(P.second) 4460b57cec5SDimitry Andric << " isn't found in LIS reported set\n"; 447bdd1243dSDimitry Andric } else if (I->second != P.second) { 448*5f757f3fSDimitry Andric OS << Pfx << printReg(P.first, TRI) 449bdd1243dSDimitry Andric << " masks doesn't match: LIS reported " << PrintLaneMask(I->second) 450bdd1243dSDimitry Andric << ", tracked " << PrintLaneMask(P.second) << '\n'; 4510b57cec5SDimitry Andric } 4520b57cec5SDimitry Andric } 4530b57cec5SDimitry Andric for (auto const &P : LISLR) { 4540b57cec5SDimitry Andric auto I = TrackedLR.find(P.first); 4550b57cec5SDimitry Andric if (I == TrackedLR.end()) { 456*5f757f3fSDimitry Andric OS << Pfx << printReg(P.first, TRI) << ":L" << PrintLaneMask(P.second) 4570b57cec5SDimitry Andric << " isn't found in tracked set\n"; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric } 460bdd1243dSDimitry Andric }); 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric bool GCNUpwardRPTracker::isValid() const { 4640b57cec5SDimitry Andric const auto &SI = LIS.getInstructionIndex(*LastTrackedMI).getBaseIndex(); 4650b57cec5SDimitry Andric const auto LISLR = llvm::getLiveRegs(SI, LIS, *MRI); 4660b57cec5SDimitry Andric const auto &TrackedLR = LiveRegs; 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric if (!isEqual(LISLR, TrackedLR)) { 4690b57cec5SDimitry Andric dbgs() << "\nGCNUpwardRPTracker error: Tracked and" 470bdd1243dSDimitry Andric " LIS reported livesets mismatch:\n" 471bdd1243dSDimitry Andric << print(LISLR, *MRI); 4720b57cec5SDimitry Andric reportMismatch(LISLR, TrackedLR, MRI->getTargetRegisterInfo()); 4730b57cec5SDimitry Andric return false; 4740b57cec5SDimitry Andric } 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric auto LISPressure = getRegPressure(*MRI, LISLR); 4770b57cec5SDimitry Andric if (LISPressure != CurPressure) { 478bdd1243dSDimitry Andric dbgs() << "GCNUpwardRPTracker error: Pressure sets different\nTracked: " 479bdd1243dSDimitry Andric << print(CurPressure) << "LIS rpt: " << print(LISPressure); 4800b57cec5SDimitry Andric return false; 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric return true; 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 485bdd1243dSDimitry Andric Printable llvm::print(const GCNRPTracker::LiveRegSet &LiveRegs, 4860b57cec5SDimitry Andric const MachineRegisterInfo &MRI) { 487bdd1243dSDimitry Andric return Printable([&LiveRegs, &MRI](raw_ostream &OS) { 4880b57cec5SDimitry Andric const TargetRegisterInfo *TRI = MRI.getTargetRegisterInfo(); 4890b57cec5SDimitry Andric for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { 49004eeddc0SDimitry Andric Register Reg = Register::index2VirtReg(I); 4910b57cec5SDimitry Andric auto It = LiveRegs.find(Reg); 4920b57cec5SDimitry Andric if (It != LiveRegs.end() && It->second.any()) 4930b57cec5SDimitry Andric OS << ' ' << printVRegOrUnit(Reg, TRI) << ':' 4940b57cec5SDimitry Andric << PrintLaneMask(It->second); 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric OS << '\n'; 497bdd1243dSDimitry Andric }); 4980b57cec5SDimitry Andric } 499bdd1243dSDimitry Andric 500bdd1243dSDimitry Andric void GCNRegPressure::dump() const { dbgs() << print(*this); } 501bdd1243dSDimitry Andric 502*5f757f3fSDimitry Andric static cl::opt<bool> UseDownwardTracker( 503*5f757f3fSDimitry Andric "amdgpu-print-rp-downward", 504*5f757f3fSDimitry Andric cl::desc("Use GCNDownwardRPTracker for GCNRegPressurePrinter pass"), 505*5f757f3fSDimitry Andric cl::init(false), cl::Hidden); 506*5f757f3fSDimitry Andric 507*5f757f3fSDimitry Andric char llvm::GCNRegPressurePrinter::ID = 0; 508*5f757f3fSDimitry Andric char &llvm::GCNRegPressurePrinterID = GCNRegPressurePrinter::ID; 509*5f757f3fSDimitry Andric 510*5f757f3fSDimitry Andric INITIALIZE_PASS(GCNRegPressurePrinter, "amdgpu-print-rp", "", true, true) 511*5f757f3fSDimitry Andric 512*5f757f3fSDimitry Andric // Return lanemask of Reg's subregs that are live-through at [Begin, End] and 513*5f757f3fSDimitry Andric // are fully covered by Mask. 514*5f757f3fSDimitry Andric static LaneBitmask 515*5f757f3fSDimitry Andric getRegLiveThroughMask(const MachineRegisterInfo &MRI, const LiveIntervals &LIS, 516*5f757f3fSDimitry Andric Register Reg, SlotIndex Begin, SlotIndex End, 517*5f757f3fSDimitry Andric LaneBitmask Mask = LaneBitmask::getAll()) { 518*5f757f3fSDimitry Andric 519*5f757f3fSDimitry Andric auto IsInOneSegment = [Begin, End](const LiveRange &LR) -> bool { 520*5f757f3fSDimitry Andric auto *Segment = LR.getSegmentContaining(Begin); 521*5f757f3fSDimitry Andric return Segment && Segment->contains(End); 522*5f757f3fSDimitry Andric }; 523*5f757f3fSDimitry Andric 524*5f757f3fSDimitry Andric LaneBitmask LiveThroughMask; 525*5f757f3fSDimitry Andric const LiveInterval &LI = LIS.getInterval(Reg); 526*5f757f3fSDimitry Andric if (LI.hasSubRanges()) { 527*5f757f3fSDimitry Andric for (auto &SR : LI.subranges()) { 528*5f757f3fSDimitry Andric if ((SR.LaneMask & Mask) == SR.LaneMask && IsInOneSegment(SR)) 529*5f757f3fSDimitry Andric LiveThroughMask |= SR.LaneMask; 530*5f757f3fSDimitry Andric } 531*5f757f3fSDimitry Andric } else { 532*5f757f3fSDimitry Andric LaneBitmask RegMask = MRI.getMaxLaneMaskForVReg(Reg); 533*5f757f3fSDimitry Andric if ((RegMask & Mask) == RegMask && IsInOneSegment(LI)) 534*5f757f3fSDimitry Andric LiveThroughMask = RegMask; 535*5f757f3fSDimitry Andric } 536*5f757f3fSDimitry Andric 537*5f757f3fSDimitry Andric return LiveThroughMask; 538*5f757f3fSDimitry Andric } 539*5f757f3fSDimitry Andric 540*5f757f3fSDimitry Andric bool GCNRegPressurePrinter::runOnMachineFunction(MachineFunction &MF) { 541*5f757f3fSDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 542*5f757f3fSDimitry Andric const TargetRegisterInfo *TRI = MRI.getTargetRegisterInfo(); 543*5f757f3fSDimitry Andric const LiveIntervals &LIS = getAnalysis<LiveIntervals>(); 544*5f757f3fSDimitry Andric 545*5f757f3fSDimitry Andric auto &OS = dbgs(); 546*5f757f3fSDimitry Andric 547*5f757f3fSDimitry Andric // Leading spaces are important for YAML syntax. 548*5f757f3fSDimitry Andric #define PFX " " 549*5f757f3fSDimitry Andric 550*5f757f3fSDimitry Andric OS << "---\nname: " << MF.getName() << "\nbody: |\n"; 551*5f757f3fSDimitry Andric 552*5f757f3fSDimitry Andric auto printRP = [](const GCNRegPressure &RP) { 553*5f757f3fSDimitry Andric return Printable([&RP](raw_ostream &OS) { 554*5f757f3fSDimitry Andric OS << format(PFX " %-5d", RP.getSGPRNum()) 555*5f757f3fSDimitry Andric << format(" %-5d", RP.getVGPRNum(false)); 556*5f757f3fSDimitry Andric }); 557*5f757f3fSDimitry Andric }; 558*5f757f3fSDimitry Andric 559*5f757f3fSDimitry Andric auto ReportLISMismatchIfAny = [&](const GCNRPTracker::LiveRegSet &TrackedLR, 560*5f757f3fSDimitry Andric const GCNRPTracker::LiveRegSet &LISLR) { 561*5f757f3fSDimitry Andric if (LISLR != TrackedLR) { 562*5f757f3fSDimitry Andric OS << PFX " mis LIS: " << llvm::print(LISLR, MRI) 563*5f757f3fSDimitry Andric << reportMismatch(LISLR, TrackedLR, TRI, PFX " "); 564*5f757f3fSDimitry Andric } 565*5f757f3fSDimitry Andric }; 566*5f757f3fSDimitry Andric 567*5f757f3fSDimitry Andric // Register pressure before and at an instruction (in program order). 568*5f757f3fSDimitry Andric SmallVector<std::pair<GCNRegPressure, GCNRegPressure>, 16> RP; 569*5f757f3fSDimitry Andric 570*5f757f3fSDimitry Andric for (auto &MBB : MF) { 571*5f757f3fSDimitry Andric RP.clear(); 572*5f757f3fSDimitry Andric RP.reserve(MBB.size()); 573*5f757f3fSDimitry Andric 574*5f757f3fSDimitry Andric OS << PFX; 575*5f757f3fSDimitry Andric MBB.printName(OS); 576*5f757f3fSDimitry Andric OS << ":\n"; 577*5f757f3fSDimitry Andric 578*5f757f3fSDimitry Andric SlotIndex MBBStartSlot = LIS.getSlotIndexes()->getMBBStartIdx(&MBB); 579*5f757f3fSDimitry Andric SlotIndex MBBEndSlot = LIS.getSlotIndexes()->getMBBEndIdx(&MBB); 580*5f757f3fSDimitry Andric 581*5f757f3fSDimitry Andric GCNRPTracker::LiveRegSet LiveIn, LiveOut; 582*5f757f3fSDimitry Andric GCNRegPressure RPAtMBBEnd; 583*5f757f3fSDimitry Andric 584*5f757f3fSDimitry Andric if (UseDownwardTracker) { 585*5f757f3fSDimitry Andric if (MBB.empty()) { 586*5f757f3fSDimitry Andric LiveIn = LiveOut = getLiveRegs(MBBStartSlot, LIS, MRI); 587*5f757f3fSDimitry Andric RPAtMBBEnd = getRegPressure(MRI, LiveIn); 588*5f757f3fSDimitry Andric } else { 589*5f757f3fSDimitry Andric GCNDownwardRPTracker RPT(LIS); 590*5f757f3fSDimitry Andric RPT.reset(MBB.front()); 591*5f757f3fSDimitry Andric 592*5f757f3fSDimitry Andric LiveIn = RPT.getLiveRegs(); 593*5f757f3fSDimitry Andric 594*5f757f3fSDimitry Andric while (!RPT.advanceBeforeNext()) { 595*5f757f3fSDimitry Andric GCNRegPressure RPBeforeMI = RPT.getPressure(); 596*5f757f3fSDimitry Andric RPT.advanceToNext(); 597*5f757f3fSDimitry Andric RP.emplace_back(RPBeforeMI, RPT.getPressure()); 598*5f757f3fSDimitry Andric } 599*5f757f3fSDimitry Andric 600*5f757f3fSDimitry Andric LiveOut = RPT.getLiveRegs(); 601*5f757f3fSDimitry Andric RPAtMBBEnd = RPT.getPressure(); 602*5f757f3fSDimitry Andric } 603*5f757f3fSDimitry Andric } else { 604*5f757f3fSDimitry Andric GCNUpwardRPTracker RPT(LIS); 605*5f757f3fSDimitry Andric RPT.reset(MRI, MBBEndSlot); 606*5f757f3fSDimitry Andric 607*5f757f3fSDimitry Andric LiveOut = RPT.getLiveRegs(); 608*5f757f3fSDimitry Andric RPAtMBBEnd = RPT.getPressure(); 609*5f757f3fSDimitry Andric 610*5f757f3fSDimitry Andric for (auto &MI : reverse(MBB)) { 611*5f757f3fSDimitry Andric RPT.resetMaxPressure(); 612*5f757f3fSDimitry Andric RPT.recede(MI); 613*5f757f3fSDimitry Andric if (!MI.isDebugInstr()) 614*5f757f3fSDimitry Andric RP.emplace_back(RPT.getPressure(), RPT.getMaxPressure()); 615*5f757f3fSDimitry Andric } 616*5f757f3fSDimitry Andric 617*5f757f3fSDimitry Andric LiveIn = RPT.getLiveRegs(); 618*5f757f3fSDimitry Andric } 619*5f757f3fSDimitry Andric 620*5f757f3fSDimitry Andric OS << PFX " Live-in: " << llvm::print(LiveIn, MRI); 621*5f757f3fSDimitry Andric if (!UseDownwardTracker) 622*5f757f3fSDimitry Andric ReportLISMismatchIfAny(LiveIn, getLiveRegs(MBBStartSlot, LIS, MRI)); 623*5f757f3fSDimitry Andric 624*5f757f3fSDimitry Andric OS << PFX " SGPR VGPR\n"; 625*5f757f3fSDimitry Andric int I = 0; 626*5f757f3fSDimitry Andric for (auto &MI : MBB) { 627*5f757f3fSDimitry Andric if (!MI.isDebugInstr()) { 628*5f757f3fSDimitry Andric auto &[RPBeforeInstr, RPAtInstr] = 629*5f757f3fSDimitry Andric RP[UseDownwardTracker ? I : (RP.size() - 1 - I)]; 630*5f757f3fSDimitry Andric ++I; 631*5f757f3fSDimitry Andric OS << printRP(RPBeforeInstr) << '\n' << printRP(RPAtInstr) << " "; 632*5f757f3fSDimitry Andric } else 633*5f757f3fSDimitry Andric OS << PFX " "; 634*5f757f3fSDimitry Andric MI.print(OS); 635*5f757f3fSDimitry Andric } 636*5f757f3fSDimitry Andric OS << printRP(RPAtMBBEnd) << '\n'; 637*5f757f3fSDimitry Andric 638*5f757f3fSDimitry Andric OS << PFX " Live-out:" << llvm::print(LiveOut, MRI); 639*5f757f3fSDimitry Andric if (UseDownwardTracker) 640*5f757f3fSDimitry Andric ReportLISMismatchIfAny(LiveOut, getLiveRegs(MBBEndSlot, LIS, MRI)); 641*5f757f3fSDimitry Andric 642*5f757f3fSDimitry Andric GCNRPTracker::LiveRegSet LiveThrough; 643*5f757f3fSDimitry Andric for (auto [Reg, Mask] : LiveIn) { 644*5f757f3fSDimitry Andric LaneBitmask MaskIntersection = Mask & LiveOut.lookup(Reg); 645*5f757f3fSDimitry Andric if (MaskIntersection.any()) { 646*5f757f3fSDimitry Andric LaneBitmask LTMask = getRegLiveThroughMask( 647*5f757f3fSDimitry Andric MRI, LIS, Reg, MBBStartSlot, MBBEndSlot, MaskIntersection); 648*5f757f3fSDimitry Andric if (LTMask.any()) 649*5f757f3fSDimitry Andric LiveThrough[Reg] = LTMask; 650*5f757f3fSDimitry Andric } 651*5f757f3fSDimitry Andric } 652*5f757f3fSDimitry Andric OS << PFX " Live-thr:" << llvm::print(LiveThrough, MRI); 653*5f757f3fSDimitry Andric OS << printRP(getRegPressure(MRI, LiveThrough)) << '\n'; 654*5f757f3fSDimitry Andric } 655*5f757f3fSDimitry Andric OS << "...\n"; 656*5f757f3fSDimitry Andric return false; 657*5f757f3fSDimitry Andric 658*5f757f3fSDimitry Andric #undef PFX 659*5f757f3fSDimitry Andric }