10b57cec5SDimitry Andric //===- InterferenceCache.cpp - Caching per-block interference -------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // InterferenceCache remembers per-block interference in LiveIntervalUnions. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "InterferenceCache.h" 140b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 200b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 210b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 220b57cec5SDimitry Andric #include <cassert> 230b57cec5SDimitry Andric #include <cstdint> 240b57cec5SDimitry Andric #include <tuple> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #define DEBUG_TYPE "regalloc" 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric // Static member used for null interference cursors. 310b57cec5SDimitry Andric const InterferenceCache::BlockInterference 320b57cec5SDimitry Andric InterferenceCache::Cursor::NoInterference; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric // Initializes PhysRegEntries (instead of a SmallVector, PhysRegEntries is a 350b57cec5SDimitry Andric // buffer of size NumPhysRegs to speed up alloc/clear for targets with large 360b57cec5SDimitry Andric // reg files). Calloced memory is used for good form, and quites tools like 370b57cec5SDimitry Andric // Valgrind too, but zero initialized memory is not required by the algorithm: 380b57cec5SDimitry Andric // this is because PhysRegEntries works like a SparseSet and its entries are 390b57cec5SDimitry Andric // only valid when there is a corresponding CacheEntries assignment. There is 400b57cec5SDimitry Andric // also support for when pass managers are reused for targets with different 410b57cec5SDimitry Andric // numbers of PhysRegs: in this case PhysRegEntries is freed and reinitialized. 420b57cec5SDimitry Andric void InterferenceCache::reinitPhysRegEntries() { 430b57cec5SDimitry Andric if (PhysRegEntriesCount == TRI->getNumRegs()) return; 440b57cec5SDimitry Andric free(PhysRegEntries); 450b57cec5SDimitry Andric PhysRegEntriesCount = TRI->getNumRegs(); 460b57cec5SDimitry Andric PhysRegEntries = static_cast<unsigned char*>( 470b57cec5SDimitry Andric safe_calloc(PhysRegEntriesCount, sizeof(unsigned char))); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric void InterferenceCache::init(MachineFunction *mf, 510b57cec5SDimitry Andric LiveIntervalUnion *liuarray, 520b57cec5SDimitry Andric SlotIndexes *indexes, 530b57cec5SDimitry Andric LiveIntervals *lis, 540b57cec5SDimitry Andric const TargetRegisterInfo *tri) { 550b57cec5SDimitry Andric MF = mf; 560b57cec5SDimitry Andric LIUArray = liuarray; 570b57cec5SDimitry Andric TRI = tri; 580b57cec5SDimitry Andric reinitPhysRegEntries(); 590eae32dcSDimitry Andric for (Entry &E : Entries) 600eae32dcSDimitry Andric E.clear(mf, indexes, lis); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 63e8d8bef9SDimitry Andric InterferenceCache::Entry *InterferenceCache::get(MCRegister PhysReg) { 64e8d8bef9SDimitry Andric unsigned char E = PhysRegEntries[PhysReg.id()]; 650b57cec5SDimitry Andric if (E < CacheEntries && Entries[E].getPhysReg() == PhysReg) { 660b57cec5SDimitry Andric if (!Entries[E].valid(LIUArray, TRI)) 670b57cec5SDimitry Andric Entries[E].revalidate(LIUArray, TRI); 680b57cec5SDimitry Andric return &Entries[E]; 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric // No valid entry exists, pick the next round-robin entry. 710b57cec5SDimitry Andric E = RoundRobin; 720b57cec5SDimitry Andric if (++RoundRobin == CacheEntries) 730b57cec5SDimitry Andric RoundRobin = 0; 740b57cec5SDimitry Andric for (unsigned i = 0; i != CacheEntries; ++i) { 750b57cec5SDimitry Andric // Skip entries that are in use. 760b57cec5SDimitry Andric if (Entries[E].hasRefs()) { 770b57cec5SDimitry Andric if (++E == CacheEntries) 780b57cec5SDimitry Andric E = 0; 790b57cec5SDimitry Andric continue; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric Entries[E].reset(PhysReg, LIUArray, TRI, MF); 820b57cec5SDimitry Andric PhysRegEntries[PhysReg] = E; 830b57cec5SDimitry Andric return &Entries[E]; 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric llvm_unreachable("Ran out of interference cache entries."); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric /// revalidate - LIU contents have changed, update tags. 890b57cec5SDimitry Andric void InterferenceCache::Entry::revalidate(LiveIntervalUnion *LIUArray, 900b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 910b57cec5SDimitry Andric // Invalidate all block entries. 920b57cec5SDimitry Andric ++Tag; 930b57cec5SDimitry Andric // Invalidate all iterators. 940b57cec5SDimitry Andric PrevPos = SlotIndex(); 950b57cec5SDimitry Andric unsigned i = 0; 9606c3fb27SDimitry Andric for (MCRegUnit Unit : TRI->regunits(PhysReg)) 9706c3fb27SDimitry Andric RegUnits[i++].VirtTag = LIUArray[Unit].getTag(); 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 100e8d8bef9SDimitry Andric void InterferenceCache::Entry::reset(MCRegister physReg, 1010b57cec5SDimitry Andric LiveIntervalUnion *LIUArray, 1020b57cec5SDimitry Andric const TargetRegisterInfo *TRI, 1030b57cec5SDimitry Andric const MachineFunction *MF) { 1040b57cec5SDimitry Andric assert(!hasRefs() && "Cannot reset cache entry with references"); 1050b57cec5SDimitry Andric // LIU's changed, invalidate cache. 1060b57cec5SDimitry Andric ++Tag; 1070b57cec5SDimitry Andric PhysReg = physReg; 1080b57cec5SDimitry Andric Blocks.resize(MF->getNumBlockIDs()); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // Reset iterators. 1110b57cec5SDimitry Andric PrevPos = SlotIndex(); 1120b57cec5SDimitry Andric RegUnits.clear(); 11306c3fb27SDimitry Andric for (MCRegUnit Unit : TRI->regunits(PhysReg)) { 11406c3fb27SDimitry Andric RegUnits.push_back(LIUArray[Unit]); 11506c3fb27SDimitry Andric RegUnits.back().Fixed = &LIS->getRegUnit(Unit); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric bool InterferenceCache::Entry::valid(LiveIntervalUnion *LIUArray, 1200b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 1210b57cec5SDimitry Andric unsigned i = 0, e = RegUnits.size(); 12206c3fb27SDimitry Andric for (MCRegUnit Unit : TRI->regunits(PhysReg)) { 1230b57cec5SDimitry Andric if (i == e) 1240b57cec5SDimitry Andric return false; 12506c3fb27SDimitry Andric if (LIUArray[Unit].changedSince(RegUnits[i].VirtTag)) 1260b57cec5SDimitry Andric return false; 12706c3fb27SDimitry Andric ++i; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric return i == e; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric void InterferenceCache::Entry::update(unsigned MBBNum) { 1330b57cec5SDimitry Andric SlotIndex Start, Stop; 1340b57cec5SDimitry Andric std::tie(Start, Stop) = Indexes->getMBBRange(MBBNum); 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric // Use advanceTo only when possible. 1370b57cec5SDimitry Andric if (PrevPos != Start) { 1380b57cec5SDimitry Andric if (!PrevPos.isValid() || Start < PrevPos) { 139*0fca6ea1SDimitry Andric for (RegUnitInfo &RUI : RegUnits) { 1400b57cec5SDimitry Andric RUI.VirtI.find(Start); 1410b57cec5SDimitry Andric RUI.FixedI = RUI.Fixed->find(Start); 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric } else { 144*0fca6ea1SDimitry Andric for (RegUnitInfo &RUI : RegUnits) { 1450b57cec5SDimitry Andric RUI.VirtI.advanceTo(Start); 1460b57cec5SDimitry Andric if (RUI.FixedI != RUI.Fixed->end()) 1470b57cec5SDimitry Andric RUI.FixedI = RUI.Fixed->advanceTo(RUI.FixedI, Start); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric PrevPos = Start; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric MachineFunction::const_iterator MFI = 1540b57cec5SDimitry Andric MF->getBlockNumbered(MBBNum)->getIterator(); 1550b57cec5SDimitry Andric BlockInterference *BI = &Blocks[MBBNum]; 1560b57cec5SDimitry Andric ArrayRef<SlotIndex> RegMaskSlots; 1570b57cec5SDimitry Andric ArrayRef<const uint32_t*> RegMaskBits; 1580b57cec5SDimitry Andric while (true) { 1590b57cec5SDimitry Andric BI->Tag = Tag; 1600b57cec5SDimitry Andric BI->First = BI->Last = SlotIndex(); 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric // Check for first interference from virtregs. 163*0fca6ea1SDimitry Andric for (RegUnitInfo &RUI : RegUnits) { 164*0fca6ea1SDimitry Andric LiveIntervalUnion::SegmentIter &I = RUI.VirtI; 1650b57cec5SDimitry Andric if (!I.valid()) 1660b57cec5SDimitry Andric continue; 1670b57cec5SDimitry Andric SlotIndex StartI = I.start(); 1680b57cec5SDimitry Andric if (StartI >= Stop) 1690b57cec5SDimitry Andric continue; 1700b57cec5SDimitry Andric if (!BI->First.isValid() || StartI < BI->First) 1710b57cec5SDimitry Andric BI->First = StartI; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric // Same thing for fixed interference. 175*0fca6ea1SDimitry Andric for (RegUnitInfo &RUI : RegUnits) { 176*0fca6ea1SDimitry Andric LiveInterval::const_iterator I = RUI.FixedI; 177*0fca6ea1SDimitry Andric LiveInterval::const_iterator E = RUI.Fixed->end(); 1780b57cec5SDimitry Andric if (I == E) 1790b57cec5SDimitry Andric continue; 1800b57cec5SDimitry Andric SlotIndex StartI = I->start; 1810b57cec5SDimitry Andric if (StartI >= Stop) 1820b57cec5SDimitry Andric continue; 1830b57cec5SDimitry Andric if (!BI->First.isValid() || StartI < BI->First) 1840b57cec5SDimitry Andric BI->First = StartI; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric // Also check for register mask interference. 1880b57cec5SDimitry Andric RegMaskSlots = LIS->getRegMaskSlotsInBlock(MBBNum); 1890b57cec5SDimitry Andric RegMaskBits = LIS->getRegMaskBitsInBlock(MBBNum); 1900b57cec5SDimitry Andric SlotIndex Limit = BI->First.isValid() ? BI->First : Stop; 1910b57cec5SDimitry Andric for (unsigned i = 0, e = RegMaskSlots.size(); 1920b57cec5SDimitry Andric i != e && RegMaskSlots[i] < Limit; ++i) 1930b57cec5SDimitry Andric if (MachineOperand::clobbersPhysReg(RegMaskBits[i], PhysReg)) { 1940b57cec5SDimitry Andric // Register mask i clobbers PhysReg before the LIU interference. 1950b57cec5SDimitry Andric BI->First = RegMaskSlots[i]; 1960b57cec5SDimitry Andric break; 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric PrevPos = Stop; 2000b57cec5SDimitry Andric if (BI->First.isValid()) 2010b57cec5SDimitry Andric break; 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric // No interference in this block? Go ahead and precompute the next block. 2040b57cec5SDimitry Andric if (++MFI == MF->end()) 2050b57cec5SDimitry Andric return; 2060b57cec5SDimitry Andric MBBNum = MFI->getNumber(); 2070b57cec5SDimitry Andric BI = &Blocks[MBBNum]; 2080b57cec5SDimitry Andric if (BI->Tag == Tag) 2090b57cec5SDimitry Andric return; 2100b57cec5SDimitry Andric std::tie(Start, Stop) = Indexes->getMBBRange(MBBNum); 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric // Check for last interference in block. 214*0fca6ea1SDimitry Andric for (RegUnitInfo &RUI : RegUnits) { 215*0fca6ea1SDimitry Andric LiveIntervalUnion::SegmentIter &I = RUI.VirtI; 2160b57cec5SDimitry Andric if (!I.valid() || I.start() >= Stop) 2170b57cec5SDimitry Andric continue; 2180b57cec5SDimitry Andric I.advanceTo(Stop); 2190b57cec5SDimitry Andric bool Backup = !I.valid() || I.start() >= Stop; 2200b57cec5SDimitry Andric if (Backup) 2210b57cec5SDimitry Andric --I; 2220b57cec5SDimitry Andric SlotIndex StopI = I.stop(); 2230b57cec5SDimitry Andric if (!BI->Last.isValid() || StopI > BI->Last) 2240b57cec5SDimitry Andric BI->Last = StopI; 2250b57cec5SDimitry Andric if (Backup) 2260b57cec5SDimitry Andric ++I; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric // Fixed interference. 230*0fca6ea1SDimitry Andric for (RegUnitInfo &RUI : RegUnits) { 231*0fca6ea1SDimitry Andric LiveInterval::iterator &I = RUI.FixedI; 232*0fca6ea1SDimitry Andric LiveRange *LR = RUI.Fixed; 2330b57cec5SDimitry Andric if (I == LR->end() || I->start >= Stop) 2340b57cec5SDimitry Andric continue; 2350b57cec5SDimitry Andric I = LR->advanceTo(I, Stop); 2360b57cec5SDimitry Andric bool Backup = I == LR->end() || I->start >= Stop; 2370b57cec5SDimitry Andric if (Backup) 2380b57cec5SDimitry Andric --I; 2390b57cec5SDimitry Andric SlotIndex StopI = I->end; 2400b57cec5SDimitry Andric if (!BI->Last.isValid() || StopI > BI->Last) 2410b57cec5SDimitry Andric BI->Last = StopI; 2420b57cec5SDimitry Andric if (Backup) 2430b57cec5SDimitry Andric ++I; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric // Also check for register mask interference. 2470b57cec5SDimitry Andric SlotIndex Limit = BI->Last.isValid() ? BI->Last : Start; 2480b57cec5SDimitry Andric for (unsigned i = RegMaskSlots.size(); 2490b57cec5SDimitry Andric i && RegMaskSlots[i-1].getDeadSlot() > Limit; --i) 2500b57cec5SDimitry Andric if (MachineOperand::clobbersPhysReg(RegMaskBits[i-1], PhysReg)) { 2510b57cec5SDimitry Andric // Register mask i-1 clobbers PhysReg after the LIU interference. 2520b57cec5SDimitry Andric // Model the regmask clobber as a dead def. 2530b57cec5SDimitry Andric BI->Last = RegMaskSlots[i-1].getDeadSlot(); 2540b57cec5SDimitry Andric break; 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric } 257