rtlil: extend per-Design meta vector to hold name slot

This commit is contained in:
Emil J. Tywoniak 2026-06-05 16:18:43 +02:00
parent ca632e82c4
commit 0f31d3089e
2 changed files with 88 additions and 52 deletions

View File

@ -971,16 +971,15 @@ void RTLIL::Design::obj_set_src_id_by_idx(uint32_t &meta_idx, Twine::Id id)
return;
meta_idx = alloc_obj_meta();
}
Twine::Id &slot = obj_meta_src_[meta_idx];
if (slot == id)
ObjMeta &m = obj_meta_[meta_idx];
if (m.src == id)
return;
if (slot != Twine::Null)
src_twines.release(slot);
slot = id;
if (slot != Twine::Null)
src_twines.retain(slot);
if (slot == Twine::Null) {
// Cleared — return the slot to the freelist.
if (m.src != Twine::Null)
src_twines.release(m.src);
m.src = id;
if (m.src != Twine::Null)
src_twines.retain(m.src);
if (m.src == Twine::Null && m.name.empty()) {
free_obj_meta(meta_idx);
meta_idx = RTLIL::AttrObject::NO_META;
}
@ -990,13 +989,42 @@ void RTLIL::Design::obj_release_src_by_idx(uint32_t &meta_idx)
{
if (meta_idx == RTLIL::AttrObject::NO_META)
return;
Twine::Id &slot = obj_meta_src_[meta_idx];
if (slot != Twine::Null) {
src_twines.release(slot);
slot = Twine::Null;
ObjMeta &m = obj_meta_[meta_idx];
if (m.src != Twine::Null) {
src_twines.release(m.src);
m.src = Twine::Null;
}
if (m.name.empty()) {
free_obj_meta(meta_idx);
meta_idx = RTLIL::AttrObject::NO_META;
}
}
void RTLIL::Design::obj_set_name_by_idx(uint32_t &meta_idx, RTLIL::IdString name)
{
if (meta_idx == RTLIL::AttrObject::NO_META) {
if (name.empty())
return;
meta_idx = alloc_obj_meta();
}
ObjMeta &m = obj_meta_[meta_idx];
m.name = name;
if (m.name.empty() && m.src == Twine::Null) {
free_obj_meta(meta_idx);
meta_idx = RTLIL::AttrObject::NO_META;
}
}
void RTLIL::Design::obj_release_name_by_idx(uint32_t &meta_idx)
{
if (meta_idx == RTLIL::AttrObject::NO_META)
return;
ObjMeta &m = obj_meta_[meta_idx];
m.name = RTLIL::IdString();
if (m.src == Twine::Null) {
free_obj_meta(meta_idx);
meta_idx = RTLIL::AttrObject::NO_META;
}
free_obj_meta(meta_idx);
meta_idx = RTLIL::AttrObject::NO_META;
}
void RTLIL::Design::set_src_attribute(RTLIL::AttrObject *obj, const RTLIL::SrcAttr &src)
@ -1094,18 +1122,19 @@ uint32_t RTLIL::Design::alloc_obj_meta()
if (!obj_meta_free_.empty()) {
uint32_t idx = obj_meta_free_.back();
obj_meta_free_.pop_back();
obj_meta_src_[idx] = Twine::Null;
obj_meta_[idx] = ObjMeta{};
return idx;
}
uint32_t idx = static_cast<uint32_t>(obj_meta_src_.size());
obj_meta_src_.push_back(Twine::Null);
uint32_t idx = static_cast<uint32_t>(obj_meta_.size());
obj_meta_.emplace_back();
return idx;
}
void RTLIL::Design::free_obj_meta(uint32_t idx)
{
log_assert(idx < obj_meta_src_.size());
log_assert(obj_meta_src_[idx] == Twine::Null);
log_assert(idx < obj_meta_.size());
log_assert(obj_meta_[idx].src == Twine::Null);
log_assert(obj_meta_[idx].name.empty());
obj_meta_free_.push_back(idx);
}
@ -1212,18 +1241,19 @@ size_t RTLIL::Design::gc_twines()
walk_attr_objects(this, [&](RTLIL::AttrObject *obj) {
if (obj->meta_idx_ == RTLIL::AttrObject::NO_META)
return;
Twine::Id &slot = obj_meta_src_[obj->meta_idx_];
if (slot == Twine::Null)
ObjMeta &m = obj_meta_[obj->meta_idx_];
if (m.src == Twine::Null)
return;
auto it = remap.find(slot);
auto it = remap.find(m.src);
if (it == remap.end()) {
// Wasn't in live set (design corruption) — zero out.
slot = Twine::Null;
free_obj_meta(obj->meta_idx_);
obj->meta_idx_ = RTLIL::AttrObject::NO_META;
m.src = Twine::Null;
if (m.name.empty()) {
free_obj_meta(obj->meta_idx_);
obj->meta_idx_ = RTLIL::AttrObject::NO_META;
}
return;
}
slot = it->second;
m.src = it->second;
});
return before - src_twines.size();
@ -1684,7 +1714,7 @@ void RTLIL::Design::clone_into(RTLIL::Design *dst) const
// assignment. The copied refcounts and the same meta_idx_ values
// assigned below 1:1 to cloned AttrObjects line up by construction.
dst->src_twines = src_twines;
dst->obj_meta_src_ = obj_meta_src_;
dst->obj_meta_ = obj_meta_;
dst->obj_meta_free_ = obj_meta_free_;
// Iterate via rbegin/rend so cloned modules land in dst in forward
// insertion order — same as how the source design's modules dict was

View File

@ -1953,42 +1953,39 @@ struct RTLIL::Design
// via cell->module->design->src_twines.
TwinePool src_twines;
// Per-object src metadata, indexed by AttrObject::meta_idx_. Holds the
// Twine::Id for an object's src — the future home of any other per-
// object cold metadata we want to evacuate from inline storage (e.g.
// name once IdString/Twine unify). Freed slots are recycled via
// obj_meta_free_ (LIFO), mirroring TwinePool's freelist.
//
// alloc_obj_meta returns a fresh index whose entry is Twine::Null;
// free_obj_meta requires the slot's src_id to already have been
// released via src_twines.release() — the freelist only handles
// the index itself, not the referenced pool slot.
std::vector<Twine::Id> obj_meta_src_;
// Per-object metadata indexed by AttrObject::meta_idx_. Slots are
// allocated lazily on first non-null write and recycled via the
// LIFO freelist obj_meta_free_. Both src and name share one slot
// so subtypes that carry either pay only one index field.
struct ObjMeta {
Twine::Id src = Twine::Null;
RTLIL::IdString name;
};
std::vector<ObjMeta> obj_meta_;
std::vector<uint32_t> obj_meta_free_;
uint32_t alloc_obj_meta();
void free_obj_meta(uint32_t idx);
// Read src for `meta_idx`. NO_META → Twine::Null.
Twine::Id obj_src_id_by_idx(uint32_t meta_idx) const {
if (meta_idx == RTLIL::AttrObject::NO_META)
return Twine::Null;
return obj_meta_src_[meta_idx];
return obj_meta_[meta_idx].src;
}
// Set src for `meta_idx`, allocating a slot lazily and freeing it
// when `id` is Twine::Null. Manages retain/release on src_twines.
// `meta_idx` is mutated as needed (NO_META -> allocated slot, or
// allocated slot -> NO_META after clearing).
// `meta_idx` is mutated as needed: NO_META -> allocated slot on first
// non-null write; allocated slot -> NO_META if src cleared and name empty.
void obj_set_src_id_by_idx(uint32_t &meta_idx, Twine::Id id);
// Release the slot's Twine ref and free the index. No-op if NO_META.
// Use from destructors. `meta_idx` becomes NO_META on return.
void obj_release_src_by_idx(uint32_t &meta_idx);
// AttrObject-keyed convenience overloads — dispatch to the _by_idx
// versions on obj->meta_idx_. Use these from generic helpers that
// already have a Design* in scope.
RTLIL::IdString obj_name_by_idx(uint32_t meta_idx) const {
if (meta_idx == RTLIL::AttrObject::NO_META)
return RTLIL::IdString();
return obj_meta_[meta_idx].name;
}
void obj_set_name_by_idx(uint32_t &meta_idx, RTLIL::IdString name);
void obj_release_name_by_idx(uint32_t &meta_idx);
Twine::Id obj_src_id(const RTLIL::AttrObject *obj) const {
return obj_src_id_by_idx(obj->meta_idx_);
}
@ -1998,6 +1995,15 @@ struct RTLIL::Design
void obj_release_src(RTLIL::AttrObject *obj) {
obj_release_src_by_idx(obj->meta_idx_);
}
RTLIL::IdString obj_name(const RTLIL::AttrObject *obj) const {
return obj_name_by_idx(obj->meta_idx_);
}
void obj_set_name(RTLIL::AttrObject *obj, RTLIL::IdString name) {
obj_set_name_by_idx(obj->meta_idx_, name);
}
void obj_release_name(RTLIL::AttrObject *obj) {
obj_release_name_by_idx(obj->meta_idx_);
}
// Replacements for the methods that used to live on AttrObject and
// took an explicit TwinePool*. Same semantics; the pool resolves