rtlil: replace AttrObject::meta_idx_ with ObjMeta pointer

This commit is contained in:
Emil J. Tywoniak 2026-06-05 18:50:58 +02:00
parent cfd7edc608
commit 8f8a07efee
4 changed files with 100 additions and 146 deletions

View File

@ -952,7 +952,7 @@ struct RTLILFrontendWorker {
// meta_idx_ is a weak ref — drop ours so the pushed copy // meta_idx_ is a weak ref — drop ours so the pushed copy
// in the vector is the sole holder. Process::~Process // in the vector is the sole holder. Process::~Process
// walks the tree to actually release. // walks the tree to actually release.
act.meta_idx_ = RTLIL::AttrObject::NO_META; act.meta_ = nullptr;
expect_eol(); expect_eol();
} }
// The old parser allowed dangling attributes before a "sync" to carry through // The old parser allowed dangling attributes before a "sync" to carry through

View File

@ -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 bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const
{ {
if (id == ID::src) if (id == ID::src)
return meta_idx_ != RTLIL::AttrObject::NO_META; return meta_ != nullptr && meta_->src != Twine::Null;
return attributes.count(id); 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 bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
{ {
if (id == ID::src) if (id == ID::src)
return meta_idx_ != RTLIL::AttrObject::NO_META; return meta_ != nullptr && meta_->src != Twine::Null;
const auto it = attributes.find(id); const auto it = attributes.find(id);
if (it == attributes.end()) if (it == attributes.end())
return false; return false;
@ -964,14 +964,14 @@ string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const
return value; 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) if (id == Twine::Null)
return; 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) if (m.src == id)
return; return;
if (m.src != Twine::Null) 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) if (m.src != Twine::Null)
src_twines.retain(m.src); src_twines.retain(m.src);
if (m.src == Twine::Null && m.name.empty()) { if (m.src == Twine::Null && m.name.empty()) {
free_obj_meta(meta_idx); free_obj_meta(obj->meta_);
meta_idx = RTLIL::AttrObject::NO_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; return;
ObjMeta &m = obj_meta_[meta_idx]; ObjMeta &m = *obj->meta_;
if (m.src != Twine::Null) { if (m.src != Twine::Null) {
src_twines.release(m.src); src_twines.release(m.src);
m.src = Twine::Null; m.src = Twine::Null;
} }
if (m.name.empty()) { if (m.name.empty()) {
free_obj_meta(meta_idx); free_obj_meta(obj->meta_);
meta_idx = RTLIL::AttrObject::NO_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()) if (name.empty())
return; return;
meta_idx = alloc_obj_meta(); obj->meta_ = alloc_obj_meta();
} }
ObjMeta &m = obj_meta_[meta_idx]; ObjMeta &m = *obj->meta_;
m.name = name; m.name = name;
if (m.name.empty() && m.src == Twine::Null) { if (m.name.empty() && m.src == Twine::Null) {
free_obj_meta(meta_idx); free_obj_meta(obj->meta_);
meta_idx = RTLIL::AttrObject::NO_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; return;
ObjMeta &m = obj_meta_[meta_idx]; ObjMeta &m = *obj->meta_;
m.name = RTLIL::IdString(); m.name = RTLIL::IdString();
if (m.src == Twine::Null) { if (m.src == Twine::Null) {
free_obj_meta(meta_idx); free_obj_meta(obj->meta_);
meta_idx = RTLIL::AttrObject::NO_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) const RTLIL::AttrObject *source, const TwinePool *src_pool)
{ {
(void)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); obj_set_src_id(obj, Twine::Null);
return; 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()) { 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_free_.pop_back();
obj_meta_[idx] = ObjMeta{}; *m = ObjMeta{};
return idx; return m;
} }
uint32_t idx = static_cast<uint32_t>(obj_meta_.size()); obj_meta_storage_.emplace_back();
obj_meta_.emplace_back(); return &obj_meta_storage_.back();
return idx;
} }
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(m != nullptr);
log_assert(obj_meta_[idx].src == Twine::Null); log_assert(m->src == Twine::Null);
log_assert(obj_meta_[idx].name.empty()); log_assert(m->name.empty());
obj_meta_free_.push_back(idx); obj_meta_free_.push_back(m);
} }
void RTLIL::Design::merge_src(RTLIL::AttrObject *target, const RTLIL::AttrObject *source) 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 // vector slots directly (bypassing retain/release, which the rebuilt
// pool already accounts for). // pool already accounts for).
walk_attr_objects(this, [&](RTLIL::AttrObject *obj) { walk_attr_objects(this, [&](RTLIL::AttrObject *obj) {
if (obj->meta_idx_ == RTLIL::AttrObject::NO_META) if (obj->meta_ == nullptr)
return; return;
ObjMeta &m = obj_meta_[obj->meta_idx_]; ObjMeta &m = *obj->meta_;
if (m.src == Twine::Null) if (m.src == Twine::Null)
return; return;
auto it = remap.find(m.src); auto it = remap.find(m.src);
if (it == remap.end()) { if (it == remap.end()) {
m.src = Twine::Null; m.src = Twine::Null;
if (m.name.empty()) { if (m.name.empty()) {
free_obj_meta(obj->meta_idx_); free_obj_meta(obj->meta_);
obj->meta_idx_ = RTLIL::AttrObject::NO_META; obj->meta_ = nullptr;
} }
return; return;
} }
@ -1708,19 +1707,7 @@ void RTLIL::Design::optimize()
void RTLIL::Design::clone_into(RTLIL::Design *dst) const void RTLIL::Design::clone_into(RTLIL::Design *dst) const
{ {
log_assert(dst->modules_.empty()); 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->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) for (auto it = modules_.rbegin(); it != modules_.rend(); ++it)
it->second->clone(dst, /*src_id_verbatim=*/true); 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) void RTLIL::Module::set_src_attribute(const RTLIL::SrcAttr &src)
{ {
if (src.empty() && meta_idx_ == NO_META) if (src.empty() && meta_ == nullptr)
return; return;
log_assert(design && "Module::set_src_attribute requires the module to be attached to a design"); log_assert(design && "Module::set_src_attribute requires the module to be attached to a design");
design->set_src_attribute(this, src); 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) for (auto &attr : attributes)
new_mod->attributes[attr.first] = attr.second; new_mod->attributes[attr.first] = attr.second;
if (src_id_verbatim) { if (src_id_verbatim) {
// Caller (Design::clone_into) copied src_twines AND the obj // Caller (Design::clone_into) copied src_twines wholesale, so
// meta vector wholesale, so the same meta_idx_ resolves to // Twine::Ids preserve their meaning. Allocate per-AttrObject
// the same Twine::Id in the destination pool — and the // meta in dst's pool and copy the fields. dst's twine refcounts
// copied refcounts already pre-account for these new // were inherited via the wholesale copy and already account for
// AttrObjects. Direct assignment, no retain. // these new AttrObjects, so no retain on src.
new_mod->meta_idx_ = meta_idx_; if (this->meta_ && new_mod->design) {
new_mod->meta_ = new_mod->design->alloc_obj_meta();
*new_mod->meta_ = *this->meta_;
}
} else { } else {
// Transfer src across designs. Both modules must be attached // Transfer src across designs. Both modules must be attached
// to a design for the migration to happen; in the // 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) { if (src_id_verbatim) {
// Build fresh wires/cells/memories/processes and transfer // Per-AttrObject meta clone via dst design's pool. Twine::Ids
// meta_idx_ verbatim. The non-verbatim branch goes through // transfer verbatim because the src_twines copy is wholesale.
// addWire/addCell/addProcess(name, other) which call auto copy_meta = [&](const RTLIL::AttrObject *src, RTLIL::AttrObject *dst) {
// copy_src_into to migrate src across designs; here both if (src->meta_ && new_mod->design) {
// designs already share the same meta vector / pool, so we dst->meta_ = new_mod->design->alloc_obj_meta();
// skip that and copy the index directly. *dst->meta_ = *src->meta_;
}
};
for (auto it = wires_.rbegin(); it != wires_.rend(); ++it) { for (auto it = wires_.rbegin(); it != wires_.rend(); ++it) {
const RTLIL::Wire *o = it->second; const RTLIL::Wire *o = it->second;
RTLIL::Wire *w = new_mod->addWire(it->first, o->width); 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->upto = o->upto;
w->is_signed = o->is_signed; w->is_signed = o->is_signed;
w->attributes = o->attributes; w->attributes = o->attributes;
w->meta_idx_ = o->meta_idx_; copy_meta(o, w);
} }
for (auto it = memories.rbegin(); it != memories.rend(); ++it) { for (auto it = memories.rbegin(); it != memories.rend(); ++it) {
const RTLIL::Memory *o = it->second; 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->start_offset = o->start_offset;
m->size = o->size; m->size = o->size;
m->attributes = o->attributes; m->attributes = o->attributes;
m->meta_idx_ = o->meta_idx_; copy_meta(o, m);
} }
for (auto it = cells_.rbegin(); it != cells_.rend(); ++it) { for (auto it = cells_.rbegin(); it != cells_.rend(); ++it) {
const RTLIL::Cell *o = it->second; 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->connections_ = o->connections_;
c->parameters = o->parameters; c->parameters = o->parameters;
c->attributes = o->attributes; c->attributes = o->attributes;
c->meta_idx_ = o->meta_idx_; copy_meta(o, c);
} }
for (auto it = processes.rbegin(); it != processes.rend(); ++it) { for (auto it = processes.rbegin(); it != processes.rend(); ++it) {
const RTLIL::Process *o = it->second; const RTLIL::Process *o = it->second;
RTLIL::Process *p = o->clone(); RTLIL::Process *p = o->clone();
p->name = it->first; p->name = it->first;
new_mod->add(p); new_mod->add(p);
// Process::clone drops meta_idx_ across the inner tree copy_meta(o, p);
// (no module backpointer there before attach); now that
// p has a module we can copy them verbatim.
p->meta_idx_ = o->meta_idx_;
std::vector<std::pair<const RTLIL::CaseRule*, RTLIL::CaseRule*>> case_stack; std::vector<std::pair<const RTLIL::CaseRule*, RTLIL::CaseRule*>> case_stack;
case_stack.emplace_back(&o->root_case, &p->root_case); case_stack.emplace_back(&o->root_case, &p->root_case);
while (!case_stack.empty()) { while (!case_stack.empty()) {
auto [s_cs, d_cs] = case_stack.back(); auto [s_cs, d_cs] = case_stack.back();
case_stack.pop_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()); log_assert(s_cs->switches.size() == d_cs->switches.size());
for (size_t i = 0; i < s_cs->switches.size(); i++) { for (size_t i = 0; i < s_cs->switches.size(); i++) {
const auto *s_sw = s_cs->switches[i]; const auto *s_sw = s_cs->switches[i];
auto *d_sw = d_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()); log_assert(s_sw->cases.size() == d_sw->cases.size());
for (size_t j = 0; j < s_sw->cases.size(); j++) for (size_t j = 0; j < s_sw->cases.size(); j++)
case_stack.emplace_back(s_sw->cases[j], d_sw->cases[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]; auto *d_sync = p->syncs[i];
log_assert(s_sync->mem_write_actions.size() == d_sync->mem_write_actions.size()); 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++) 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 { } else {
@ -4798,7 +4787,7 @@ void RTLIL::Wire::set_src_id(Twine::Id id)
void RTLIL::Wire::set_src_attribute(const RTLIL::SrcAttr &src) void RTLIL::Wire::set_src_attribute(const RTLIL::SrcAttr &src)
{ {
if (src.empty() && meta_idx_ == NO_META) if (src.empty() && meta_ == nullptr)
return; return;
log_assert(module && module->design && "Wire::set_src_attribute requires the wire to be attached to a module in a design"); 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); 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) void RTLIL::Cell::set_src_attribute(const RTLIL::SrcAttr &src)
{ {
if (src.empty() && meta_idx_ == NO_META) if (src.empty() && meta_ == nullptr)
return; return;
log_assert(module && module->design && "Cell::set_src_attribute requires the cell to be attached to a module in a design"); 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); 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 // any pool; the caller is responsible for migrating src across the
// clone via context (see Process::clone). // clone via context (see Process::clone).
for (auto &mwa : new_syncrule->mem_write_actions) for (auto &mwa : new_syncrule->mem_write_actions)
mwa.meta_idx_ = RTLIL::AttrObject::NO_META; mwa.meta_ = nullptr;
return new_syncrule; 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) void RTLIL::Process::set_src_attribute(const RTLIL::SrcAttr &src)
{ {
if (src.empty() && meta_idx_ == NO_META) if (src.empty() && meta_ == nullptr)
return; return;
log_assert(module && module->design && "Process::set_src_attribute requires the process to be attached to a module in a design"); 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); 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) void RTLIL::Memory::set_src_attribute(const RTLIL::SrcAttr &src)
{ {
if (src.empty() && meta_idx_ == NO_META) if (src.empty() && meta_ == nullptr)
return; return;
log_assert(module && module->design && "Memory::set_src_attribute requires the memory to be attached to a module in a design"); 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); 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) void RTLIL::CaseRule::set_src_attribute(const RTLIL::SrcAttr &src)
{ {
if (src.empty() && meta_idx_ == NO_META) if (src.empty() && meta_ == nullptr)
return; return;
log_assert(module && module->design && "CaseRule::set_src_attribute requires the case to belong to a module in a design"); 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); 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) void RTLIL::SwitchRule::set_src_attribute(const RTLIL::SrcAttr &src)
{ {
if (src.empty() && meta_idx_ == NO_META) if (src.empty() && meta_ == nullptr)
return; return;
log_assert(module && module->design && "SwitchRule::set_src_attribute requires the switch to belong to a module in a design"); 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); 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) void RTLIL::MemWriteAction::set_src_attribute(const RTLIL::SrcAttr &src)
{ {
if (src.empty() && meta_idx_ == NO_META) if (src.empty() && meta_ == nullptr)
return; return;
log_assert(module && module->design && "MemWriteAction::set_src_attribute requires the action to belong to a module in a design"); 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); module->design->set_src_attribute(this, src);

View File

@ -24,6 +24,7 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/twine.h" #include "kernel/twine.h"
#include <deque>
#include <string_view> #include <string_view>
#include <unordered_map> #include <unordered_map>
@ -127,6 +128,7 @@ namespace RTLIL
struct StaticIdString; struct StaticIdString;
struct SigNormIndex; struct SigNormIndex;
struct SrcAttr; struct SrcAttr;
struct ObjMeta;
typedef std::pair<SigSpec, SigSpec> SigSig; typedef std::pair<SigSpec, SigSpec> SigSig;
struct PortBit; struct PortBit;
@ -1291,25 +1293,20 @@ public:
[[nodiscard]] Hasher hash_into(Hasher h) const; [[nodiscard]] Hasher hash_into(Hasher h) const;
}; };
struct RTLIL::ObjMeta
{
Twine::Id src = Twine::Null;
RTLIL::IdString name;
};
struct RTLIL::AttrObject struct RTLIL::AttrObject
{ {
dict<RTLIL::IdString, RTLIL::Const> attributes; dict<RTLIL::IdString, RTLIL::Const> attributes;
// Per-Design metadata slot index, or NO_META. The slot lives in // Pointer to a per-object metadata record in some pool (typically
// Design::obj_meta_src_ and holds this object's Twine::Id src; the // the owning Design's). Nullable: cleared until first non-null write
// slot is allocated lazily on the first non-null src write and // of any field (src or name) and reset to null when all fields empty.
// freed when src returns to null. Per-object cost is just this RTLIL::ObjMeta *meta_ = nullptr;
// 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;
bool has_attribute(RTLIL::IdString id) const; bool has_attribute(RTLIL::IdString id) const;
@ -1953,57 +1950,25 @@ struct RTLIL::Design
// via cell->module->design->src_twines. // via cell->module->design->src_twines.
TwinePool src_twines; TwinePool src_twines;
// Per-object metadata indexed by AttrObject::meta_idx_. Slots are // Per-Design ObjMeta pool: stable storage (deque) + LIFO freelist of
// allocated lazily on first non-null write and recycled via the // returned slots. AttrObject::meta_ points into obj_meta_storage_.
// LIFO freelist obj_meta_free_. Both src and name share one slot std::deque<RTLIL::ObjMeta> obj_meta_storage_;
// so subtypes that carry either pay only one index field. std::vector<RTLIL::ObjMeta*> obj_meta_free_;
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(); RTLIL::ObjMeta *alloc_obj_meta();
void free_obj_meta(uint32_t idx); void free_obj_meta(RTLIL::ObjMeta *m);
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);
Twine::Id obj_src_id(const RTLIL::AttrObject *obj) const { Twine::Id obj_src_id(const RTLIL::AttrObject *obj) const {
return obj_src_id_by_idx(obj->meta_idx_); return (obj->meta_ ? obj->meta_->src : Twine::Null);
}
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_);
} }
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 { RTLIL::IdString obj_name(const RTLIL::AttrObject *obj) const {
return obj_name_by_idx(obj->meta_idx_); return (obj->meta_ ? obj->meta_->name : RTLIL::IdString());
}
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_);
} }
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 // Replacements for the methods that used to live on AttrObject and
// took an explicit TwinePool*. Same semantics; the pool resolves // took an explicit TwinePool*. Same semantics; the pool resolves

View File

@ -147,7 +147,7 @@ static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, co
// uses were rare and the dict-path migration is a separate concern. // 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) 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("<!=>"); size_t pos = match_expr.find_first_of("<!=>");
std::string name_part = (pos == std::string::npos) ? match_expr : match_expr.substr(0, pos); std::string name_part = (pos == std::string::npos) ? match_expr : match_expr.substr(0, pos);
if (name_part == "src" || name_part == "\\src") { if (name_part == "src" || name_part == "\\src") {