diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 0e974b141..466ed0a74 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -38,7 +38,7 @@ RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard; std::vector RTLIL::IdString::global_id_storage_; std::unordered_map RTLIL::IdString::global_id_index_; #ifndef YOSYS_NO_IDS_REFCNT -std::vector RTLIL::IdString::global_refcount_storage_; +std::unordered_map RTLIL::IdString::global_refcount_storage_; std::vector RTLIL::IdString::global_free_idx_list_; #endif @@ -61,7 +61,6 @@ void RTLIL::IdString::prepopulate() int size = static_cast(RTLIL::StaticId::STATIC_ID_END); global_id_storage_.reserve(size); global_id_index_.reserve(size); - global_refcount_storage_.resize(size, 1); RTLIL::IdString::global_id_index_.insert({"", 0}); RTLIL::IdString::global_id_storage_.push_back({const_cast(""), 0}); #define X(N) populate("\\" #N); @@ -180,17 +179,20 @@ struct IdStringCollector { void RTLIL::OwningIdString::collect_garbage() { #ifndef YOSYS_NO_IDS_REFCNT - int size = GetSize(global_refcount_storage_); + int size = GetSize(global_id_storage_); IdStringCollector collector(size); for (auto &[idx, design] : *RTLIL::Design::get_all_designs()) { collector.trace(*design); } for (int i = static_cast(StaticId::STATIC_ID_END); i < size; ++i) { - if (collector.live[i] || global_refcount_storage_[i] > 0) + if (collector.live[i]) continue; RTLIL::IdString::Storage &storage = global_id_storage_.at(i); if (storage.buf == nullptr) continue; + if (global_refcount_storage_.find(i) != global_refcount_storage_.end()) + continue; + if (yosys_xtrace) { log("#X# Removed IdString '%s' with index %d.\n", storage.buf, i); log_backtrace("-X- ", yosys_xtrace-1); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 9d3919162..a081762c9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -159,16 +159,18 @@ struct RTLIL::IdString static std::vector global_id_storage_; static std::unordered_map global_id_index_; #ifndef YOSYS_NO_IDS_REFCNT - // For prepopulated IdStrings, the refcount is meaningless since they - // are never freed even if the refcount is zero. For code efficiency - // we increment the refcount of prepopulated IdStrings like any other string, - // but we never decrement the refcount or check whether it's zero. - // So, make this unsigned because refcounts of preopulated IdStrings may overflow - // and overflow of signed integers is undefined behavior. - static std::vector global_refcount_storage_; + // All (index, refcount) pairs in this map have refcount > 0. + static std::unordered_map global_refcount_storage_; static std::vector global_free_idx_list_; #endif + static int refcount(int idx) { + auto it = global_refcount_storage_.find(idx); + if (it == global_refcount_storage_.end()) + return 0; + return it->second; + } + static inline void xtrace_db_dump() { #ifdef YOSYS_XTRACE_GET_PUT @@ -177,7 +179,7 @@ struct RTLIL::IdString if (global_id_storage_.at(idx).buf == nullptr) log("#X# DB-DUMP index %d: FREE\n", idx); else - log("#X# DB-DUMP index %d: '%s' (ref %u)\n", idx, global_id_storage_.at(idx).buf, global_refcount_storage_.at(idx)); + log("#X# DB-DUMP index %d: '%s' (ref %u)\n", idx, refcount(idx).buf, refcount); } #endif } @@ -197,7 +199,7 @@ struct RTLIL::IdString if (it != global_id_index_.end()) { #ifdef YOSYS_XTRACE_GET_PUT if (yosys_xtrace) - log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(it->second).buf, it->second, global_refcount_storage_.at(it->second)); + log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(it->second).buf, it->second, refcount(it->second)); #endif return it->second; } @@ -214,7 +216,6 @@ struct RTLIL::IdString log_assert(global_id_storage_.size() < 0x40000000); global_free_idx_list_.push_back(global_id_storage_.size()); global_id_storage_.push_back({nullptr, 0}); - global_refcount_storage_.push_back(0); } int idx = global_free_idx_list_.back(); @@ -236,7 +237,7 @@ struct RTLIL::IdString #ifdef YOSYS_XTRACE_GET_PUT if (yosys_xtrace) - log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx).buf, idx, global_refcount_storage_.at(idx)); + log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx).buf, idx, refcount(idx)); #endif return idx; @@ -443,11 +444,17 @@ private: static void get_reference(int idx) { #ifndef YOSYS_NO_IDS_REFCNT - global_refcount_storage_[idx]++; + if (idx < static_cast(StaticId::STATIC_ID_END)) + return; + auto it = global_refcount_storage_.find(idx); + if (it == global_refcount_storage_.end()) + global_refcount_storage_.insert(it, {idx, 1}); + else + ++it->second; #endif #ifdef YOSYS_XTRACE_GET_PUT if (yosys_xtrace && idx >= static_cast(StaticId::STATIC_ID_END)) - log("#X# GET-BY-INDEX '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + log("#X# GET-BY-INDEX '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx), idx, refcount(idx)); #endif } @@ -459,11 +466,14 @@ private: if (index_ < static_cast(StaticId::STATIC_ID_END) || !destruct_guard_ok) return; #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) { - log("#X# PUT '%s' (index %d, refcount %u)\n", global_id_storage_.at(index_), index_, global_refcount_storage_.at(index_)); - } + if (yosys_xtrace) + log("#X# PUT '%s' (index %d, refcount %u)\n", global_id_storage_.at(index_), index_, refcount(index_)); #endif - --global_refcount_storage_[index_]; + auto it = global_refcount_storage_.find(index_); + log_assert(it != global_refcount_storage_.end() && it->second >= 1); + if (--it->second == 0) { + global_refcount_storage_.erase(it); + } #endif } };