From 64362272b6bcbc6ea72784d08fa86045877a3c15 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 19 Apr 2013 04:31:49 +0000 Subject: [PATCH] Add support for index resources (for a SlotIndex) to be relinquished. When the SlotIndexes pass was introduced it was intended to support insertion of code during register allocation. Removal of code was a minor consideration (and raised the question of what to do about dangling SlotIndex objects pointing to the erased index), so I opted to keep all indexes around indefinitely and simply null out those that weren't being used. Nowadays people are moving more code around (e.g. via HandleMove), which means more zombie indexes. I want to start killing off indexes when we're done with them to reclaim the resources they use up. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@179834 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/SlotIndexes.h | 49 +++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/include/llvm/CodeGen/SlotIndexes.h b/include/llvm/CodeGen/SlotIndexes.h index a2770804668..26d0433f3e8 100644 --- a/include/llvm/CodeGen/SlotIndexes.h +++ b/include/llvm/CodeGen/SlotIndexes.h @@ -53,6 +53,20 @@ namespace llvm { this->index = index; } +#ifdef EXPENSIVE_CHECKS + // When EXPENSIVE_CHECKS is defined, "erased" index list entries will + // actually be moved to a "graveyard" list, and have their pointers + // poisoned, so that dangling SlotIndex access can be reliably detected. + void setPoison() { + intptr_t tmp = reinterpret_cast(mi); + assert(((tmp & 0x1) == 0x0) && "Pointer already poisoned?"); + tmp |= 0x1; + mi = reinterpret_cast(tmp); + } + + bool isPoisoned() const { return (reinterpret_cast(mi) & 0x1) == 0x1; } +#endif // EXPENSIVE_CHECKS + }; template <> @@ -109,6 +123,10 @@ namespace llvm { IndexListEntry* listEntry() const { assert(isValid() && "Attempt to compare reserved index."); +#ifdef EXPENSIVE_CHECKS + assert(!lie.getPointer()->isPoisoned() && + "Attempt to access deleted list-entry."); +#endif // EXPENSIVE_CHECKS return lie.getPointer(); } @@ -282,7 +300,6 @@ namespace llvm { template <> struct isPodLike { static const bool value = true; }; - inline raw_ostream& operator<<(raw_ostream &os, SlotIndex li) { li.print(os); return os; @@ -313,6 +330,10 @@ namespace llvm { typedef ilist IndexList; IndexList indexList; +#ifdef EXPENSIVE_CHECKS + IndexList graveyardList; +#endif // EXPENSIVE_CHECKS + MachineFunction *mf; typedef DenseMap Mi2IndexMap; @@ -643,6 +664,32 @@ namespace llvm { std::sort(idx2MBBMap.begin(), idx2MBBMap.end(), Idx2MBBCompare()); } + /// \brief Free the resources that were required to maintain a SlotIndex. + /// + /// Once an index is no longer needed (for instance because the instruction + /// at that index has been moved), the resources required to maintain the + /// index can be relinquished to reduce memory use and improve renumbering + /// performance. Any remaining SlotIndex objects that point to the same + /// index are left 'dangling' (much the same as a dangling pointer to a + /// freed object) and should not be accessed, except to destruct them. + /// + /// Like dangling pointers, access to dangling SlotIndexes can cause + /// painful-to-track-down bugs, especially if the memory for the index + /// previously pointed to has been re-used. To detect dangling SlotIndex + /// bugs, build with EXPENSIVE_CHECKS=1. This will cause "erased" indexes to + /// be retained in a graveyard instead of being freed. Operations on indexes + /// in the graveyard will trigger an assertion. + void eraseIndex(SlotIndex index) { + IndexListEntry *entry = index.listEntry(); +#ifdef EXPENSIVE_CHECKS + indexList.remove(entry); + graveyardList.push_back(entry); + entry->setPoison(); +#else + indexList.erase(entry); +#endif + } + }; -- 2.34.1