diff --git a/kernel/twine.h b/kernel/twine.h index 4a217efd8..9cac7d6ad 100644 --- a/kernel/twine.h +++ b/kernel/twine.h @@ -7,6 +7,7 @@ #include #include "libs/plf_colony/plf_colony.h" +#include #include #include #include @@ -165,6 +166,8 @@ struct TwinePool { static std::vector globals_; plf::colony backing; std::unordered_set index; + // Indices of monostate, kept sorted + std::vector free_list; const Twine& operator[] (TwineRef ref) const { ref = twine_untag(ref); @@ -267,8 +270,15 @@ struct TwinePool { void rebuild_index() { for (TwineRef ref = 0; ref < STATIC_TWINE_END; ref++) index.insert(ref); - for (auto it = backing.begin(); it != backing.end(); ++it) - index.insert(STATIC_TWINE_END + backing.get_index(it)); + free_list.clear(); + for (auto it = backing.begin(); it != backing.end(); ++it) { + size_t idx = backing.get_index(it); + if (it->is_dead()) + free_list.push_back(idx); + else + index.insert(STATIC_TWINE_END + idx); + } + std::sort(free_list.begin(), free_list.end(), std::greater()); } TwineRef find(Twine t) const { @@ -303,8 +313,16 @@ struct TwinePool { return *it; } - auto colony_it = backing.insert(std::move(t)); - TwineRef ref = STATIC_TWINE_END + backing.get_index(colony_it); + TwineRef ref; + if (!free_list.empty()) { + size_t idx = free_list.back(); + free_list.pop_back(); + backing[idx] = std::move(t); + ref = STATIC_TWINE_END + idx; + } else { + auto colony_it = backing.insert(std::move(t)); + ref = STATIC_TWINE_END + backing.get_index(colony_it); + } index.insert(ref); if (yosys_xtrace) { std::cout << "#X# add_inner added "; @@ -342,7 +360,7 @@ struct TwinePool { } } - size_t size() const { return backing.size(); } + size_t size() const { return backing.size() - free_list.size(); } TwineRef concat(std::span ids) { if (ids.size() == 1) @@ -387,16 +405,19 @@ struct TwinePool { for (TwineRef ref : roots) mark_live(ref, live); size_t erased = 0; - for (auto it = backing.begin(); it != backing.end();) { - TwineRef ref = STATIC_TWINE_END + backing.get_index(it); - if (live.count(ref)) { - ++it; - } else { - index.erase(ref); - it = backing.erase(it); + for (auto it = backing.begin(); it != backing.end(); ++it) { + if (it->is_dead()) + continue; + size_t idx = backing.get_index(it); + if (!live.count(STATIC_TWINE_END + idx)) { + index.erase(STATIC_TWINE_END + idx); + free_list.push_back(idx); + *it = Twine{}; erased++; } } + // TODO something like YOSYS_SORT_ID_FREE_LIST to make it optional? + std::sort(free_list.begin(), free_list.end(), std::greater()); return erased; }