10b57cec5SDimitry Andric //===- InterferenceCache.h - Caching per-block interference ----*- C++ -*--===// 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 from LiveIntervalUnions, 100b57cec5SDimitry Andric // fixed RegUnit interference, and register masks. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef LLVM_LIB_CODEGEN_INTERFERENCECACHE_H 150b57cec5SDimitry Andric #define LLVM_LIB_CODEGEN_INTERFERENCECACHE_H 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/LiveInterval.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/LiveIntervalUnion.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/SlotIndexes.h" 210b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 220b57cec5SDimitry Andric #include <cassert> 230b57cec5SDimitry Andric #include <cstddef> 240b57cec5SDimitry Andric #include <cstdlib> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric namespace llvm { 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric class LiveIntervals; 290b57cec5SDimitry Andric class MachineFunction; 300b57cec5SDimitry Andric class TargetRegisterInfo; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric class LLVM_LIBRARY_VISIBILITY InterferenceCache { 330b57cec5SDimitry Andric /// BlockInterference - information about the interference in a single basic 340b57cec5SDimitry Andric /// block. 350b57cec5SDimitry Andric struct BlockInterference { 360b57cec5SDimitry Andric unsigned Tag = 0; 370b57cec5SDimitry Andric SlotIndex First; 380b57cec5SDimitry Andric SlotIndex Last; 390b57cec5SDimitry Andric 4081ad6265SDimitry Andric BlockInterference() = default; 410b57cec5SDimitry Andric }; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric /// Entry - A cache entry containing interference information for all aliases 440b57cec5SDimitry Andric /// of PhysReg in all basic blocks. 450b57cec5SDimitry Andric class Entry { 460b57cec5SDimitry Andric /// PhysReg - The register currently represented. 47e8d8bef9SDimitry Andric MCRegister PhysReg = 0; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric /// Tag - Cache tag is changed when any of the underlying LiveIntervalUnions 500b57cec5SDimitry Andric /// change. 510b57cec5SDimitry Andric unsigned Tag = 0; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric /// RefCount - The total number of Cursor instances referring to this Entry. 540b57cec5SDimitry Andric unsigned RefCount = 0; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric /// MF - The current function. 57*06c3fb27SDimitry Andric MachineFunction *MF = nullptr; 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric /// Indexes - Mapping block numbers to SlotIndex ranges. 600b57cec5SDimitry Andric SlotIndexes *Indexes = nullptr; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric /// LIS - Used for accessing register mask interference maps. 630b57cec5SDimitry Andric LiveIntervals *LIS = nullptr; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric /// PrevPos - The previous position the iterators were moved to. 660b57cec5SDimitry Andric SlotIndex PrevPos; 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric /// RegUnitInfo - Information tracked about each RegUnit in PhysReg. 690b57cec5SDimitry Andric /// When PrevPos is set, the iterators are valid as if advanceTo(PrevPos) 700b57cec5SDimitry Andric /// had just been called. 710b57cec5SDimitry Andric struct RegUnitInfo { 720b57cec5SDimitry Andric /// Iterator pointing into the LiveIntervalUnion containing virtual 730b57cec5SDimitry Andric /// register interference. 740b57cec5SDimitry Andric LiveIntervalUnion::SegmentIter VirtI; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric /// Tag of the LIU last time we looked. 770b57cec5SDimitry Andric unsigned VirtTag; 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric /// Fixed interference in RegUnit. 800b57cec5SDimitry Andric LiveRange *Fixed = nullptr; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric /// Iterator pointing into the fixed RegUnit interference. 830b57cec5SDimitry Andric LiveInterval::iterator FixedI; 840b57cec5SDimitry Andric RegUnitInfoRegUnitInfo850b57cec5SDimitry Andric RegUnitInfo(LiveIntervalUnion &LIU) : VirtTag(LIU.getTag()) { 860b57cec5SDimitry Andric VirtI.setMap(LIU.getMap()); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric }; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric /// Info for each RegUnit in PhysReg. It is very rare ofr a PHysReg to have 910b57cec5SDimitry Andric /// more than 4 RegUnits. 920b57cec5SDimitry Andric SmallVector<RegUnitInfo, 4> RegUnits; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric /// Blocks - Interference for each block in the function. 950b57cec5SDimitry Andric SmallVector<BlockInterference, 8> Blocks; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric /// update - Recompute Blocks[MBBNum] 980b57cec5SDimitry Andric void update(unsigned MBBNum); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric public: 1010b57cec5SDimitry Andric Entry() = default; 1020b57cec5SDimitry Andric clear(MachineFunction * mf,SlotIndexes * indexes,LiveIntervals * lis)1030b57cec5SDimitry Andric void clear(MachineFunction *mf, SlotIndexes *indexes, LiveIntervals *lis) { 1040b57cec5SDimitry Andric assert(!hasRefs() && "Cannot clear cache entry with references"); 105e8d8bef9SDimitry Andric PhysReg = MCRegister::NoRegister; 1060b57cec5SDimitry Andric MF = mf; 1070b57cec5SDimitry Andric Indexes = indexes; 1080b57cec5SDimitry Andric LIS = lis; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric getPhysReg()111e8d8bef9SDimitry Andric MCRegister getPhysReg() const { return PhysReg; } 1120b57cec5SDimitry Andric addRef(int Delta)1130b57cec5SDimitry Andric void addRef(int Delta) { RefCount += Delta; } 1140b57cec5SDimitry Andric hasRefs()1150b57cec5SDimitry Andric bool hasRefs() const { return RefCount > 0; } 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric void revalidate(LiveIntervalUnion *LIUArray, const TargetRegisterInfo *TRI); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric /// valid - Return true if this is a valid entry for physReg. 1200b57cec5SDimitry Andric bool valid(LiveIntervalUnion *LIUArray, const TargetRegisterInfo *TRI); 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric /// reset - Initialize entry to represent physReg's aliases. 123e8d8bef9SDimitry Andric void reset(MCRegister physReg, LiveIntervalUnion *LIUArray, 124e8d8bef9SDimitry Andric const TargetRegisterInfo *TRI, const MachineFunction *MF); 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric /// get - Return an up to date BlockInterference. get(unsigned MBBNum)1270b57cec5SDimitry Andric BlockInterference *get(unsigned MBBNum) { 1280b57cec5SDimitry Andric if (Blocks[MBBNum].Tag != Tag) 1290b57cec5SDimitry Andric update(MBBNum); 1300b57cec5SDimitry Andric return &Blocks[MBBNum]; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric }; 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric // We don't keep a cache entry for every physical register, that would use too 1350b57cec5SDimitry Andric // much memory. Instead, a fixed number of cache entries are used in a round- 1360b57cec5SDimitry Andric // robin manner. 1370b57cec5SDimitry Andric enum { CacheEntries = 32 }; 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric const TargetRegisterInfo *TRI = nullptr; 1400b57cec5SDimitry Andric LiveIntervalUnion *LIUArray = nullptr; 1410b57cec5SDimitry Andric MachineFunction *MF = nullptr; 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric // Point to an entry for each physreg. The entry pointed to may not be up to 1440b57cec5SDimitry Andric // date, and it may have been reused for a different physreg. 1450b57cec5SDimitry Andric unsigned char* PhysRegEntries = nullptr; 1460b57cec5SDimitry Andric size_t PhysRegEntriesCount = 0; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric // Next round-robin entry to be picked. 1490b57cec5SDimitry Andric unsigned RoundRobin = 0; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // The actual cache entries. 1520b57cec5SDimitry Andric Entry Entries[CacheEntries]; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric // get - Get a valid entry for PhysReg. 155e8d8bef9SDimitry Andric Entry *get(MCRegister PhysReg); 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric public: 1580b57cec5SDimitry Andric InterferenceCache() = default; 159*06c3fb27SDimitry Andric InterferenceCache &operator=(const InterferenceCache &other) = delete; 160*06c3fb27SDimitry Andric InterferenceCache(const InterferenceCache &other) = delete; ~InterferenceCache()1610b57cec5SDimitry Andric ~InterferenceCache() { 1620b57cec5SDimitry Andric free(PhysRegEntries); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric void reinitPhysRegEntries(); 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric /// init - Prepare cache for a new function. 1680b57cec5SDimitry Andric void init(MachineFunction *mf, LiveIntervalUnion *liuarray, 1690b57cec5SDimitry Andric SlotIndexes *indexes, LiveIntervals *lis, 1700b57cec5SDimitry Andric const TargetRegisterInfo *tri); 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric /// getMaxCursors - Return the maximum number of concurrent cursors that can 1730b57cec5SDimitry Andric /// be supported. getMaxCursors()1740b57cec5SDimitry Andric unsigned getMaxCursors() const { return CacheEntries; } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric /// Cursor - The primary query interface for the block interference cache. 1770b57cec5SDimitry Andric class Cursor { 1780b57cec5SDimitry Andric Entry *CacheEntry = nullptr; 1790b57cec5SDimitry Andric const BlockInterference *Current = nullptr; 1800b57cec5SDimitry Andric static const BlockInterference NoInterference; 1810b57cec5SDimitry Andric setEntry(Entry * E)1820b57cec5SDimitry Andric void setEntry(Entry *E) { 1830b57cec5SDimitry Andric Current = nullptr; 1840b57cec5SDimitry Andric // Update reference counts. Nothing happens when RefCount reaches 0, so 1850b57cec5SDimitry Andric // we don't have to check for E == CacheEntry etc. 1860b57cec5SDimitry Andric if (CacheEntry) 1870b57cec5SDimitry Andric CacheEntry->addRef(-1); 1880b57cec5SDimitry Andric CacheEntry = E; 1890b57cec5SDimitry Andric if (CacheEntry) 1900b57cec5SDimitry Andric CacheEntry->addRef(+1); 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric public: 1940b57cec5SDimitry Andric /// Cursor - Create a dangling cursor. 1950b57cec5SDimitry Andric Cursor() = default; 1960b57cec5SDimitry Andric Cursor(const Cursor & O)1970b57cec5SDimitry Andric Cursor(const Cursor &O) { 1980b57cec5SDimitry Andric setEntry(O.CacheEntry); 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric Cursor &operator=(const Cursor &O) { 2020b57cec5SDimitry Andric setEntry(O.CacheEntry); 2030b57cec5SDimitry Andric return *this; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric ~Cursor()2060b57cec5SDimitry Andric ~Cursor() { setEntry(nullptr); } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric /// setPhysReg - Point this cursor to PhysReg's interference. setPhysReg(InterferenceCache & Cache,MCRegister PhysReg)209e8d8bef9SDimitry Andric void setPhysReg(InterferenceCache &Cache, MCRegister PhysReg) { 2100b57cec5SDimitry Andric // Release reference before getting a new one. That guarantees we can 2110b57cec5SDimitry Andric // actually have CacheEntries live cursors. 2120b57cec5SDimitry Andric setEntry(nullptr); 213e8d8bef9SDimitry Andric if (PhysReg.isValid()) 2140b57cec5SDimitry Andric setEntry(Cache.get(PhysReg)); 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric /// moveTo - Move cursor to basic block MBBNum. moveToBlock(unsigned MBBNum)2180b57cec5SDimitry Andric void moveToBlock(unsigned MBBNum) { 2190b57cec5SDimitry Andric Current = CacheEntry ? CacheEntry->get(MBBNum) : &NoInterference; 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric /// hasInterference - Return true if the current block has any interference. hasInterference()2230b57cec5SDimitry Andric bool hasInterference() { 2240b57cec5SDimitry Andric return Current->First.isValid(); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric /// first - Return the starting index of the first interfering range in the 2280b57cec5SDimitry Andric /// current block. first()2290b57cec5SDimitry Andric SlotIndex first() { 2300b57cec5SDimitry Andric return Current->First; 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric /// last - Return the ending index of the last interfering range in the 2340b57cec5SDimitry Andric /// current block. last()2350b57cec5SDimitry Andric SlotIndex last() { 2360b57cec5SDimitry Andric return Current->Last; 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric }; 2390b57cec5SDimitry Andric }; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric } // end namespace llvm 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric #endif // LLVM_LIB_CODEGEN_INTERFERENCECACHE_H 244