1 //===- GCNRegPressure.h -----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIB_TARGET_AMDGPU_GCNREGPRESSURE_H
10 #define LLVM_LIB_TARGET_AMDGPU_GCNREGPRESSURE_H
12 #include "AMDGPUSubtarget.h"
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/CodeGen/LiveIntervals.h"
15 #include "llvm/CodeGen/MachineBasicBlock.h"
16 #include "llvm/CodeGen/MachineInstr.h"
17 #include "llvm/CodeGen/SlotIndexes.h"
18 #include "llvm/MC/LaneBitmask.h"
19 #include "llvm/Support/Debug.h"
25 class MachineRegisterInfo
;
28 struct GCNRegPressure
{
43 bool empty() const { return getSGPRNum() == 0 && getVGPRNum() == 0; }
45 void clear() { std::fill(&Value
[0], &Value
[TOTAL_KINDS
], 0); }
47 unsigned getSGPRNum() const { return Value
[SGPR32
]; }
48 unsigned getVGPRNum() const { return std::max(Value
[VGPR32
], Value
[AGPR32
]); }
50 unsigned getVGPRTuplesWeight() const { return std::max(Value
[VGPR_TUPLE
],
52 unsigned getSGPRTuplesWeight() const { return Value
[SGPR_TUPLE
]; }
54 unsigned getOccupancy(const GCNSubtarget
&ST
) const {
55 return std::min(ST
.getOccupancyWithNumSGPRs(getSGPRNum()),
56 ST
.getOccupancyWithNumVGPRs(getVGPRNum()));
59 void inc(unsigned Reg
,
62 const MachineRegisterInfo
&MRI
);
64 bool higherOccupancy(const GCNSubtarget
&ST
, const GCNRegPressure
& O
) const {
65 return getOccupancy(ST
) > O
.getOccupancy(ST
);
68 bool less(const GCNSubtarget
&ST
, const GCNRegPressure
& O
,
69 unsigned MaxOccupancy
= std::numeric_limits
<unsigned>::max()) const;
71 bool operator==(const GCNRegPressure
&O
) const {
72 return std::equal(&Value
[0], &Value
[TOTAL_KINDS
], O
.Value
);
75 bool operator!=(const GCNRegPressure
&O
) const {
79 void print(raw_ostream
&OS
, const GCNSubtarget
*ST
= nullptr) const;
80 void dump() const { print(dbgs()); }
83 unsigned Value
[TOTAL_KINDS
];
85 static unsigned getRegKind(unsigned Reg
, const MachineRegisterInfo
&MRI
);
87 friend GCNRegPressure
max(const GCNRegPressure
&P1
,
88 const GCNRegPressure
&P2
);
91 inline GCNRegPressure
max(const GCNRegPressure
&P1
, const GCNRegPressure
&P2
) {
93 for (unsigned I
= 0; I
< GCNRegPressure::TOTAL_KINDS
; ++I
)
94 Res
.Value
[I
] = std::max(P1
.Value
[I
], P2
.Value
[I
]);
100 using LiveRegSet
= DenseMap
<unsigned, LaneBitmask
>;
103 const LiveIntervals
&LIS
;
105 GCNRegPressure CurPressure
, MaxPressure
;
106 const MachineInstr
*LastTrackedMI
= nullptr;
107 mutable const MachineRegisterInfo
*MRI
= nullptr;
109 GCNRPTracker(const LiveIntervals
&LIS_
) : LIS(LIS_
) {}
111 void reset(const MachineInstr
&MI
, const LiveRegSet
*LiveRegsCopy
,
115 // live regs for the current state
116 const decltype(LiveRegs
) &getLiveRegs() const { return LiveRegs
; }
117 const MachineInstr
*getLastTrackedMI() const { return LastTrackedMI
; }
119 void clearMaxPressure() { MaxPressure
.clear(); }
121 // returns MaxPressure, resetting it
122 decltype(MaxPressure
) moveMaxPressure() {
123 auto Res
= MaxPressure
;
128 decltype(LiveRegs
) moveLiveRegs() {
129 return std::move(LiveRegs
);
132 static void printLiveRegs(raw_ostream
&OS
, const LiveRegSet
& LiveRegs
,
133 const MachineRegisterInfo
&MRI
);
136 class GCNUpwardRPTracker
: public GCNRPTracker
{
138 GCNUpwardRPTracker(const LiveIntervals
&LIS_
) : GCNRPTracker(LIS_
) {}
140 // reset tracker to the point just below MI
141 // filling live regs upon this point using LIS
142 void reset(const MachineInstr
&MI
, const LiveRegSet
*LiveRegs
= nullptr);
144 // move to the state just above the MI
145 void recede(const MachineInstr
&MI
);
147 // checks whether the tracker's state after receding MI corresponds
148 // to reported by LIS
149 bool isValid() const;
152 class GCNDownwardRPTracker
: public GCNRPTracker
{
153 // Last position of reset or advanceBeforeNext
154 MachineBasicBlock::const_iterator NextMI
;
156 MachineBasicBlock::const_iterator MBBEnd
;
159 GCNDownwardRPTracker(const LiveIntervals
&LIS_
) : GCNRPTracker(LIS_
) {}
161 const MachineBasicBlock::const_iterator
getNext() const { return NextMI
; }
163 // Reset tracker to the point before the MI
164 // filling live regs upon this point using LIS.
165 // Returns false if block is empty except debug values.
166 bool reset(const MachineInstr
&MI
, const LiveRegSet
*LiveRegs
= nullptr);
168 // Move to the state right before the next MI. Returns false if reached
170 bool advanceBeforeNext();
172 // Move to the state at the MI, advanceBeforeNext has to be called first.
173 void advanceToNext();
175 // Move to the state at the next MI. Returns false if reached end of block.
178 // Advance instructions until before End.
179 bool advance(MachineBasicBlock::const_iterator End
);
181 // Reset to Begin and advance to End.
182 bool advance(MachineBasicBlock::const_iterator Begin
,
183 MachineBasicBlock::const_iterator End
,
184 const LiveRegSet
*LiveRegsCopy
= nullptr);
187 LaneBitmask
getLiveLaneMask(unsigned Reg
,
189 const LiveIntervals
&LIS
,
190 const MachineRegisterInfo
&MRI
);
192 GCNRPTracker::LiveRegSet
getLiveRegs(SlotIndex SI
,
193 const LiveIntervals
&LIS
,
194 const MachineRegisterInfo
&MRI
);
196 /// creates a map MachineInstr -> LiveRegSet
197 /// R - range of iterators on instructions
198 /// After - upon entry or exit of every instruction
199 /// Note: there is no entry in the map for instructions with empty live reg set
200 /// Complexity = O(NumVirtRegs * averageLiveRangeSegmentsPerReg * lg(R))
201 template <typename Range
>
202 DenseMap
<MachineInstr
*, GCNRPTracker::LiveRegSet
>
203 getLiveRegMap(Range
&&R
, bool After
, LiveIntervals
&LIS
) {
204 std::vector
<SlotIndex
> Indexes
;
205 Indexes
.reserve(std::distance(R
.begin(), R
.end()));
206 auto &SII
= *LIS
.getSlotIndexes();
207 for (MachineInstr
*I
: R
) {
208 auto SI
= SII
.getInstructionIndex(*I
);
209 Indexes
.push_back(After
? SI
.getDeadSlot() : SI
.getBaseIndex());
211 std::sort(Indexes
.begin(), Indexes
.end());
213 auto &MRI
= (*R
.begin())->getParent()->getParent()->getRegInfo();
214 DenseMap
<MachineInstr
*, GCNRPTracker::LiveRegSet
> LiveRegMap
;
215 SmallVector
<SlotIndex
, 32> LiveIdxs
, SRLiveIdxs
;
216 for (unsigned I
= 0, E
= MRI
.getNumVirtRegs(); I
!= E
; ++I
) {
217 auto Reg
= Register::index2VirtReg(I
);
218 if (!LIS
.hasInterval(Reg
))
220 auto &LI
= LIS
.getInterval(Reg
);
222 if (!LI
.findIndexesLiveAt(Indexes
, std::back_inserter(LiveIdxs
)))
224 if (!LI
.hasSubRanges()) {
225 for (auto SI
: LiveIdxs
)
226 LiveRegMap
[SII
.getInstructionFromIndex(SI
)][Reg
] =
227 MRI
.getMaxLaneMaskForVReg(Reg
);
229 for (const auto &S
: LI
.subranges()) {
230 // constrain search for subranges by indexes live at main range
232 S
.findIndexesLiveAt(LiveIdxs
, std::back_inserter(SRLiveIdxs
));
233 for (auto SI
: SRLiveIdxs
)
234 LiveRegMap
[SII
.getInstructionFromIndex(SI
)][Reg
] |= S
.LaneMask
;
240 inline GCNRPTracker::LiveRegSet
getLiveRegsAfter(const MachineInstr
&MI
,
241 const LiveIntervals
&LIS
) {
242 return getLiveRegs(LIS
.getInstructionIndex(MI
).getDeadSlot(), LIS
,
243 MI
.getParent()->getParent()->getRegInfo());
246 inline GCNRPTracker::LiveRegSet
getLiveRegsBefore(const MachineInstr
&MI
,
247 const LiveIntervals
&LIS
) {
248 return getLiveRegs(LIS
.getInstructionIndex(MI
).getBaseIndex(), LIS
,
249 MI
.getParent()->getParent()->getRegInfo());
252 template <typename Range
>
253 GCNRegPressure
getRegPressure(const MachineRegisterInfo
&MRI
,
256 for (const auto &RM
: LiveRegs
)
257 Res
.inc(RM
.first
, LaneBitmask::getNone(), RM
.second
, MRI
);
261 bool isEqual(const GCNRPTracker::LiveRegSet
&S1
,
262 const GCNRPTracker::LiveRegSet
&S2
);
264 void printLivesAt(SlotIndex SI
,
265 const LiveIntervals
&LIS
,
266 const MachineRegisterInfo
&MRI
);
268 } // end namespace llvm
270 #endif // LLVM_LIB_TARGET_AMDGPU_GCNREGPRESSURE_H