//===- RegisterPressure.cpp - Dynamic Register Pressure -------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the RegisterPressure class which can be used to track // MachineInstr level register pressure. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/RegisterPressure.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/LiveInterval.h" #include "llvm/CodeGen/LiveIntervals.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBundle.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterClassInfo.h" #include "llvm/CodeGen/SlotIndexes.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Config/llvm-config.h" #include "llvm/MC/LaneBitmask.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include using namespace llvm; /// Increase pressure for each pressure set provided by TargetRegisterInfo. static void increaseSetPressure(std::vector &CurrSetPressure, const MachineRegisterInfo &MRI, unsigned Reg, LaneBitmask PrevMask, LaneBitmask NewMask) { assert((PrevMask & ~NewMask).none() && "Must not remove bits"); if (PrevMask.any() || NewMask.none()) return; PSetIterator PSetI = MRI.getPressureSets(Reg); unsigned Weight = PSetI.getWeight(); for (; PSetI.isValid(); ++PSetI) CurrSetPressure[*PSetI] += Weight; } /// Decrease pressure for each pressure set provided by TargetRegisterInfo. static void decreaseSetPressure(std::vector &CurrSetPressure, const MachineRegisterInfo &MRI, Register Reg, LaneBitmask PrevMask, LaneBitmask NewMask) { //assert((NewMask & !PrevMask) == 0 && "Must not add bits"); if (NewMask.any() || PrevMask.none()) return; PSetIterator PSetI = MRI.getPressureSets(Reg); unsigned Weight = PSetI.getWeight(); for (; PSetI.isValid(); ++PSetI) { assert(CurrSetPressure[*PSetI] >= Weight && "register pressure underflow"); CurrSetPressure[*PSetI] -= Weight; } } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void llvm::dumpRegSetPressure(ArrayRef SetPressure, const TargetRegisterInfo *TRI) { bool Empty = true; for (unsigned i = 0, e = SetPressure.size(); i < e; ++i) { if (SetPressure[i] != 0) { dbgs() << TRI->getRegPressureSetName(i) << "=" << SetPressure[i] << '\n'; Empty = false; } } if (Empty) dbgs() << "\n"; } LLVM_DUMP_METHOD void RegisterPressure::dump(const TargetRegisterInfo *TRI) const { dbgs() << "Max Pressure: "; dumpRegSetPressure(MaxSetPressure, TRI); dbgs() << "Live In: "; for (const RegisterMaskPair &P : LiveInRegs) { dbgs() << printVRegOrUnit(P.RegUnit, TRI); if (!P.LaneMask.all()) dbgs() << ':' << PrintLaneMask(P.LaneMask); dbgs() << ' '; } dbgs() << '\n'; dbgs() << "Live Out: "; for (const RegisterMaskPair &P : LiveOutRegs) { dbgs() << printVRegOrUnit(P.RegUnit, TRI); if (!P.LaneMask.all()) dbgs() << ':' << PrintLaneMask(P.LaneMask); dbgs() << ' '; } dbgs() << '\n'; } LLVM_DUMP_METHOD void RegPressureTracker::dump() const { if (!isTopClosed() || !isBottomClosed()) { dbgs() << "Curr Pressure: "; dumpRegSetPressure(CurrSetPressure, TRI); } P.dump(TRI); } LLVM_DUMP_METHOD void PressureDiff::dump(const TargetRegisterInfo &TRI) const { const char *sep = ""; for (const PressureChange &Change : *this) { if (!Change.isValid()) break; dbgs() << sep << TRI.getRegPressureSetName(Change.getPSet()) << " " << Change.getUnitInc(); sep = " "; } dbgs() << '\n'; } LLVM_DUMP_METHOD void PressureChange::dump() const { dbgs() << "[" << getPSetOrMax() << ", " << getUnitInc() << "]\n"; } void RegPressureDelta::dump() const { dbgs() << "[Excess="; Excess.dump(); dbgs() << ", CriticalMax="; CriticalMax.dump(); dbgs() << ", CurrentMax="; CurrentMax.dump(); dbgs() << "]\n"; } #endif void RegPressureTracker::increaseRegPressure(Register RegUnit, LaneBitmask PreviousMask, LaneBitmask NewMask) { if (PreviousMask.any() || NewMask.none()) return; PSetIterator PSetI = MRI->getPressureSets(RegUnit); unsigned Weight = PSetI.getWeight(); for (; PSetI.isValid(); ++PSetI) { CurrSetPressure[*PSetI] += Weight; P.MaxSetPressure[*PSetI] = std::max(P.MaxSetPressure[*PSetI], CurrSetPressure[*PSetI]); } } void RegPressureTracker::decreaseRegPressure(Register RegUnit, LaneBitmask PreviousMask, LaneBitmask NewMask) { decreaseSetPressure(CurrSetPressure, *MRI, RegUnit, PreviousMask, NewMask); } /// Clear the result so it can be used for another round of pressure tracking. void IntervalPressure::reset() { TopIdx = BottomIdx = SlotIndex(); MaxSetPressure.clear(); LiveInRegs.clear(); LiveOutRegs.clear(); } /// Clear the result so it can be used for another round of pressure tracking. void RegionPressure::reset() { TopPos = BottomPos = MachineBasicBlock::const_iterator(); MaxSetPressure.clear(); LiveInRegs.clear(); LiveOutRegs.clear(); } /// If the current top is not less than or equal to the next index, open it. /// We happen to need the SlotIndex for the next top for pressure update. void IntervalPressure::openTop(SlotIndex NextTop) { if (TopIdx <= NextTop) return; TopIdx = SlotIndex(); LiveInRegs.clear(); } /// If the current top is the previous instruction (before receding), open it. void RegionPressure::openTop(MachineBasicBlock::const_iterator PrevTop) { if (TopPos != PrevTop) return; TopPos = MachineBasicBlock::const_iterator(); LiveInRegs.clear(); } /// If the current bottom is not greater than the previous index, open it. void IntervalPressure::openBottom(SlotIndex PrevBottom) { if (BottomIdx > PrevBottom) return; BottomIdx = SlotIndex(); LiveInRegs.clear(); } /// If the current bottom is the previous instr (before advancing), open it. void RegionPressure::openBottom(MachineBasicBlock::const_iterator PrevBottom) { if (BottomPos != PrevBottom) return; BottomPos = MachineBasicBlock::const_iterator(); LiveInRegs.clear(); } void LiveRegSet::init(const MachineRegisterInfo &MRI) { const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); unsigned NumRegUnits = TRI.getNumRegs(); unsigned NumVirtRegs = MRI.getNumVirtRegs(); Regs.setUniverse(NumRegUnits + NumVirtRegs); this->NumRegUnits = NumRegUnits; } void LiveRegSet::clear() { Regs.clear(); } static const LiveRange *getLiveRange(const LiveIntervals &LIS, unsigned Reg) { if (Register::isVirtualRegister(Reg)) return &LIS.getInterval(Reg); return LIS.getCachedRegUnit(Reg); } void RegPressureTracker::reset() { MBB = nullptr; LIS = nullptr; CurrSetPressure.clear(); LiveThruPressure.clear(); P.MaxSetPressure.clear(); if (RequireIntervals) static_cast(P).reset(); else static_cast(P).reset(); LiveRegs.clear(); UntiedDefs.clear(); } /// Setup the RegPressureTracker. /// /// TODO: Add support for pressure without LiveIntervals. void RegPressureTracker::init(const MachineFunction *mf, const RegisterClassInfo *rci, const LiveIntervals *lis, const MachineBasicBlock *mbb, MachineBasicBlock::const_iterator pos, bool TrackLaneMasks, bool TrackUntiedDefs) { reset(); MF = mf; TRI = MF->getSubtarget().getRegisterInfo(); RCI = rci; MRI = &MF->getRegInfo(); MBB = mbb; this->TrackUntiedDefs = TrackUntiedDefs; this->TrackLaneMasks = TrackLaneMasks; if (RequireIntervals) { assert(lis && "IntervalPressure requires LiveIntervals"); LIS = lis; } CurrPos = pos; CurrSetPressure.assign(TRI->getNumRegPressureSets(), 0); P.MaxSetPressure = CurrSetPressure; LiveRegs.init(*MRI); if (TrackUntiedDefs) UntiedDefs.setUniverse(MRI->getNumVirtRegs()); } /// Does this pressure result have a valid top position and live ins. bool RegPressureTracker::isTopClosed() const { if (RequireIntervals) return static_cast(P).TopIdx.isValid(); return (static_cast(P).TopPos == MachineBasicBlock::const_iterator()); } /// Does this pressure result have a valid bottom position and live outs. bool RegPressureTracker::isBottomClosed() const { if (RequireIntervals) return static_cast(P).BottomIdx.isValid(); return (static_cast(P).BottomPos == MachineBasicBlock::const_iterator()); } SlotIndex RegPressureTracker::getCurrSlot() const { MachineBasicBlock::const_iterator IdxPos = skipDebugInstructionsForward(CurrPos, MBB->end()); if (IdxPos == MBB->end()) return LIS->getMBBEndIdx(MBB); return LIS->getInstructionIndex(*IdxPos).getRegSlot(); } /// Set the boundary for the top of the region and summarize live ins. void RegPressureTracker::closeTop() { if (RequireIntervals) static_cast(P).TopIdx = getCurrSlot(); else static_cast(P).TopPos = CurrPos; assert(P.LiveInRegs.empty() && "inconsistent max pressure result"); P.LiveInRegs.reserve(LiveRegs.size()); LiveRegs.appendTo(P.LiveInRegs); } /// Set the boundary for the bottom of the region and summarize live outs. void RegPressureTracker::closeBottom() { if (RequireIntervals) static_cast(P).BottomIdx = getCurrSlot(); else static_cast(P).BottomPos = CurrPos; assert(P.LiveOutRegs.empty() && "inconsistent max pressure result"); P.LiveOutRegs.reserve(LiveRegs.size()); LiveRegs.appendTo(P.LiveOutRegs); } /// Finalize the region boundaries and record live ins and live outs. void RegPressureTracker::closeRegion() { if (!isTopClosed() && !isBottomClosed()) { assert(LiveRegs.size() == 0 && "no region boundary"); return; } if (!isBottomClosed()) closeBottom(); else if (!isTopClosed()) closeTop(); // If both top and bottom are closed, do nothing. } /// The register tracker is unaware of global liveness so ignores normal /// live-thru ranges. However, two-address or coalesced chains can also lead /// to live ranges with no holes. Count these to inform heuristics that we /// can never drop below this pressure. void RegPressureTracker::initLiveThru(const RegPressureTracker &RPTracker) { LiveThruPressure.assign(TRI->getNumRegPressureSets(), 0); assert(isBottomClosed() && "need bottom-up tracking to intialize."); for (const RegisterMaskPair &Pair : P.LiveOutRegs) { Register RegUnit = Pair.RegUnit; if (Register::isVirtualRegister(RegUnit) && !RPTracker.hasUntiedDef(RegUnit)) increaseSetPressure(LiveThruPressure, *MRI, RegUnit, LaneBitmask::getNone(), Pair.LaneMask); } } static LaneBitmask getRegLanes(ArrayRef RegUnits, Register RegUnit) { auto I = llvm::find_if(RegUnits, [RegUnit](const RegisterMaskPair Other) { return Other.RegUnit == RegUnit; }); if (I == RegUnits.end()) return LaneBitmask::getNone(); return I->LaneMask; } static void addRegLanes(SmallVectorImpl &RegUnits, RegisterMaskPair Pair) { Register RegUnit = Pair.RegUnit; assert(Pair.LaneMask.any()); auto I = llvm::find_if(RegUnits, [RegUnit](const RegisterMaskPair Other) { return Other.RegUnit == RegUnit; }); if (I == RegUnits.end()) { RegUnits.push_back(Pair); } else { I->LaneMask |= Pair.LaneMask; } } static void setRegZero(SmallVectorImpl &RegUnits, Register RegUnit) { auto I = llvm::find_if(RegUnits, [RegUnit](const RegisterMaskPair Other) { return Other.RegUnit == RegUnit; }); if (I == RegUnits.end()) { RegUnits.push_back(RegisterMaskPair(RegUnit, LaneBitmask::getNone())); } else { I->LaneMask = LaneBitmask::getNone(); } } static void removeRegLanes(SmallVectorImpl &RegUnits, RegisterMaskPair Pair) { Register RegUnit = Pair.RegUnit; assert(Pair.LaneMask.any()); auto I = llvm::find_if(RegUnits, [RegUnit](const RegisterMaskPair Other) { return Other.RegUnit == RegUnit; }); if (I != RegUnits.end()) { I->LaneMask &= ~Pair.LaneMask; if (I->LaneMask.none()) RegUnits.erase(I); } } static LaneBitmask getLanesWithProperty(const LiveIntervals &LIS, const MachineRegisterInfo &MRI, bool TrackLaneMasks, Register RegUnit, SlotIndex Pos, LaneBitmask SafeDefault, bool (*Property)(const LiveRange &LR, SlotIndex Pos)) { if (RegUnit.isVirtual()) { const LiveInterval &LI = LIS.getInterval(RegUnit); LaneBitmask Result; if (TrackLaneMasks && LI.hasSubRanges()) { for (const LiveInterval::SubRange &SR : LI.subranges()) { if (Property(SR, Pos)) Result |= SR.LaneMask; } } else if (Property(LI, Pos)) { Result = TrackLaneMasks ? MRI.getMaxLaneMaskForVReg(RegUnit) : LaneBitmask::getAll(); } return Result; } else { const LiveRange *LR = LIS.getCachedRegUnit(RegUnit); // Be prepared for missing liveranges: We usually do not compute liveranges // for physical registers on targets with many registers (GPUs). if (LR == nullptr) return SafeDefault; return Property(*LR, Pos) ? LaneBitmask::getAll() : LaneBitmask::getNone(); } } static LaneBitmask getLiveLanesAt(const LiveIntervals &LIS, const MachineRegisterInfo &MRI, bool TrackLaneMasks, Register RegUnit, SlotIndex Pos) { return getLanesWithProperty(LIS, MRI, TrackLaneMasks, RegUnit, Pos, LaneBitmask::getAll(), [](const LiveRange &LR, SlotIndex Pos) { return LR.liveAt(Pos); }); } namespace { /// Collect this instruction's unique uses and defs into SmallVectors for /// processing defs and uses in order. /// /// FIXME: always ignore tied opers class RegisterOperandsCollector { friend class llvm::RegisterOperands; RegisterOperands &RegOpers; const TargetRegisterInfo &TRI; const MachineRegisterInfo &MRI; bool IgnoreDead; RegisterOperandsCollector(RegisterOperands &RegOpers, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI, bool IgnoreDead) : RegOpers(RegOpers), TRI(TRI), MRI(MRI), IgnoreDead(IgnoreDead) {} void collectInstr(const MachineInstr &MI) const { for (ConstMIBundleOperands OperI(MI); OperI.isValid(); ++OperI) collectOperand(*OperI); // Remove redundant physreg dead defs. for (const RegisterMaskPair &P : RegOpers.Defs) removeRegLanes(RegOpers.DeadDefs, P); } void collectInstrLanes(const MachineInstr &MI) const { for (ConstMIBundleOperands OperI(MI); OperI.isValid(); ++OperI) collectOperandLanes(*OperI); // Remove redundant physreg dead defs. for (const RegisterMaskPair &P : RegOpers.Defs) removeRegLanes(RegOpers.DeadDefs, P); } /// Push this operand's register onto the correct vectors. void collectOperand(const MachineOperand &MO) const { if (!MO.isReg() || !MO.getReg()) return; Register Reg = MO.getReg(); if (MO.isUse()) { if (!MO.isUndef() && !MO.isInternalRead()) pushReg(Reg, RegOpers.Uses); } else { assert(MO.isDef()); // Subregister definitions may imply a register read. if (MO.readsReg()) pushReg(Reg, RegOpers.Uses); if (MO.isDead()) { if (!IgnoreDead) pushReg(Reg, RegOpers.DeadDefs); } else pushReg(Reg, RegOpers.Defs); } } void pushReg(Register Reg, SmallVectorImpl &RegUnits) const { if (Reg.isVirtual()) { addRegLanes(RegUnits, RegisterMaskPair(Reg, LaneBitmask::getAll())); } else if (MRI.isAllocatable(Reg)) { for (MCRegUnitIterator Units(Reg.asMCReg(), &TRI); Units.isValid(); ++Units) addRegLanes(RegUnits, RegisterMaskPair(*Units, LaneBitmask::getAll())); } } void collectOperandLanes(const MachineOperand &MO) const { if (!MO.isReg() || !MO.getReg()) return; Register Reg = MO.getReg(); unsigned SubRegIdx = MO.getSubReg(); if (MO.isUse()) { if (!MO.isUndef() && !MO.isInternalRead()) pushRegLanes(Reg, SubRegIdx, RegOpers.Uses); } else { assert(MO.isDef()); // Treat read-undef subreg defs as definitions of the whole register. if (MO.isUndef()) SubRegIdx = 0; if (MO.isDead()) { if (!IgnoreDead) pushRegLanes(Reg, SubRegIdx, RegOpers.DeadDefs); } else pushRegLanes(Reg, SubRegIdx, RegOpers.Defs); } } void pushRegLanes(Register Reg, unsigned SubRegIdx, SmallVectorImpl &RegUnits) const { if (Reg.isVirtual()) { LaneBitmask LaneMask = SubRegIdx != 0 ? TRI.getSubRegIndexLaneMask(SubRegIdx) : MRI.getMaxLaneMaskForVReg(Reg); addRegLanes(RegUnits, RegisterMaskPair(Reg, LaneMask)); } else if (MRI.isAllocatable(Reg)) { for (MCRegUnitIterator Units(Reg.asMCReg(), &TRI); Units.isValid(); ++Units) addRegLanes(RegUnits, RegisterMaskPair(*Units, LaneBitmask::getAll())); } } }; } // end anonymous namespace void RegisterOperands::collect(const MachineInstr &MI, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI, bool TrackLaneMasks, bool IgnoreDead) { RegisterOperandsCollector Collector(*this, TRI, MRI, IgnoreDead); if (TrackLaneMasks) Collector.collectInstrLanes(MI); else Collector.collectInstr(MI); } void RegisterOperands::detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS) { SlotIndex SlotIdx = LIS.getInstructionIndex(MI); for (auto RI = Defs.begin(); RI != Defs.end(); /*empty*/) { Register Reg = RI->RegUnit; const LiveRange *LR = getLiveRange(LIS, Reg); if (LR != nullptr) { LiveQueryResult LRQ = LR->Query(SlotIdx); if (LRQ.isDeadDef()) { // LiveIntervals knows this is a dead even though it's MachineOperand is // not flagged as such. DeadDefs.push_back(*RI); RI = Defs.erase(RI); continue; } } ++RI; } } void RegisterOperands::adjustLaneLiveness(const LiveIntervals &LIS, const MachineRegisterInfo &MRI, SlotIndex Pos, MachineInstr *AddFlagsMI) { for (auto I = Defs.begin(); I != Defs.end(); ) { LaneBitmask LiveAfter = getLiveLanesAt(LIS, MRI, true, I->RegUnit, Pos.getDeadSlot()); // If the def is all that is live after the instruction, then in case // of a subregister def we need a read-undef flag. Register RegUnit = I->RegUnit; if (Register::isVirtualRegister(RegUnit) && AddFlagsMI != nullptr && (LiveAfter & ~I->LaneMask).none()) AddFlagsMI->setRegisterDefReadUndef(RegUnit); LaneBitmask ActualDef = I->LaneMask & LiveAfter; if (ActualDef.none()) { I = Defs.erase(I); } else { I->LaneMask = ActualDef; ++I; } } for (auto I = Uses.begin(); I != Uses.end(); ) { LaneBitmask LiveBefore = getLiveLanesAt(LIS, MRI, true, I->RegUnit, Pos.getBaseIndex()); LaneBitmask LaneMask = I->LaneMask & LiveBefore; if (LaneMask.none()) { I = Uses.erase(I); } else { I->LaneMask = LaneMask; ++I; } } if (AddFlagsMI != nullptr) { for (const RegisterMaskPair &P : DeadDefs) { Register RegUnit = P.RegUnit; if (!Register::isVirtualRegister(RegUnit)) continue; LaneBitmask LiveAfter = getLiveLanesAt(LIS, MRI, true, RegUnit, Pos.getDeadSlot()); if (LiveAfter.none()) AddFlagsMI->setRegisterDefReadUndef(RegUnit); } } } /// Initialize an array of N PressureDiffs. void PressureDiffs::init(unsigned N) { Size = N; if (N <= Max) { memset(PDiffArray, 0, N * sizeof(PressureDiff)); return; } Max = Size; free(PDiffArray); PDiffArray = static_cast(safe_calloc(N, sizeof(PressureDiff))); } void PressureDiffs::addInstruction(unsigned Idx, const RegisterOperands &RegOpers, const MachineRegisterInfo &MRI) { PressureDiff &PDiff = (*this)[Idx]; assert(!PDiff.begin()->isValid() && "stale PDiff"); for (const RegisterMaskPair &P : RegOpers.Defs) PDiff.addPressureChange(P.RegUnit, true, &MRI); for (const RegisterMaskPair &P : RegOpers.Uses) PDiff.addPressureChange(P.RegUnit, false, &MRI); } /// Add a change in pressure to the pressure diff of a given instruction. void PressureDiff::addPressureChange(Register RegUnit, bool IsDec, const MachineRegisterInfo *MRI) { PSetIterator PSetI = MRI->getPressureSets(RegUnit); int Weight = IsDec ? -PSetI.getWeight() : PSetI.getWeight(); for (; PSetI.isValid(); ++PSetI) { // Find an existing entry in the pressure diff for this PSet. PressureDiff::iterator I = nonconst_begin(), E = nonconst_end(); for (; I != E && I->isValid(); ++I) { if (I->getPSet() >= *PSetI) break; } // If all pressure sets are more constrained, skip the remaining PSets. if (I == E) break; // Insert this PressureChange. if (!I->isValid() || I->getPSet() != *PSetI) { PressureChange PTmp = PressureChange(*PSetI); for (PressureDiff::iterator J = I; J != E && PTmp.isValid(); ++J) std::swap(*J, PTmp); } // Update the units for this pressure set. unsigned NewUnitInc = I->getUnitInc() + Weight; if (NewUnitInc != 0) { I->setUnitInc(NewUnitInc); } else { // Remove entry PressureDiff::iterator J; for (J = std::next(I); J != E && J->isValid(); ++J, ++I) *I = *J; *I = PressureChange(); } } } /// Force liveness of registers. void RegPressureTracker::addLiveRegs(ArrayRef Regs) { for (const RegisterMaskPair &P : Regs) { LaneBitmask PrevMask = LiveRegs.insert(P); LaneBitmask NewMask = PrevMask | P.LaneMask; increaseRegPressure(P.RegUnit, PrevMask, NewMask); } } void RegPressureTracker::discoverLiveInOrOut(RegisterMaskPair Pair, SmallVectorImpl &LiveInOrOut) { assert(Pair.LaneMask.any()); Register RegUnit = Pair.RegUnit; auto I = llvm::find_if(LiveInOrOut, [RegUnit](const RegisterMaskPair &Other) { return Other.RegUnit == RegUnit; }); LaneBitmask PrevMask; LaneBitmask NewMask; if (I == LiveInOrOut.end()) { PrevMask = LaneBitmask::getNone(); NewMask = Pair.LaneMask; LiveInOrOut.push_back(Pair); } else { PrevMask = I->LaneMask; NewMask = PrevMask | Pair.LaneMask; I->LaneMask = NewMask; } increaseSetPressure(P.MaxSetPressure, *MRI, RegUnit, PrevMask, NewMask); } void RegPressureTracker::discoverLiveIn(RegisterMaskPair Pair) { discoverLiveInOrOut(Pair, P.LiveInRegs); } void RegPressureTracker::discoverLiveOut(RegisterMaskPair Pair) { discoverLiveInOrOut(Pair, P.LiveOutRegs); } void RegPressureTracker::bumpDeadDefs(ArrayRef DeadDefs) { for (const RegisterMaskPair &P : DeadDefs) { Register Reg = P.RegUnit; LaneBitmask LiveMask = LiveRegs.contains(Reg); LaneBitmask BumpedMask = LiveMask | P.LaneMask; increaseRegPressure(Reg, LiveMask, BumpedMask); } for (const RegisterMaskPair &P : DeadDefs) { Register Reg = P.RegUnit; LaneBitmask LiveMask = LiveRegs.contains(Reg); LaneBitmask BumpedMask = LiveMask | P.LaneMask; decreaseRegPressure(Reg, BumpedMask, LiveMask); } } /// Recede across the previous instruction. If LiveUses is provided, record any /// RegUnits that are made live by the current instruction's uses. This includes /// registers that are both defined and used by the instruction. If a pressure /// difference pointer is provided record the changes is pressure caused by this /// instruction independent of liveness. void RegPressureTracker::recede(const RegisterOperands &RegOpers, SmallVectorImpl *LiveUses) { assert(!CurrPos->isDebugInstr()); // Boost pressure for all dead defs together. bumpDeadDefs(RegOpers.DeadDefs); // Kill liveness at live defs. // TODO: consider earlyclobbers? for (const RegisterMaskPair &Def : RegOpers.Defs) { Register Reg = Def.RegUnit; LaneBitmask PreviousMask = LiveRegs.erase(Def); LaneBitmask NewMask = PreviousMask & ~Def.LaneMask; LaneBitmask LiveOut = Def.LaneMask & ~PreviousMask; if (LiveOut.any()) { discoverLiveOut(RegisterMaskPair(Reg, LiveOut)); // Retroactively model effects on pressure of the live out lanes. increaseSetPressure(CurrSetPressure, *MRI, Reg, LaneBitmask::getNone(), LiveOut); PreviousMask = LiveOut; } if (NewMask.none()) { // Add a 0 entry to LiveUses as a marker that the complete vreg has become // dead. if (TrackLaneMasks && LiveUses != nullptr) setRegZero(*LiveUses, Reg); } decreaseRegPressure(Reg, PreviousMask, NewMask); } SlotIndex SlotIdx; if (RequireIntervals) SlotIdx = LIS->getInstructionIndex(*CurrPos).getRegSlot(); // Generate liveness for uses. for (const RegisterMaskPair &Use : RegOpers.Uses) { Register Reg = Use.RegUnit; assert(Use.LaneMask.any()); LaneBitmask PreviousMask = LiveRegs.insert(Use); LaneBitmask NewMask = PreviousMask | Use.LaneMask; if (NewMask == PreviousMask) continue; // Did the register just become live? if (PreviousMask.none()) { if (LiveUses != nullptr) { if (!TrackLaneMasks) { addRegLanes(*LiveUses, RegisterMaskPair(Reg, NewMask)); } else { auto I = llvm::find_if(*LiveUses, [Reg](const RegisterMaskPair Other) { return Other.RegUnit == Reg; }); bool IsRedef = I != LiveUses->end(); if (IsRedef) { // ignore re-defs here... assert(I->LaneMask.none()); removeRegLanes(*LiveUses, RegisterMaskPair(Reg, NewMask)); } else { addRegLanes(*LiveUses, RegisterMaskPair(Reg, NewMask)); } } } // Discover live outs if this may be the first occurance of this register. if (RequireIntervals) { LaneBitmask LiveOut = getLiveThroughAt(Reg, SlotIdx); if (LiveOut.any()) discoverLiveOut(RegisterMaskPair(Reg, LiveOut)); } } increaseRegPressure(Reg, PreviousMask, NewMask); } if (TrackUntiedDefs) { for (const RegisterMaskPair &Def : RegOpers.Defs) { Register RegUnit = Def.RegUnit; if (Register::isVirtualRegister(RegUnit) && (LiveRegs.contains(RegUnit) & Def.LaneMask).none()) UntiedDefs.insert(RegUnit); } } } void RegPressureTracker::recedeSkipDebugValues() { assert(CurrPos != MBB->begin()); if (!isBottomClosed()) closeBottom(); // Open the top of the region using block iterators. if (!RequireIntervals && isTopClosed()) static_cast(P).openTop(CurrPos); // Find the previous instruction. CurrPos = prev_nodbg(CurrPos, MBB->begin()); SlotIndex SlotIdx; if (RequireIntervals && !CurrPos->isDebugInstr()) SlotIdx = LIS->getInstructionIndex(*CurrPos).getRegSlot(); // Open the top of the region using slot indexes. if (RequireIntervals && isTopClosed()) static_cast(P).openTop(SlotIdx); } void RegPressureTracker::recede(SmallVectorImpl *LiveUses) { recedeSkipDebugValues(); if (CurrPos->isDebugValue()) { // It's possible to only have debug_value instructions and hit the start of // the block. assert(CurrPos == MBB->begin()); return; } const MachineInstr &MI = *CurrPos; RegisterOperands RegOpers; RegOpers.collect(MI, *TRI, *MRI, TrackLaneMasks, false); if (TrackLaneMasks) { SlotIndex SlotIdx = LIS->getInstructionIndex(*CurrPos).getRegSlot(); RegOpers.adjustLaneLiveness(*LIS, *MRI, SlotIdx); } else if (RequireIntervals) { RegOpers.detectDeadDefs(MI, *LIS); } recede(RegOpers, LiveUses); } /// Advance across the current instruction. void RegPressureTracker::advance(const RegisterOperands &RegOpers) { assert(!TrackUntiedDefs && "unsupported mode"); assert(CurrPos != MBB->end()); if (!isTopClosed()) closeTop(); SlotIndex SlotIdx; if (RequireIntervals) SlotIdx = getCurrSlot(); // Open the bottom of the region using slot indexes. if (isBottomClosed()) { if (RequireIntervals) static_cast(P).openBottom(SlotIdx); else static_cast(P).openBottom(CurrPos); } for (const RegisterMaskPair &Use : RegOpers.Uses) { Register Reg = Use.RegUnit; LaneBitmask LiveMask = LiveRegs.contains(Reg); LaneBitmask LiveIn = Use.LaneMask & ~LiveMask; if (LiveIn.any()) { discoverLiveIn(RegisterMaskPair(Reg, LiveIn)); increaseRegPressure(Reg, LiveMask, LiveMask | LiveIn); LiveRegs.insert(RegisterMaskPair(Reg, LiveIn)); } // Kill liveness at last uses. if (RequireIntervals) { LaneBitmask LastUseMask = getLastUsedLanes(Reg, SlotIdx); if (LastUseMask.any()) { LiveRegs.erase(RegisterMaskPair(Reg, LastUseMask)); decreaseRegPressure(Reg, LiveMask, LiveMask & ~LastUseMask); } } } // Generate liveness for defs. for (const RegisterMaskPair &Def : RegOpers.Defs) { LaneBitmask PreviousMask = LiveRegs.insert(Def); LaneBitmask NewMask = PreviousMask | Def.LaneMask; increaseRegPressure(Def.RegUnit, PreviousMask, NewMask); } // Boost pressure for all dead defs together. bumpDeadDefs(RegOpers.DeadDefs); // Find the next instruction. CurrPos = next_nodbg(CurrPos, MBB->end()); } void RegPressureTracker::advance() { const MachineInstr &MI = *CurrPos; RegisterOperands RegOpers; RegOpers.collect(MI, *TRI, *MRI, TrackLaneMasks, false); if (TrackLaneMasks) { SlotIndex SlotIdx = getCurrSlot(); RegOpers.adjustLaneLiveness(*LIS, *MRI, SlotIdx); } advance(RegOpers); } /// Find the max change in excess pressure across all sets. static void computeExcessPressureDelta(ArrayRef OldPressureVec, ArrayRef NewPressureVec, RegPressureDelta &Delta, const RegisterClassInfo *RCI, ArrayRef LiveThruPressureVec) { Delta.Excess = PressureChange(); for (unsigned i = 0, e = OldPressureVec.size(); i < e; ++i) { unsigned POld = OldPressureVec[i]; unsigned PNew = NewPressureVec[i]; int PDiff = (int)PNew - (int)POld; if (!PDiff) // No change in this set in the common case. continue; // Only consider change beyond the limit. unsigned Limit = RCI->getRegPressureSetLimit(i); if (!LiveThruPressureVec.empty()) Limit += LiveThruPressureVec[i]; if (Limit > POld) { if (Limit > PNew) PDiff = 0; // Under the limit else PDiff = PNew - Limit; // Just exceeded limit. } else if (Limit > PNew) PDiff = Limit - POld; // Just obeyed limit. if (PDiff) { Delta.Excess = PressureChange(i); Delta.Excess.setUnitInc(PDiff); break; } } } /// Find the max change in max pressure that either surpasses a critical PSet /// limit or exceeds the current MaxPressureLimit. /// /// FIXME: comparing each element of the old and new MaxPressure vectors here is /// silly. It's done now to demonstrate the concept but will go away with a /// RegPressureTracker API change to work with pressure differences. static void computeMaxPressureDelta(ArrayRef OldMaxPressureVec, ArrayRef NewMaxPressureVec, ArrayRef CriticalPSets, ArrayRef MaxPressureLimit, RegPressureDelta &Delta) { Delta.CriticalMax = PressureChange(); Delta.CurrentMax = PressureChange(); unsigned CritIdx = 0, CritEnd = CriticalPSets.size(); for (unsigned i = 0, e = OldMaxPressureVec.size(); i < e; ++i) { unsigned POld = OldMaxPressureVec[i]; unsigned PNew = NewMaxPressureVec[i]; if (PNew == POld) // No change in this set in the common case. continue; if (!Delta.CriticalMax.isValid()) { while (CritIdx != CritEnd && CriticalPSets[CritIdx].getPSet() < i) ++CritIdx; if (CritIdx != CritEnd && CriticalPSets[CritIdx].getPSet() == i) { int PDiff = (int)PNew - (int)CriticalPSets[CritIdx].getUnitInc(); if (PDiff > 0) { Delta.CriticalMax = PressureChange(i); Delta.CriticalMax.setUnitInc(PDiff); } } } // Find the first increase above MaxPressureLimit. // (Ignores negative MDiff). if (!Delta.CurrentMax.isValid() && PNew > MaxPressureLimit[i]) { Delta.CurrentMax = PressureChange(i); Delta.CurrentMax.setUnitInc(PNew - POld); if (CritIdx == CritEnd || Delta.CriticalMax.isValid()) break; } } } /// Record the upward impact of a single instruction on current register /// pressure. Unlike the advance/recede pressure tracking interface, this does /// not discover live in/outs. /// /// This is intended for speculative queries. It leaves pressure inconsistent /// with the current position, so must be restored by the caller. void RegPressureTracker::bumpUpwardPressure(const MachineInstr *MI) { assert(!MI->isDebugInstr() && "Expect a nondebug instruction."); SlotIndex SlotIdx; if (RequireIntervals) SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot(); // Account for register pressure similar to RegPressureTracker::recede(). RegisterOperands RegOpers; RegOpers.collect(*MI, *TRI, *MRI, TrackLaneMasks, /*IgnoreDead=*/true); assert(RegOpers.DeadDefs.size() == 0); if (TrackLaneMasks) RegOpers.adjustLaneLiveness(*LIS, *MRI, SlotIdx); else if (RequireIntervals) RegOpers.detectDeadDefs(*MI, *LIS); // Boost max pressure for all dead defs together. // Since CurrSetPressure and MaxSetPressure bumpDeadDefs(RegOpers.DeadDefs); // Kill liveness at live defs. for (const RegisterMaskPair &P : RegOpers.Defs) { Register Reg = P.RegUnit; LaneBitmask LiveLanes = LiveRegs.contains(Reg); LaneBitmask UseLanes = getRegLanes(RegOpers.Uses, Reg); LaneBitmask DefLanes = P.LaneMask; LaneBitmask LiveAfter = (LiveLanes & ~DefLanes) | UseLanes; decreaseRegPressure(Reg, LiveLanes, LiveAfter); } // Generate liveness for uses. for (const RegisterMaskPair &P : RegOpers.Uses) { Register Reg = P.RegUnit; LaneBitmask LiveLanes = LiveRegs.contains(Reg); LaneBitmask LiveAfter = LiveLanes | P.LaneMask; increaseRegPressure(Reg, LiveLanes, LiveAfter); } } /// Consider the pressure increase caused by traversing this instruction /// bottom-up. Find the pressure set with the most change beyond its pressure /// limit based on the tracker's current pressure, and return the change in /// number of register units of that pressure set introduced by this /// instruction. /// /// This assumes that the current LiveOut set is sufficient. /// /// This is expensive for an on-the-fly query because it calls /// bumpUpwardPressure to recompute the pressure sets based on current /// liveness. This mainly exists to verify correctness, e.g. with /// -verify-misched. getUpwardPressureDelta is the fast version of this query /// that uses the per-SUnit cache of the PressureDiff. void RegPressureTracker:: getMaxUpwardPressureDelta(const MachineInstr *MI, PressureDiff *PDiff, RegPressureDelta &Delta, ArrayRef CriticalPSets, ArrayRef MaxPressureLimit) { // Snapshot Pressure. // FIXME: The snapshot heap space should persist. But I'm planning to // summarize the pressure effect so we don't need to snapshot at all. std::vector SavedPressure = CurrSetPressure; std::vector SavedMaxPressure = P.MaxSetPressure; bumpUpwardPressure(MI); computeExcessPressureDelta(SavedPressure, CurrSetPressure, Delta, RCI, LiveThruPressure); computeMaxPressureDelta(SavedMaxPressure, P.MaxSetPressure, CriticalPSets, MaxPressureLimit, Delta); assert(Delta.CriticalMax.getUnitInc() >= 0 && Delta.CurrentMax.getUnitInc() >= 0 && "cannot decrease max pressure"); // Restore the tracker's state. P.MaxSetPressure.swap(SavedMaxPressure); CurrSetPressure.swap(SavedPressure); #ifndef NDEBUG if (!PDiff) return; // Check if the alternate algorithm yields the same result. RegPressureDelta Delta2; getUpwardPressureDelta(MI, *PDiff, Delta2, CriticalPSets, MaxPressureLimit); if (Delta != Delta2) { dbgs() << "PDiff: "; PDiff->dump(*TRI); dbgs() << "DELTA: " << *MI; if (Delta.Excess.isValid()) dbgs() << "Excess1 " << TRI->getRegPressureSetName(Delta.Excess.getPSet()) << " " << Delta.Excess.getUnitInc() << "\n"; if (Delta.CriticalMax.isValid()) dbgs() << "Critic1 " << TRI->getRegPressureSetName(Delta.CriticalMax.getPSet()) << " " << Delta.CriticalMax.getUnitInc() << "\n"; if (Delta.CurrentMax.isValid()) dbgs() << "CurrMx1 " << TRI->getRegPressureSetName(Delta.CurrentMax.getPSet()) << " " << Delta.CurrentMax.getUnitInc() << "\n"; if (Delta2.Excess.isValid()) dbgs() << "Excess2 " << TRI->getRegPressureSetName(Delta2.Excess.getPSet()) << " " << Delta2.Excess.getUnitInc() << "\n"; if (Delta2.CriticalMax.isValid()) dbgs() << "Critic2 " << TRI->getRegPressureSetName(Delta2.CriticalMax.getPSet()) << " " << Delta2.CriticalMax.getUnitInc() << "\n"; if (Delta2.CurrentMax.isValid()) dbgs() << "CurrMx2 " << TRI->getRegPressureSetName(Delta2.CurrentMax.getPSet()) << " " << Delta2.CurrentMax.getUnitInc() << "\n"; llvm_unreachable("RegP Delta Mismatch"); } #endif } /// This is the fast version of querying register pressure that does not /// directly depend on current liveness. /// /// @param Delta captures information needed for heuristics. /// /// @param CriticalPSets Are the pressure sets that are known to exceed some /// limit within the region, not necessarily at the current position. /// /// @param MaxPressureLimit Is the max pressure within the region, not /// necessarily at the current position. void RegPressureTracker:: getUpwardPressureDelta(const MachineInstr *MI, /*const*/ PressureDiff &PDiff, RegPressureDelta &Delta, ArrayRef CriticalPSets, ArrayRef MaxPressureLimit) const { unsigned CritIdx = 0, CritEnd = CriticalPSets.size(); for (PressureDiff::const_iterator PDiffI = PDiff.begin(), PDiffE = PDiff.end(); PDiffI != PDiffE && PDiffI->isValid(); ++PDiffI) { unsigned PSetID = PDiffI->getPSet(); unsigned Limit = RCI->getRegPressureSetLimit(PSetID); if (!LiveThruPressure.empty()) Limit += LiveThruPressure[PSetID]; unsigned POld = CurrSetPressure[PSetID]; unsigned MOld = P.MaxSetPressure[PSetID]; unsigned MNew = MOld; // Ignore DeadDefs here because they aren't captured by PressureChange. unsigned PNew = POld + PDiffI->getUnitInc(); assert((PDiffI->getUnitInc() >= 0) == (PNew >= POld) && "PSet overflow/underflow"); if (PNew > MOld) MNew = PNew; // Check if current pressure has exceeded the limit. if (!Delta.Excess.isValid()) { unsigned ExcessInc = 0; if (PNew > Limit) ExcessInc = POld > Limit ? PNew - POld : PNew - Limit; else if (POld > Limit) ExcessInc = Limit - POld; if (ExcessInc) { Delta.Excess = PressureChange(PSetID); Delta.Excess.setUnitInc(ExcessInc); } } // Check if max pressure has exceeded a critical pressure set max. if (MNew == MOld) continue; if (!Delta.CriticalMax.isValid()) { while (CritIdx != CritEnd && CriticalPSets[CritIdx].getPSet() < PSetID) ++CritIdx; if (CritIdx != CritEnd && CriticalPSets[CritIdx].getPSet() == PSetID) { int CritInc = (int)MNew - (int)CriticalPSets[CritIdx].getUnitInc(); if (CritInc > 0 && CritInc <= std::numeric_limits::max()) { Delta.CriticalMax = PressureChange(PSetID); Delta.CriticalMax.setUnitInc(CritInc); } } } // Check if max pressure has exceeded the current max. if (!Delta.CurrentMax.isValid() && MNew > MaxPressureLimit[PSetID]) { Delta.CurrentMax = PressureChange(PSetID); Delta.CurrentMax.setUnitInc(MNew - MOld); } } } /// Helper to find a vreg use between two indices [PriorUseIdx, NextUseIdx). /// The query starts with a lane bitmask which gets lanes/bits removed for every /// use we find. static LaneBitmask findUseBetween(unsigned Reg, LaneBitmask LastUseMask, SlotIndex PriorUseIdx, SlotIndex NextUseIdx, const MachineRegisterInfo &MRI, const LiveIntervals *LIS) { const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); for (const MachineOperand &MO : MRI.use_nodbg_operands(Reg)) { if (MO.isUndef()) continue; const MachineInstr *MI = MO.getParent(); SlotIndex InstSlot = LIS->getInstructionIndex(*MI).getRegSlot(); if (InstSlot >= PriorUseIdx && InstSlot < NextUseIdx) { unsigned SubRegIdx = MO.getSubReg(); LaneBitmask UseMask = TRI.getSubRegIndexLaneMask(SubRegIdx); LastUseMask &= ~UseMask; if (LastUseMask.none()) return LaneBitmask::getNone(); } } return LastUseMask; } LaneBitmask RegPressureTracker::getLiveLanesAt(Register RegUnit, SlotIndex Pos) const { assert(RequireIntervals); return getLanesWithProperty(*LIS, *MRI, TrackLaneMasks, RegUnit, Pos, LaneBitmask::getAll(), [](const LiveRange &LR, SlotIndex Pos) { return LR.liveAt(Pos); }); } LaneBitmask RegPressureTracker::getLastUsedLanes(Register RegUnit, SlotIndex Pos) const { assert(RequireIntervals); return getLanesWithProperty(*LIS, *MRI, TrackLaneMasks, RegUnit, Pos.getBaseIndex(), LaneBitmask::getNone(), [](const LiveRange &LR, SlotIndex Pos) { const LiveRange::Segment *S = LR.getSegmentContaining(Pos); return S != nullptr && S->end == Pos.getRegSlot(); }); } LaneBitmask RegPressureTracker::getLiveThroughAt(Register RegUnit, SlotIndex Pos) const { assert(RequireIntervals); return getLanesWithProperty(*LIS, *MRI, TrackLaneMasks, RegUnit, Pos, LaneBitmask::getNone(), [](const LiveRange &LR, SlotIndex Pos) { const LiveRange::Segment *S = LR.getSegmentContaining(Pos); return S != nullptr && S->start < Pos.getRegSlot(true) && S->end != Pos.getDeadSlot(); }); } /// Record the downward impact of a single instruction on current register /// pressure. Unlike the advance/recede pressure tracking interface, this does /// not discover live in/outs. /// /// This is intended for speculative queries. It leaves pressure inconsistent /// with the current position, so must be restored by the caller. void RegPressureTracker::bumpDownwardPressure(const MachineInstr *MI) { assert(!MI->isDebugInstr() && "Expect a nondebug instruction."); SlotIndex SlotIdx; if (RequireIntervals) SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot(); // Account for register pressure similar to RegPressureTracker::recede(). RegisterOperands RegOpers; RegOpers.collect(*MI, *TRI, *MRI, TrackLaneMasks, false); if (TrackLaneMasks) RegOpers.adjustLaneLiveness(*LIS, *MRI, SlotIdx); if (RequireIntervals) { for (const RegisterMaskPair &Use : RegOpers.Uses) { Register Reg = Use.RegUnit; LaneBitmask LastUseMask = getLastUsedLanes(Reg, SlotIdx); if (LastUseMask.none()) continue; // The LastUseMask is queried from the liveness information of instruction // which may be further down the schedule. Some lanes may actually not be // last uses for the current position. // FIXME: allow the caller to pass in the list of vreg uses that remain // to be bottom-scheduled to avoid searching uses at each query. SlotIndex CurrIdx = getCurrSlot(); LastUseMask = findUseBetween(Reg, LastUseMask, CurrIdx, SlotIdx, *MRI, LIS); if (LastUseMask.none()) continue; LaneBitmask LiveMask = LiveRegs.contains(Reg); LaneBitmask NewMask = LiveMask & ~LastUseMask; decreaseRegPressure(Reg, LiveMask, NewMask); } } // Generate liveness for defs. for (const RegisterMaskPair &Def : RegOpers.Defs) { Register Reg = Def.RegUnit; LaneBitmask LiveMask = LiveRegs.contains(Reg); LaneBitmask NewMask = LiveMask | Def.LaneMask; increaseRegPressure(Reg, LiveMask, NewMask); } // Boost pressure for all dead defs together. bumpDeadDefs(RegOpers.DeadDefs); } /// Consider the pressure increase caused by traversing this instruction /// top-down. Find the register class with the most change in its pressure limit /// based on the tracker's current pressure, and return the number of excess /// register units of that pressure set introduced by this instruction. /// /// This assumes that the current LiveIn set is sufficient. /// /// This is expensive for an on-the-fly query because it calls /// bumpDownwardPressure to recompute the pressure sets based on current /// liveness. We don't yet have a fast version of downward pressure tracking /// analogous to getUpwardPressureDelta. void RegPressureTracker:: getMaxDownwardPressureDelta(const MachineInstr *MI, RegPressureDelta &Delta, ArrayRef CriticalPSets, ArrayRef MaxPressureLimit) { // Snapshot Pressure. std::vector SavedPressure = CurrSetPressure; std::vector SavedMaxPressure = P.MaxSetPressure; bumpDownwardPressure(MI); computeExcessPressureDelta(SavedPressure, CurrSetPressure, Delta, RCI, LiveThruPressure); computeMaxPressureDelta(SavedMaxPressure, P.MaxSetPressure, CriticalPSets, MaxPressureLimit, Delta); assert(Delta.CriticalMax.getUnitInc() >= 0 && Delta.CurrentMax.getUnitInc() >= 0 && "cannot decrease max pressure"); // Restore the tracker's state. P.MaxSetPressure.swap(SavedMaxPressure); CurrSetPressure.swap(SavedPressure); } /// Get the pressure of each PSet after traversing this instruction bottom-up. void RegPressureTracker:: getUpwardPressure(const MachineInstr *MI, std::vector &PressureResult, std::vector &MaxPressureResult) { // Snapshot pressure. PressureResult = CurrSetPressure; MaxPressureResult = P.MaxSetPressure; bumpUpwardPressure(MI); // Current pressure becomes the result. Restore current pressure. P.MaxSetPressure.swap(MaxPressureResult); CurrSetPressure.swap(PressureResult); } /// Get the pressure of each PSet after traversing this instruction top-down. void RegPressureTracker:: getDownwardPressure(const MachineInstr *MI, std::vector &PressureResult, std::vector &MaxPressureResult) { // Snapshot pressure. PressureResult = CurrSetPressure; MaxPressureResult = P.MaxSetPressure; bumpDownwardPressure(MI); // Current pressure becomes the result. Restore current pressure. P.MaxSetPressure.swap(MaxPressureResult); CurrSetPressure.swap(PressureResult); }