3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-15 03:35:40 +00:00

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
// 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

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
{
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<uint32_t>(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<std::pair<const RTLIL::CaseRule*, RTLIL::CaseRule*>> 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);

View file

@ -24,6 +24,7 @@
#include "kernel/yosys.h"
#include "kernel/twine.h"
#include <deque>
#include <string_view>
#include <unordered_map>
@ -127,6 +128,7 @@ namespace RTLIL
struct StaticIdString;
struct SigNormIndex;
struct SrcAttr;
struct ObjMeta;
typedef std::pair<SigSpec, SigSpec> 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<RTLIL::IdString, RTLIL::Const> 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<ObjMeta> obj_meta_;
std::vector<uint32_t> obj_meta_free_;
// Per-Design ObjMeta pool: stable storage (deque) + LIFO freelist of
// returned slots. AttrObject::meta_ points into obj_meta_storage_.
std::deque<RTLIL::ObjMeta> obj_meta_storage_;
std::vector<RTLIL::ObjMeta*> 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

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.
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") {