namespace llvm {
class LiveIntervals;
+class LiveRange;
class RegisterClassInfo;
class MachineInstr;
/// Map of max reg pressure indexed by pressure set ID, not class ID.
std::vector<unsigned> MaxSetPressure;
- /// List of live in registers.
+ /// List of live in virtual registers or physical register units.
SmallVector<unsigned,8> LiveInRegs;
SmallVector<unsigned,8> LiveOutRegs;
/// Increase register pressure for each pressure set impacted by this register
/// class. Normally called by RegPressureTracker, but may be called manually
/// to account for live through (global liveness).
- void increase(const TargetRegisterClass *RC, const TargetRegisterInfo *TRI);
+ ///
+ /// \param Reg is either a virtual register number or register unit number.
+ void increase(unsigned Reg, const TargetRegisterInfo *TRI,
+ const MachineRegisterInfo *MRI);
/// Decrease register pressure for each pressure set impacted by this register
/// class. This is only useful to account for spilling or rematerialization.
- void decrease(const TargetRegisterClass *RC, const TargetRegisterInfo *TRI);
+ ///
+ /// \param Reg is either a virtual register number or register unit number.
+ void decrease(unsigned Reg, const TargetRegisterInfo *TRI,
+ const MachineRegisterInfo *MRI);
void dump(const TargetRegisterInfo *TRI) const;
};
void openBottom(MachineBasicBlock::const_iterator PrevBottom);
};
-/// An element of pressure difference that identifies the pressure set and
-/// amount of increase or decrease in units of pressure.
-struct PressureElement {
- unsigned PSetID;
- int UnitIncrease;
+/// Capture a change in pressure for a single pressure set. UnitInc may be
+/// expressed in terms of upward or downward pressure depending on the client
+/// and will be dynamically adjusted for current liveness.
+///
+/// Pressure increments are tiny, typically 1-2 units, and this is only for
+/// heuristics, so we don't check UnitInc overflow. Instead, we may have a
+/// higher level assert that pressure is consistent within a region. We also
+/// effectively ignore dead defs which don't affect heuristics much.
+class PressureChange {
+ uint16_t PSetID; // ID+1. 0=Invalid.
+ int16_t UnitInc;
+public:
+ PressureChange(): PSetID(0), UnitInc(0) {}
+ PressureChange(unsigned id): PSetID(id+1), UnitInc(0) {
+ assert(id < UINT16_MAX && "PSetID overflow.");
+ }
+
+ bool isValid() const { return PSetID > 0; }
+
+ unsigned getPSet() const {
+ assert(isValid() && "invalid PressureChange");
+ return PSetID - 1;
+ }
+ // If PSetID is invalid, return UINT16_MAX to give it lowest priority.
+ unsigned getPSetOrMax() const { return (PSetID - 1) & UINT16_MAX; }
+
+ int getUnitInc() const { return UnitInc; }
+
+ void setUnitInc(int Inc) { UnitInc = Inc; }
+
+ bool operator==(const PressureChange &RHS) const {
+ return PSetID == RHS.PSetID && UnitInc == RHS.UnitInc;
+ }
+};
+
+template <> struct isPodLike<PressureChange> {
+ static const bool value = true;
+};
+
+/// List of PressureChanges in order of increasing, unique PSetID.
+///
+/// Use a small fixed number, because we can fit more PressureChanges in an
+/// empty SmallVector than ever need to be tracked per register class. If more
+/// PSets are affected, then we only track the most constrained.
+class PressureDiff {
+ // The initial design was for MaxPSets=4, but that requires PSet partitions,
+ // which are not yet implemented. (PSet partitions are equivalent PSets given
+ // the register classes actually in use within the scheduling region.)
+ enum { MaxPSets = 16 };
+
+ PressureChange PressureChanges[MaxPSets];
+public:
+ typedef PressureChange* iterator;
+ typedef const PressureChange* const_iterator;
+ iterator begin() { return &PressureChanges[0]; }
+ iterator end() { return &PressureChanges[MaxPSets]; }
+ const_iterator begin() const { return &PressureChanges[0]; }
+ const_iterator end() const { return &PressureChanges[MaxPSets]; }
+
+ void addPressureChange(unsigned RegUnit, bool IsDec,
+ const MachineRegisterInfo *MRI);
+};
+
+/// Array of PressureDiffs.
+class PressureDiffs {
+ PressureDiff *PDiffArray;
+ unsigned Size;
+ unsigned Max;
+public:
+ PressureDiffs(): PDiffArray(nullptr), Size(0), Max(0) {}
+ ~PressureDiffs() { free(PDiffArray); }
+
+ void clear() { Size = 0; }
- PressureElement(): PSetID(~0U), UnitIncrease(0) {}
- PressureElement(unsigned id, int inc): PSetID(id), UnitIncrease(inc) {}
+ void init(unsigned N);
- bool isValid() const { return PSetID != ~0U; }
+ PressureDiff &operator[](unsigned Idx) {
+ assert(Idx < Size && "PressureDiff index out of bounds");
+ return PDiffArray[Idx];
+ }
+ const PressureDiff &operator[](unsigned Idx) const {
+ return const_cast<PressureDiffs*>(this)->operator[](Idx);
+ }
};
/// Store the effects of a change in pressure on things that MI scheduler cares
/// CurrentMax records the largest increase in the tracker's max pressure that
/// exceeds the current limit for some pressure set determined by the client.
struct RegPressureDelta {
- PressureElement Excess;
- PressureElement CriticalMax;
- PressureElement CurrentMax;
+ PressureChange Excess;
+ PressureChange CriticalMax;
+ PressureChange CurrentMax;
RegPressureDelta() {}
+
+ bool operator==(const RegPressureDelta &RHS) const {
+ return Excess == RHS.Excess && CriticalMax == RHS.CriticalMax
+ && CurrentMax == RHS.CurrentMax;
+ }
+ bool operator!=(const RegPressureDelta &RHS) const {
+ return !operator==(RHS);
+ }
+};
+
+/// \brief A set of live virtual registers and physical register units.
+///
+/// Virtual and physical register numbers require separate sparse sets, but most
+/// of the RegisterPressureTracker handles them uniformly.
+struct LiveRegSet {
+ SparseSet<unsigned> PhysRegs;
+ SparseSet<unsigned, VirtReg2IndexFunctor> VirtRegs;
+
+ bool contains(unsigned Reg) const {
+ if (TargetRegisterInfo::isVirtualRegister(Reg))
+ return VirtRegs.count(Reg);
+ return PhysRegs.count(Reg);
+ }
+
+ bool insert(unsigned Reg) {
+ if (TargetRegisterInfo::isVirtualRegister(Reg))
+ return VirtRegs.insert(Reg).second;
+ return PhysRegs.insert(Reg).second;
+ }
+
+ bool erase(unsigned Reg) {
+ if (TargetRegisterInfo::isVirtualRegister(Reg))
+ return VirtRegs.erase(Reg);
+ return PhysRegs.erase(Reg);
+ }
};
/// Track the current register pressure at some position in the instruction
/// or RegisterPressure. If requireIntervals is false, LIS are ignored.
bool RequireIntervals;
+ /// True if UntiedDefs will be populated.
+ bool TrackUntiedDefs;
+
/// Register pressure corresponds to liveness before this instruction
/// iterator. It may point to the end of the block or a DebugValue rather than
/// an instruction.
/// Pressure map indexed by pressure set ID, not class ID.
std::vector<unsigned> CurrSetPressure;
- /// List of live registers.
- SparseSet<unsigned> LivePhysRegs;
- SparseSet<unsigned, VirtReg2IndexFunctor> LiveVirtRegs;
+ /// Set of live registers.
+ LiveRegSet LiveRegs;
+
+ /// Set of vreg defs that start a live range.
+ SparseSet<unsigned, VirtReg2IndexFunctor> UntiedDefs;
+ /// Live-through pressure.
+ std::vector<unsigned> LiveThruPressure;
public:
RegPressureTracker(IntervalPressure &rp) :
- MF(0), TRI(0), RCI(0), LIS(0), MBB(0), P(rp), RequireIntervals(true) {}
+ MF(nullptr), TRI(nullptr), RCI(nullptr), LIS(nullptr), MBB(nullptr), P(rp),
+ RequireIntervals(true), TrackUntiedDefs(false) {}
RegPressureTracker(RegionPressure &rp) :
- MF(0), TRI(0), RCI(0), LIS(0), MBB(0), P(rp), RequireIntervals(false) {}
+ MF(nullptr), TRI(nullptr), RCI(nullptr), LIS(nullptr), MBB(nullptr), P(rp),
+ RequireIntervals(false), TrackUntiedDefs(false) {}
+
+ void reset();
void init(const MachineFunction *mf, const RegisterClassInfo *rci,
const LiveIntervals *lis, const MachineBasicBlock *mbb,
- MachineBasicBlock::const_iterator pos);
+ MachineBasicBlock::const_iterator pos,
+ bool ShouldTrackUntiedDefs = false);
- /// Force liveness of registers. Particularly useful to initialize the
- /// livein/out state of the tracker before the first call to advance/recede.
+ /// Force liveness of virtual registers or physical register
+ /// units. Particularly useful to initialize the livein/out state of the
+ /// tracker before the first call to advance/recede.
void addLiveRegs(ArrayRef<unsigned> Regs);
/// Get the MI position corresponding to this register pressure.
SlotIndex getCurrSlot() const;
/// Recede across the previous instruction.
- bool recede();
+ bool recede(SmallVectorImpl<unsigned> *LiveUses = nullptr,
+ PressureDiff *PDiff = nullptr);
/// Advance across the current instruction.
bool advance();
/// Finalize the region boundaries and recored live ins and live outs.
void closeRegion();
+ /// Initialize the LiveThru pressure set based on the untied defs found in
+ /// RPTracker.
+ void initLiveThru(const RegPressureTracker &RPTracker);
+
+ /// Copy an existing live thru pressure result.
+ void initLiveThru(ArrayRef<unsigned> PressureSet) {
+ LiveThruPressure.assign(PressureSet.begin(), PressureSet.end());
+ }
+
+ ArrayRef<unsigned> getLiveThru() const { return LiveThruPressure; }
+
/// Get the resulting register pressure over the traversed region.
/// This result is complete if either advance() or recede() has returned true,
/// or if closeRegion() was explicitly invoked.
/// than the pressure across the traversed region.
std::vector<unsigned> &getRegSetPressureAtPos() { return CurrSetPressure; }
- void discoverPhysLiveIn(unsigned Reg);
- void discoverPhysLiveOut(unsigned Reg);
-
- void discoverVirtLiveIn(unsigned Reg);
- void discoverVirtLiveOut(unsigned Reg);
+ void discoverLiveOut(unsigned Reg);
+ void discoverLiveIn(unsigned Reg);
bool isTopClosed() const;
bool isBottomClosed() const;
/// limit based on the tracker's current pressure, and record the number of
/// excess register units of that pressure set introduced by this instruction.
void getMaxUpwardPressureDelta(const MachineInstr *MI,
+ PressureDiff *PDiff,
RegPressureDelta &Delta,
- ArrayRef<PressureElement> CriticalPSets,
+ ArrayRef<PressureChange> CriticalPSets,
ArrayRef<unsigned> MaxPressureLimit);
+ void getUpwardPressureDelta(const MachineInstr *MI,
+ /*const*/ PressureDiff &PDiff,
+ RegPressureDelta &Delta,
+ ArrayRef<PressureChange> CriticalPSets,
+ ArrayRef<unsigned> MaxPressureLimit) const;
+
/// Consider the pressure increase caused by traversing this instruction
/// top-down. Find the pressure set with the most change beyond its pressure
/// limit based on the tracker's current pressure, and record the number of
/// excess register units of that pressure set introduced by this instruction.
void getMaxDownwardPressureDelta(const MachineInstr *MI,
RegPressureDelta &Delta,
- ArrayRef<PressureElement> CriticalPSets,
+ ArrayRef<PressureChange> CriticalPSets,
ArrayRef<unsigned> MaxPressureLimit);
/// Find the pressure set with the most change beyond its pressure limit after
/// traversing this instruction either upward or downward depending on the
/// closed end of the current region.
- void getMaxPressureDelta(const MachineInstr *MI, RegPressureDelta &Delta,
- ArrayRef<PressureElement> CriticalPSets,
+ void getMaxPressureDelta(const MachineInstr *MI,
+ RegPressureDelta &Delta,
+ ArrayRef<PressureChange> CriticalPSets,
ArrayRef<unsigned> MaxPressureLimit) {
if (isTopClosed())
return getMaxDownwardPressureDelta(MI, Delta, CriticalPSets,
MaxPressureLimit);
assert(isBottomClosed() && "Uninitialized pressure tracker");
- return getMaxUpwardPressureDelta(MI, Delta, CriticalPSets,
+ return getMaxUpwardPressureDelta(MI, nullptr, Delta, CriticalPSets,
MaxPressureLimit);
}
return getDownwardPressure(MI, PressureResult, MaxPressureResult);
}
+ bool hasUntiedDef(unsigned VirtReg) const {
+ return UntiedDefs.count(VirtReg);
+ }
+
+ void dump() const;
+
protected:
- void increasePhysRegPressure(ArrayRef<unsigned> Regs);
- void decreasePhysRegPressure(ArrayRef<unsigned> Regs);
+ const LiveRange *getLiveRange(unsigned Reg) const;
- void increaseVirtRegPressure(ArrayRef<unsigned> Regs);
- void decreaseVirtRegPressure(ArrayRef<unsigned> Regs);
+ void increaseRegPressure(ArrayRef<unsigned> Regs);
+ void decreaseRegPressure(ArrayRef<unsigned> Regs);
void bumpUpwardPressure(const MachineInstr *MI);
void bumpDownwardPressure(const MachineInstr *MI);
};
+
+void dumpRegSetPressure(ArrayRef<unsigned> SetPressure,
+ const TargetRegisterInfo *TRI);
} // end namespace llvm
#endif