| //===- LiveRegMatrix.cpp - Track register interference --------------------===// | |
| // | |
| // 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 defines the LiveRegMatrix analysis pass. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/CodeGen/LiveRegMatrix.h" | |
| #include "RegisterCoalescer.h" | |
| #include "llvm/ADT/DenseSet.h" | |
| #include "llvm/ADT/Statistic.h" | |
| #include "llvm/CodeGen/LiveInterval.h" | |
| #include "llvm/CodeGen/LiveIntervalUnion.h" | |
| #include "llvm/CodeGen/LiveIntervals.h" | |
| #include "llvm/CodeGen/MachineFunction.h" | |
| #include "llvm/CodeGen/MachineOperand.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/TargetRegisterInfo.h" | |
| #include "llvm/CodeGen/TargetSubtargetInfo.h" | |
| #include "llvm/CodeGen/VirtRegMap.h" | |
| #include "llvm/InitializePasses.h" | |
| #include "llvm/MC/LaneBitmask.h" | |
| #include "llvm/MC/MCRegisterInfo.h" | |
| #include "llvm/Pass.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include <cassert> | |
| using namespace llvm; | |
| #define DEBUG_TYPE "regalloc" | |
| STATISTIC(NumAssigned , "Number of registers assigned"); | |
| STATISTIC(NumUnassigned , "Number of registers unassigned"); | |
| char LiveRegMatrixWrapperLegacy::ID = 0; | |
| INITIALIZE_PASS_BEGIN(LiveRegMatrixWrapperLegacy, "liveregmatrix", | |
| "Live Register Matrix", false, false) | |
| INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass) | |
| INITIALIZE_PASS_DEPENDENCY(VirtRegMapWrapperLegacy) | |
| INITIALIZE_PASS_END(LiveRegMatrixWrapperLegacy, "liveregmatrix", | |
| "Live Register Matrix", false, true) | |
| void LiveRegMatrixWrapperLegacy::getAnalysisUsage(AnalysisUsage &AU) const { | |
| AU.setPreservesAll(); | |
| AU.addRequiredTransitive<LiveIntervalsWrapperPass>(); | |
| AU.addRequiredTransitive<VirtRegMapWrapperLegacy>(); | |
| MachineFunctionPass::getAnalysisUsage(AU); | |
| } | |
| bool LiveRegMatrixWrapperLegacy::runOnMachineFunction(MachineFunction &MF) { | |
| auto &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS(); | |
| auto &VRM = getAnalysis<VirtRegMapWrapperLegacy>().getVRM(); | |
| LRM.init(MF, LIS, VRM); | |
| return false; | |
| } | |
| void LiveRegMatrix::init(MachineFunction &MF, LiveIntervals &pLIS, | |
| VirtRegMap &pVRM) { | |
| TRI = MF.getSubtarget().getRegisterInfo(); | |
| LIS = &pLIS; | |
| VRM = &pVRM; | |
| unsigned NumRegUnits = TRI->getNumRegUnits(); | |
| if (NumRegUnits != Matrix.size()) | |
| Queries.reset(new LiveIntervalUnion::Query[NumRegUnits]); | |
| Matrix.init(*LIUAlloc, NumRegUnits); | |
| // Make sure no stale queries get reused. | |
| invalidateVirtRegs(); | |
| } | |
| void LiveRegMatrixWrapperLegacy::releaseMemory() { LRM.releaseMemory(); } | |
| void LiveRegMatrix::releaseMemory() { | |
| for (unsigned i = 0, e = Matrix.size(); i != e; ++i) { | |
| Matrix[static_cast<MCRegUnit>(i)].clear(); | |
| // No need to clear Queries here, since LiveIntervalUnion::Query doesn't | |
| // have anything important to clear and LiveRegMatrix's runOnFunction() | |
| // does a std::unique_ptr::reset anyways. | |
| } | |
| } | |
| template <typename Callable> | |
| static bool foreachUnit(const TargetRegisterInfo *TRI, | |
| const LiveInterval &VRegInterval, MCRegister PhysReg, | |
| Callable Func) { | |
| if (VRegInterval.hasSubRanges()) { | |
| for (MCRegUnitMaskIterator Units(PhysReg, TRI); Units.isValid(); ++Units) { | |
| MCRegUnit Unit = (*Units).first; | |
| LaneBitmask Mask = (*Units).second; | |
| for (const LiveInterval::SubRange &S : VRegInterval.subranges()) { | |
| if ((S.LaneMask & Mask).any()) { | |
| if (Func(Unit, S)) | |
| return true; | |
| break; | |
| } | |
| } | |
| } | |
| } else { | |
| for (MCRegUnit Unit : TRI->regunits(PhysReg)) { | |
| if (Func(Unit, VRegInterval)) | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| void LiveRegMatrix::assign(const LiveInterval &VirtReg, MCRegister PhysReg) { | |
| LLVM_DEBUG(dbgs() << "assigning " << printReg(VirtReg.reg(), TRI) << " to " | |
| << printReg(PhysReg, TRI) << ':'); | |
| assert(!VRM->hasPhys(VirtReg.reg()) && "Duplicate VirtReg assignment"); | |
| VRM->assignVirt2Phys(VirtReg.reg(), PhysReg); | |
| foreachUnit( | |
| TRI, VirtReg, PhysReg, [&](MCRegUnit Unit, const LiveRange &Range) { | |
| LLVM_DEBUG(dbgs() << ' ' << printRegUnit(Unit, TRI) << ' ' << Range); | |
| Matrix[Unit].unify(VirtReg, Range); | |
| return false; | |
| }); | |
| ++NumAssigned; | |
| LLVM_DEBUG(dbgs() << '\n'); | |
| } | |
| void LiveRegMatrix::unassign(const LiveInterval &VirtReg, | |
| bool ClearAllReferencingSegments) { | |
| Register PhysReg = VRM->getPhys(VirtReg.reg()); | |
| LLVM_DEBUG(dbgs() << "unassigning " << printReg(VirtReg.reg(), TRI) | |
| << " from " << printReg(PhysReg, TRI) << ':'); | |
| VRM->clearVirt(VirtReg.reg()); | |
| if (!ClearAllReferencingSegments) { | |
| foreachUnit(TRI, VirtReg, PhysReg, | |
| [&](MCRegUnit Unit, const LiveRange &Range) { | |
| LLVM_DEBUG(dbgs() << ' ' << printRegUnit(Unit, TRI)); | |
| Matrix[Unit].extract(VirtReg, Range); | |
| return false; | |
| }); | |
| } else { | |
| for (MCRegUnit Unit : TRI->regunits(PhysReg)) { | |
| Matrix[Unit].clearAllSegmentsReferencing(VirtReg); | |
| } | |
| } | |
| ++NumUnassigned; | |
| LLVM_DEBUG(dbgs() << '\n'); | |
| } | |
| bool LiveRegMatrix::isPhysRegUsed(MCRegister PhysReg) const { | |
| for (MCRegUnit Unit : TRI->regunits(PhysReg)) { | |
| if (!Matrix[Unit].empty()) | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool LiveRegMatrix::checkRegMaskInterference(const LiveInterval &VirtReg, | |
| MCRegister PhysReg) { | |
| // Check if the cached information is valid. | |
| // The same BitVector can be reused for all PhysRegs. | |
| // We could cache multiple VirtRegs if it becomes necessary. | |
| if (RegMaskVirtReg != VirtReg.reg() || RegMaskTag != UserTag) { | |
| RegMaskVirtReg = VirtReg.reg(); | |
| RegMaskTag = UserTag; | |
| RegMaskUsable.clear(); | |
| LIS->checkRegMaskInterference(VirtReg, RegMaskUsable); | |
| } | |
| // The BitVector is indexed by PhysReg, not register unit. | |
| // Regmask interference is more fine grained than regunits. | |
| // For example, a Win64 call can clobber %ymm8 yet preserve %xmm8. | |
| return !RegMaskUsable.empty() && | |
| (!PhysReg || !RegMaskUsable.test(PhysReg.id())); | |
| } | |
| bool LiveRegMatrix::checkRegUnitInterference(const LiveInterval &VirtReg, | |
| MCRegister PhysReg) { | |
| if (VirtReg.empty()) | |
| return false; | |
| CoalescerPair CP(VirtReg.reg(), PhysReg, *TRI); | |
| bool Result = foreachUnit( | |
| TRI, VirtReg, PhysReg, [&](MCRegUnit Unit, const LiveRange &Range) { | |
| const LiveRange &UnitRange = LIS->getRegUnit(Unit); | |
| return Range.overlaps(UnitRange, CP, *LIS->getSlotIndexes()); | |
| }); | |
| return Result; | |
| } | |
| bool LiveRegMatrix::checkRegMaskInterference(SlotIndex Start, SlotIndex End, | |
| MCRegister PhysReg) { | |
| ArrayRef<SlotIndex> Slots = LIS->getRegMaskSlots(); | |
| ArrayRef<const uint32_t *> Bits = LIS->getRegMaskBits(); | |
| // Find the first regmask slot that is not before Start. | |
| auto SlotI = llvm::lower_bound(Slots, Start); | |
| for (; SlotI != Slots.end() && *SlotI < End; ++SlotI) { | |
| if (MachineOperand::clobbersPhysReg(Bits[SlotI - Slots.begin()], PhysReg)) | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool LiveRegMatrix::checkRegUnitInterference(SlotIndex Start, SlotIndex End, | |
| MCRegister PhysReg) { | |
| for (MCRegUnit Unit : TRI->regunits(PhysReg)) { | |
| if (LIS->getRegUnit(Unit).overlaps(Start, End)) | |
| return true; | |
| } | |
| return false; | |
| } | |
| LiveIntervalUnion::Query &LiveRegMatrix::query(const LiveRange &LR, | |
| MCRegUnit RegUnit) { | |
| LiveIntervalUnion::Query &Q = Queries[static_cast<unsigned>(RegUnit)]; | |
| Q.init(UserTag, LR, Matrix[RegUnit]); | |
| return Q; | |
| } | |
| LiveRegMatrix::InterferenceKind | |
| LiveRegMatrix::checkInterference(const LiveInterval &VirtReg, | |
| MCRegister PhysReg) { | |
| if (VirtReg.empty()) | |
| return IK_Free; | |
| // Regmask interference is the fastest check. | |
| if (checkRegMaskInterference(VirtReg, PhysReg)) | |
| return IK_RegMask; | |
| // Check for fixed interference. | |
| if (checkRegUnitInterference(VirtReg, PhysReg)) | |
| return IK_RegUnit; | |
| // Check the matrix for virtual register interference. | |
| bool Interference = foreachUnit(TRI, VirtReg, PhysReg, | |
| [&](MCRegUnit Unit, const LiveRange &LR) { | |
| return query(LR, Unit).checkInterference(); | |
| }); | |
| if (Interference) | |
| return IK_VirtReg; | |
| return IK_Free; | |
| } | |
| bool LiveRegMatrix::checkInterference(SlotIndex Start, SlotIndex End, | |
| MCRegister PhysReg) { | |
| // Regmask interference is the fastest check. | |
| if (checkRegMaskInterference(Start, End, PhysReg)) | |
| return true; | |
| // Check for fixed interference. | |
| if (checkRegUnitInterference(Start, End, PhysReg)) | |
| return true; | |
| // Construct artificial live range containing only one segment [Start, End). | |
| VNInfo valno(0, Start); | |
| LiveRange::Segment Seg(Start, End, &valno); | |
| LiveRange LR; | |
| LR.addSegment(Seg); | |
| // Check the matrix for virtual register interference with that segment. | |
| for (MCRegUnit Unit : TRI->regunits(PhysReg)) { | |
| // LR is stack-allocated. LiveRegMatrix caches queries by a key that | |
| // includes the address of the live range. If (for the same reg unit) this | |
| // checkInterference overload is called twice, without any other query() | |
| // calls in between (on heap-allocated LiveRanges) - which would invalidate | |
| // the cached query - the LR address seen the second time may well be the | |
| // same as that seen the first time, while the Start/End/valno may not - yet | |
| // the same cached result would be fetched. To avoid that, we don't cache | |
| // this query. | |
| // | |
| // FIXME: the usability of the Query API needs to be improved to avoid | |
| // subtle bugs due to query identity. Avoiding caching, for example, would | |
| // greatly simplify things. | |
| LiveIntervalUnion::Query Q; | |
| Q.reset(UserTag, LR, Matrix[Unit]); | |
| if (Q.checkInterference()) | |
| return true; | |
| } | |
| return false; | |
| } | |
| LaneBitmask LiveRegMatrix::checkInterferenceLanes(SlotIndex Start, | |
| SlotIndex End, | |
| MCRegister PhysReg) { | |
| // Construct artificial live range containing only one segment [Start, End). | |
| VNInfo valno(0, Start); | |
| LiveRange::Segment Seg(Start, End, &valno); | |
| LiveRange LR; | |
| LR.addSegment(Seg); | |
| LaneBitmask InterferingLanes; | |
| // Check for interference with that segment | |
| for (MCRegUnitMaskIterator MCRU(PhysReg, TRI); MCRU.isValid(); ++MCRU) { | |
| auto [Unit, Lanes] = *MCRU; | |
| // LR is stack-allocated. LiveRegMatrix caches queries by a key that | |
| // includes the address of the live range. If (for the same reg unit) this | |
| // checkInterference overload is called twice, without any other query() | |
| // calls in between (on heap-allocated LiveRanges) - which would invalidate | |
| // the cached query - the LR address seen the second time may well be the | |
| // same as that seen the first time, while the Start/End/valno may not - yet | |
| // the same cached result would be fetched. To avoid that, we don't cache | |
| // this query. | |
| // | |
| // FIXME: the usability of the Query API needs to be improved to avoid | |
| // subtle bugs due to query identity. Avoiding caching, for example, would | |
| // greatly simplify things. | |
| LiveIntervalUnion::Query Q; | |
| Q.reset(UserTag, LR, Matrix[Unit]); | |
| if (Q.checkInterference()) | |
| InterferingLanes |= Lanes; | |
| } | |
| return InterferingLanes; | |
| } | |
| Register LiveRegMatrix::getOneVReg(unsigned PhysReg) const { | |
| const LiveInterval *VRegInterval = nullptr; | |
| for (MCRegUnit Unit : TRI->regunits(PhysReg)) { | |
| if ((VRegInterval = Matrix[Unit].getOneVReg())) | |
| return VRegInterval->reg(); | |
| } | |
| return MCRegister::NoRegister; | |
| } | |
| #ifndef NDEBUG | |
| bool LiveRegMatrix::isValid() const { | |
| // Build set of all valid LiveInterval pointers from LiveIntervals. | |
| DenseSet<const LiveInterval *> ValidIntervals; | |
| for (unsigned RegIdx = 0, NumRegs = VRM->getRegInfo().getNumVirtRegs(); | |
| RegIdx < NumRegs; ++RegIdx) { | |
| Register VReg = Register::index2VirtReg(RegIdx); | |
| // Only track assigned registers since unassigned ones won't be in Matrix | |
| if (VRM->hasPhys(VReg) && LIS->hasInterval(VReg)) | |
| ValidIntervals.insert(&LIS->getInterval(VReg)); | |
| } | |
| // Now scan all LiveIntervalUnions in the matrix and verify each pointer | |
| unsigned NumDanglingPointers = 0; | |
| for (unsigned I = 0, Size = Matrix.size(); I < Size; ++I) { | |
| MCRegUnit Unit = static_cast<MCRegUnit>(I); | |
| for (const LiveInterval *LI : Matrix[Unit]) { | |
| if (!ValidIntervals.contains(LI)) { | |
| ++NumDanglingPointers; | |
| dbgs() << "ERROR: LiveInterval pointer is not found in LiveIntervals:\n" | |
| << " Register Unit: " << printRegUnit(Unit, TRI) << '\n' | |
| << " LiveInterval pointer: " << LI << '\n'; | |
| } | |
| } | |
| } | |
| // Reverse check: every VRM-assigned vreg with a non-empty live interval | |
| // must have its segments present in the Matrix for its assigned phys reg. | |
| unsigned NumMissing = 0; | |
| for (unsigned RegIdx = 0, NumRegs = VRM->getRegInfo().getNumVirtRegs(); | |
| RegIdx < NumRegs; ++RegIdx) { | |
| Register VReg = Register::index2VirtReg(RegIdx); | |
| if (!VRM->hasPhys(VReg) || !LIS->hasInterval(VReg)) | |
| continue; | |
| const LiveInterval &LI = LIS->getInterval(VReg); | |
| if (LI.empty()) | |
| continue; | |
| MCRegister PhysReg = VRM->getPhys(VReg); | |
| // Check that the first segment of LI is present in the LiveUnion for | |
| // at least one reg unit of PhysReg. | |
| SlotIndex FirstStart = LI.beginIndex(); | |
| bool Found = false; | |
| for (MCRegUnit Unit : TRI->regunits(PhysReg)) { | |
| auto It = Matrix[Unit].find(FirstStart); | |
| if (It.valid() && It.start() == FirstStart && It.value() == &LI) { | |
| Found = true; | |
| break; | |
| } | |
| } | |
| if (!Found) { | |
| ++NumMissing; | |
| dbgs() << "ERROR: VirtReg " << printReg(VReg, TRI) << " assigned to " | |
| << printReg(PhysReg, TRI) | |
| << " in VirtRegMap but not found in LiveRegMatrix\n"; | |
| dbgs() << " LiveInterval: " << LI << "\n"; | |
| dbgs() << " FirstStart: " << FirstStart << "\n"; | |
| for (MCRegUnit Unit : TRI->regunits(PhysReg)) { | |
| dbgs() << " RegUnit " << printRegUnit(Unit, TRI) << " segments: "; | |
| auto It = Matrix[Unit].find(FirstStart); | |
| if (It.valid()) | |
| dbgs() << "[" << It.start() << "," << It.stop() << ") -> " | |
| << printReg(It.value()->reg(), TRI); | |
| else | |
| dbgs() << "(none found)"; | |
| dbgs() << "\n"; | |
| } | |
| } | |
| } | |
| return NumDanglingPointers == 0 && NumMissing == 0; | |
| } | |
| #endif | |
| AnalysisKey LiveRegMatrixAnalysis::Key; | |
| LiveRegMatrix LiveRegMatrixAnalysis::run(MachineFunction &MF, | |
| MachineFunctionAnalysisManager &MFAM) { | |
| auto &LIS = MFAM.getResult<LiveIntervalsAnalysis>(MF); | |
| auto &VRM = MFAM.getResult<VirtRegMapAnalysis>(MF); | |
| LiveRegMatrix LRM; | |
| LRM.init(MF, LIS, VRM); | |
| return LRM; | |
| } |