//===- llvm/CodeGen/SlotIndexes.h - Slot indexes representation -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements SlotIndex and related classes. The purpose of SlotIndex // is to describe a position at which a register can become live, or cease to // be live. // // SlotIndex is mostly a proxy for entries of the SlotIndexList, a class which // is held is LiveIntervals and provides the real numbering. This allows // LiveIntervals to perform largely transparent renumbering. //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_SLOTINDEXES_H #define LLVM_CODEGEN_SLOTINDEXES_H #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Allocator.h" namespace llvm { /// This class represents an entry in the slot index list held in the /// SlotIndexes pass. It should not be used directly. See the /// SlotIndex & SlotIndexes classes for the public interface to this /// information. class IndexListEntry { IndexListEntry *next, *prev; MachineInstr *mi; unsigned index; public: IndexListEntry(MachineInstr *mi, unsigned index) : mi(mi), index(index) {} MachineInstr* getInstr() const { return mi; } void setInstr(MachineInstr *mi) { this->mi = mi; } unsigned getIndex() const { return index; } void setIndex(unsigned index) { this->index = index; } IndexListEntry* getNext() { return next; } const IndexListEntry* getNext() const { return next; } void setNext(IndexListEntry *next) { this->next = next; } IndexListEntry* getPrev() { return prev; } const IndexListEntry* getPrev() const { return prev; } void setPrev(IndexListEntry *prev) { this->prev = prev; } }; // Specialize PointerLikeTypeTraits for IndexListEntry. template <> class PointerLikeTypeTraits<IndexListEntry*> { public: static inline void* getAsVoidPointer(IndexListEntry *p) { return p; } static inline IndexListEntry* getFromVoidPointer(void *p) { return static_cast<IndexListEntry*>(p); } enum { NumLowBitsAvailable = 3 }; }; /// SlotIndex - An opaque wrapper around machine indexes. class SlotIndex { friend class SlotIndexes; friend struct DenseMapInfo<SlotIndex>; enum Slot { LOAD, USE, DEF, STORE, NUM }; PointerIntPair<IndexListEntry*, 2, unsigned> lie; SlotIndex(IndexListEntry *entry, unsigned slot) : lie(entry, slot) {} IndexListEntry& entry() const { assert(isValid() && "Attempt to compare reserved index."); return *lie.getPointer(); } int getIndex() const { return entry().getIndex() | getSlot(); } /// Returns the slot for this SlotIndex. Slot getSlot() const { return static_cast<Slot>(lie.getInt()); } static inline unsigned getHashValue(const SlotIndex &v) { void *ptrVal = v.lie.getOpaqueValue(); return (unsigned((intptr_t)ptrVal)) ^ (unsigned((intptr_t)ptrVal) >> 9); } public: enum { /// The default distance between instructions as returned by distance(). /// This may vary as instructions are inserted and removed. InstrDist = 4*NUM }; static inline SlotIndex getEmptyKey() { return SlotIndex(0, 1); } static inline SlotIndex getTombstoneKey() { return SlotIndex(0, 2); } /// Construct an invalid index. SlotIndex() : lie(0, 0) {} // Construct a new slot index from the given one, and set the slot. SlotIndex(const SlotIndex &li, Slot s) : lie(&li.entry(), unsigned(s)) { assert(lie.getPointer() != 0 && "Attempt to construct index with 0 pointer."); } /// Returns true if this is a valid index. Invalid indicies do /// not point into an index table, and cannot be compared. bool isValid() const { return lie.getPointer(); } /// Return true for a valid index. operator bool() const { return isValid(); } /// Print this index to the given raw_ostream. void print(raw_ostream &os) const; /// Dump this index to stderr. void dump() const; /// Compare two SlotIndex objects for equality. bool operator==(SlotIndex other) const { return lie == other.lie; } /// Compare two SlotIndex objects for inequality. bool operator!=(SlotIndex other) const { return lie != other.lie; } /// Compare two SlotIndex objects. Return true if the first index /// is strictly lower than the second. bool operator<(SlotIndex other) const { return getIndex() < other.getIndex(); } /// Compare two SlotIndex objects. Return true if the first index /// is lower than, or equal to, the second. bool operator<=(SlotIndex other) const { return getIndex() <= other.getIndex(); } /// Compare two SlotIndex objects. Return true if the first index /// is greater than the second. bool operator>(SlotIndex other) const { return getIndex() > other.getIndex(); } /// Compare two SlotIndex objects. Return true if the first index /// is greater than, or equal to, the second. bool operator>=(SlotIndex other) const { return getIndex() >= other.getIndex(); } /// isSameInstr - Return true if A and B refer to the same instruction. static bool isSameInstr(SlotIndex A, SlotIndex B) { return A.lie.getPointer() == B.lie.getPointer(); } /// Return the distance from this index to the given one. int distance(SlotIndex other) const { return other.getIndex() - getIndex(); } /// isLoad - Return true if this is a LOAD slot. bool isLoad() const { return getSlot() == LOAD; } /// isDef - Return true if this is a DEF slot. bool isDef() const { return getSlot() == DEF; } /// isUse - Return true if this is a USE slot. bool isUse() const { return getSlot() == USE; } /// isStore - Return true if this is a STORE slot. bool isStore() const { return getSlot() == STORE; } /// Returns the base index for associated with this index. The base index /// is the one associated with the LOAD slot for the instruction pointed to /// by this index. SlotIndex getBaseIndex() const { return getLoadIndex(); } /// Returns the boundary index for associated with this index. The boundary /// index is the one associated with the LOAD slot for the instruction /// pointed to by this index. SlotIndex getBoundaryIndex() const { return getStoreIndex(); } /// Returns the index of the LOAD slot for the instruction pointed to by /// this index. SlotIndex getLoadIndex() const { return SlotIndex(&entry(), SlotIndex::LOAD); } /// Returns the index of the USE slot for the instruction pointed to by /// this index. SlotIndex getUseIndex() const { return SlotIndex(&entry(), SlotIndex::USE); } /// Returns the index of the DEF slot for the instruction pointed to by /// this index. SlotIndex getDefIndex() const { return SlotIndex(&entry(), SlotIndex::DEF); } /// Returns the index of the STORE slot for the instruction pointed to by /// this index. SlotIndex getStoreIndex() const { return SlotIndex(&entry(), SlotIndex::STORE); } /// Returns the next slot in the index list. This could be either the /// next slot for the instruction pointed to by this index or, if this /// index is a STORE, the first slot for the next instruction. /// WARNING: This method is considerably more expensive than the methods /// that return specific slots (getUseIndex(), etc). If you can - please /// use one of those methods. SlotIndex getNextSlot() const { Slot s = getSlot(); if (s == SlotIndex::STORE) { return SlotIndex(entry().getNext(), SlotIndex::LOAD); } return SlotIndex(&entry(), s + 1); } /// Returns the next index. This is the index corresponding to the this /// index's slot, but for the next instruction. SlotIndex getNextIndex() const { return SlotIndex(entry().getNext(), getSlot()); } /// Returns the previous slot in the index list. This could be either the /// previous slot for the instruction pointed to by this index or, if this /// index is a LOAD, the last slot for the previous instruction. /// WARNING: This method is considerably more expensive than the methods /// that return specific slots (getUseIndex(), etc). If you can - please /// use one of those methods. SlotIndex getPrevSlot() const { Slot s = getSlot(); if (s == SlotIndex::LOAD) { return SlotIndex(entry().getPrev(), SlotIndex::STORE); } return SlotIndex(&entry(), s - 1); } /// Returns the previous index. This is the index corresponding to this /// index's slot, but for the previous instruction. SlotIndex getPrevIndex() const { return SlotIndex(entry().getPrev(), getSlot()); } }; /// DenseMapInfo specialization for SlotIndex. template <> struct DenseMapInfo<SlotIndex> { static inline SlotIndex getEmptyKey() { return SlotIndex::getEmptyKey(); } static inline SlotIndex getTombstoneKey() { return SlotIndex::getTombstoneKey(); } static inline unsigned getHashValue(const SlotIndex &v) { return SlotIndex::getHashValue(v); } static inline bool isEqual(const SlotIndex &LHS, const SlotIndex &RHS) { return (LHS == RHS); } }; template <> struct isPodLike<SlotIndex> { static const bool value = true; }; inline raw_ostream& operator<<(raw_ostream &os, SlotIndex li) { li.print(os); return os; } typedef std::pair<SlotIndex, MachineBasicBlock*> IdxMBBPair; inline bool operator<(SlotIndex V, const IdxMBBPair &IM) { return V < IM.first; } inline bool operator<(const IdxMBBPair &IM, SlotIndex V) { return IM.first < V; } struct Idx2MBBCompare { bool operator()(const IdxMBBPair &LHS, const IdxMBBPair &RHS) const { return LHS.first < RHS.first; } }; /// SlotIndexes pass. /// /// This pass assigns indexes to each instruction. class SlotIndexes : public MachineFunctionPass { private: MachineFunction *mf; IndexListEntry *indexListHead; unsigned functionSize; typedef DenseMap<const MachineInstr*, SlotIndex> Mi2IndexMap; Mi2IndexMap mi2iMap; /// MBBRanges - Map MBB number to (start, stop) indexes. SmallVector<std::pair<SlotIndex, SlotIndex>, 8> MBBRanges; /// Idx2MBBMap - Sorted list of pairs of index of first instruction /// and MBB id. SmallVector<IdxMBBPair, 8> idx2MBBMap; // IndexListEntry allocator. BumpPtrAllocator ileAllocator; IndexListEntry* createEntry(MachineInstr *mi, unsigned index) { IndexListEntry *entry = static_cast<IndexListEntry*>( ileAllocator.Allocate(sizeof(IndexListEntry), alignOf<IndexListEntry>())); new (entry) IndexListEntry(mi, index); return entry; } void initList() { assert(indexListHead == 0 && "Zero entry non-null at initialisation."); indexListHead = createEntry(0, ~0U); indexListHead->setNext(0); indexListHead->setPrev(indexListHead); } void clearList() { indexListHead = 0; ileAllocator.Reset(); } IndexListEntry* getTail() { assert(indexListHead != 0 && "Call to getTail on uninitialized list."); return indexListHead->getPrev(); } const IndexListEntry* getTail() const { assert(indexListHead != 0 && "Call to getTail on uninitialized list."); return indexListHead->getPrev(); } // Returns true if the index list is empty. bool empty() const { return (indexListHead == getTail()); } IndexListEntry* front() { assert(!empty() && "front() called on empty index list."); return indexListHead; } const IndexListEntry* front() const { assert(!empty() && "front() called on empty index list."); return indexListHead; } IndexListEntry* back() { assert(!empty() && "back() called on empty index list."); return getTail()->getPrev(); } const IndexListEntry* back() const { assert(!empty() && "back() called on empty index list."); return getTail()->getPrev(); } /// Insert a new entry before itr. void insert(IndexListEntry *itr, IndexListEntry *val) { assert(itr != 0 && "itr should not be null."); IndexListEntry *prev = itr->getPrev(); val->setNext(itr); val->setPrev(prev); if (itr != indexListHead) { prev->setNext(val); } else { indexListHead = val; } itr->setPrev(val); } /// Push a new entry on to the end of the list. void push_back(IndexListEntry *val) { insert(getTail(), val); } /// Renumber locally after inserting newEntry. void renumberIndexes(IndexListEntry *newEntry); public: static char ID; SlotIndexes() : MachineFunctionPass(ID), indexListHead(0) { initializeSlotIndexesPass(*PassRegistry::getPassRegistry()); } virtual void getAnalysisUsage(AnalysisUsage &au) const; virtual void releaseMemory(); virtual bool runOnMachineFunction(MachineFunction &fn); /// Dump the indexes. void dump() const; /// Renumber the index list, providing space for new instructions. void renumberIndexes(); /// Returns the zero index for this analysis. SlotIndex getZeroIndex() { assert(front()->getIndex() == 0 && "First index is not 0?"); return SlotIndex(front(), 0); } /// Returns the base index of the last slot in this analysis. SlotIndex getLastIndex() { return SlotIndex(back(), 0); } /// Returns the invalid index marker for this analysis. SlotIndex getInvalidIndex() { return getZeroIndex(); } /// Returns the distance between the highest and lowest indexes allocated /// so far. unsigned getIndexesLength() const { assert(front()->getIndex() == 0 && "Initial index isn't zero?"); return back()->getIndex(); } /// Returns the number of instructions in the function. unsigned getFunctionSize() const { return functionSize; } /// Returns true if the given machine instr is mapped to an index, /// otherwise returns false. bool hasIndex(const MachineInstr *instr) const { return (mi2iMap.find(instr) != mi2iMap.end()); } /// Returns the base index for the given instruction. SlotIndex getInstructionIndex(const MachineInstr *instr) const { Mi2IndexMap::const_iterator itr = mi2iMap.find(instr); assert(itr != mi2iMap.end() && "Instruction not found in maps."); return itr->second; } /// Returns the instruction for the given index, or null if the given /// index has no instruction associated with it. MachineInstr* getInstructionFromIndex(SlotIndex index) const { return index.isValid() ? index.entry().getInstr() : 0; } /// Returns the next non-null index. SlotIndex getNextNonNullIndex(SlotIndex index) { SlotIndex nextNonNull = index.getNextIndex(); while (&nextNonNull.entry() != getTail() && getInstructionFromIndex(nextNonNull) == 0) { nextNonNull = nextNonNull.getNextIndex(); } return nextNonNull; } /// getIndexBefore - Returns the index of the last indexed instruction /// before MI, or the the start index of its basic block. /// MI is not required to have an index. SlotIndex getIndexBefore(const MachineInstr *MI) const { const MachineBasicBlock *MBB = MI->getParent(); assert(MBB && "MI must be inserted inna basic block"); MachineBasicBlock::const_iterator I = MI, B = MBB->begin(); for (;;) { if (I == B) return getMBBStartIdx(MBB); --I; Mi2IndexMap::const_iterator MapItr = mi2iMap.find(I); if (MapItr != mi2iMap.end()) return MapItr->second; } } /// getIndexAfter - Returns the index of the first indexed instruction /// after MI, or the end index of its basic block. /// MI is not required to have an index. SlotIndex getIndexAfter(const MachineInstr *MI) const { const MachineBasicBlock *MBB = MI->getParent(); assert(MBB && "MI must be inserted inna basic block"); MachineBasicBlock::const_iterator I = MI, E = MBB->end(); for (;;) { ++I; if (I == E) return getMBBEndIdx(MBB); Mi2IndexMap::const_iterator MapItr = mi2iMap.find(I); if (MapItr != mi2iMap.end()) return MapItr->second; } } /// Return the (start,end) range of the given basic block number. const std::pair<SlotIndex, SlotIndex> & getMBBRange(unsigned Num) const { return MBBRanges[Num]; } /// Return the (start,end) range of the given basic block. const std::pair<SlotIndex, SlotIndex> & getMBBRange(const MachineBasicBlock *MBB) const { return getMBBRange(MBB->getNumber()); } /// Returns the first index in the given basic block number. SlotIndex getMBBStartIdx(unsigned Num) const { return getMBBRange(Num).first; } /// Returns the first index in the given basic block. SlotIndex getMBBStartIdx(const MachineBasicBlock *mbb) const { return getMBBRange(mbb).first; } /// Returns the last index in the given basic block number. SlotIndex getMBBEndIdx(unsigned Num) const { return getMBBRange(Num).second; } /// Returns the last index in the given basic block. SlotIndex getMBBEndIdx(const MachineBasicBlock *mbb) const { return getMBBRange(mbb).second; } /// Returns the basic block which the given index falls in. MachineBasicBlock* getMBBFromIndex(SlotIndex index) const { if (MachineInstr *MI = getInstructionFromIndex(index)) return MI->getParent(); SmallVectorImpl<IdxMBBPair>::const_iterator I = std::lower_bound(idx2MBBMap.begin(), idx2MBBMap.end(), index); // Take the pair containing the index SmallVectorImpl<IdxMBBPair>::const_iterator J = ((I != idx2MBBMap.end() && I->first > index) || (I == idx2MBBMap.end() && idx2MBBMap.size()>0)) ? (I-1): I; assert(J != idx2MBBMap.end() && J->first <= index && index < getMBBEndIdx(J->second) && "index does not correspond to an MBB"); return J->second; } bool findLiveInMBBs(SlotIndex start, SlotIndex end, SmallVectorImpl<MachineBasicBlock*> &mbbs) const { SmallVectorImpl<IdxMBBPair>::const_iterator itr = std::lower_bound(idx2MBBMap.begin(), idx2MBBMap.end(), start); bool resVal = false; while (itr != idx2MBBMap.end()) { if (itr->first >= end) break; mbbs.push_back(itr->second); resVal = true; ++itr; } return resVal; } /// Returns the MBB covering the given range, or null if the range covers /// more than one basic block. MachineBasicBlock* getMBBCoveringRange(SlotIndex start, SlotIndex end) const { assert(start < end && "Backwards ranges not allowed."); SmallVectorImpl<IdxMBBPair>::const_iterator itr = std::lower_bound(idx2MBBMap.begin(), idx2MBBMap.end(), start); if (itr == idx2MBBMap.end()) { itr = prior(itr); return itr->second; } // Check that we don't cross the boundary into this block. if (itr->first < end) return 0; itr = prior(itr); if (itr->first <= start) return itr->second; return 0; } /// Insert the given machine instruction into the mapping. Returns the /// assigned index. /// If Late is set and there are null indexes between mi's neighboring /// instructions, create the new index after the null indexes instead of /// before them. SlotIndex insertMachineInstrInMaps(MachineInstr *mi, bool Late = false) { assert(mi2iMap.find(mi) == mi2iMap.end() && "Instr already indexed."); // Numbering DBG_VALUE instructions could cause code generation to be // affected by debug information. assert(!mi->isDebugValue() && "Cannot number DBG_VALUE instructions."); assert(mi->getParent() != 0 && "Instr must be added to function."); // Get the entries where mi should be inserted. IndexListEntry *prevEntry, *nextEntry; if (Late) { // Insert mi's index immediately before the following instruction. nextEntry = &getIndexAfter(mi).entry(); prevEntry = nextEntry->getPrev(); } else { // Insert mi's index immediately after the preceeding instruction. prevEntry = &getIndexBefore(mi).entry(); nextEntry = prevEntry->getNext(); } // Get a number for the new instr, or 0 if there's no room currently. // In the latter case we'll force a renumber later. unsigned dist = ((nextEntry->getIndex() - prevEntry->getIndex())/2) & ~3u; unsigned newNumber = prevEntry->getIndex() + dist; // Insert a new list entry for mi. IndexListEntry *newEntry = createEntry(mi, newNumber); insert(nextEntry, newEntry); // Renumber locally if we need to. if (dist == 0) renumberIndexes(newEntry); SlotIndex newIndex(newEntry, SlotIndex::LOAD); mi2iMap.insert(std::make_pair(mi, newIndex)); return newIndex; } /// Remove the given machine instruction from the mapping. void removeMachineInstrFromMaps(MachineInstr *mi) { // remove index -> MachineInstr and // MachineInstr -> index mappings Mi2IndexMap::iterator mi2iItr = mi2iMap.find(mi); if (mi2iItr != mi2iMap.end()) { IndexListEntry *miEntry(&mi2iItr->second.entry()); assert(miEntry->getInstr() == mi && "Instruction indexes broken."); // FIXME: Eventually we want to actually delete these indexes. miEntry->setInstr(0); mi2iMap.erase(mi2iItr); } } /// ReplaceMachineInstrInMaps - Replacing a machine instr with a new one in /// maps used by register allocator. void replaceMachineInstrInMaps(MachineInstr *mi, MachineInstr *newMI) { Mi2IndexMap::iterator mi2iItr = mi2iMap.find(mi); if (mi2iItr == mi2iMap.end()) return; SlotIndex replaceBaseIndex = mi2iItr->second; IndexListEntry *miEntry(&replaceBaseIndex.entry()); assert(miEntry->getInstr() == mi && "Mismatched instruction in index tables."); miEntry->setInstr(newMI); mi2iMap.erase(mi2iItr); mi2iMap.insert(std::make_pair(newMI, replaceBaseIndex)); } /// Add the given MachineBasicBlock into the maps. void insertMBBInMaps(MachineBasicBlock *mbb) { MachineFunction::iterator nextMBB = llvm::next(MachineFunction::iterator(mbb)); IndexListEntry *startEntry = createEntry(0, 0); IndexListEntry *stopEntry = createEntry(0, 0); IndexListEntry *nextEntry = 0; if (nextMBB == mbb->getParent()->end()) { nextEntry = getTail(); } else { nextEntry = &getMBBStartIdx(nextMBB).entry(); } insert(nextEntry, startEntry); insert(nextEntry, stopEntry); SlotIndex startIdx(startEntry, SlotIndex::LOAD); SlotIndex endIdx(nextEntry, SlotIndex::LOAD); assert(unsigned(mbb->getNumber()) == MBBRanges.size() && "Blocks must be added in order"); MBBRanges.push_back(std::make_pair(startIdx, endIdx)); idx2MBBMap.push_back(IdxMBBPair(startIdx, mbb)); renumberIndexes(); std::sort(idx2MBBMap.begin(), idx2MBBMap.end(), Idx2MBBCompare()); } }; // Specialize IntervalMapInfo for half-open slot index intervals. template <typename> struct IntervalMapInfo; template <> struct IntervalMapInfo<SlotIndex> { static inline bool startLess(const SlotIndex &x, const SlotIndex &a) { return x < a; } static inline bool stopLess(const SlotIndex &b, const SlotIndex &x) { return b <= x; } static inline bool adjacent(const SlotIndex &a, const SlotIndex &b) { return a == b; } }; } #endif // LLVM_CODEGEN_LIVEINDEX_H