3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-11-03 13:07:58 +00:00

Make IdString refcounts a hashtable containing only the nonzero refcounts

This saves space and doesn't cost very much since we hardly ever have nonzero refcounts any more.

It also allows for IdStrings with negative indexes, which we're going to add.
This commit is contained in:
Robert O'Callahan 2025-10-13 00:12:51 +00:00
parent bc7895505e
commit 3c2caffffe
2 changed files with 33 additions and 21 deletions

View file

@ -38,7 +38,7 @@ RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
std::vector<RTLIL::IdString::Storage> RTLIL::IdString::global_id_storage_;
std::unordered_map<std::string_view, int> RTLIL::IdString::global_id_index_;
#ifndef YOSYS_NO_IDS_REFCNT
std::vector<uint32_t> RTLIL::IdString::global_refcount_storage_;
std::unordered_map<int, int> RTLIL::IdString::global_refcount_storage_;
std::vector<int> RTLIL::IdString::global_free_idx_list_;
#endif
@ -61,7 +61,6 @@ void RTLIL::IdString::prepopulate()
int size = static_cast<short>(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<char*>(""), 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<int>(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);

View file

@ -158,16 +158,18 @@ struct RTLIL::IdString
static std::vector<Storage> global_id_storage_;
static std::unordered_map<std::string_view, int> 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<uint32_t> global_refcount_storage_;
// All (index, refcount) pairs in this map have refcount > 0.
static std::unordered_map<int, int> global_refcount_storage_;
static std::vector<int> 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
@ -176,7 +178,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
}
@ -196,7 +198,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;
}
@ -213,7 +215,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();
@ -235,7 +236,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;
@ -442,11 +443,17 @@ private:
static void get_reference(int idx)
{
#ifndef YOSYS_NO_IDS_REFCNT
global_refcount_storage_[idx]++;
if (idx < static_cast<short>(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<short>(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
}
@ -458,11 +465,14 @@ private:
if (index_ < static_cast<short>(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
}
};