Valery Pykhtin | 4b7cf6c | 2017-03-21 13:15:46 +0000 | [diff] [blame] | 1 | //===------------------------- GCNRegPressure.cpp - -----------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | /// \file |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "GCNRegPressure.h" |
| 15 | |
| 16 | using namespace llvm; |
| 17 | |
| 18 | #define DEBUG_TYPE "misched" |
| 19 | |
| 20 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| 21 | LLVM_DUMP_METHOD |
| 22 | void llvm::printLivesAt(SlotIndex SI, |
| 23 | const LiveIntervals &LIS, |
| 24 | const MachineRegisterInfo &MRI) { |
| 25 | dbgs() << "Live regs at " << SI << ": " |
| 26 | << *LIS.getInstructionFromIndex(SI); |
| 27 | unsigned Num = 0; |
| 28 | for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { |
| 29 | const unsigned Reg = TargetRegisterInfo::index2VirtReg(I); |
| 30 | if (MRI.reg_nodbg_empty(Reg)) |
| 31 | continue; |
| 32 | const auto &LI = LIS.getInterval(Reg); |
| 33 | if (LI.hasSubRanges()) { |
| 34 | bool firstTime = true; |
| 35 | for (const auto &S : LI.subranges()) { |
| 36 | if (!S.liveAt(SI)) continue; |
| 37 | if (firstTime) { |
| 38 | dbgs() << " " << PrintReg(Reg, MRI.getTargetRegisterInfo()) |
| 39 | << '\n'; |
| 40 | firstTime = false; |
| 41 | } |
| 42 | dbgs() << " " << S << '\n'; |
| 43 | ++Num; |
| 44 | } |
| 45 | } else if (LI.liveAt(SI)) { |
| 46 | dbgs() << " " << LI << '\n'; |
| 47 | ++Num; |
| 48 | } |
| 49 | } |
| 50 | if (!Num) dbgs() << " <none>\n"; |
| 51 | } |
| 52 | |
| 53 | static bool isEqual(const GCNRPTracker::LiveRegSet &S1, |
| 54 | const GCNRPTracker::LiveRegSet &S2) { |
| 55 | if (S1.size() != S2.size()) |
| 56 | return false; |
| 57 | |
| 58 | for (const auto &P : S1) { |
| 59 | auto I = S2.find(P.first); |
| 60 | if (I == S2.end() || I->second != P.second) |
| 61 | return false; |
| 62 | } |
| 63 | return true; |
| 64 | } |
| 65 | |
| 66 | static GCNRPTracker::LiveRegSet |
| 67 | stripEmpty(const GCNRPTracker::LiveRegSet &LR) { |
| 68 | GCNRPTracker::LiveRegSet Res; |
| 69 | for (const auto &P : LR) { |
| 70 | if (P.second.any()) |
| 71 | Res.insert(P); |
| 72 | } |
| 73 | return Res; |
| 74 | } |
| 75 | #endif |
| 76 | |
| 77 | /////////////////////////////////////////////////////////////////////////////// |
| 78 | // GCNRegPressure |
| 79 | |
| 80 | unsigned GCNRegPressure::getRegKind(unsigned Reg, |
| 81 | const MachineRegisterInfo &MRI) { |
| 82 | assert(TargetRegisterInfo::isVirtualRegister(Reg)); |
| 83 | const auto RC = MRI.getRegClass(Reg); |
| 84 | auto STI = static_cast<const SIRegisterInfo*>(MRI.getTargetRegisterInfo()); |
| 85 | return STI->isSGPRClass(RC) ? |
Krzysztof Parzyszek | 36d7c2b | 2017-04-24 18:55:33 +0000 | [diff] [blame^] | 86 | (STI->getRegSizeInBits(*RC) == 32 ? SGPR32 : SGPR_TUPLE) : |
| 87 | (STI->getRegSizeInBits(*RC) == 32 ? VGPR32 : VGPR_TUPLE); |
Valery Pykhtin | 4b7cf6c | 2017-03-21 13:15:46 +0000 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | void GCNRegPressure::inc(unsigned Reg, |
| 91 | LaneBitmask PrevMask, |
| 92 | LaneBitmask NewMask, |
| 93 | const MachineRegisterInfo &MRI) { |
| 94 | if (NewMask == PrevMask) |
| 95 | return; |
| 96 | |
| 97 | int Sign = 1; |
| 98 | if (NewMask < PrevMask) { |
| 99 | std::swap(NewMask, PrevMask); |
| 100 | Sign = -1; |
| 101 | } |
| 102 | #ifndef NDEBUG |
| 103 | const auto MaxMask = MRI.getMaxLaneMaskForVReg(Reg); |
| 104 | #endif |
| 105 | switch (auto Kind = getRegKind(Reg, MRI)) { |
| 106 | case SGPR32: |
| 107 | case VGPR32: |
| 108 | assert(PrevMask.none() && NewMask == MaxMask); |
| 109 | Value[Kind] += Sign; |
| 110 | break; |
| 111 | |
| 112 | case SGPR_TUPLE: |
| 113 | case VGPR_TUPLE: |
| 114 | assert(NewMask < MaxMask || NewMask == MaxMask); |
| 115 | assert(PrevMask < NewMask); |
| 116 | |
| 117 | Value[Kind == SGPR_TUPLE ? SGPR32 : VGPR32] += |
| 118 | Sign * countPopulation((~PrevMask & NewMask).getAsInteger()); |
| 119 | |
| 120 | if (PrevMask.none()) { |
| 121 | assert(NewMask.any()); |
| 122 | Value[Kind] += Sign * MRI.getPressureSets(Reg).getWeight(); |
| 123 | } |
| 124 | break; |
| 125 | |
| 126 | default: llvm_unreachable("Unknown register kind"); |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | bool GCNRegPressure::less(const SISubtarget &ST, |
| 131 | const GCNRegPressure& O, |
| 132 | unsigned MaxOccupancy) const { |
| 133 | const auto SGPROcc = std::min(MaxOccupancy, |
| 134 | ST.getOccupancyWithNumSGPRs(getSGRPNum())); |
| 135 | const auto VGPROcc = std::min(MaxOccupancy, |
| 136 | ST.getOccupancyWithNumVGPRs(getVGRPNum())); |
| 137 | const auto OtherSGPROcc = std::min(MaxOccupancy, |
| 138 | ST.getOccupancyWithNumSGPRs(O.getSGRPNum())); |
| 139 | const auto OtherVGPROcc = std::min(MaxOccupancy, |
| 140 | ST.getOccupancyWithNumVGPRs(O.getVGRPNum())); |
| 141 | |
| 142 | const auto Occ = std::min(SGPROcc, VGPROcc); |
| 143 | const auto OtherOcc = std::min(OtherSGPROcc, OtherVGPROcc); |
| 144 | if (Occ != OtherOcc) |
| 145 | return Occ > OtherOcc; |
| 146 | |
| 147 | bool SGPRImportant = SGPROcc < VGPROcc; |
| 148 | const bool OtherSGPRImportant = OtherSGPROcc < OtherVGPROcc; |
| 149 | |
| 150 | // if both pressures disagree on what is more important compare vgprs |
| 151 | if (SGPRImportant != OtherSGPRImportant) { |
| 152 | SGPRImportant = false; |
| 153 | } |
| 154 | |
| 155 | // compare large regs pressure |
| 156 | bool SGPRFirst = SGPRImportant; |
| 157 | for (int I = 2; I > 0; --I, SGPRFirst = !SGPRFirst) { |
| 158 | if (SGPRFirst) { |
| 159 | auto SW = getSGPRTuplesWeight(); |
| 160 | auto OtherSW = O.getSGPRTuplesWeight(); |
| 161 | if (SW != OtherSW) |
| 162 | return SW < OtherSW; |
| 163 | } else { |
| 164 | auto VW = getVGPRTuplesWeight(); |
| 165 | auto OtherVW = O.getVGPRTuplesWeight(); |
| 166 | if (VW != OtherVW) |
| 167 | return VW < OtherVW; |
| 168 | } |
| 169 | } |
| 170 | return SGPRImportant ? (getSGRPNum() < O.getSGRPNum()): |
| 171 | (getVGRPNum() < O.getVGRPNum()); |
| 172 | } |
| 173 | |
| 174 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| 175 | LLVM_DUMP_METHOD |
| 176 | void GCNRegPressure::print(raw_ostream &OS, const SISubtarget *ST) const { |
| 177 | OS << "VGPRs: " << getVGRPNum(); |
| 178 | if (ST) OS << "(O" << ST->getOccupancyWithNumVGPRs(getVGRPNum()) << ')'; |
| 179 | OS << ", SGPRs: " << getSGRPNum(); |
| 180 | if (ST) OS << "(O" << ST->getOccupancyWithNumSGPRs(getSGRPNum()) << ')'; |
| 181 | OS << ", LVGPR WT: " << getVGPRTuplesWeight() |
| 182 | << ", LSGPR WT: " << getSGPRTuplesWeight(); |
| 183 | if (ST) OS << " -> Occ: " << getOccupancy(*ST); |
| 184 | OS << '\n'; |
| 185 | } |
| 186 | #endif |
| 187 | |
| 188 | /////////////////////////////////////////////////////////////////////////////// |
| 189 | // GCNRPTracker |
| 190 | |
| 191 | LaneBitmask llvm::getLiveLaneMask(unsigned Reg, |
| 192 | SlotIndex SI, |
| 193 | const LiveIntervals &LIS, |
| 194 | const MachineRegisterInfo &MRI) { |
| 195 | assert(!MRI.reg_nodbg_empty(Reg)); |
| 196 | LaneBitmask LiveMask; |
| 197 | const auto &LI = LIS.getInterval(Reg); |
| 198 | if (LI.hasSubRanges()) { |
| 199 | for (const auto &S : LI.subranges()) |
| 200 | if (S.liveAt(SI)) { |
| 201 | LiveMask |= S.LaneMask; |
| 202 | assert(LiveMask < MRI.getMaxLaneMaskForVReg(Reg) || |
| 203 | LiveMask == MRI.getMaxLaneMaskForVReg(Reg)); |
| 204 | } |
| 205 | } else if (LI.liveAt(SI)) { |
| 206 | LiveMask = MRI.getMaxLaneMaskForVReg(Reg); |
| 207 | } |
| 208 | return LiveMask; |
| 209 | } |
| 210 | |
| 211 | GCNRPTracker::LiveRegSet llvm::getLiveRegs(SlotIndex SI, |
| 212 | const LiveIntervals &LIS, |
| 213 | const MachineRegisterInfo &MRI) { |
| 214 | GCNRPTracker::LiveRegSet LiveRegs; |
| 215 | for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { |
| 216 | auto Reg = TargetRegisterInfo::index2VirtReg(I); |
| 217 | if (MRI.reg_nodbg_empty(Reg)) |
| 218 | continue; |
| 219 | auto LiveMask = getLiveLaneMask(Reg, SI, LIS, MRI); |
| 220 | if (LiveMask.any()) |
| 221 | LiveRegs[Reg] = LiveMask; |
| 222 | } |
| 223 | return LiveRegs; |
| 224 | } |
| 225 | |
| 226 | void GCNUpwardRPTracker::reset(const MachineInstr &MI) { |
| 227 | MRI = &MI.getParent()->getParent()->getRegInfo(); |
| 228 | LiveRegs = getLiveRegsAfter(MI, LIS); |
| 229 | MaxPressure = CurPressure = getRegPressure(*MRI, LiveRegs); |
| 230 | } |
| 231 | |
| 232 | LaneBitmask GCNUpwardRPTracker::getDefRegMask(const MachineOperand &MO) const { |
| 233 | assert(MO.isDef() && MO.isReg() && |
| 234 | TargetRegisterInfo::isVirtualRegister(MO.getReg())); |
| 235 | |
| 236 | // We don't rely on read-undef flag because in case of tentative schedule |
| 237 | // tracking it isn't set correctly yet. This works correctly however since |
| 238 | // use mask has been tracked before using LIS. |
| 239 | return MO.getSubReg() == 0 ? |
| 240 | MRI->getMaxLaneMaskForVReg(MO.getReg()) : |
| 241 | MRI->getTargetRegisterInfo()->getSubRegIndexLaneMask(MO.getSubReg()); |
| 242 | } |
| 243 | |
| 244 | LaneBitmask GCNUpwardRPTracker::getUsedRegMask(const MachineOperand &MO) const { |
| 245 | assert(MO.isUse() && MO.isReg() && |
| 246 | TargetRegisterInfo::isVirtualRegister(MO.getReg())); |
| 247 | |
| 248 | if (auto SubReg = MO.getSubReg()) |
| 249 | return MRI->getTargetRegisterInfo()->getSubRegIndexLaneMask(SubReg); |
| 250 | |
| 251 | auto MaxMask = MRI->getMaxLaneMaskForVReg(MO.getReg()); |
| 252 | if (MaxMask.getAsInteger() == 1) // cannot have subregs |
| 253 | return MaxMask; |
| 254 | |
| 255 | // For a tentative schedule LIS isn't updated yet but livemask should remain |
| 256 | // the same on any schedule. Subreg defs can be reordered but they all must |
| 257 | // dominate uses anyway. |
| 258 | auto SI = LIS.getInstructionIndex(*MO.getParent()).getBaseIndex(); |
| 259 | return getLiveLaneMask(MO.getReg(), SI, LIS, *MRI); |
| 260 | } |
| 261 | |
| 262 | void GCNUpwardRPTracker::recede(const MachineInstr &MI) { |
| 263 | assert(MRI && "call reset first"); |
| 264 | |
| 265 | LastTrackedMI = &MI; |
| 266 | |
| 267 | if (MI.isDebugValue()) |
| 268 | return; |
| 269 | |
| 270 | // process all defs first to ensure early clobbers are handled correctly |
| 271 | // iterating over operands() to catch implicit defs |
| 272 | for (const auto &MO : MI.operands()) { |
| 273 | if (!MO.isReg() || !MO.isDef() || |
| 274 | !TargetRegisterInfo::isVirtualRegister(MO.getReg())) |
| 275 | continue; |
| 276 | |
| 277 | auto Reg = MO.getReg(); |
| 278 | auto &LiveMask = LiveRegs[Reg]; |
| 279 | auto PrevMask = LiveMask; |
| 280 | LiveMask &= ~getDefRegMask(MO); |
| 281 | CurPressure.inc(Reg, PrevMask, LiveMask, *MRI); |
| 282 | } |
| 283 | |
| 284 | // then all uses |
| 285 | for (const auto &MO : MI.uses()) { |
| 286 | if (!MO.isReg() || !MO.readsReg() || |
| 287 | !TargetRegisterInfo::isVirtualRegister(MO.getReg())) |
| 288 | continue; |
| 289 | |
| 290 | auto Reg = MO.getReg(); |
| 291 | auto &LiveMask = LiveRegs[Reg]; |
| 292 | auto PrevMask = LiveMask; |
| 293 | LiveMask |= getUsedRegMask(MO); |
| 294 | CurPressure.inc(Reg, PrevMask, LiveMask, *MRI); |
| 295 | } |
| 296 | |
| 297 | MaxPressure = max(MaxPressure, CurPressure); |
| 298 | } |
| 299 | |
| 300 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| 301 | LLVM_DUMP_METHOD |
| 302 | static void reportMismatch(const GCNRPTracker::LiveRegSet &LISLR, |
| 303 | const GCNRPTracker::LiveRegSet &TrackedLR, |
| 304 | const TargetRegisterInfo *TRI) { |
| 305 | for (auto const &P : TrackedLR) { |
| 306 | auto I = LISLR.find(P.first); |
| 307 | if (I == LISLR.end()) { |
| 308 | dbgs() << " " << PrintReg(P.first, TRI) |
| 309 | << ":L" << PrintLaneMask(P.second) |
| 310 | << " isn't found in LIS reported set\n"; |
| 311 | } |
| 312 | else if (I->second != P.second) { |
| 313 | dbgs() << " " << PrintReg(P.first, TRI) |
| 314 | << " masks doesn't match: LIS reported " |
| 315 | << PrintLaneMask(I->second) |
| 316 | << ", tracked " |
| 317 | << PrintLaneMask(P.second) |
| 318 | << '\n'; |
| 319 | } |
| 320 | } |
| 321 | for (auto const &P : LISLR) { |
| 322 | auto I = TrackedLR.find(P.first); |
| 323 | if (I == TrackedLR.end()) { |
| 324 | dbgs() << " " << PrintReg(P.first, TRI) |
| 325 | << ":L" << PrintLaneMask(P.second) |
| 326 | << " isn't found in tracked set\n"; |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | bool GCNUpwardRPTracker::isValid() const { |
| 332 | const auto &SI = LIS.getInstructionIndex(*LastTrackedMI).getBaseIndex(); |
| 333 | const auto LISLR = llvm::getLiveRegs(SI, LIS, *MRI); |
| 334 | const auto TrackedLR = stripEmpty(LiveRegs); |
| 335 | |
| 336 | if (!isEqual(LISLR, TrackedLR)) { |
| 337 | dbgs() << "\nGCNUpwardRPTracker error: Tracked and" |
| 338 | " LIS reported livesets mismatch:\n"; |
| 339 | printLivesAt(SI, LIS, *MRI); |
| 340 | reportMismatch(LISLR, TrackedLR, MRI->getTargetRegisterInfo()); |
| 341 | return false; |
| 342 | } |
| 343 | |
| 344 | auto LISPressure = getRegPressure(*MRI, LISLR); |
| 345 | if (LISPressure != CurPressure) { |
| 346 | dbgs() << "GCNUpwardRPTracker error: Pressure sets different\nTracked: "; |
| 347 | CurPressure.print(dbgs()); |
| 348 | dbgs() << "LIS rpt: "; |
| 349 | LISPressure.print(dbgs()); |
| 350 | return false; |
| 351 | } |
| 352 | return true; |
| 353 | } |
| 354 | |
| 355 | #endif |