1//===- GCNRegPressure.h -----------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file defines the GCNRegPressure class, which tracks registry pressure
11/// by bookkeeping number of SGPR/VGPRs used, weights for large SGPR/VGPRs. It
12/// also implements a compare function, which compares different register
13/// pressures, and declares one with max occupancy as winner.
14///
15//===----------------------------------------------------------------------===//
16
17#ifndef LLVM_LIB_TARGET_AMDGPU_GCNREGPRESSURE_H
18#define LLVM_LIB_TARGET_AMDGPU_GCNREGPRESSURE_H
19
20#include "GCNSubtarget.h"
21#include "llvm/CodeGen/LiveIntervals.h"
22#include "llvm/CodeGen/RegisterPressure.h"
23#include <algorithm>
24#include <array>
25
26namespace llvm {
27
28class MachineRegisterInfo;
29class raw_ostream;
30class SlotIndex;
31
32struct GCNRegPressure {
33 enum RegKind { SGPR, VGPR, AGPR, AVGPR, TOTAL_KINDS };
34
35 static constexpr const char *getName(RegKind Kind) {
36 const char *Names[] = {"SGPR", "VGPR", "AGPR", "AVGPR"};
37 assert(Kind < TOTAL_KINDS);
38 return Names[Kind];
39 }
40
41 GCNRegPressure() {
42 clear();
43 }
44
45 bool empty() const {
46 return !Value[SGPR] && !Value[VGPR] && !Value[AGPR] && !Value[AVGPR];
47 }
48
49 void clear() { Value.fill(u: 0); }
50
51 unsigned getNumRegs(RegKind Kind) const {
52 assert(Kind < TOTAL_KINDS);
53 return Value[Kind];
54 }
55
56 /// \returns the SGPR32 pressure
57 unsigned getSGPRNum() const { return Value[SGPR]; }
58 /// \returns the aggregated ArchVGPR32, AccVGPR32, and Pseudo AVGPR pressure
59 /// dependent upon \p UnifiedVGPRFile
60 unsigned getVGPRNum(bool UnifiedVGPRFile) const {
61 if (UnifiedVGPRFile) {
62 return Value[AGPR]
63 ? getUnifiedVGPRNum(NumArchVGPRs: Value[VGPR], NumAGPRs: Value[AGPR], NumAVGPRs: Value[AVGPR])
64 : Value[VGPR] + Value[AVGPR];
65 }
66 // AVGPR assignment priority is based on the width of the register. Account
67 // AVGPR pressure as VGPR.
68 return std::max(a: Value[VGPR] + Value[AVGPR], b: Value[AGPR]);
69 }
70
71 /// Returns the aggregated VGPR pressure, assuming \p NumArchVGPRs ArchVGPRs
72 /// \p NumAGPRs AGPRS, and \p NumAVGPRs AVGPRs for a target with a unified
73 /// VGPR file.
74 inline static unsigned getUnifiedVGPRNum(unsigned NumArchVGPRs,
75 unsigned NumAGPRs,
76 unsigned NumAVGPRs) {
77
78 // Assume AVGPRs will be assigned as VGPRs.
79 return alignTo(Value: NumArchVGPRs + NumAVGPRs,
80 Align: AMDGPU::IsaInfo::getArchVGPRAllocGranule()) +
81 NumAGPRs;
82 }
83
84 /// \returns the ArchVGPR32 pressure, plus the AVGPRS which we assume will be
85 /// allocated as VGPR
86 unsigned getArchVGPRNum() const { return Value[VGPR] + Value[AVGPR]; }
87 /// \returns the AccVGPR32 pressure
88 unsigned getAGPRNum() const { return Value[AGPR]; }
89 /// \returns the AVGPR32 pressure
90 unsigned getAVGPRNum() const { return Value[AVGPR]; }
91
92 unsigned getVGPRTuplesWeight() const {
93 return std::max(a: Value[TOTAL_KINDS + VGPR] + Value[TOTAL_KINDS + AVGPR],
94 b: Value[TOTAL_KINDS + AGPR]);
95 }
96 unsigned getSGPRTuplesWeight() const { return Value[TOTAL_KINDS + SGPR]; }
97
98 unsigned getOccupancy(const GCNSubtarget &ST,
99 unsigned DynamicVGPRBlockSize) const {
100 return std::min(a: ST.getOccupancyWithNumSGPRs(SGPRs: getSGPRNum()),
101 b: ST.getOccupancyWithNumVGPRs(VGPRs: getVGPRNum(UnifiedVGPRFile: ST.hasGFX90AInsts()),
102 DynamicVGPRBlockSize));
103 }
104
105 unsigned getVGPRSpills(MachineFunction &MF, unsigned ArchVGPRThreshold,
106 unsigned AGPRThreshold, unsigned CombinedThreshold) {
107 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
108 if (!ST.hasGFX90AInsts())
109 return 0;
110
111 unsigned ArchPressure = getArchVGPRNum();
112 unsigned AGPRPressure = getAGPRNum();
113
114 unsigned ArchSpill = ArchPressure > ArchVGPRThreshold
115 ? (ArchPressure - ArchVGPRThreshold)
116 : 0;
117 unsigned AGPRSpill =
118 AGPRPressure > AGPRThreshold ? (AGPRPressure - AGPRThreshold) : 0;
119
120 unsigned UnifiedPressure = getVGPRNum(/*UnifiedVGPRFile=*/UnifiedVGPRFile: true);
121 unsigned UnifiedSpill = UnifiedPressure > CombinedThreshold
122 ? (UnifiedPressure - CombinedThreshold)
123 : 0;
124
125 return std::max(a: UnifiedSpill, b: ArchSpill + AGPRSpill);
126 }
127
128 void inc(unsigned Reg,
129 LaneBitmask PrevMask,
130 LaneBitmask NewMask,
131 const MachineRegisterInfo &MRI);
132
133 bool higherOccupancy(const GCNSubtarget &ST, const GCNRegPressure &O,
134 unsigned DynamicVGPRBlockSize) const {
135 return getOccupancy(ST, DynamicVGPRBlockSize) >
136 O.getOccupancy(ST, DynamicVGPRBlockSize);
137 }
138
139 /// Compares \p this GCNRegpressure to \p O, returning true if \p this is
140 /// less. Since GCNRegpressure contains different types of pressures, and due
141 /// to target-specific pecularities (e.g. we care about occupancy rather than
142 /// raw register usage), we determine if \p this GCNRegPressure is less than
143 /// \p O based on the following tiered comparisons (in order order of
144 /// precedence):
145 /// 1. Better occupancy
146 /// 2. Less spilling (first preference to VGPR spills, then to SGPR spills)
147 /// 3. Less tuple register pressure (first preference to VGPR tuples if we
148 /// determine that SGPR pressure is not important)
149 /// 4. Less raw register pressure (first preference to VGPR tuples if we
150 /// determine that SGPR pressure is not important)
151 bool less(const MachineFunction &MF, const GCNRegPressure &O,
152 unsigned MaxOccupancy = std::numeric_limits<unsigned>::max()) const;
153
154 bool operator==(const GCNRegPressure &O) const { return Value == O.Value; }
155
156 bool operator!=(const GCNRegPressure &O) const {
157 return !(*this == O);
158 }
159
160 GCNRegPressure &operator+=(const GCNRegPressure &RHS) {
161 for (unsigned I = 0; I < ValueArraySize; ++I)
162 Value[I] += RHS.Value[I];
163 return *this;
164 }
165
166 GCNRegPressure &operator-=(const GCNRegPressure &RHS) {
167 for (unsigned I = 0; I < ValueArraySize; ++I)
168 Value[I] -= RHS.Value[I];
169 return *this;
170 }
171
172 void dump() const;
173
174 static RegKind getRegKind(unsigned Reg, const MachineRegisterInfo &MRI) {
175 const TargetRegisterInfo *TRI = MRI.getTargetRegisterInfo();
176 const SIRegisterInfo *STI = static_cast<const SIRegisterInfo *>(TRI);
177 return (RegKind)getRegKind(RC: MRI.getRegClass(Reg), STI);
178 }
179
180private:
181 static constexpr unsigned ValueArraySize = TOTAL_KINDS * 2;
182
183 /// Pressure for all register kinds (first all regular registers kinds, then
184 /// all tuple register kinds).
185 std::array<unsigned, ValueArraySize> Value;
186
187 static unsigned getRegKind(const TargetRegisterClass *RC,
188 const SIRegisterInfo *STI);
189
190 friend GCNRegPressure max(const GCNRegPressure &P1,
191 const GCNRegPressure &P2);
192
193 friend Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST,
194 unsigned DynamicVGPRBlockSize);
195};
196
197inline GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2) {
198 GCNRegPressure Res;
199 for (unsigned I = 0; I < GCNRegPressure::ValueArraySize; ++I)
200 Res.Value[I] = std::max(a: P1.Value[I], b: P2.Value[I]);
201 return Res;
202}
203
204inline GCNRegPressure operator+(const GCNRegPressure &P1,
205 const GCNRegPressure &P2) {
206 GCNRegPressure Sum = P1;
207 Sum += P2;
208 return Sum;
209}
210
211inline GCNRegPressure operator-(const GCNRegPressure &P1,
212 const GCNRegPressure &P2) {
213 GCNRegPressure Diff = P1;
214 Diff -= P2;
215 return Diff;
216}
217
218////////////////////////////////////////////////////////////////////////////////
219// GCNRPTarget
220
221/// Models a register pressure target, allowing to evaluate and track register
222/// savings against that target from a starting \ref GCNRegPressure.
223class GCNRPTarget {
224public:
225 /// Sets up the target such that the register pressure starting at \p RP does
226 /// not show register spilling on function \p MF (w.r.t. the function's
227 /// mininum target occupancy).
228 GCNRPTarget(const MachineFunction &MF, const GCNRegPressure &RP);
229
230 /// Sets up the target such that the register pressure starting at \p RP does
231 /// not use more than \p NumSGPRs SGPRs and \p NumVGPRs VGPRs on function \p
232 /// MF.
233 GCNRPTarget(unsigned NumSGPRs, unsigned NumVGPRs, const MachineFunction &MF,
234 const GCNRegPressure &RP);
235
236 /// Sets up the target such that the register pressure starting at \p RP does
237 /// not prevent achieving an occupancy of at least \p Occupancy on function
238 /// \p MF.
239 GCNRPTarget(unsigned Occupancy, const MachineFunction &MF,
240 const GCNRegPressure &RP);
241
242 /// Changes the target (same semantics as constructor).
243 void setTarget(unsigned NumSGPRs, unsigned NumVGPRs);
244
245 const GCNRegPressure &getCurrentRP() const { return RP; }
246
247 void setRP(const GCNRegPressure &NewRP) { RP = NewRP; }
248
249 /// Determines whether saving virtual register \p Reg will be beneficial
250 /// towards achieving the RP target.
251 bool isSaveBeneficial(Register Reg) const;
252
253 /// Saves virtual register \p Reg with lanemask \p Mask.
254 void saveReg(Register Reg, LaneBitmask Mask, const MachineRegisterInfo &MRI) {
255 RP.inc(Reg, PrevMask: Mask, NewMask: LaneBitmask::getNone(), MRI);
256 }
257
258 /// Whether the current RP is at or below the defined pressure target.
259 bool satisfied() const;
260 bool hasVectorRegisterExcess() const;
261
262 unsigned getMaxSGPRs() const { return MaxSGPRs; }
263 unsigned getMaxVGPRs() const {
264 return UnifiedRF ? MaxUnifiedVGPRs : MaxVGPRs;
265 }
266
267#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
268 friend raw_ostream &operator<<(raw_ostream &OS, const GCNRPTarget &Target) {
269 OS << "Actual/Target: " << Target.RP.getSGPRNum() << '/' << Target.MaxSGPRs
270 << " SGPRs, " << Target.RP.getArchVGPRNum() << '/' << Target.MaxVGPRs
271 << " ArchVGPRs, " << Target.RP.getAGPRNum() << '/' << Target.MaxVGPRs
272 << " AGPRs";
273
274 if (Target.MaxUnifiedVGPRs) {
275 OS << ", " << Target.RP.getVGPRNum(true) << '/' << Target.MaxUnifiedVGPRs
276 << " VGPRs (unified)";
277 }
278 return OS;
279 }
280#endif
281
282private:
283 const MachineFunction &MF;
284 const bool UnifiedRF;
285
286 /// Current register pressure.
287 GCNRegPressure RP;
288
289 /// Target number of SGPRs.
290 unsigned MaxSGPRs;
291 /// Target number of ArchVGPRs and AGPRs.
292 unsigned MaxVGPRs;
293 /// Target number of overall VGPRs for subtargets with unified RFs. Always 0
294 /// for subtargets with non-unified RFs.
295 unsigned MaxUnifiedVGPRs;
296
297 GCNRPTarget(const GCNRegPressure &RP, const MachineFunction &MF)
298 : MF(MF), UnifiedRF(MF.getSubtarget<GCNSubtarget>().hasGFX90AInsts()),
299 RP(RP) {}
300};
301
302///////////////////////////////////////////////////////////////////////////////
303// GCNRPTracker
304
305class GCNRPTracker {
306public:
307 using LiveRegSet = DenseMap<unsigned, LaneBitmask>;
308
309protected:
310 const LiveIntervals &LIS;
311 LiveRegSet LiveRegs;
312 GCNRegPressure CurPressure, MaxPressure;
313 const MachineInstr *LastTrackedMI = nullptr;
314 mutable const MachineRegisterInfo *MRI = nullptr;
315
316 GCNRPTracker(const LiveIntervals &LIS_) : LIS(LIS_) {}
317
318 void reset(const MachineInstr &MI, const LiveRegSet *LiveRegsCopy,
319 bool After);
320
321 /// Mostly copy/paste from CodeGen/RegisterPressure.cpp
322 void bumpDeadDefs(ArrayRef<VRegMaskOrUnit> DeadDefs);
323
324 LaneBitmask getLastUsedLanes(Register Reg, SlotIndex Pos) const;
325
326public:
327 // reset tracker and set live register set to the specified value.
328 void reset(const MachineRegisterInfo &MRI_, const LiveRegSet &LiveRegs_);
329 // live regs for the current state
330 const decltype(LiveRegs) &getLiveRegs() const { return LiveRegs; }
331 const MachineInstr *getLastTrackedMI() const { return LastTrackedMI; }
332
333 void clearMaxPressure() { MaxPressure.clear(); }
334
335 GCNRegPressure getPressure() const { return CurPressure; }
336
337 decltype(LiveRegs) moveLiveRegs() {
338 return std::move(LiveRegs);
339 }
340};
341
342GCNRPTracker::LiveRegSet
343getLiveRegs(SlotIndex SI, const LiveIntervals &LIS,
344 const MachineRegisterInfo &MRI,
345 GCNRegPressure::RegKind RegKind = GCNRegPressure::TOTAL_KINDS);
346
347////////////////////////////////////////////////////////////////////////////////
348// GCNUpwardRPTracker
349
350class GCNUpwardRPTracker : public GCNRPTracker {
351public:
352 GCNUpwardRPTracker(const LiveIntervals &LIS_) : GCNRPTracker(LIS_) {}
353
354 using GCNRPTracker::reset;
355
356 /// reset tracker at the specified slot index \p SI.
357 void reset(const MachineRegisterInfo &MRI, SlotIndex SI) {
358 GCNRPTracker::reset(MRI_: MRI, LiveRegs_: llvm::getLiveRegs(SI, LIS, MRI));
359 }
360
361 /// reset tracker to the end of the \p MBB.
362 void reset(const MachineBasicBlock &MBB) {
363 SlotIndex MBBLastSlot = LIS.getSlotIndexes()->getMBBLastIdx(MBB: &MBB);
364 reset(MRI: MBB.getParent()->getRegInfo(), SI: MBBLastSlot);
365 }
366
367 /// reset tracker to the point just after \p MI (in program order).
368 void reset(const MachineInstr &MI) {
369 reset(MRI: MI.getMF()->getRegInfo(), SI: LIS.getInstructionIndex(Instr: MI).getDeadSlot());
370 }
371
372 /// Move to the state of RP just before the \p MI . If \p UseInternalIterator
373 /// is set, also update the internal iterators. Setting \p UseInternalIterator
374 /// to false allows for an externally managed iterator / program order.
375 void recede(const MachineInstr &MI);
376
377 /// \p returns whether the tracker's state after receding MI corresponds
378 /// to reported by LIS.
379 bool isValid() const;
380
381 const GCNRegPressure &getMaxPressure() const { return MaxPressure; }
382
383 void resetMaxPressure() { MaxPressure = CurPressure; }
384
385 GCNRegPressure getMaxPressureAndReset() {
386 GCNRegPressure RP = MaxPressure;
387 resetMaxPressure();
388 return RP;
389 }
390};
391
392////////////////////////////////////////////////////////////////////////////////
393// GCNDownwardRPTracker
394
395class GCNDownwardRPTracker : public GCNRPTracker {
396 // Last position of reset or advanceBeforeNext
397 MachineBasicBlock::const_iterator NextMI;
398
399 MachineBasicBlock::const_iterator MBBEnd;
400
401public:
402 GCNDownwardRPTracker(const LiveIntervals &LIS_) : GCNRPTracker(LIS_) {}
403
404 using GCNRPTracker::reset;
405
406 MachineBasicBlock::const_iterator getNext() const { return NextMI; }
407
408 /// \p return MaxPressure and clear it.
409 GCNRegPressure moveMaxPressure() {
410 auto Res = MaxPressure;
411 MaxPressure.clear();
412 return Res;
413 }
414
415 /// Reset tracker to the point before the \p MI
416 /// filling \p LiveRegs upon this point using LIS.
417 /// \p returns false if block is empty except debug values.
418 bool reset(const MachineInstr &MI, const LiveRegSet *LiveRegs = nullptr);
419
420 /// Move to the state right before the next MI or after the end of MBB.
421 /// \p returns false if reached end of the block.
422 /// If \p UseInternalIterator is true, then internal iterators are used and
423 /// set to process in program order. If \p UseInternalIterator is false, then
424 /// it is assumed that the tracker is using an externally managed iterator,
425 /// and advance* calls will not update the state of the iterator. In such
426 /// cases, the tracker will move to the state right before the provided \p MI
427 /// and use LIS for RP calculations.
428 bool advanceBeforeNext(MachineInstr *MI = nullptr,
429 bool UseInternalIterator = true);
430
431 /// Move to the state at the MI, advanceBeforeNext has to be called first.
432 /// If \p UseInternalIterator is true, then internal iterators are used and
433 /// set to process in program order. If \p UseInternalIterator is false, then
434 /// it is assumed that the tracker is using an externally managed iterator,
435 /// and advance* calls will not update the state of the iterator. In such
436 /// cases, the tracker will move to the state at the provided \p MI .
437 void advanceToNext(MachineInstr *MI = nullptr,
438 bool UseInternalIterator = true);
439
440 /// Move to the state at the next MI. \p returns false if reached end of
441 /// block. If \p UseInternalIterator is true, then internal iterators are used
442 /// and set to process in program order. If \p UseInternalIterator is false,
443 /// then it is assumed that the tracker is using an externally managed
444 /// iterator, and advance* calls will not update the state of the iterator. In
445 /// such cases, the tracker will move to the state right before the provided
446 /// \p MI and use LIS for RP calculations.
447 bool advance(MachineInstr *MI = nullptr, bool UseInternalIterator = true);
448
449 /// Advance instructions until before \p End.
450 bool advance(MachineBasicBlock::const_iterator End);
451
452 /// Reset to \p Begin and advance to \p End.
453 bool advance(MachineBasicBlock::const_iterator Begin,
454 MachineBasicBlock::const_iterator End,
455 const LiveRegSet *LiveRegsCopy = nullptr);
456
457 /// Mostly copy/paste from CodeGen/RegisterPressure.cpp
458 /// Calculate the impact \p MI will have on CurPressure and \return the
459 /// speculated pressure. In order to support RP Speculation, this does not
460 /// rely on the implicit program ordering in the LiveIntervals.
461 GCNRegPressure bumpDownwardPressure(const MachineInstr *MI,
462 const SIRegisterInfo *TRI) const;
463};
464
465/// \returns the LaneMask of live lanes of \p Reg at position \p SI. Only the
466/// active lanes of \p LaneMaskFilter will be set in the return value. This is
467/// used, for example, to limit the live lanes to a specific subreg when
468/// calculating use masks.
469LaneBitmask getLiveLaneMask(unsigned Reg, SlotIndex SI,
470 const LiveIntervals &LIS,
471 const MachineRegisterInfo &MRI,
472 LaneBitmask LaneMaskFilter = LaneBitmask::getAll());
473
474LaneBitmask getLiveLaneMask(const LiveInterval &LI, SlotIndex SI,
475 const MachineRegisterInfo &MRI,
476 LaneBitmask LaneMaskFilter = LaneBitmask::getAll());
477
478/// creates a map MachineInstr -> LiveRegSet
479/// R - range of iterators on instructions
480/// After - upon entry or exit of every instruction
481/// Note: there is no entry in the map for instructions with empty live reg set
482/// Complexity = O(NumVirtRegs * averageLiveRangeSegmentsPerReg * lg(R))
483template <typename Range>
484DenseMap<MachineInstr*, GCNRPTracker::LiveRegSet>
485getLiveRegMap(Range &&R, bool After, LiveIntervals &LIS) {
486 std::vector<SlotIndex> Indexes;
487 Indexes.reserve(n: llvm::size(R));
488 auto &SII = *LIS.getSlotIndexes();
489 for (MachineInstr *I : R) {
490 auto SI = SII.getInstructionIndex(MI: *I);
491 Indexes.push_back(x: After ? SI.getDeadSlot() : SI.getBaseIndex());
492 }
493 llvm::sort(C&: Indexes);
494
495 auto &MRI = (*R.begin())->getMF()->getRegInfo();
496 DenseMap<MachineInstr *, GCNRPTracker::LiveRegSet> LiveRegMap;
497 SmallVector<SlotIndex, 32> LiveIdxs, SRLiveIdxs;
498 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
499 auto Reg = Register::index2VirtReg(Index: I);
500 if (!LIS.hasInterval(Reg))
501 continue;
502 auto &LI = LIS.getInterval(Reg);
503 LiveIdxs.clear();
504 if (!LI.findIndexesLiveAt(R&: Indexes, O: std::back_inserter(x&: LiveIdxs)))
505 continue;
506 if (!LI.hasSubRanges()) {
507 for (auto SI : LiveIdxs)
508 LiveRegMap[SII.getInstructionFromIndex(index: SI)][Reg] =
509 MRI.getMaxLaneMaskForVReg(Reg);
510 } else
511 for (const auto &S : LI.subranges()) {
512 // constrain search for subranges by indexes live at main range
513 SRLiveIdxs.clear();
514 S.findIndexesLiveAt(R&: LiveIdxs, O: std::back_inserter(x&: SRLiveIdxs));
515 for (auto SI : SRLiveIdxs)
516 LiveRegMap[SII.getInstructionFromIndex(index: SI)][Reg] |= S.LaneMask;
517 }
518 }
519 return LiveRegMap;
520}
521
522inline GCNRPTracker::LiveRegSet getLiveRegsAfter(const MachineInstr &MI,
523 const LiveIntervals &LIS) {
524 return getLiveRegs(SI: LIS.getInstructionIndex(Instr: MI).getDeadSlot(), LIS,
525 MRI: MI.getMF()->getRegInfo());
526}
527
528inline GCNRPTracker::LiveRegSet getLiveRegsBefore(const MachineInstr &MI,
529 const LiveIntervals &LIS) {
530 return getLiveRegs(SI: LIS.getInstructionIndex(Instr: MI).getBaseIndex(), LIS,
531 MRI: MI.getMF()->getRegInfo());
532}
533
534template <typename Range>
535GCNRegPressure getRegPressure(const MachineRegisterInfo &MRI,
536 Range &&LiveRegs) {
537 GCNRegPressure Res;
538 for (const auto &RM : LiveRegs)
539 Res.inc(Reg: RM.first, PrevMask: LaneBitmask::getNone(), NewMask: RM.second, MRI);
540 return Res;
541}
542
543bool isEqual(const GCNRPTracker::LiveRegSet &S1,
544 const GCNRPTracker::LiveRegSet &S2);
545
546Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST = nullptr,
547 unsigned DynamicVGPRBlockSize = 0);
548
549Printable print(const GCNRPTracker::LiveRegSet &LiveRegs,
550 const MachineRegisterInfo &MRI);
551
552Printable reportMismatch(const GCNRPTracker::LiveRegSet &LISLR,
553 const GCNRPTracker::LiveRegSet &TrackedL,
554 const TargetRegisterInfo *TRI, StringRef Pfx = " ");
555
556struct GCNRegPressurePrinter : public MachineFunctionPass {
557 static char ID;
558
559public:
560 GCNRegPressurePrinter() : MachineFunctionPass(ID) {}
561
562 bool runOnMachineFunction(MachineFunction &MF) override;
563
564 void getAnalysisUsage(AnalysisUsage &AU) const override {
565 AU.addRequired<LiveIntervalsWrapperPass>();
566 AU.setPreservesAll();
567 MachineFunctionPass::getAnalysisUsage(AU);
568 }
569};
570
571LLVM_ABI void dumpMaxRegPressure(MachineFunction &MF,
572 GCNRegPressure::RegKind Kind,
573 LiveIntervals &LIS,
574 const MachineLoopInfo *MLI);
575
576} // end namespace llvm
577
578#endif // LLVM_LIB_TARGET_AMDGPU_GCNREGPRESSURE_H
579