25#define DEBUG_TYPE "gcn-rematerialization-strategy"
31GCNRematStrategy::RematRegions::RematRegions(
36 : Bounds(Regions), LiveIns(LiveIns), LiveOuts(LiveOuts),
37 Frequencies(Regions.
size(), 0), LIS(LIS),
MRI(
MRI) {
45 for (
unsigned RegionIdx :
seq(Regions.
size())) {
48 Frequencies[RegionIdx] = BlockFreq;
49 if (BlockFreq && BlockFreq < MinFreq)
51 else if (BlockFreq > MaxFreq)
58 if (MinFreq >= FreqScaleFactor * FreqScaleFactor) {
60 Freq /= FreqScaleFactor;
61 MinFreq /= FreqScaleFactor;
62 MaxFreq /= FreqScaleFactor;
66GCNRegPressure GCNRematStrategy::RematRegions::computeMaxRegPressure(
67 unsigned RegionIdx)
const {
68 assert(RegionIdx < Bounds.size() &&
"out of bounds");
69 const auto &[Begin,
End] = Bounds[RegionIdx];
72 GCNDownwardRPTracker RPTracker(LIS);
73 RPTracker.advance(Begin,
End, &LiveIns[RegionIdx]);
74 return RPTracker.moveMaxPressure();
77void GCNRematStrategy::RematRegions::removeFromLiveMaps(
78 Register Reg,
const BitVector &LiveIn,
const BitVector &LiveOut) {
80 LiveIns[
I].erase(
Reg);
82 LiveOuts[
I].erase(
Reg);
85void GCNRematStrategy::RematRegions::addToLiveMaps(
Register Reg,
87 const BitVector &LiveIn,
88 const BitVector &LiveOut) {
89 std::pair<Register, LaneBitmask> LiveReg(
Reg, Mask);
91 LiveIns[
I].insert(LiveReg);
93 LiveOuts[
I].insert(LiveReg);
96GCNRematStrategy::RematTargets::RematTargets(
97 unsigned MaxSGPRs,
unsigned MaxVGPRs,
bool SpillReduction,
100 : ExcessRP(Regions.
size()), Regions(Regions),
101 SpillReduction(SpillReduction) {
102 RPTargets.reserve(Regions.size());
103 for (
unsigned RegionIdx :
seq(Regions.size())) {
105 RPTargets.emplace_back(MaxSGPRs, MaxVGPRs, MF, (*MaxPressure)[RegionIdx]);
107 RPTargets.emplace_back(MaxSGPRs, MaxVGPRs, MF,
108 Regions.computeMaxRegPressure(RegionIdx));
110 if (!RPTargets.back().satisfied())
111 ExcessRP.set(RegionIdx);
115void GCNRematStrategy::RematTargets::updateRPTargets(
117 for (
unsigned I : UpdateRegions.
set_bits()) {
118 RPTargets[
I].saveRP(RPSave);
119 if (ExcessRP[
I] && RPTargets[
I].satisfied()) {
126bool GCNRematStrategy::RematTargets::updateAndVerifyRPTargets(
127 const BitVector &UpdateRegions) {
128 bool TooOptimistic =
false;
129 for (
unsigned RegionIdx : UpdateRegions.
set_bits()) {
130 GCNRPTarget &
Target = RPTargets[RegionIdx];
131 Target.setRP(Regions.computeMaxRegPressure(RegionIdx));
136 if (!ExcessRP.test(RegionIdx) && !
Target.satisfied()) {
137 LLVM_DEBUG(
dbgs() <<
" [" << RegionIdx <<
"] Incorrect RP estimation\n");
138 TooOptimistic =
true;
139 ExcessRP.set(RegionIdx);
142 return TooOptimistic;
145void GCNRematStrategy::RematCandidate::init(
const RematRegions &RF,
146 const Rematerializer &Remater,
147 const MachineRegisterInfo &MRI) {
148 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
154 for (
unsigned I : Live.set_bits()) {
157 if (!LiveIn[
I] || !LiveOut[
I] ||
Reg.Uses.contains(
I))
158 UnpredictableRPSave.set(
I);
169 Reg.hasUsersInDefRegion() ? 0 : RF.getFrequencyOrMin(
Reg.DefRegion);
170 int64_t UseOrMax = 0;
171 for (
const auto &[UseRegion,
_] :
Reg.Uses) {
172 if (
Reg.DefRegion == UseRegion)
174 UseOrMax += RF.getFrequencyOrMax(UseRegion);
176 FreqDiff = DefOrMin - UseOrMax;
179void GCNRematStrategy::RematCandidate::update(
const RematTargets &Targets) {
180 MaxFreq = RegionImpact = 0;
181 for (
unsigned RegionIdx : Targets.ExcessRP.set_bits()) {
182 if (!Live[RegionIdx])
188 const GCNRPTarget &RegionTarget = Targets.RPTargets[RegionIdx];
194 RegionImpact += (UnpredictableRPSave[RegionIdx] ? 1 : 2) * NumRegsBenefit;
196 if (Targets.SpillReduction) {
197 uint64_t Freq = Targets.Regions.getFrequency(RegionIdx);
198 if (UnpredictableRPSave[RegionIdx]) {
203 MaxFreq = std::max(MaxFreq, Freq);
208bool GCNRematStrategy::RematCandidate::maybeBeneficial(
209 const RematTargets &Targets)
const {
210 for (
unsigned I : Targets.ExcessRP.set_bits()) {
211 if (Live[
I] && Targets.RPTargets[
I].isSaveBeneficial(RPSave))
217void GCNRematStrategy::RematCandidate::rematerialize(
218 Rematerializer &Remater)
const {
219 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
222 Rematerializer::DependencyReuseInfo DRI;
223 for (RegisterIdx DepRegIdx :
Reg.Dependencies)
224 DRI.
reuse(DepRegIdx);
227 SmallVector<unsigned, 8> RematRegions;
228 RematRegions.reserve(
Reg.Uses.size());
229 for (
const auto &[UseRegion,
_] :
Reg.Uses) {
230 if (
Reg.DefRegion != UseRegion)
231 RematRegions.push_back(UseRegion);
233 for (
const unsigned UseRegion : RematRegions) {
234 Rematerializer::DependencyReuseInfo RegionDRI(DRI);
235 Remater.rematerializeToRegion(RegIdx, UseRegion, RegionDRI);
240 unsigned MaxSGPRs,
unsigned MaxVGPRs,
bool SpillReduction,
242 assert(AffectedRegions.
size() == Regions.size());
243 assert(!MaxPressure || MaxPressure->
size() == Regions.size());
245 RematTargets Targets(MaxSGPRs, MaxVGPRs, SpillReduction, MF, Regions,
247 if (Targets.allAchieved())
249 if (!CandidatesCreated) {
255 dbgs() <<
"Rematerializing across regions to reduce RP below target in "
257 MF.getFunction().printAsOperand(
dbgs(),
false);
260 <<
" rematerialization candidates were identified in the function\n"
261 << Targets.print() <<
'\n';
262 MF.print(
dbgs(), LIS.getSlotIndexes());
267 for (
auto [CandIdx, Cand] :
enumerate(Candidates)) {
268 Cand.update(Targets);
269 if (!Cand.hasNullScore())
270 CandidateOrder.push_back(CandIdx);
280 sort(CandidateOrder, [&](
unsigned LHSIndex,
unsigned RHSIndex) {
281 return Candidates[LHSIndex] < Candidates[RHSIndex];
285 dbgs() <<
"==== NEW REMAT ROUND ====\n"
286 <<
"Candidates with non-null score, in rematerialization order:\n";
287 for (
const RematCandidate &Cand :
reverse(Candidates)) {
288 dbgs() <<
" " << Cand.print() <<
" | "
289 << Remater.printRematReg(Cand.RegIdx) <<
'\n';
291 dbgs() << Targets.print();
297 while (!CandidateOrder.empty()) {
298 const RematCandidate &Cand = Candidates[CandidateOrder.back()];
307 if (!Cand.maybeBeneficial(Targets)) {
309 << Cand.print() <<
" | "
310 << Remater.printRematReg(Cand.RegIdx));
313 CandidateOrder.pop_back();
315#ifdef EXPENSIVE_CHECKS
325 if (!MO.isReg() || !MO.getReg() || !MO.readsReg() || MO.isDef())
333 LaneBitmask LM = MRI.getMaxLaneMaskForVReg(MO.getReg());
335 LM =
TRI.getSubRegIndexLaneMask(MO.getSubReg());
337 for (
const auto &[UseRegion,
_] : Reg.Uses) {
338 if (UseRegion == Reg.DefRegion)
341 LaneBitmask UncoveredLanes = LM & ~(LiveInMask & LM);
345 if (UncoveredLanes.
any()) {
348 assert((SR.LaneMask & UncoveredLanes).none());
357 LLVM_DEBUG(
dbgs() <<
"** REMAT " << Remater.printRematReg(Cand.RegIdx)
359 Regions.removeFromLiveMaps(Reg.getDefReg(), Cand.LiveIn, Cand.LiveOut);
361 Recorder->LiveMapUpdates.emplace_back(Cand.RegIdx, Cand.LiveIn,
364 Cand.rematerialize(Remater);
369 Targets.updateRPTargets(Cand.Live, Cand.RPSave);
370 RecomputeRP |= Cand.UnpredictableRPSave;
371 AffectedRegions |= Cand.Live;
372 if (Targets.allAchieved()) {
378 if (!Targets.updateAndVerifyRPTargets(RecomputeRP) &&
379 Targets.allAchieved()) {
388 unsigned NumUsefulCandidates = 0;
389 for (
unsigned CandIdx : CandidateOrder) {
390 RematCandidate &Candidate = Candidates[CandIdx];
391 Candidate.update(Targets);
392 if (!Candidate.hasNullScore())
393 CandidateOrder[NumUsefulCandidates++] = CandIdx;
395 if (NumUsefulCandidates == 0) {
396 LLVM_DEBUG(
dbgs() <<
"Stop on exhausted rematerialization candidates\n");
399 CandidateOrder.truncate(NumUsefulCandidates);
404 for (
unsigned RegionIdx : AffectedRegions.
set_bits())
405 (*MaxPressure)[RegionIdx] = Targets.RPTargets[RegionIdx].getCurrentRP();
408void GCNRematStrategy::createCandidates() {
409 CandidatesCreated =
true;
418 DefRegToCandIdx.resize(
MRI.getNumVirtRegs());
419 const unsigned NumRegions = Regions.size();
421 for (
unsigned RegIdx = 0, E = Remater.
getNumRegs(); RegIdx < E; ++RegIdx) {
438 if (CandReg.
Uses.size() > 1 &&
451 return MarkedRegs.contains(Remater.getReg(DepRegIdx).getDefReg());
455 if (!candidateHasValidUsers(RegIdx, MarkedRegs))
459 MarkedRegs.
insert(DefReg);
460 DefRegToCandIdx[DefReg] =
static_cast<unsigned>(Candidates.
size());
466 for (
unsigned RegionIdx = 0; RegionIdx < NumRegions; ++RegionIdx) {
467 for (
const auto &[
Reg, Mask] : Regions.getLiveIns(RegionIdx)) {
470 unsigned CandIdx = DefRegToCandIdx[
Reg];
472 Candidates[CandIdx].LiveIn.set(RegionIdx);
474 for (
const auto &[
Reg, Mask] : Regions.getLiveOuts(RegionIdx)) {
477 unsigned CandIdx = DefRegToCandIdx[
Reg];
479 Candidates[CandIdx].LiveOut.set(RegionIdx);
483 for (RematCandidate &Cand : Candidates)
484 Cand.init(Regions, Remater, MRI);
487bool GCNRematStrategy::candidateHasValidUsers(
488 RegisterIdx CandIdx,
const SmallSet<Register, 4> &MarkedRegs)
const {
489 const Rematerializer::Reg &CandReg = Remater.getReg(CandIdx);
491 LIS.getInstructionIndex(*CandReg.
getLastDef()).getRegSlot(
true);
493 for (
const auto &[UseRegion,
Users] : CandReg.
Uses) {
497 "user must have at least one operand");
500 const MachineOperand &DefMO = UserMI->
getOperand(0);
506 assert(FirstUseMI &&
"there must be a user in the region");
507 SlotIndex FirstUseIdx =
508 LIS.getInstructionIndex(*FirstUseMI).getRegSlot(
true);
512 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
513 Register DepDefReg = DepReg.getDefReg();
514 return !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
519 [&](
const std::pair<Register, LaneBitmask> &RegAndMask) {
520 const auto &[
Reg,
Mask] = RegAndMask;
521 return !Remater.isRegIdenticalAtUses(
Reg, Mask, RefIdx,
531 assert(Recorder &&
"recorder should be defined");
532 Recorder->Listener.rollback(Remater);
533 for (
const auto &[RegIdx, LiveIn, LiveOut] : Recorder->LiveMapUpdates) {
535 Regions.addToLiveMaps(Reg.getDefReg(), Reg.Mask, LiveIn, LiveOut);
539#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
540Printable GCNRematStrategy::RematCandidate::print()
const {
542 OS <<
'(' << MaxFreq <<
", " << FreqDiff <<
", " << RegionImpact <<
')';
546Printable GCNRematStrategy::RematTargets::print()
const {
547 return Printable([&](raw_ostream &OS) {
549 OS <<
"No target regions\n";
552 OS <<
"Target regions:\n";
553 for (
unsigned I : ExcessRP.set_bits())
554 OS <<
" [" <<
I <<
"] " << RPTargets[
I] <<
'\n';
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements the BitVector class.
This file defines the GCNRegPressure class, which tracks registry pressure by bookkeeping number of S...
Rematerialization strategy, based on the target-independent rematerializer.
static Register UseReg(const MachineOperand &MO)
iv Induction Variable Users
A common definition of LaneBitmask for use in TableGen and CodeGen.
TargetInstrInfo::RegSubRegPair RegSubRegPair
Register const TargetRegisterInfo * TRI
Promote Memory to Register
MachineRegisterInfo & MRI
Rematerializer::RegisterIdx RegisterIdx
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BitVector & reset()
Reset all bits in the bitvector.
iterator_range< const_set_bits_iterator > set_bits() const
size_type size() const
Returns the number of bits in this bitvector.
uint64_t getFrequency() const
Returns the frequency as a fixpoint number scaled by the entry frequency.
unsigned getNumRegsBenefit(const GCNRegPressure &SaveRP) const
Returns the benefit towards achieving the RP target that saving SaveRP represents,...
void rollbackRecordedRemats()
Rolls back all recorded rematerializations.
void rematerializeFor(unsigned MaxSGPRs, unsigned MaxVGPRs, bool SpillReduction, BitVector &AffectedRegions, MutableArrayRef< GCNRegPressure > *MaxPressure=nullptr)
Rematerializes with the goal of reducing the maximum pressure in all Regions to MaxSGPRs SGPRs and Ma...
A live range for subregisters.
LiveInterval - This class represents the liveness of a register, or stack slot.
bool hasSubRanges() const
Returns true if subregister liveness information is available.
iterator_range< subrange_iterator > subranges()
MachineBlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate machine basic b...
LLVM_ABI BlockFrequency getBlockFreq(const MachineBasicBlock *MBB) const
getblockFreq - Return block frequency.
LLVM_ABI BlockFrequency getEntryFreq() const
Divide a block's BlockFrequency::getFrequency() value by this value to obtain the entry block - relat...
Representation of each machine instruction.
unsigned getNumOperands() const
Retuns the total number of operands.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Simple wrapper around std::function<void(raw_ostream&)>.
Wrapper class representing virtual and physical registers.
static constexpr bool isPhysicalRegister(unsigned Reg)
Return true if the specified register number is in the physical register namespace.
unsigned getNumRegs() const
const Reg & getReg(RegisterIdx RegIdx) const
unsigned RegisterIdx
Index type for rematerializable registers.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
bool contains(const T &V) const
Check if the SmallSet contains the given element.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
This class implements an extremely fast bulk output stream that can only output to a stream.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
GCNRegPressure getRegPressure(const MachineRegisterInfo &MRI, Range &&LiveRegs)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
@ End
Run the machine verifier once, at the end of the pipeline.
void inc(unsigned Reg, LaneBitmask PrevMask, LaneBitmask NewMask, const MachineRegisterInfo &MRI)
constexpr bool any() const
static constexpr LaneBitmask getNone()
DependencyReuseInfo & reuse(RegisterIdx DepIdx)
A rematerializable register, potentially defined by multiple instructions.
LLVM_ABI std::pair< MachineInstr *, MachineInstr * > getRegionUseBounds(unsigned UseRegion, const LiveIntervals &LIS) const
Returns the first and last user of the register in region UseRegion.
SmallVector< MachineInstr *, 1 > Defs
All instructions that define the register, in program order.
bool hasUsersOutsideDefRegion() const
SmallDenseMap< unsigned, RegionUsers, 2 > Uses
Uses of the register, mapped by region.
MachineInstr * getLastDef() const
Register getDefReg() const
Returns the rematerializable register from one of its defining instructions.
SmallVector< RegisterIdx, 2 > Dependencies
This register's rematerializable dependencies, one per unique rematerializable register operand over ...
A pair composed of a register and a sub-register index.