From c4f3e61339fa21d18dc48ded84e9467a8854f553 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 12:41:50 +0000 Subject: [PATCH 01/30] Make Module stop accessing internals of SigSpec --- kernel/rtlil.cc | 25 +++++++++++++++---------- kernel/rtlil.h | 6 ++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index aa4743a87..21a466b42 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2657,10 +2657,9 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const RTLIL::Module *mod; void operator()(RTLIL::SigSpec &sig) { - sig.pack(); - for (auto &c : sig.chunks_) - if (c.wire != NULL) - c.wire = mod->wires_.at(c.wire->name); + sig.rewrite_wires([this](RTLIL::Wire *&wire) { + wire = mod->wires_.at(wire->name); + }); } }; @@ -2808,12 +2807,10 @@ void RTLIL::Module::remove(const pool &wires) const pool *wires_p; void operator()(RTLIL::SigSpec &sig) { - sig.pack(); - for (auto &c : sig.chunks_) - if (c.wire != NULL && wires_p->count(c.wire)) { - c.wire = module->addWire(stringf("$delete_wire$%d", autoidx++), c.width); - c.offset = 0; - } + sig.rewrite_wires([this](RTLIL::Wire *&wire) { + if (wires_p->count(wire)) + wire = module->addWire(stringf("$delete_wire$%d", autoidx++), wire->width); + }); } void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) { @@ -5151,6 +5148,14 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const } } +void RTLIL::SigSpec::rewrite_wires(std::function rewrite) +{ + pack(); + for (RTLIL::SigChunk &chunk : chunks_) + if (chunk.wire != nullptr) + rewrite(chunk.wire); +} + void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) { if (signal.width_ == 0) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 394c6f25d..a2be435bd 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1251,10 +1251,6 @@ private: unpack(); } - // Only used by Module::remove(const pool &wires) - // but cannot be more specific as it isn't yet declared - friend struct RTLIL::Module; - public: SigSpec() : width_(0), hash_(0) {} SigSpec(std::initializer_list parts); @@ -1326,6 +1322,8 @@ public: RTLIL::SigSpec extract(int offset, int length = 1) const; RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); } + void rewrite_wires(std::function rewrite); + RTLIL::SigBit lsb() const { log_assert(width_); return (*this)[0]; }; RTLIL::SigBit msb() const { log_assert(width_); return (*this)[width_ - 1]; }; From 37e4c2e8f8759db52a5a5d05daf87455e9d44eed Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 15:46:36 +0000 Subject: [PATCH 02/30] Make SigSpec::chunks() return an object that can be iterated over without packing the SigSpec --- kernel/rtlil.cc | 25 +++++++++++++ kernel/rtlil.h | 77 ++++++++++++++++++++++++++++++++++++-- passes/cmds/show.cc | 7 ++-- passes/techmap/abc9_ops.cc | 4 +- 4 files changed, 104 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 21a466b42..d1b695dd0 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4648,6 +4648,31 @@ RTLIL::SigSpec::SigSpec(bool bit) check(); } +void RTLIL::SigSpec::Chunks::const_iterator::next_chunk_bits() +{ + int bits_size = GetSize(spec.bits_); + if (bit_index >= bits_size) + return; + int i = bit_index; + const SigBit &bit = spec.bits_[i++]; + chunk.wire = bit.wire; + chunk.data.clear(); + if (bit.is_wire()) { + chunk.offset = bit.offset; + while (i < bits_size && spec.bits_[i].wire == bit.wire && + spec.bits_[i].offset == bit.offset + i - bit_index) + ++i; + } else { + chunk.offset = 0; + chunk.data.push_back(bit.data); + while (i < bits_size && !spec.bits_[i].is_wire()) { + chunk.data.push_back(spec.bits_[i].data); + ++i; + } + } + chunk.width = i - bit_index; +} + void RTLIL::SigSpec::pack() const { RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index a2be435bd..31aff3245 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1275,7 +1275,75 @@ public: SigSpec &operator=(const SigSpec &rhs) = default; SigSpec &operator=(SigSpec &&rhs) = default; - inline const std::vector &chunks() const { pack(); return chunks_; } + struct Chunks { + const SigSpec &spec; + + struct const_iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const SigChunk &; + using difference_type = std::ptrdiff_t; + using pointer = const SigChunk *; + using reference = const SigChunk &; + + const SigSpec &spec; + int chunk_index; + int bit_index; + SigChunk chunk; + + const_iterator(const SigSpec &spec) : spec(spec) { + chunk_index = 0; + bit_index = 0; + if (!spec.packed()) + next_chunk_bits(); + } + void next_chunk_bits(); + + const SigChunk &operator*() { + if (spec.packed()) + return spec.chunks_[chunk_index]; + return chunk; + }; + const SigChunk *operator->() { return &**this; } + const_iterator &operator++() { + bit_index += (**this).width; + ++chunk_index; + if (!spec.packed()) + next_chunk_bits(); + return *this; + } + bool operator==(const const_iterator &rhs) const { return bit_index == rhs.bit_index; } + bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); } + }; + const_iterator begin() const { return const_iterator(spec); } + const_iterator end() const { + const_iterator it(spec); + it.bit_index = spec.size(); + return it; + } + std::vector::const_reverse_iterator rbegin() const { + spec.pack(); + return spec.chunks_.rbegin(); + } + std::vector::const_reverse_iterator rend() const { + spec.pack(); + return spec.chunks_.rend(); + } + int size() const { + spec.pack(); + return spec.chunks_.size(); + } + const SigChunk &at(int index) const { + spec.pack(); + return spec.chunks_.at(index); + } + operator const std::vector&() const { + spec.pack(); + return spec.chunks_; + } + }; + friend struct Chunks::const_iterator; + + inline Chunks chunks() const { return {*this}; } inline const std::vector &bits() const { inline_unpack(); return bits_; } inline int size() const { return width_; } @@ -1402,7 +1470,7 @@ public: static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str); static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); - operator std::vector() const { return chunks(); } + operator std::vector() const { pack(); return chunks_; } operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } @@ -2315,8 +2383,9 @@ inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const { } inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) { - log_assert(sig.size() == 1 && sig.chunks().size() == 1); - *this = SigBit(sig.chunks().front()); + log_assert(sig.size() == 1); + auto it = sig.chunks().begin(); + *this = SigBit(*it); } template diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index d0d9c0f85..14a251c41 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -278,11 +278,12 @@ struct ShowWorker std::vector label_pieces; int bitpos = sig.size()-1; - for (int rep, chunk_idx = ((int) sig.chunks().size()) - 1; chunk_idx >= 0; chunk_idx -= rep) { - const RTLIL::SigChunk &c = sig.chunks().at(chunk_idx); + RTLIL::SigSpec::Chunks sig_chunks = sig.chunks(); + for (int rep, chunk_idx = ((int) sig_chunks.size()) - 1; chunk_idx >= 0; chunk_idx -= rep) { + const RTLIL::SigChunk &c = sig_chunks.at(chunk_idx); // Find the number of times this chunk is repeating - for (rep = 1; chunk_idx - rep >= 0 && c == sig.chunks().at(chunk_idx - rep); rep++); + for (rep = 1; chunk_idx - rep >= 0 && c == sig_chunks.at(chunk_idx - rep); rep++); int cl, cr; cl = c.offset + c.width - 1; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 373d5d15e..8d3869ece 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1428,13 +1428,13 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) // Copy connections (and rename) from mapped_mod to module for (auto conn : mapped_mod->connections()) { if (!conn.first.is_fully_const()) { - auto chunks = conn.first.chunks(); + std::vector chunks = conn.first.chunks(); for (auto &c : chunks) c.wire = module->wires_.at(remap_name(c.wire->name)); conn.first = std::move(chunks); } if (!conn.second.is_fully_const()) { - auto chunks = conn.second.chunks(); + std::vector chunks = conn.second.chunks(); for (auto &c : chunks) if (c.wire) c.wire = module->wires_.at(remap_name(c.wire->name)); From fd7b4f4a8b37ae0aeee88f99da492b7c81710f14 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:35:47 +0000 Subject: [PATCH 03/30] Make SigSpec::updhash() use chunk iterator --- kernel/rtlil.cc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d1b695dd0..71109f60d 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4736,10 +4736,9 @@ void RTLIL::SigSpec::updhash() const return; cover("kernel.rtlil.sigspec.hash"); - that->pack(); Hasher h; - for (auto &c : that->chunks_) + for (auto &c : that->chunks()) if (c.wire == NULL) { for (auto &v : c.data) h.eat(v); @@ -5193,13 +5192,8 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) cover("kernel.rtlil.sigspec.append"); - if (packed() != signal.packed()) { - pack(); - signal.pack(); - } - if (packed()) - for (auto &other_c : signal.chunks_) + for (auto &other_c : signal.chunks()) { auto &my_last_c = chunks_.back(); if (my_last_c.wire == NULL && other_c.wire == NULL) { @@ -5213,8 +5207,10 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) } else chunks_.push_back(other_c); } - else + else { + signal.unpack(); bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); + } width_ += signal.width_; check(); From bf4cfbd72d2effda7f30ca26f4740a80a348cf3a Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:12 +0000 Subject: [PATCH 04/30] Make SigSpec::is_wire/is_chunk/is_fully_const use chunk iterator --- kernel/rtlil.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 71109f60d..9bb7927a8 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5401,22 +5401,28 @@ bool RTLIL::SigSpec::is_wire() const { cover("kernel.rtlil.sigspec.is_wire"); - pack(); - return GetSize(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_; + Chunks cs = chunks(); + auto it = cs.begin(); + if (it == cs.end()) + return false; + const RTLIL::SigChunk &chunk = *it; + return chunk.wire && chunk.wire->width == width_ && ++it == cs.end(); } bool RTLIL::SigSpec::is_chunk() const { cover("kernel.rtlil.sigspec.is_chunk"); - pack(); - return GetSize(chunks_) == 1; + Chunks cs = chunks(); + auto it = cs.begin(); + if (it == cs.end()) + return false; + return ++it == cs.end(); } bool RTLIL::SigSpec::known_driver() const { - pack(); - for (auto &chunk : chunks_) + for (auto &chunk : chunks()) if (chunk.is_wire() && !chunk.wire->known_driver()) return false; return true; From 20e64ee17b77a22b9527efdc660b1fc27afcb56b Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:36 +0000 Subject: [PATCH 05/30] Make is_fully_const use chunk iterator --- kernel/rtlil.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 9bb7927a8..bb4c6a722 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5432,9 +5432,8 @@ bool RTLIL::SigSpec::is_fully_const() const { cover("kernel.rtlil.sigspec.is_fully_const"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) + if (chunk.width > 0 && chunk.wire != NULL) return false; return true; } From 58dbf758850ca8891f04afbea25a207283295e35 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:47 +0000 Subject: [PATCH 06/30] Make SigSpec::is_fully_zero use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index bb4c6a722..a1f4b27a5 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5442,12 +5442,11 @@ bool RTLIL::SigSpec::is_fully_zero() const { cover("kernel.rtlil.sigspec.is_fully_zero"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) { + if (chunk.width > 0 && chunk.wire != NULL) return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S0) + for (RTLIL::State d : chunk.data) + if (d != RTLIL::State::S0) return false; } return true; From 8a88acd9b8a5edcd6c9b6b1cc45e9b6353a6d619 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:58 +0000 Subject: [PATCH 07/30] Make SigSpec::is_fully_ones use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a1f4b27a5..ca9daa448 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5456,12 +5456,11 @@ bool RTLIL::SigSpec::is_fully_ones() const { cover("kernel.rtlil.sigspec.is_fully_ones"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) { + if (chunk.width > 0 && chunk.wire != NULL) return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S1) + for (RTLIL::State d : chunk.data) + if (d != RTLIL::State::S1) return false; } return true; From b2de56cae261fe3bcfc8187e8acc5fad51b8b6ae Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:08 +0000 Subject: [PATCH 08/30] Make SigSpec::is_fully_def use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index ca9daa448..72875a741 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5470,12 +5470,11 @@ bool RTLIL::SigSpec::is_fully_def() const { cover("kernel.rtlil.sigspec.is_fully_def"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) { + if (chunk.width > 0 && chunk.wire != NULL) return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S0 && it->data[i] != RTLIL::State::S1) + for (RTLIL::State d : chunk.data) + if (d != RTLIL::State::S0 && d != RTLIL::State::S1) return false; } return true; From 5c8f9f14ca6f1805a49558a95e2794f0952739bf Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:17 +0000 Subject: [PATCH 09/30] Make SigSpec::is_fully_undef use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 72875a741..118673f76 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5484,12 +5484,11 @@ bool RTLIL::SigSpec::is_fully_undef() const { cover("kernel.rtlil.sigspec.is_fully_undef"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) { + if (chunk.width > 0 && chunk.wire != NULL) return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::Sx && it->data[i] != RTLIL::State::Sz) + for (RTLIL::State d : chunk.data) + if (d != RTLIL::State::Sx && d != RTLIL::State::Sz) return false; } return true; From 213d665ae165085abbdfe4e79358ce46a2da6520 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:38 +0000 Subject: [PATCH 10/30] Make SigSpec::has_const use chunk iterator --- kernel/rtlil.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 118673f76..2042df075 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5498,9 +5498,8 @@ bool RTLIL::SigSpec::has_const() const { cover("kernel.rtlil.sigspec.has_const"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire == NULL) + for (auto &chunk : chunks()) + if (chunk.width > 0 && chunk.wire == NULL) return true; return false; } From 7bd6b4f28728f0adfc6ea867f3f0ceb7466b26ac Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:51 +0000 Subject: [PATCH 11/30] Make SigSpec::has_const(State) use chunk iterator --- kernel/rtlil.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2042df075..ab16c89b9 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5508,9 +5508,8 @@ bool RTLIL::SigSpec::has_const(State state) const { cover("kernel.rtlil.sigspec.has_const"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire == NULL && std::find(it->data.begin(), it->data.end(), state) != it->data.end()) + for (auto &chunk : chunks()) + if (chunk.width > 0 && chunk.wire == NULL && std::find(chunk.data.begin(), chunk.data.end(), state) != chunk.data.end()) return true; return false; } From 04a6dbc562b5d950272b1d93a2f764faa4d159bf Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:38:03 +0000 Subject: [PATCH 12/30] Make SigSpec::has_marked_bits use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index ab16c89b9..279b7b2ce 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5519,11 +5519,10 @@ bool RTLIL::SigSpec::has_marked_bits() const { cover("kernel.rtlil.sigspec.has_marked_bits"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire == NULL) { - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] == RTLIL::State::Sm) + for (auto &chunk : chunks()) + if (chunk.width > 0 && chunk.wire == NULL) { + for (RTLIL::State d : chunk.data) + if (d == RTLIL::State::Sm) return true; } return false; From 000c0819659693ec566f23c46eea2c2935c284e8 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 15:48:24 +0000 Subject: [PATCH 13/30] Add try_as_const and use the const iterator a bit more --- kernel/rtlil.cc | 37 ++++++++++++++++++++++++++----------- kernel/rtlil.h | 3 +++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 279b7b2ce..1335b766b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5621,33 +5621,48 @@ std::string RTLIL::SigSpec::as_string() const return str; } +std::optional RTLIL::SigSpec::try_as_const() const +{ + cover("kernel.rtlil.sigspec.as_const"); + + auto it = chunks().begin(); + if (it == chunks().end()) + return RTLIL::Const(); + SigChunk chunk = *it; + if (chunk.wire != NULL || ++it != chunks().end()) + return std::nullopt; + return RTLIL::Const(std::move(chunk.data)); +} + RTLIL::Const RTLIL::SigSpec::as_const() const { cover("kernel.rtlil.sigspec.as_const"); - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return chunks_[0].data; - return RTLIL::Const(); + std::optional c = try_as_const(); + log_assert(c.has_value()); + return *c; } RTLIL::Wire *RTLIL::SigSpec::as_wire() const { cover("kernel.rtlil.sigspec.as_wire"); - pack(); - log_assert(is_wire()); - return chunks_[0].wire; + auto it = chunks().begin(); + log_assert(it != chunks().end()); + RTLIL::SigChunk chunk = *it; + log_assert(++it == chunks().end() && chunk.wire && chunk.wire->width == width_); + return chunk.wire; } RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const { cover("kernel.rtlil.sigspec.as_chunk"); - pack(); - log_assert(is_chunk()); - return chunks_[0]; + auto it = chunks().begin(); + log_assert(it != chunks().end()); + RTLIL::SigChunk chunk = *it; + log_assert(++it == chunks().end()); + return chunk; } RTLIL::SigBit RTLIL::SigSpec::as_bit() const diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 31aff3245..72613ea02 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1453,6 +1453,9 @@ public: int as_int_saturating(bool is_signed = false) const; std::string as_string() const; + // Returns std::nullopt if there are any non-constant bits. Returns an empty + // Const if this has zero width. + std::optional try_as_const() const; RTLIL::Const as_const() const; RTLIL::Wire *as_wire() const; RTLIL::SigChunk as_chunk() const; From a0e9e2d364593cae59753d2b11165f946f837480 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:59:57 +0000 Subject: [PATCH 14/30] Fix try_as_const/as_wire/as_chunk --- kernel/rtlil.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1335b766b..69b7afa6e 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5625,11 +5625,12 @@ std::optional RTLIL::SigSpec::try_as_const() const { cover("kernel.rtlil.sigspec.as_const"); - auto it = chunks().begin(); - if (it == chunks().end()) + Chunks cs = chunks(); + auto it = cs.begin(); + if (it == cs.end()) return RTLIL::Const(); SigChunk chunk = *it; - if (chunk.wire != NULL || ++it != chunks().end()) + if (chunk.wire != NULL || ++it != cs.end()) return std::nullopt; return RTLIL::Const(std::move(chunk.data)); } @@ -5647,10 +5648,11 @@ RTLIL::Wire *RTLIL::SigSpec::as_wire() const { cover("kernel.rtlil.sigspec.as_wire"); - auto it = chunks().begin(); - log_assert(it != chunks().end()); + Chunks cs = chunks(); + auto it = cs.begin(); + log_assert(it != cs.end()); RTLIL::SigChunk chunk = *it; - log_assert(++it == chunks().end() && chunk.wire && chunk.wire->width == width_); + log_assert(++it == cs.end() && chunk.wire && chunk.wire->width == width_); return chunk.wire; } @@ -5658,10 +5660,11 @@ RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const { cover("kernel.rtlil.sigspec.as_chunk"); - auto it = chunks().begin(); - log_assert(it != chunks().end()); + Chunks cs = chunks(); + auto it = cs.begin(); + log_assert(it != cs.end()); RTLIL::SigChunk chunk = *it; - log_assert(++it == chunks().end()); + log_assert(++it == cs.end()); return chunk; } From 0d45d9cc6eb7ad37e67d5bd8c9569bab8a00a95c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:39:31 +0000 Subject: [PATCH 15/30] Make SigSpec::is_one_hot use try_as_const --- kernel/rtlil.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 69b7afa6e..316969e6b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5532,12 +5532,8 @@ bool RTLIL::SigSpec::is_onehot(int *pos) const { cover("kernel.rtlil.sigspec.is_onehot"); - pack(); - if (!is_fully_const()) - return false; - log_assert(GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).is_onehot(pos); + if (std::optional c = try_as_const()) + return c->is_onehot(pos); return false; } From 82f86164d3c9c3e5f0632b89e18ee519da1a2d7a Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:39:53 +0000 Subject: [PATCH 16/30] Use SigSpec::try_as_const in some places --- kernel/rtlil.cc | 52 +++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 316969e6b..25f99b07a 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5541,74 +5541,58 @@ bool RTLIL::SigSpec::as_bool() const { cover("kernel.rtlil.sigspec.as_bool"); - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).as_bool(); - return false; + std::optional c = try_as_const(); + log_assert(c.has_value()); + return c->as_bool(); } int RTLIL::SigSpec::as_int(bool is_signed) const { cover("kernel.rtlil.sigspec.as_int"); - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).as_int(is_signed); - return 0; + std::optional c = try_as_const(); + log_assert(c.has_value()); + return c->as_int(is_signed); } bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const { cover("kernel.rtlil.sigspec.convertible_to_int"); - pack(); - if (!is_fully_const()) + std::optional c = try_as_const(); + if (!c.has_value()) return false; - - if (empty()) - return true; - - return RTLIL::Const(chunks_[0].data).convertible_to_int(is_signed); + return c->convertible_to_int(is_signed); } std::optional RTLIL::SigSpec::try_as_int(bool is_signed) const { cover("kernel.rtlil.sigspec.try_as_int"); - pack(); - if (!is_fully_const()) + std::optional c = try_as_const(); + if (!c.has_value()) return std::nullopt; - - if (empty()) - return 0; - - return RTLIL::Const(chunks_[0].data).try_as_int(is_signed); + return c->try_as_int(is_signed); } int RTLIL::SigSpec::as_int_saturating(bool is_signed) const { cover("kernel.rtlil.sigspec.try_as_int"); - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - - if (empty()) - return 0; - - return RTLIL::Const(chunks_[0].data).as_int_saturating(is_signed); + std::optional c = try_as_const(); + log_assert(c.has_value()); + return c->as_int_saturating(is_signed); } std::string RTLIL::SigSpec::as_string() const { cover("kernel.rtlil.sigspec.as_string"); - pack(); std::string str; str.reserve(size()); - for (size_t i = chunks_.size(); i > 0; i--) { - const RTLIL::SigChunk &chunk = chunks_[i-1]; + std::vector chunks = *this; + for (size_t i = chunks.size(); i > 0; i--) { + const RTLIL::SigChunk &chunk = chunks[i-1]; if (chunk.wire != NULL) str.append(chunk.width, '?'); else From 8cb7cd7ac16f312715d45baafcc69036361c733b Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:08 +0000 Subject: [PATCH 17/30] Make SigSpec::to_sigbit_set use chunk iterator --- kernel/rtlil.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 25f99b07a..35cf2c525 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5692,9 +5692,8 @@ std::set RTLIL::SigSpec::to_sigbit_set() const { cover("kernel.rtlil.sigspec.to_sigbit_set"); - pack(); std::set sigbits; - for (auto &c : chunks_) + for (auto &c : chunks()) for (int i = 0; i < c.width; i++) sigbits.insert(RTLIL::SigBit(c, i)); return sigbits; From 11a91af920bb2580b9247b5611397c7267a2f9f7 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:20 +0000 Subject: [PATCH 18/30] Make SigSpec::to_sigbit_pool use chunk iterator --- kernel/rtlil.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 35cf2c525..1c6044e26 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5703,10 +5703,9 @@ pool RTLIL::SigSpec::to_sigbit_pool() const { cover("kernel.rtlil.sigspec.to_sigbit_pool"); - pack(); pool sigbits; sigbits.reserve(size()); - for (auto &c : chunks_) + for (auto &c : chunks()) for (int i = 0; i < c.width; i++) sigbits.insert(RTLIL::SigBit(c, i)); return sigbits; From 4672127610cb82a40f4e86fd1ca628073b5f1fed Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:45 +0000 Subject: [PATCH 19/30] Make SigSpec::parse_rhs use is_chunk to avoid direct access to chunks_ --- kernel/rtlil.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1c6044e26..674e8a7cb 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5882,7 +5882,7 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R return true; } - if (lhs.chunks_.size() == 1) { + if (lhs.is_chunk()) { char *p = (char*)str.c_str(), *endptr; long int val = strtol(p, &endptr, 10); if (endptr && endptr != p && *endptr == 0) { From 8c9dd3209a053e5635d75df80cb686b7dca75623 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 10:30:03 +0000 Subject: [PATCH 20/30] Make SigSpec conversion to vector of SigChunk use chunks iterator --- kernel/rtlil.cc | 8 ++++++++ kernel/rtlil.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 674e8a7cb..2f0f5dddb 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5899,6 +5899,14 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R return true; } +RTLIL::SigSpec::operator std::vector() const +{ + std::vector result; + for (const RTLIL::SigChunk &c : chunks()) + result.push_back(c); + return result; +} + RTLIL::CaseRule::~CaseRule() { for (auto it = switches.begin(); it != switches.end(); it++) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 72613ea02..8f6119914 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1473,7 +1473,7 @@ public: static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str); static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); - operator std::vector() const { pack(); return chunks_; } + operator std::vector() const; operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } From 973e8a3928e1eb551b5dba5cdfcd243782bfc274 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:07:02 +0000 Subject: [PATCH 21/30] Build a temporary SigChunk list in the iterator in the cases where that's needed --- backends/rtlil/rtlil_backend.cc | 3 +- backends/verilog/verilog_backend.cc | 5 +-- kernel/rtlil.h | 48 +++++++++++++++++++---------- kernel/utils.h | 24 +++++++++++---- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index d607be837..057edc584 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -121,7 +121,8 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo dump_sigchunk(f, sig.as_chunk(), autoint); } else { f << stringf("{ "); - for (const auto& chunk : reversed(sig.chunks())) { + auto chunks = sig.chunks(); + for (const auto& chunk : reversed(chunks)) { dump_sigchunk(f, chunk, false); f << stringf(" "); } diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index c747aa901..faeb2cd0b 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -382,8 +382,9 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) dump_sigchunk(f, sig.as_chunk()); } else { f << stringf("{ "); - for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) { - if (it != sig.chunks().rbegin()) + auto chunks = sig.chunks(); + for (auto it = chunks.rbegin(); it != chunks.rend(); ++it) { + if (it != chunks.rbegin()) f << stringf(", "); dump_sigchunk(f, *it, true); } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 8f6119914..31c643614 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1276,8 +1276,7 @@ public: SigSpec &operator=(SigSpec &&rhs) = default; struct Chunks { - const SigSpec &spec; - + Chunks(const SigSpec &spec) : spec(spec) {} struct const_iterator { using iterator_category = std::forward_iterator_tag; using value_type = const SigChunk &; @@ -1320,26 +1319,43 @@ public: it.bit_index = spec.size(); return it; } - std::vector::const_reverse_iterator rbegin() const { - spec.pack(); - return spec.chunks_.rbegin(); + // Later we should deprecate these and remove their in-tree calls, + // so we can eventually remove chunk_vector. + std::vector::const_reverse_iterator rbegin() { + ensure_chunk_vector(); + return chunk_vector.rbegin(); } - std::vector::const_reverse_iterator rend() const { - spec.pack(); - return spec.chunks_.rend(); + std::vector::const_reverse_iterator rend() { + ensure_chunk_vector(); + return chunk_vector.rend(); + } + int size() { + ensure_chunk_vector(); + return chunk_vector.size(); } int size() const { - spec.pack(); - return spec.chunks_.size(); + int result = 0; + for (const SigChunk &_: *this) + ++result; + return result; } - const SigChunk &at(int index) const { - spec.pack(); - return spec.chunks_.at(index); + const SigChunk &at(int index) { + ensure_chunk_vector(); + return chunk_vector.at(index); } - operator const std::vector&() const { - spec.pack(); - return spec.chunks_; + operator const std::vector&() { + ensure_chunk_vector(); + return chunk_vector; } + private: + void ensure_chunk_vector() { + if (spec.size() > 0 && chunk_vector.empty()) { + for (const RTLIL::SigChunk &c : *this) + chunk_vector.push_back(c); + } + } + const SigSpec &spec; + std::vector chunk_vector; }; friend struct Chunks::const_iterator; diff --git a/kernel/utils.h b/kernel/utils.h index 5c739aceb..e90ba09d8 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -277,14 +277,26 @@ inline int ceil_log2(int x) #endif } +template +auto reversed(T& container) { + struct reverse_view { + reverse_view(T& container) : container(container) {} + auto begin() const { return container.rbegin(); } + auto end() const { return container.rend(); } + T& container; + }; + return reverse_view{container}; +} + template auto reversed(const T& container) { - struct reverse_view { - const T& cont; - auto begin() const { return cont.rbegin(); } - auto end() const { return cont.rend(); } - }; - return reverse_view{container}; + struct reverse_view { + reverse_view(const T& container) : container(container) {} + auto begin() const { return container.rbegin(); } + auto end() const { return container.rend(); } + const T& container; + }; + return reverse_view{container}; } YOSYS_NAMESPACE_END From be530bef73151b7ac2bb5f108f8c335995dc99c6 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:24:00 +0000 Subject: [PATCH 22/30] Instead of using packing and hashing to compute SigSpec ordering and equality, just use the width and chunkwise comparisons This avoids having to pack and compute hashes, and generally results in a simpler ordering. --- kernel/rtlil.cc | 50 +++++++++++-------------------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2f0f5dddb..2c08bb524 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5337,23 +5337,12 @@ bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const if (width_ != other.width_) return width_ < other.width_; - pack(); - other.pack(); - - if (chunks_.size() != other.chunks_.size()) - return chunks_.size() < other.chunks_.size(); - - updhash(); - other.updhash(); - - if (hash_ != other.hash_) - return hash_ < other.hash_; - - for (size_t i = 0; i < chunks_.size(); i++) - if (chunks_[i] != other.chunks_[i]) { - cover("kernel.rtlil.sigspec.comp_lt.hash_collision"); - return chunks_[i] < other.chunks_[i]; - } + auto other_it = other.chunks().begin(); + for (const SigChunk &c : chunks()) { + if (c != *other_it) + return c < *other_it; + ++other_it; + } cover("kernel.rtlil.sigspec.comp_lt.equal"); return false; @@ -5369,29 +5358,12 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const if (width_ != other.width_) return false; - // Without this, SigSpec() == SigSpec(State::S0, 0) will fail - // since the RHS will contain one SigChunk of width 0 causing - // the size check below to fail - if (width_ == 0) - return true; - - pack(); - other.pack(); - - if (chunks_.size() != other.chunks_.size()) - return false; - - updhash(); - other.updhash(); - - if (hash_ != other.hash_) - return false; - - for (size_t i = 0; i < chunks_.size(); i++) - if (chunks_[i] != other.chunks_[i]) { - cover("kernel.rtlil.sigspec.comp_eq.hash_collision"); + auto other_it = other.chunks().begin(); + for (const SigChunk &c : chunks()) { + if (c != *other_it) return false; - } + ++other_it; + } cover("kernel.rtlil.sigspec.comp_eq.equal"); return true; From d314c47a55d33d2241bab4867e0bf6f7e9186a07 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:34:42 +0000 Subject: [PATCH 23/30] Simplify SigSpec::as_bit() --- kernel/rtlil.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2c08bb524..dc2983dd4 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5623,12 +5623,7 @@ RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const RTLIL::SigBit RTLIL::SigSpec::as_bit() const { cover("kernel.rtlil.sigspec.as_bit"); - - log_assert(width_ == 1); - if (packed()) - return RTLIL::SigBit(*chunks_.begin()); - else - return bits_[0]; + return RTLIL::SigBit(*this); } bool RTLIL::SigSpec::match(const char* pattern) const From dbb83549968edfa9320bd7b9b9aff8cd79092e89 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 13:42:53 +0000 Subject: [PATCH 24/30] Remove unnecessary pack() from SigSpec::extend_u0() --- kernel/rtlil.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index dc2983dd4..209c181d8 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5251,8 +5251,6 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { cover("kernel.rtlil.sigspec.extend_u0"); - pack(); - if (width_ > width) remove(width, width_ - width); From a1f7d6c9bf39e82426cb3d8cd875a17568589732 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 14:13:46 +0000 Subject: [PATCH 25/30] Use size() instead of direct access to width_ in many places --- kernel/rtlil.cc | 122 ++++++++++++++++++++++++++---------------------- kernel/rtlil.h | 16 +++---- 2 files changed, 73 insertions(+), 65 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 209c181d8..d78ccbc14 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4719,7 +4719,7 @@ void RTLIL::SigSpec::unpack() const cover("kernel.rtlil.sigspec.convert.unpack"); log_assert(that->bits_.empty()); - that->bits_.reserve(that->width_); + that->bits_.reserve(that->size()); for (auto &c : that->chunks_) for (int i = 0; i < c.width; i++) that->bits_.emplace_back(c, i); @@ -4783,8 +4783,8 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const { log_assert(other != NULL); - log_assert(width_ == other->width_); - log_assert(pattern.width_ == with.width_); + log_assert(size() == other->size()); + log_assert(pattern.size() == with.size()); pattern.unpack(); with.unpack(); @@ -4818,7 +4818,7 @@ void RTLIL::SigSpec::replace(const dict &rules, RT cover("kernel.rtlil.sigspec.replace_dict"); log_assert(other != NULL); - log_assert(width_ == other->width_); + log_assert(size() == other->size()); if (rules.empty()) return; unpack(); @@ -4843,7 +4843,7 @@ void RTLIL::SigSpec::replace(const std::map &rules cover("kernel.rtlil.sigspec.replace_map"); log_assert(other != NULL); - log_assert(width_ == other->width_); + log_assert(size() == other->size()); if (rules.empty()) return; unpack(); @@ -4878,7 +4878,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe unpack(); if (other != NULL) { - log_assert(width_ == other->width_); + log_assert(size() == other->size()); other->unpack(); } @@ -4924,7 +4924,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec unpack(); if (other != NULL) { - log_assert(width_ == other->width_); + log_assert(size() == other->size()); other->unpack(); } @@ -4952,7 +4952,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS unpack(); if (other != NULL) { - log_assert(width_ == other->width_); + log_assert(size() == other->size()); other->unpack(); } @@ -4980,7 +4980,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * unpack(); if (other != NULL) { - log_assert(width_ == other->width_); + log_assert(size() == other->size()); other->unpack(); } @@ -5005,7 +5005,7 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLI else cover("kernel.rtlil.sigspec.extract"); - log_assert(other == NULL || width_ == other->width_); + log_assert(other == NULL || size() == other->size()); RTLIL::SigSpec ret; std::vector bits_match = to_sigbit_vector(); @@ -5013,19 +5013,22 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLI for (auto& pattern_chunk : pattern.chunks()) { if (other) { std::vector bits_other = other->to_sigbit_vector(); - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && - bits_match[i].wire == pattern_chunk.wire && - bits_match[i].offset >= pattern_chunk.offset && - bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width) + int i = 0; + for (const RTLIL::SigBit &bit : bits_match) { + if (bit.wire && + bit.wire == pattern_chunk.wire && + bit.offset >= pattern_chunk.offset && + bit.offset < pattern_chunk.offset + pattern_chunk.width) ret.append(bits_other[i]); + ++i; + } } else { - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && - bits_match[i].wire == pattern_chunk.wire && - bits_match[i].offset >= pattern_chunk.offset && - bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width) - ret.append(bits_match[i]); + for (const RTLIL::SigBit &bit : bits_match) + if (bit.wire && + bit.wire == pattern_chunk.wire && + bit.offset >= pattern_chunk.offset && + bit.offset < pattern_chunk.offset + pattern_chunk.width) + ret.append(bit); } } @@ -5040,20 +5043,23 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const pool &pattern, const else cover("kernel.rtlil.sigspec.extract"); - log_assert(other == NULL || width_ == other->width_); + log_assert(other == NULL || size() == other->size()); std::vector bits_match = to_sigbit_vector(); RTLIL::SigSpec ret; if (other) { std::vector bits_other = other->to_sigbit_vector(); - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && pattern.count(bits_match[i])) + int i = 0; + for (const RTLIL::SigBit &bit : bits_match) { + if (bit.wire && pattern.count(bit)) ret.append(bits_other[i]); + ++i; + } } else { - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && pattern.count(bits_match[i])) - ret.append(bits_match[i]); + for (const RTLIL::SigBit &bit : bits_match) + if (bit.wire && pattern.count(bit)) + ret.append(bit); } ret.check(); @@ -5065,14 +5071,16 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) cover("kernel.rtlil.sigspec.replace_pos"); unpack(); - with.unpack(); log_assert(offset >= 0); - log_assert(with.width_ >= 0); - log_assert(offset+with.width_ <= width_); + log_assert(with.size() >= 0); + log_assert(offset+with.size() <= size()); - for (int i = 0; i < with.width_; i++) - bits_.at(offset + i) = with.bits_.at(i); + int i = 0; + for (const RTLIL::SigBit &bit : with.bits()) { + bits_.at(offset + i) = bit; + ++i; + } check(); } @@ -5127,7 +5135,7 @@ void RTLIL::SigSpec::remove(int offset, int length) log_assert(offset >= 0); log_assert(length >= 0); - log_assert(offset + length <= width_); + log_assert(offset + length <= size()); bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); width_ = bits_.size(); @@ -5139,7 +5147,7 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const { log_assert(offset >= 0); log_assert(length >= 0); - log_assert(offset + length <= width_); + log_assert(offset + length <= size()); cover("kernel.rtlil.sigspec.extract_pos"); @@ -5182,10 +5190,10 @@ void RTLIL::SigSpec::rewrite_wires(std::function rewri void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) { - if (signal.width_ == 0) + if (signal.size() == 0) return; - if (width_ == 0) { + if (size() == 0) { *this = signal; return; } @@ -5212,7 +5220,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); } - width_ += signal.width_; + width_ += signal.size(); check(); } @@ -5251,14 +5259,14 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { cover("kernel.rtlil.sigspec.extend_u0"); - if (width_ > width) - remove(width, width_ - width); + if (size() > width) + remove(width, size() - width); - if (width_ < width) { - RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx; + if (size() < width) { + RTLIL::SigBit padding = size() > 0 ? (*this)[size() - 1] : RTLIL::State::Sx; if (!is_signed) padding = RTLIL::State::S0; - while (width_ < width) + while (size() < width) append(padding); } @@ -5277,7 +5285,7 @@ RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const #ifndef NDEBUG void RTLIL::SigSpec::check(Module *mod) const { - if (width_ > 64) + if (size() > 64) { cover("kernel.rtlil.sigspec.check.skip"); } @@ -5306,7 +5314,7 @@ void RTLIL::SigSpec::check(Module *mod) const } w += chunk.width; } - log_assert(w == width_); + log_assert(w == size()); log_assert(bits_.empty()); } else @@ -5319,7 +5327,7 @@ void RTLIL::SigSpec::check(Module *mod) const log_assert(bits_[i].wire->module == mod); } - log_assert(width_ == GetSize(bits_)); + log_assert(size() == GetSize(bits_)); log_assert(chunks_.empty()); } } @@ -5332,8 +5340,8 @@ bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const if (this == &other) return false; - if (width_ != other.width_) - return width_ < other.width_; + if (size() != other.size()) + return size() < other.size(); auto other_it = other.chunks().begin(); for (const SigChunk &c : chunks()) { @@ -5353,7 +5361,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const if (this == &other) return true; - if (width_ != other.width_) + if (size() != other.size()) return false; auto other_it = other.chunks().begin(); @@ -5376,7 +5384,7 @@ bool RTLIL::SigSpec::is_wire() const if (it == cs.end()) return false; const RTLIL::SigChunk &chunk = *it; - return chunk.wire && chunk.wire->width == width_ && ++it == cs.end(); + return chunk.wire && chunk.wire->width == size() && ++it == cs.end(); } bool RTLIL::SigSpec::is_chunk() const @@ -5602,7 +5610,7 @@ RTLIL::Wire *RTLIL::SigSpec::as_wire() const auto it = cs.begin(); log_assert(it != cs.end()); RTLIL::SigChunk chunk = *it; - log_assert(++it == cs.end() && chunk.wire && chunk.wire->width == width_); + log_assert(++it == cs.end() && chunk.wire && chunk.wire->width == size()); return chunk.wire; } @@ -5691,7 +5699,7 @@ std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL unpack(); other.unpack(); - log_assert(width_ == other.width_); + log_assert(size() == other.size()); std::map new_map; for (int i = 0; i < width_; i++) @@ -5707,7 +5715,7 @@ dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S unpack(); other.unpack(); - log_assert(width_ == other.width_); + log_assert(size() == other.size()); dict new_map; new_map.reserve(size()); @@ -5837,13 +5845,13 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R { if (str == "0") { cover("kernel.rtlil.sigspec.parse.rhs_zeros"); - sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.width_); + sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.size()); return true; } if (str == "~0") { cover("kernel.rtlil.sigspec.parse.rhs_ones"); - sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.width_); + sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.size()); return true; } @@ -5851,7 +5859,7 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R char *p = (char*)str.c_str(), *endptr; long int val = strtol(p, &endptr, 10); if (endptr && endptr != p && *endptr == 0) { - sig = RTLIL::SigSpec(val, lhs.width_); + sig = RTLIL::SigSpec(val, lhs.size()); cover("kernel.rtlil.sigspec.parse.rhs_dec"); return true; } @@ -5859,8 +5867,8 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R if (!parse(sig, module, str)) return false; - if (sig.width_ > lhs.width_) - sig.remove(lhs.width_, sig.width_ - lhs.width_); + if (sig.size() > lhs.size()) + sig.remove(lhs.size(), sig.size() - lhs.size()); return true; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 31c643614..e166913bd 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1363,16 +1363,16 @@ public: inline const std::vector &bits() const { inline_unpack(); return bits_; } inline int size() const { return width_; } - inline bool empty() const { return width_ == 0; } + inline bool empty() const { return size() == 0; } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); } inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } - inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; } + inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = size(); return it; } inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; } - inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; } + inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = size(); return it; } void sort(); void sort_and_unify(); @@ -1404,12 +1404,12 @@ public: RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(const pool &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(int offset, int length = 1) const; - RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); } + RTLIL::SigSpec extract_end(int offset) const { return extract(offset, size() - offset); } void rewrite_wires(std::function rewrite); - RTLIL::SigBit lsb() const { log_assert(width_); return (*this)[0]; }; - RTLIL::SigBit msb() const { log_assert(width_); return (*this)[width_ - 1]; }; + RTLIL::SigBit lsb() const { log_assert(size()); return (*this)[0]; }; + RTLIL::SigBit msb() const { log_assert(size()); return (*this)[size() - 1]; }; void append(const RTLIL::SigSpec &signal); inline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); } @@ -1432,7 +1432,7 @@ public: bool is_wire() const; bool is_chunk() const; - inline bool is_bit() const { return width_ == 1; } + inline bool is_bit() const { return size() == 1; } bool known_driver() const; @@ -1491,7 +1491,7 @@ public: operator std::vector() const; operator std::vector() const { return bits(); } - const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } + const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; } [[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } From ab525643a7fec9858340869b642b0e7ded9f45e6 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 15:03:47 +0000 Subject: [PATCH 26/30] Don't reset the hash when unpacking, instead clear the hash whenever bits are modified --- kernel/rtlil.cc | 21 +++++++++++++++++++-- kernel/rtlil.h | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d78ccbc14..0dbb95699 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4725,7 +4725,6 @@ void RTLIL::SigSpec::unpack() const that->bits_.emplace_back(c, i); that->chunks_.clear(); - that->hash_ = 0; } void RTLIL::SigSpec::updhash() const @@ -4757,6 +4756,7 @@ void RTLIL::SigSpec::sort() unpack(); cover("kernel.rtlil.sigspec.sort"); std::sort(bits_.begin(), bits_.end()); + hash_ = 0; } void RTLIL::SigSpec::sort_and_unify() @@ -4773,6 +4773,7 @@ void RTLIL::SigSpec::sort_and_unify() unique_bits.erase(last, unique_bits.end()); *this = unique_bits; + hash_ = 0; } void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) @@ -4804,6 +4805,7 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec other->bits_[j] = with.bits_[it->second]; } } + other->hash_ = 0; other->check(); } @@ -4829,6 +4831,7 @@ void RTLIL::SigSpec::replace(const dict &rules, RT if (it != rules.end()) other->bits_[i] = it->second; } + other->hash_ = 0; other->check(); } @@ -4854,6 +4857,7 @@ void RTLIL::SigSpec::replace(const std::map &rules if (it != rules.end()) other->bits_[i] = it->second; } + other->hash_ = 0; other->check(); } @@ -4880,6 +4884,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe if (other != NULL) { log_assert(size() == other->size()); other->unpack(); + other->hash_ = 0; } for (int i = GetSize(bits_) - 1; i >= 0; i--) @@ -4899,6 +4904,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe break; } } + hash_ = 0; check(); } @@ -4926,6 +4932,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec if (other != NULL) { log_assert(size() == other->size()); other->unpack(); + other->hash_ = 0; } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4938,6 +4945,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec } } } + hash_ = 0; check(); } @@ -4954,6 +4962,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS if (other != NULL) { log_assert(size() == other->size()); other->unpack(); + other->hash_ = 0; } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4966,6 +4975,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS } } } + hash_ = 0; check(); } @@ -4982,6 +4992,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * if (other != NULL) { log_assert(size() == other->size()); other->unpack(); + other->hash_ = 0; } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4994,6 +5005,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * } } } + hash_ = 0; check(); } @@ -5081,6 +5093,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) bits_.at(offset + i) = bit; ++i; } + hash_ = 0; check(); } @@ -5124,6 +5137,7 @@ void RTLIL::SigSpec::remove_const() width_ = bits_.size(); } + hash_ = 0; check(); } @@ -5140,6 +5154,7 @@ void RTLIL::SigSpec::remove(int offset, int length) bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); width_ = bits_.size(); + hash_ = 0; check(); } @@ -5186,6 +5201,7 @@ void RTLIL::SigSpec::rewrite_wires(std::function rewri for (RTLIL::SigChunk &chunk : chunks_) if (chunk.wire != nullptr) rewrite(chunk.wire); + hash_ = 0; } void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) @@ -5221,6 +5237,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) } width_ += signal.size(); + hash_ = 0; check(); } @@ -5252,6 +5269,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) } width_++; + hash_ = 0; check(); } @@ -5269,7 +5287,6 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) while (size() < width) append(padding); } - } RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const diff --git a/kernel/rtlil.h b/kernel/rtlil.h index e166913bd..f22c3541c 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1365,7 +1365,7 @@ public: inline int size() const { return width_; } inline bool empty() const { return size() == 0; } - inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); } + inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } From 1af5d4f2db250f2ade63d23d91ed7074ebd42969 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 17:42:58 +0000 Subject: [PATCH 27/30] Use chunks iterator for SigSpec::extract() --- kernel/rtlil.cc | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 0dbb95699..500d1a7c1 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5166,33 +5166,27 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const cover("kernel.rtlil.sigspec.extract_pos"); - if (packed()) { - SigSpec extracted; - extracted.width_ = length; - - auto it = chunks_.begin(); - for (; offset; offset -= it->width, it++) { - if (offset < it->width) { - int chunk_length = min(it->width - offset, length); - extracted.chunks_.emplace_back(it->extract(offset, chunk_length)); - length -= chunk_length; - it++; - break; - } + SigSpec extracted; + Chunks cs = chunks(); + auto it = cs.begin(); + for (; offset; offset -= it->width, ++it) { + if (offset < it->width) { + int chunk_length = min(it->width - offset, length); + extracted.append(it->extract(offset, chunk_length)); + length -= chunk_length; + ++it; + break; } - for (; length; length -= it->width, it++) { - if (length >= it->width) { - extracted.chunks_.emplace_back(*it); - } else { - extracted.chunks_.emplace_back(it->extract(0, length)); - break; - } - } - - return extracted; - } else { - return std::vector(bits_.begin() + offset, bits_.begin() + offset + length); } + for (; length; length -= it->width, ++it) { + if (length >= it->width) { + extracted.append(*it); + } else { + extracted.append(it->extract(0, length)); + break; + } + } + return extracted; } void RTLIL::SigSpec::rewrite_wires(std::function rewrite) From 9a2fd4c31b4f76cde0657a0246b381413695cf6f Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 15:02:39 +0000 Subject: [PATCH 28/30] Switch the SigSpec packed representation to allow just a single chunk that's inline in the SigSpec. Single-chunk SigSpecs are very common and this avoids a heap allocation. It also simplifies some algorithms. --- kernel/rtlil.cc | 363 +++++++++++++++++++----------------------------- kernel/rtlil.h | 88 +++++++++--- 2 files changed, 208 insertions(+), 243 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 500d1a7c1..9dadf7ccb 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4448,9 +4448,7 @@ RTLIL::SigSpec::SigSpec(std::initializer_list parts) { cover("kernel.rtlil.sigspec.init.list"); - width_ = 0; - hash_ = 0; - + init_empty_bits(); log_assert(parts.size() > 0); auto ie = parts.begin(); auto it = ie + parts.size() - 1; @@ -4463,12 +4461,11 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) cover("kernel.rtlil.sigspec.init.const"); if (GetSize(value) != 0) { - chunks_.emplace_back(value); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(value); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4477,12 +4474,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) cover("kernel.rtlil.sigspec.init.const.move"); if (GetSize(value) != 0) { - chunks_.emplace_back(std::move(value)); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(value); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4491,12 +4487,11 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) cover("kernel.rtlil.sigspec.init.chunk"); if (chunk.width != 0) { - chunks_.emplace_back(chunk); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(chunk); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4505,12 +4500,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) cover("kernel.rtlil.sigspec.init.chunk.move"); if (chunk.width != 0) { - chunks_.emplace_back(std::move(chunk)); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(chunk); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4519,12 +4513,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) cover("kernel.rtlil.sigspec.init.wire"); if (wire->width != 0) { - chunks_.emplace_back(wire); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(wire); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4533,12 +4526,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) cover("kernel.rtlil.sigspec.init.wire_part"); if (width != 0) { - chunks_.emplace_back(wire, offset, width); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(wire, offset, width); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4547,12 +4539,11 @@ RTLIL::SigSpec::SigSpec(const std::string &str) cover("kernel.rtlil.sigspec.init.str"); if (str.size() != 0) { - chunks_.emplace_back(str); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(str); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4560,10 +4551,11 @@ RTLIL::SigSpec::SigSpec(int val, int width) { cover("kernel.rtlil.sigspec.init.int"); - if (width != 0) - chunks_.emplace_back(val, width); - width_ = width; - hash_ = 0; + if (width != 0) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(val, width); + } else + init_empty_bits(); check(); } @@ -4571,10 +4563,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) { cover("kernel.rtlil.sigspec.init.state"); - if (width != 0) - chunks_.emplace_back(bit, width); - width_ = width; - hash_ = 0; + if (width != 0) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit, width); + } else + init_empty_bits(); check(); } @@ -4583,14 +4576,20 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width) cover("kernel.rtlil.sigspec.init.bit"); if (width != 0) { - if (bit.wire == NULL) - chunks_.emplace_back(bit.data, width); - else + if (bit.wire == NULL) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit.data, width); + } else if (width == 1) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit); + } else { + init_empty_bits(); + bits_.reserve(width); for (int i = 0; i < width; i++) - chunks_.push_back(bit); - } - width_ = width; - hash_ = 0; + bits_.push_back(bit); + } + } else + init_empty_bits(); check(); } @@ -4598,8 +4597,7 @@ RTLIL::SigSpec::SigSpec(const std::vector &chunks) { cover("kernel.rtlil.sigspec.init.stdvec_chunks"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &c : chunks) append(c); check(); @@ -4609,8 +4607,7 @@ RTLIL::SigSpec::SigSpec(const std::vector &bits) { cover("kernel.rtlil.sigspec.init.stdvec_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4620,8 +4617,7 @@ RTLIL::SigSpec::SigSpec(const pool &bits) { cover("kernel.rtlil.sigspec.init.pool_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4631,8 +4627,7 @@ RTLIL::SigSpec::SigSpec(const std::set &bits) { cover("kernel.rtlil.sigspec.init.stdset_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4642,9 +4637,8 @@ RTLIL::SigSpec::SigSpec(bool bit) { cover("kernel.rtlil.sigspec.init.bool"); - width_ = 0; - hash_ = 0; - append(SigBit(bit)); + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit ? RTLIL::S1 : RTLIL::S0); check(); } @@ -4673,58 +4667,23 @@ void RTLIL::SigSpec::Chunks::const_iterator::next_chunk_bits() chunk.width = i - bit_index; } -void RTLIL::SigSpec::pack() const -{ - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->bits_.empty()) - return; - - cover("kernel.rtlil.sigspec.convert.pack"); - log_assert(that->chunks_.empty()); - - std::vector old_bits; - old_bits.swap(that->bits_); - - RTLIL::SigChunk *last = NULL; - int last_end_offset = 0; - - for (auto &bit : old_bits) { - if (last && bit.wire == last->wire) { - if (bit.wire == NULL) { - last->data.push_back(bit.data); - last->width++; - continue; - } else if (last_end_offset == bit.offset) { - last_end_offset++; - last->width++; - continue; - } - } - that->chunks_.push_back(bit); - last = &that->chunks_.back(); - last_end_offset = bit.offset + 1; - } - - check(); -} - void RTLIL::SigSpec::unpack() const { - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->chunks_.empty()) + if (rep_ == BITS) return; + RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; + cover("kernel.rtlil.sigspec.convert.unpack"); - log_assert(that->bits_.empty()); - that->bits_.reserve(that->size()); - for (auto &c : that->chunks_) - for (int i = 0; i < c.width; i++) - that->bits_.emplace_back(c, i); + std::vector bits; + bits.reserve(that->chunk_.width); + for (int i = 0; i < that->chunk_.width; i++) + bits.emplace_back(that->chunk_, i); - that->chunks_.clear(); + that->chunk_.~SigChunk(); + that->rep_ = BITS; + new (&that->bits_) std::vector(std::move(bits)); } void RTLIL::SigSpec::updhash() const @@ -4896,11 +4855,8 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe bits_[i].offset >= pattern_chunk.offset && bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } break; } } @@ -4938,11 +4894,8 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -4968,11 +4921,8 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -4998,11 +4948,8 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i].wire)) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -5100,41 +5047,27 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) void RTLIL::SigSpec::remove_const() { - if (packed()) + if (rep_ == CHUNK) { cover("kernel.rtlil.sigspec.remove_const.packed"); - std::vector new_chunks; - new_chunks.reserve(GetSize(chunks_)); - - width_ = 0; - for (auto &chunk : chunks_) - if (chunk.wire != NULL) { - if (!new_chunks.empty() && - new_chunks.back().wire == chunk.wire && - new_chunks.back().offset + new_chunks.back().width == chunk.offset) { - new_chunks.back().width += chunk.width; - } else { - new_chunks.push_back(chunk); - } - width_ += chunk.width; - } - - chunks_.swap(new_chunks); + if (chunk_.wire == NULL) { + chunk_.~SigChunk(); + init_empty_bits(); + } } else { cover("kernel.rtlil.sigspec.remove_const.unpacked"); std::vector new_bits; - new_bits.reserve(width_); + new_bits.reserve(bits_.size()); for (auto &bit : bits_) if (bit.wire != NULL) new_bits.push_back(bit); bits_.swap(new_bits); - width_ = bits_.size(); } hash_ = 0; @@ -5152,7 +5085,6 @@ void RTLIL::SigSpec::remove(int offset, int length) log_assert(offset + length <= size()); bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); - width_ = bits_.size(); hash_ = 0; check(); @@ -5191,10 +5123,21 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const void RTLIL::SigSpec::rewrite_wires(std::function rewrite) { - pack(); - for (RTLIL::SigChunk &chunk : chunks_) - if (chunk.wire != nullptr) - rewrite(chunk.wire); + if (rep_ == CHUNK) { + if (chunk_.wire != nullptr) + rewrite(chunk_.wire); + return; + } + + std::vector new_bits; + for (const RTLIL::SigChunk &chunk : chunks()) { + RTLIL::SigChunk c = chunk; + if (c.wire != nullptr) + rewrite(c.wire); + for (int i = 0; i < c.width; i++) + new_bits.emplace_back(c, i); + } + bits_ = std::move(new_bits); hash_ = 0; } @@ -5210,60 +5153,54 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) cover("kernel.rtlil.sigspec.append"); - if (packed()) - for (auto &other_c : signal.chunks()) - { - auto &my_last_c = chunks_.back(); - if (my_last_c.wire == NULL && other_c.wire == NULL) { - auto &this_data = my_last_c.data; - auto &other_data = other_c.data; - this_data.insert(this_data.end(), other_data.begin(), other_data.end()); - my_last_c.width += other_c.width; - } else - if (my_last_c.wire == other_c.wire && my_last_c.offset + my_last_c.width == other_c.offset) { - my_last_c.width += other_c.width; - } else - chunks_.push_back(other_c); + hash_ = 0; + if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) { + if (chunk_.wire == NULL) { + chunk_.data.insert(chunk_.data.end(), signal.chunk_.data.begin(), signal.chunk_.data.end()); + chunk_.width = GetSize(chunk_.data); + return; + } + if (chunk_.offset + chunk_.width == signal.chunk_.offset) { + chunk_.width += signal.chunk_.width; + return; } - else { - signal.unpack(); - bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); } - width_ += signal.size(); - hash_ = 0; + unpack(); + for (const SigBit &bit : signal.bits()) + bits_.push_back(bit); check(); } void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) { - if (packed()) - { + hash_ = 0; + + if (size() == 0) { + destroy(); + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit); + return; + } + + if (rep_ == CHUNK && chunk_.wire == bit.wire) { cover("kernel.rtlil.sigspec.append_bit.packed"); - if (chunks_.size() == 0) - chunks_.push_back(bit); - else - if (bit.wire == NULL) - if (chunks_.back().wire == NULL) { - chunks_.back().data.push_back(bit.data); - chunks_.back().width++; - } else - chunks_.push_back(bit); - else - if (chunks_.back().wire == bit.wire && chunks_.back().offset + chunks_.back().width == bit.offset) - chunks_.back().width++; - else - chunks_.push_back(bit); - } - else - { - cover("kernel.rtlil.sigspec.append_bit.unpacked"); - bits_.push_back(bit); + if (chunk_.wire == NULL) { + chunk_.data.push_back(bit.data); + chunk_.width++; + return; + } + if (chunk_.offset + chunk_.width == bit.offset) { + chunk_.width++; + return; + } } - width_++; - hash_ = 0; + unpack(); + + cover("kernel.rtlil.sigspec.append_bit.unpacked"); + bits_.push_back(bit); check(); } @@ -5296,50 +5233,36 @@ RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const #ifndef NDEBUG void RTLIL::SigSpec::check(Module *mod) const { - if (size() > 64) - { - cover("kernel.rtlil.sigspec.check.skip"); - } - else if (packed()) + if (rep_ == CHUNK) { cover("kernel.rtlil.sigspec.check.packed"); - int w = 0; - for (size_t i = 0; i < chunks_.size(); i++) { - const RTLIL::SigChunk &chunk = chunks_[i]; - log_assert(chunk.width != 0); - if (chunk.wire == NULL) { - if (i > 0) - log_assert(chunks_[i-1].wire != NULL); - log_assert(chunk.offset == 0); - log_assert(chunk.data.size() == (size_t)chunk.width); - } else { - if (i > 0 && chunks_[i-1].wire == chunk.wire) - log_assert(chunk.offset != chunks_[i-1].offset + chunks_[i-1].width); - log_assert(chunk.offset >= 0); - log_assert(chunk.width >= 0); - log_assert(chunk.offset + chunk.width <= chunk.wire->width); - log_assert(chunk.data.size() == 0); - if (mod != nullptr) - log_assert(chunk.wire->module == mod); - } - w += chunk.width; + log_assert(chunk_.width != 0); + if (chunk_.wire == NULL) { + log_assert(chunk_.offset == 0); + log_assert(chunk_.data.size() == (size_t)chunk_.width); + } else { + log_assert(chunk_.offset >= 0); + log_assert(chunk_.width >= 0); + log_assert(chunk_.offset + chunk_.width <= chunk_.wire->width); + log_assert(chunk_.data.size() == 0); + if (mod != nullptr) + log_assert(chunk_.wire->module == mod); } - log_assert(w == size()); - log_assert(bits_.empty()); + } + else if (size() > 64) + { + cover("kernel.rtlil.sigspec.check.skip"); } else { cover("kernel.rtlil.sigspec.check.unpacked"); if (mod != nullptr) { - for (size_t i = 0; i < bits_.size(); i++) - if (bits_[i].wire != nullptr) - log_assert(bits_[i].wire->module == mod); + for (const RTLIL::SigBit &bit : bits_) + if (bit.wire != nullptr) + log_assert(bit.wire->module == mod); } - - log_assert(size() == GetSize(bits_)); - log_assert(chunks_.empty()); } } #endif @@ -5713,7 +5636,7 @@ std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL log_assert(size() == other.size()); std::map new_map; - for (int i = 0; i < width_; i++) + for (int i = 0; i < GetSize(bits_); i++) new_map[bits_[i]] = other.bits_[i]; return new_map; @@ -5730,7 +5653,7 @@ dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S dict new_map; new_map.reserve(size()); - for (int i = 0; i < width_; i++) + for (int i = 0; i < GetSize(bits_); i++) new_map[bits_[i]] = other.bits_[i]; return new_map; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f22c3541c..1265875e3 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1233,29 +1233,53 @@ struct RTLIL::SigSpecConstIterator struct RTLIL::SigSpec { private: - int width_; - Hasher::hash_t hash_; - std::vector chunks_; // LSB at index 0 - std::vector bits_; // LSB at index 0 + enum Representation : char { + CHUNK, + BITS, + }; - void pack() const; - void unpack() const; - void updhash() const; + Representation rep_; + Hasher::hash_t hash_ = 0; + union { + RTLIL::SigChunk chunk_; + std::vector bits_; // LSB at index 0 + }; - inline bool packed() const { - return bits_.empty(); + void init_empty_bits() { + rep_ = BITS; + new (&bits_) std::vector; } + void unpack() const; inline void inline_unpack() const { - if (!chunks_.empty()) + if (rep_ == CHUNK) unpack(); } + void updhash() const; + void destroy() { + if (rep_ == CHUNK) + chunk_.~SigChunk(); + else + bits_.~vector(); + } + friend struct Chunks; + public: - SigSpec() : width_(0), hash_(0) {} + SigSpec() { init_empty_bits(); } SigSpec(std::initializer_list parts); - SigSpec(const SigSpec &value) = default; - SigSpec(SigSpec &&value) = default; + SigSpec(const SigSpec &value) : rep_(value.rep_), hash_(value.hash_) { + if (value.rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(value.chunk_); + else + new (&bits_) std::vector(value.bits_); + } + SigSpec(SigSpec &&value) : rep_(value.rep_), hash_(value.hash_) { + if (value.rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(std::move(value.chunk_)); + else + new (&bits_) std::vector(std::move(value.bits_)); + } SigSpec(const RTLIL::Const &value); SigSpec(RTLIL::Const &&value); SigSpec(const RTLIL::SigChunk &chunk); @@ -1271,9 +1295,30 @@ public: SigSpec(const pool &bits); SigSpec(const std::set &bits); explicit SigSpec(bool bit); + ~SigSpec() { + destroy(); + } - SigSpec &operator=(const SigSpec &rhs) = default; - SigSpec &operator=(SigSpec &&rhs) = default; + SigSpec &operator=(const SigSpec &rhs) { + destroy(); + rep_ = rhs.rep_; + hash_ = rhs.hash_; + if (rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(rhs.chunk_); + else + new (&bits_) std::vector(rhs.bits_); + return *this; + } + SigSpec &operator=(SigSpec &&rhs) { + destroy(); + rep_ = rhs.rep_; + hash_ = rhs.hash_; + if (rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(std::move(rhs.chunk_)); + else + new (&bits_) std::vector(std::move(rhs.bits_)); + return *this; + } struct Chunks { Chunks(const SigSpec &spec) : spec(spec) {} @@ -1285,28 +1330,25 @@ public: using reference = const SigChunk &; const SigSpec &spec; - int chunk_index; int bit_index; SigChunk chunk; const_iterator(const SigSpec &spec) : spec(spec) { - chunk_index = 0; bit_index = 0; - if (!spec.packed()) + if (spec.rep_ == BITS) next_chunk_bits(); } void next_chunk_bits(); const SigChunk &operator*() { - if (spec.packed()) - return spec.chunks_[chunk_index]; + if (spec.rep_ == CHUNK) + return spec.chunk_; return chunk; }; const SigChunk *operator->() { return &**this; } const_iterator &operator++() { bit_index += (**this).width; - ++chunk_index; - if (!spec.packed()) + if (spec.rep_ == BITS) next_chunk_bits(); return *this; } @@ -1362,7 +1404,7 @@ public: inline Chunks chunks() const { return {*this}; } inline const std::vector &bits() const { inline_unpack(); return bits_; } - inline int size() const { return width_; } + inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); } inline bool empty() const { return size() == 0; } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } From 45017e19ec8498285835a83d0c55eac38506e5a1 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 31 Oct 2025 10:06:13 +0000 Subject: [PATCH 29/30] Make SigSpec::unpack() non-const --- kernel/rtlil.cc | 108 ++++++++++++++++++++++-------------------------- kernel/rtlil.h | 29 +++++++++---- 2 files changed, 71 insertions(+), 66 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 9dadf7ccb..5f36ab4e5 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4667,23 +4667,21 @@ void RTLIL::SigSpec::Chunks::const_iterator::next_chunk_bits() chunk.width = i - bit_index; } -void RTLIL::SigSpec::unpack() const +void RTLIL::SigSpec::unpack() { if (rep_ == BITS) return; - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - cover("kernel.rtlil.sigspec.convert.unpack"); std::vector bits; - bits.reserve(that->chunk_.width); - for (int i = 0; i < that->chunk_.width; i++) - bits.emplace_back(that->chunk_, i); + bits.reserve(chunk_.width); + for (int i = 0; i < chunk_.width; i++) + bits.emplace_back(chunk_, i); - that->chunk_.~SigChunk(); - that->rep_ = BITS; - new (&that->bits_) std::vector(std::move(bits)); + chunk_.~SigChunk(); + rep_ = BITS; + new (&bits_) std::vector(std::move(bits)); } void RTLIL::SigSpec::updhash() const @@ -4746,25 +4744,22 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec log_assert(size() == other->size()); log_assert(pattern.size() == with.size()); - pattern.unpack(); - with.unpack(); - unpack(); - other->unpack(); - dict pattern_to_with; - for (int i = 0; i < GetSize(pattern.bits_); i++) { - if (pattern.bits_[i].wire != NULL) { - pattern_to_with.emplace(pattern.bits_[i], i); + int pattern_size = pattern.size(); + for (int i = 0; i < pattern_size; i++) { + SigBit pattern_bit = pattern[i]; + if (pattern_bit.wire != NULL) { + pattern_to_with.emplace(pattern_bit, i); } } - for (int j = 0; j < GetSize(bits_); j++) { - auto it = pattern_to_with.find(bits_[j]); + int this_size = size(); + for (int j = 0; j < this_size; j++) { + auto it = pattern_to_with.find((*this)[j]); if (it != pattern_to_with.end()) { - other->bits_[j] = with.bits_[it->second]; + (*other)[j] = with[it->second]; } } - other->hash_ = 0; other->check(); } @@ -4782,15 +4777,13 @@ void RTLIL::SigSpec::replace(const dict &rules, RT log_assert(size() == other->size()); if (rules.empty()) return; - unpack(); - other->unpack(); - for (int i = 0; i < GetSize(bits_); i++) { - auto it = rules.find(bits_[i]); + int this_size = size(); + for (int i = 0; i < this_size; i++) { + auto it = rules.find((*this)[i]); if (it != rules.end()) - other->bits_[i] = it->second; + (*other)[i] = it->second; } - other->hash_ = 0; other->check(); } @@ -4808,15 +4801,13 @@ void RTLIL::SigSpec::replace(const std::map &rules log_assert(size() == other->size()); if (rules.empty()) return; - unpack(); - other->unpack(); - for (int i = 0; i < GetSize(bits_); i++) { - auto it = rules.find(bits_[i]); + int this_size = size(); + for (int i = 0; i < this_size; i++) { + auto it = rules.find((*this)[i]); if (it != rules.end()) - other->bits_[i] = it->second; + (*other)[i] = it->second; } - other->hash_ = 0; other->check(); } @@ -5570,23 +5561,25 @@ bool RTLIL::SigSpec::match(const char* pattern) const { cover("kernel.rtlil.sigspec.match"); - unpack(); - log_assert(int(strlen(pattern)) == GetSize(bits_)); + int pattern_len = strlen(pattern); + log_assert(pattern_len == size()); - for (auto it = bits_.rbegin(); it != bits_.rend(); it++, pattern++) { - if (*pattern == ' ') + for (int i = 0; i < pattern_len; ++i) { + char ch = pattern[i]; + if (ch == ' ') continue; - if (*pattern == '*') { - if (*it != State::Sz && *it != State::Sx) + RTLIL::SigBit bit = (*this)[pattern_len - 1 - i]; + if (ch == '*') { + if (bit != State::Sz && bit != State::Sx) return false; continue; } - if (*pattern == '0') { - if (*it != State::S0) + if (ch == '0') { + if (bit != State::S0) return false; } else - if (*pattern == '1') { - if (*it != State::S1) + if (ch == '1') { + if (bit != State::S1) return false; } else log_abort(); @@ -5622,22 +5615,23 @@ std::vector RTLIL::SigSpec::to_sigbit_vector() const { cover("kernel.rtlil.sigspec.to_sigbit_vector"); - unpack(); - return bits_; + std::vector result; + result.reserve(size()); + for (SigBit bit : *this) + result.push_back(bit); + return result; } std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL::SigSpec &other) const { cover("kernel.rtlil.sigspec.to_sigbit_map"); - unpack(); - other.unpack(); - - log_assert(size() == other.size()); + int this_size = size(); + log_assert(this_size == other.size()); std::map new_map; - for (int i = 0; i < GetSize(bits_); i++) - new_map[bits_[i]] = other.bits_[i]; + for (int i = 0; i < this_size; i++) + new_map[(*this)[i]] = other[i]; return new_map; } @@ -5646,15 +5640,13 @@ dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S { cover("kernel.rtlil.sigspec.to_sigbit_dict"); - unpack(); - other.unpack(); - - log_assert(size() == other.size()); + int this_size = size(); + log_assert(this_size == other.size()); dict new_map; - new_map.reserve(size()); - for (int i = 0; i < GetSize(bits_); i++) - new_map[bits_[i]] = other.bits_[i]; + new_map.reserve(this_size); + for (int i = 0; i < this_size; i++) + new_map[(*this)[i]] = other[i]; return new_map; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 1265875e3..4e21cbe1e 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1222,9 +1222,10 @@ struct RTLIL::SigSpecConstIterator typedef RTLIL::SigBit& reference; const RTLIL::SigSpec *sig_p; + RTLIL::SigBit bit; int index; - inline const RTLIL::SigBit &operator*() const; + inline const RTLIL::SigBit &operator*(); inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; } inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; } inline void operator++() { index++; } @@ -1250,8 +1251,8 @@ private: new (&bits_) std::vector; } - void unpack() const; - inline void inline_unpack() const { + void unpack(); + inline void inline_unpack() { if (rep_ == CHUNK) unpack(); } @@ -1402,13 +1403,22 @@ public: friend struct Chunks::const_iterator; inline Chunks chunks() const { return {*this}; } - inline const std::vector &bits() const { inline_unpack(); return bits_; } + inline const SigSpec &bits() const { return *this; } inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); } inline bool empty() const { return size() == 0; } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } - inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } + inline RTLIL::SigBit operator[](int index) const { + if (rep_ == CHUNK) { + if (index < 0 || index >= chunk_.width) + throw std::out_of_range("SigSpec::operator[]"); + if (chunk_.wire) + return RTLIL::SigBit(chunk_.wire, chunk_.offset + index); + return RTLIL::SigBit(chunk_.data[index]); + } + return bits_.at(index); + } inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = size(); return it; } @@ -1452,6 +1462,8 @@ public: RTLIL::SigBit lsb() const { log_assert(size()); return (*this)[0]; }; RTLIL::SigBit msb() const { log_assert(size()); return (*this)[size() - 1]; }; + RTLIL::SigBit front() const { return (*this)[0]; } + RTLIL::SigBit back() const { return (*this)[size() - 1]; } void append(const RTLIL::SigSpec &signal); inline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); } @@ -1532,7 +1544,7 @@ public: static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); operator std::vector() const; - operator std::vector() const { return bits(); } + operator std::vector() const { return to_sigbit_vector(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; } [[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } @@ -2439,8 +2451,9 @@ inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const { return (*sig_p)[index]; } -inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const { - return (*sig_p)[index]; +inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() { + bit = (*sig_p)[index]; + return bit; } inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) { From 0d3cd5d6c89169e143ea23c3cb0b7ab5b79e81c3 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 31 Oct 2025 10:48:39 +0000 Subject: [PATCH 30/30] Implement SigSpec::updhash() using a relaxed atomic for thread-safety --- kernel/rtlil.cc | 49 +++++++++++++++++++++++-------------------------- kernel/rtlil.h | 48 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 31 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 5f36ab4e5..75e7c9d72 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4684,17 +4684,12 @@ void RTLIL::SigSpec::unpack() new (&bits_) std::vector(std::move(bits)); } -void RTLIL::SigSpec::updhash() const +Hasher::hash_t RTLIL::SigSpec::updhash() const { - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->hash_ != 0) - return; - cover("kernel.rtlil.sigspec.hash"); Hasher h; - for (auto &c : that->chunks()) + for (auto &c : chunks()) if (c.wire == NULL) { for (auto &v : c.data) h.eat(v); @@ -4703,9 +4698,11 @@ void RTLIL::SigSpec::updhash() const h.eat(c.offset); h.eat(c.width); } - that->hash_ = h.yield(); - if (that->hash_ == 0) - that->hash_ = 1; + Hasher::hash_t result = h.yield(); + if (result == 0) + result = 1; + hash_.set(result); + return result; } void RTLIL::SigSpec::sort() @@ -4713,7 +4710,7 @@ void RTLIL::SigSpec::sort() unpack(); cover("kernel.rtlil.sigspec.sort"); std::sort(bits_.begin(), bits_.end()); - hash_ = 0; + hash_.clear(); } void RTLIL::SigSpec::sort_and_unify() @@ -4730,7 +4727,7 @@ void RTLIL::SigSpec::sort_and_unify() unique_bits.erase(last, unique_bits.end()); *this = unique_bits; - hash_ = 0; + hash_.clear(); } void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) @@ -4834,7 +4831,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_ = 0; + other->hash_.clear(); } for (int i = GetSize(bits_) - 1; i >= 0; i--) @@ -4851,7 +4848,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe break; } } - hash_ = 0; + hash_.clear(); check(); } @@ -4879,7 +4876,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_ = 0; + other->hash_.clear(); } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4889,7 +4886,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -4906,7 +4903,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_ = 0; + other->hash_.clear(); } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4916,7 +4913,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -4933,7 +4930,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_ = 0; + other->hash_.clear(); } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4943,7 +4940,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -5031,7 +5028,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) bits_.at(offset + i) = bit; ++i; } - hash_ = 0; + hash_.clear(); check(); } @@ -5061,7 +5058,7 @@ void RTLIL::SigSpec::remove_const() bits_.swap(new_bits); } - hash_ = 0; + hash_.clear(); check(); } @@ -5077,7 +5074,7 @@ void RTLIL::SigSpec::remove(int offset, int length) bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); - hash_ = 0; + hash_.clear(); check(); } @@ -5129,7 +5126,7 @@ void RTLIL::SigSpec::rewrite_wires(std::function rewri new_bits.emplace_back(c, i); } bits_ = std::move(new_bits); - hash_ = 0; + hash_.clear(); } void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) @@ -5144,7 +5141,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) cover("kernel.rtlil.sigspec.append"); - hash_ = 0; + hash_.clear(); if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) { if (chunk_.wire == NULL) { chunk_.data.insert(chunk_.data.end(), signal.chunk_.data.begin(), signal.chunk_.data.end()); @@ -5165,7 +5162,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) { - hash_ = 0; + hash_.clear(); if (size() == 0) { destroy(); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 4e21cbe1e..454945536 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1238,9 +1238,39 @@ private: CHUNK, BITS, }; + // An AtomicHash is either clear or a nonzero integer. + struct AtomicHash { + // Create an initially clear value. + AtomicHash() : atomic_(0) {} + AtomicHash(const AtomicHash &rhs) : atomic_(rhs.load()) {} + AtomicHash &operator=(const AtomicHash &rhs) { store(rhs.load()); return *this; } + // Read the hash. Returns nullopt if the hash is clear. + std::optional read() const { + Hasher::hash_t value = load(); + if (value == 0) + return std::nullopt; + return value; + } + // Set the hash. If the value is already set, then the new value must + // equal the current value. + void set(Hasher::hash_t value) const { + log_assert(value != 0); + Hasher::hash_t old = const_cast&>(atomic_) + .exchange(value, std::memory_order_relaxed); + log_assert(old == 0 || old == value); + } + void clear() { store(0); } + private: + int load() const { return atomic_.load(std::memory_order_relaxed); } + void store(Hasher::hash_t value) const { + const_cast&>(atomic_).store(value, std::memory_order_relaxed); + } + + std::atomic atomic_; + }; Representation rep_; - Hasher::hash_t hash_ = 0; + AtomicHash hash_; union { RTLIL::SigChunk chunk_; std::vector bits_; // LSB at index 0 @@ -1257,7 +1287,7 @@ private: unpack(); } - void updhash() const; + Hasher::hash_t updhash() const; void destroy() { if (rep_ == CHUNK) chunk_.~SigChunk(); @@ -1406,9 +1436,9 @@ public: inline const SigSpec &bits() const { return *this; } inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); } - inline bool empty() const { return size() == 0; } + inline bool empty() const { return size() == 0; }; - inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } + inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_.clear(); return bits_.at(index); } inline RTLIL::SigBit operator[](int index) const { if (rep_ == CHUNK) { if (index < 0 || index >= chunk_.width) @@ -1547,7 +1577,15 @@ public: operator std::vector() const { return to_sigbit_vector(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; } - [[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { + Hasher::hash_t val; + if (std::optional current = hash_.read()) + val = *current; + else + val = updhash(); + h.eat(val); + return h; + } #ifndef NDEBUG void check(Module *mod = nullptr) const;