diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 664cc7a8c..745f00935 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -952,7 +952,7 @@ struct RTLILFrontendWorker { // meta_idx_ is a weak ref — drop ours so the pushed copy // in the vector is the sole holder. Process::~Process // walks the tree to actually release. - act.meta_idx_ = RTLIL::AttrObject::NO_META; + act.meta_ = nullptr; expect_eol(); } // The old parser allowed dangling attributes before a "sync" to carry through diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 3bfb135af..c15a54015 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -917,7 +917,7 @@ RTLIL::Const RTLIL::Const::extract(int offset, int len, RTLIL::State padding) co bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const { if (id == ID::src) - return meta_idx_ != RTLIL::AttrObject::NO_META; + return meta_ != nullptr && meta_->src != Twine::Null; return attributes.count(id); } @@ -933,7 +933,7 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const { if (id == ID::src) - return meta_idx_ != RTLIL::AttrObject::NO_META; + return meta_ != nullptr && meta_->src != Twine::Null; const auto it = attributes.find(id); if (it == attributes.end()) return false; @@ -964,14 +964,14 @@ string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const return value; } -void RTLIL::Design::obj_set_src_id_by_idx(uint32_t &meta_idx, Twine::Id id) +void RTLIL::Design::obj_set_src_id(RTLIL::AttrObject *obj, Twine::Id id) { - if (meta_idx == RTLIL::AttrObject::NO_META) { + if (obj->meta_ == nullptr) { if (id == Twine::Null) return; - meta_idx = alloc_obj_meta(); + obj->meta_ = alloc_obj_meta(); } - ObjMeta &m = obj_meta_[meta_idx]; + ObjMeta &m = *obj->meta_; if (m.src == id) return; if (m.src != Twine::Null) @@ -980,50 +980,50 @@ void RTLIL::Design::obj_set_src_id_by_idx(uint32_t &meta_idx, Twine::Id 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; + free_obj_meta(obj->meta_); + obj->meta_ = nullptr; } } -void RTLIL::Design::obj_release_src_by_idx(uint32_t &meta_idx) +void RTLIL::Design::obj_release_src(RTLIL::AttrObject *obj) { - if (meta_idx == RTLIL::AttrObject::NO_META) + if (obj->meta_ == nullptr) return; - ObjMeta &m = obj_meta_[meta_idx]; + ObjMeta &m = *obj->meta_; 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; + free_obj_meta(obj->meta_); + obj->meta_ = nullptr; } } -void RTLIL::Design::obj_set_name_by_idx(uint32_t &meta_idx, RTLIL::IdString name) +void RTLIL::Design::obj_set_name(RTLIL::AttrObject *obj, RTLIL::IdString name) { - if (meta_idx == RTLIL::AttrObject::NO_META) { + if (obj->meta_ == nullptr) { if (name.empty()) return; - meta_idx = alloc_obj_meta(); + obj->meta_ = alloc_obj_meta(); } - ObjMeta &m = obj_meta_[meta_idx]; + ObjMeta &m = *obj->meta_; m.name = name; if (m.name.empty() && m.src == Twine::Null) { - free_obj_meta(meta_idx); - meta_idx = RTLIL::AttrObject::NO_META; + free_obj_meta(obj->meta_); + obj->meta_ = nullptr; } } -void RTLIL::Design::obj_release_name_by_idx(uint32_t &meta_idx) +void RTLIL::Design::obj_release_name(RTLIL::AttrObject *obj) { - if (meta_idx == RTLIL::AttrObject::NO_META) + if (obj->meta_ == nullptr) return; - ObjMeta &m = obj_meta_[meta_idx]; + ObjMeta &m = *obj->meta_; m.name = RTLIL::IdString(); if (m.src == Twine::Null) { - free_obj_meta(meta_idx); - meta_idx = RTLIL::AttrObject::NO_META; + free_obj_meta(obj->meta_); + obj->meta_ = nullptr; } } @@ -1070,7 +1070,7 @@ void RTLIL::Design::adopt_src_from(RTLIL::AttrObject *obj, const RTLIL::AttrObject *source, const TwinePool *src_pool) { (void)src_pool; - if (!source || source->meta_idx_ == RTLIL::AttrObject::NO_META) { + if (!source || source->meta_ == nullptr) { obj_set_src_id(obj, Twine::Null); return; } @@ -1117,25 +1117,24 @@ namespace { } } -uint32_t RTLIL::Design::alloc_obj_meta() +RTLIL::ObjMeta *RTLIL::Design::alloc_obj_meta() { if (!obj_meta_free_.empty()) { - uint32_t idx = obj_meta_free_.back(); + ObjMeta *m = obj_meta_free_.back(); obj_meta_free_.pop_back(); - obj_meta_[idx] = ObjMeta{}; - return idx; + *m = ObjMeta{}; + return m; } - uint32_t idx = static_cast(obj_meta_.size()); - obj_meta_.emplace_back(); - return idx; + obj_meta_storage_.emplace_back(); + return &obj_meta_storage_.back(); } -void RTLIL::Design::free_obj_meta(uint32_t idx) +void RTLIL::Design::free_obj_meta(RTLIL::ObjMeta *m) { - 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); + log_assert(m != nullptr); + log_assert(m->src == Twine::Null); + log_assert(m->name.empty()); + obj_meta_free_.push_back(m); } void RTLIL::Design::merge_src(RTLIL::AttrObject *target, const RTLIL::AttrObject *source) @@ -1239,17 +1238,17 @@ size_t RTLIL::Design::gc_twines() // vector slots directly (bypassing retain/release, which the rebuilt // pool already accounts for). walk_attr_objects(this, [&](RTLIL::AttrObject *obj) { - if (obj->meta_idx_ == RTLIL::AttrObject::NO_META) + if (obj->meta_ == nullptr) return; - ObjMeta &m = obj_meta_[obj->meta_idx_]; + ObjMeta &m = *obj->meta_; if (m.src == Twine::Null) return; auto it = remap.find(m.src); if (it == remap.end()) { m.src = Twine::Null; if (m.name.empty()) { - free_obj_meta(obj->meta_idx_); - obj->meta_idx_ = RTLIL::AttrObject::NO_META; + free_obj_meta(obj->meta_); + obj->meta_ = nullptr; } return; } @@ -1708,19 +1707,7 @@ void RTLIL::Design::optimize() void RTLIL::Design::clone_into(RTLIL::Design *dst) const { log_assert(dst->modules_.empty()); - // Copy the twine pool and the per-object src meta vector wholesale. - // Any prior pool / meta state in dst (e.g. dead slots left over from - // a -reset / -pop preceding the clone) is discarded by the - // 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_ = 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 - // built — keeping write_rtlil output byte-stable across clone cycles. - // Use virtual clone(dst, verbatim) so AstModule preserves its subtype - // (and its ast pointer + frontend-config flags). for (auto it = modules_.rbegin(); it != modules_.rend(); ++it) it->second->clone(dst, /*src_id_verbatim=*/true); } @@ -1901,7 +1888,7 @@ void RTLIL::Module::set_src_id(Twine::Id id) void RTLIL::Module::set_src_attribute(const RTLIL::SrcAttr &src) { - if (src.empty() && meta_idx_ == NO_META) + if (src.empty() && meta_ == nullptr) return; log_assert(design && "Module::set_src_attribute requires the module to be attached to a design"); design->set_src_attribute(this, src); @@ -3134,12 +3121,15 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons for (auto &attr : attributes) new_mod->attributes[attr.first] = attr.second; if (src_id_verbatim) { - // Caller (Design::clone_into) copied src_twines AND the obj - // meta vector wholesale, so the same meta_idx_ resolves to - // the same Twine::Id in the destination pool — and the - // copied refcounts already pre-account for these new - // AttrObjects. Direct assignment, no retain. - new_mod->meta_idx_ = meta_idx_; + // Caller (Design::clone_into) copied src_twines wholesale, so + // Twine::Ids preserve their meaning. Allocate per-AttrObject + // meta in dst's pool and copy the fields. dst's twine refcounts + // were inherited via the wholesale copy and already account for + // these new AttrObjects, so no retain on src. + if (this->meta_ && new_mod->design) { + new_mod->meta_ = new_mod->design->alloc_obj_meta(); + *new_mod->meta_ = *this->meta_; + } } else { // Transfer src across designs. Both modules must be attached // to a design for the migration to happen; in the @@ -3151,12 +3141,14 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons } if (src_id_verbatim) { - // Build fresh wires/cells/memories/processes and transfer - // meta_idx_ verbatim. The non-verbatim branch goes through - // addWire/addCell/addProcess(name, other) which call - // copy_src_into to migrate src across designs; here both - // designs already share the same meta vector / pool, so we - // skip that and copy the index directly. + // Per-AttrObject meta clone via dst design's pool. Twine::Ids + // transfer verbatim because the src_twines copy is wholesale. + auto copy_meta = [&](const RTLIL::AttrObject *src, RTLIL::AttrObject *dst) { + if (src->meta_ && new_mod->design) { + dst->meta_ = new_mod->design->alloc_obj_meta(); + *dst->meta_ = *src->meta_; + } + }; for (auto it = wires_.rbegin(); it != wires_.rend(); ++it) { const RTLIL::Wire *o = it->second; RTLIL::Wire *w = new_mod->addWire(it->first, o->width); @@ -3167,7 +3159,7 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons w->upto = o->upto; w->is_signed = o->is_signed; w->attributes = o->attributes; - w->meta_idx_ = o->meta_idx_; + copy_meta(o, w); } for (auto it = memories.rbegin(); it != memories.rend(); ++it) { const RTLIL::Memory *o = it->second; @@ -3176,7 +3168,7 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons m->start_offset = o->start_offset; m->size = o->size; m->attributes = o->attributes; - m->meta_idx_ = o->meta_idx_; + copy_meta(o, m); } for (auto it = cells_.rbegin(); it != cells_.rend(); ++it) { const RTLIL::Cell *o = it->second; @@ -3184,28 +3176,25 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons c->connections_ = o->connections_; c->parameters = o->parameters; c->attributes = o->attributes; - c->meta_idx_ = o->meta_idx_; + copy_meta(o, c); } for (auto it = processes.rbegin(); it != processes.rend(); ++it) { const RTLIL::Process *o = it->second; RTLIL::Process *p = o->clone(); p->name = it->first; new_mod->add(p); - // Process::clone drops meta_idx_ across the inner tree - // (no module backpointer there before attach); now that - // p has a module we can copy them verbatim. - p->meta_idx_ = o->meta_idx_; + copy_meta(o, p); std::vector> case_stack; case_stack.emplace_back(&o->root_case, &p->root_case); while (!case_stack.empty()) { auto [s_cs, d_cs] = case_stack.back(); case_stack.pop_back(); - d_cs->meta_idx_ = s_cs->meta_idx_; + copy_meta(s_cs, d_cs); log_assert(s_cs->switches.size() == d_cs->switches.size()); for (size_t i = 0; i < s_cs->switches.size(); i++) { const auto *s_sw = s_cs->switches[i]; auto *d_sw = d_cs->switches[i]; - d_sw->meta_idx_ = s_sw->meta_idx_; + copy_meta(s_sw, d_sw); log_assert(s_sw->cases.size() == d_sw->cases.size()); for (size_t j = 0; j < s_sw->cases.size(); j++) case_stack.emplace_back(s_sw->cases[j], d_sw->cases[j]); @@ -3217,7 +3206,7 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod, bool src_id_verbatim) cons auto *d_sync = p->syncs[i]; log_assert(s_sync->mem_write_actions.size() == d_sync->mem_write_actions.size()); for (size_t j = 0; j < s_sync->mem_write_actions.size(); j++) - d_sync->mem_write_actions[j].meta_idx_ = s_sync->mem_write_actions[j].meta_idx_; + copy_meta(&s_sync->mem_write_actions[j], &d_sync->mem_write_actions[j]); } } } else { @@ -4798,7 +4787,7 @@ void RTLIL::Wire::set_src_id(Twine::Id id) void RTLIL::Wire::set_src_attribute(const RTLIL::SrcAttr &src) { - if (src.empty() && meta_idx_ == NO_META) + if (src.empty() && meta_ == nullptr) return; log_assert(module && module->design && "Wire::set_src_attribute requires the wire to be attached to a module in a design"); module->design->set_src_attribute(this, src); @@ -4911,7 +4900,7 @@ void RTLIL::Cell::set_src_id(Twine::Id id) void RTLIL::Cell::set_src_attribute(const RTLIL::SrcAttr &src) { - if (src.empty() && meta_idx_ == NO_META) + if (src.empty() && meta_ == nullptr) return; log_assert(module && module->design && "Cell::set_src_attribute requires the cell to be attached to a module in a design"); module->design->set_src_attribute(this, src); @@ -6600,7 +6589,7 @@ RTLIL::SyncRule *RTLIL::SyncRule::clone() const // any pool; the caller is responsible for migrating src across the // clone via context (see Process::clone). for (auto &mwa : new_syncrule->mem_write_actions) - mwa.meta_idx_ = RTLIL::AttrObject::NO_META; + mwa.meta_ = nullptr; return new_syncrule; } @@ -6655,7 +6644,7 @@ void RTLIL::Process::set_src_id(Twine::Id id) void RTLIL::Process::set_src_attribute(const RTLIL::SrcAttr &src) { - if (src.empty() && meta_idx_ == NO_META) + if (src.empty() && meta_ == nullptr) return; log_assert(module && module->design && "Process::set_src_attribute requires the process to be attached to a module in a design"); module->design->set_src_attribute(this, src); @@ -6724,7 +6713,7 @@ void RTLIL::Memory::set_src_id(Twine::Id id) void RTLIL::Memory::set_src_attribute(const RTLIL::SrcAttr &src) { - if (src.empty() && meta_idx_ == NO_META) + if (src.empty() && meta_ == nullptr) return; log_assert(module && module->design && "Memory::set_src_attribute requires the memory to be attached to a module in a design"); module->design->set_src_attribute(this, src); @@ -6764,7 +6753,7 @@ void RTLIL::CaseRule::set_src_id(Twine::Id id) } void RTLIL::CaseRule::set_src_attribute(const RTLIL::SrcAttr &src) { - if (src.empty() && meta_idx_ == NO_META) + if (src.empty() && meta_ == nullptr) return; log_assert(module && module->design && "CaseRule::set_src_attribute requires the case to belong to a module in a design"); module->design->set_src_attribute(this, src); @@ -6799,7 +6788,7 @@ void RTLIL::SwitchRule::set_src_id(Twine::Id id) } void RTLIL::SwitchRule::set_src_attribute(const RTLIL::SrcAttr &src) { - if (src.empty() && meta_idx_ == NO_META) + if (src.empty() && meta_ == nullptr) return; log_assert(module && module->design && "SwitchRule::set_src_attribute requires the switch to belong to a module in a design"); module->design->set_src_attribute(this, src); @@ -6834,7 +6823,7 @@ void RTLIL::MemWriteAction::set_src_id(Twine::Id id) } void RTLIL::MemWriteAction::set_src_attribute(const RTLIL::SrcAttr &src) { - if (src.empty() && meta_idx_ == NO_META) + if (src.empty() && meta_ == nullptr) return; log_assert(module && module->design && "MemWriteAction::set_src_attribute requires the action to belong to a module in a design"); module->design->set_src_attribute(this, src); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 338b7442a..ebb4959a4 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -24,6 +24,7 @@ #include "kernel/yosys.h" #include "kernel/twine.h" +#include #include #include @@ -127,6 +128,7 @@ namespace RTLIL struct StaticIdString; struct SigNormIndex; struct SrcAttr; + struct ObjMeta; typedef std::pair SigSig; struct PortBit; @@ -1291,25 +1293,20 @@ public: [[nodiscard]] Hasher hash_into(Hasher h) const; }; +struct RTLIL::ObjMeta +{ + Twine::Id src = Twine::Null; + RTLIL::IdString name; +}; + struct RTLIL::AttrObject { dict attributes; - // Per-Design metadata slot index, or NO_META. The slot lives in - // Design::obj_meta_src_ and holds this object's Twine::Id src; the - // slot is allocated lazily on the first non-null src write and - // freed when src returns to null. Per-object cost is just this - // 4-byte index (replacing the prior inline 4-byte src_id_). - // - // AttrObject can't resolve its owning Design on its own. Lookups - // route either through a leaf subtype's src_id() sugar (which knows - // its container chain — Cell/Wire/Process/Memory via module->design, - // Module via design, CaseRule/SwitchRule/MemWriteAction via the - // module back-pointer added in prior commits) or through the - // Design::obj_src_id / obj_set_src_id / obj_release_src helpers - // when generic AttrObject* code already has a Design* in hand. - static constexpr uint32_t NO_META = ~0u; - uint32_t meta_idx_ = NO_META; + // Pointer to a per-object metadata record in some pool (typically + // the owning Design's). Nullable: cleared until first non-null write + // of any field (src or name) and reset to null when all fields empty. + RTLIL::ObjMeta *meta_ = nullptr; bool has_attribute(RTLIL::IdString id) const; @@ -1953,57 +1950,25 @@ struct RTLIL::Design // via cell->module->design->src_twines. TwinePool src_twines; - // 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 obj_meta_; - std::vector obj_meta_free_; + // Per-Design ObjMeta pool: stable storage (deque) + LIFO freelist of + // returned slots. AttrObject::meta_ points into obj_meta_storage_. + std::deque obj_meta_storage_; + std::vector obj_meta_free_; - uint32_t alloc_obj_meta(); - void free_obj_meta(uint32_t idx); - - 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_[meta_idx].src; - } - - // `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); - void obj_release_src_by_idx(uint32_t &meta_idx); - - 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); + RTLIL::ObjMeta *alloc_obj_meta(); + void free_obj_meta(RTLIL::ObjMeta *m); Twine::Id obj_src_id(const RTLIL::AttrObject *obj) const { - return obj_src_id_by_idx(obj->meta_idx_); - } - void obj_set_src_id(RTLIL::AttrObject *obj, Twine::Id id) { - obj_set_src_id_by_idx(obj->meta_idx_, id); - } - void obj_release_src(RTLIL::AttrObject *obj) { - obj_release_src_by_idx(obj->meta_idx_); + return (obj->meta_ ? obj->meta_->src : Twine::Null); } + void obj_set_src_id(RTLIL::AttrObject *obj, Twine::Id id); + void obj_release_src(RTLIL::AttrObject *obj); + 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_); + return (obj->meta_ ? obj->meta_->name : RTLIL::IdString()); } + void obj_set_name(RTLIL::AttrObject *obj, RTLIL::IdString name); + void obj_release_name(RTLIL::AttrObject *obj); // Replacements for the methods that used to live on AttrObject and // took an explicit TwinePool*. Same semantics; the pool resolves diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 7eae5065d..375469bbb 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -147,7 +147,7 @@ static bool match_attr(const dict &attributes, co // uses were rare and the dict-path migration is a separate concern. static bool match_attr(const RTLIL::Design *design, const RTLIL::AttrObject *obj, const std::string &match_expr) { - if (design && obj->meta_idx_ != RTLIL::AttrObject::NO_META) { + if (design && obj->meta_ != nullptr) { size_t pos = match_expr.find_first_of(""); std::string name_part = (pos == std::string::npos) ? match_expr : match_expr.substr(0, pos); if (name_part == "src" || name_part == "\\src") {