xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/InterferenceCache.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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