From 8d4f790951b237eeb4871f719d4f72ab385797ec Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 12:41:50 +0000 Subject: [PATCH 01/34] 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 adfda7d5f..1d0d45197 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) { @@ -5159,6 +5156,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 7e699b365..77b434e1d 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1252,10 +1252,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); @@ -1327,6 +1323,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 3f7af10edae8d4a5b633b984a4b30bac33cd540f Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 15:46:36 +0000 Subject: [PATCH 02/34] Make SigSpec::chunks() return an object that can be iterated over without packing the SigSpec --- kernel/rtlil.cc | 25 ++++++++++++ kernel/rtlil.h | 80 ++++++++++++++++++++++++++++++++++++-- passes/cmds/show.cc | 7 ++-- passes/techmap/abc9_ops.cc | 4 +- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1d0d45197..0991b9709 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4656,6 +4656,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 77b434e1d..8e93f5f05 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1276,7 +1276,78 @@ 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(); + } + enum End { END }; + const_iterator(const SigSpec &spec, End) : spec(spec) { + bit_index = spec.size(); + } + 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, const_iterator::END); + 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_; } @@ -1403,7 +1474,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; } @@ -2317,8 +2388,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 fc7d61132d9c95d6c07ba00b0019cd66797b49b0 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:35:47 +0000 Subject: [PATCH 03/34] 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 0991b9709..e7330842f 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4744,10 +4744,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); @@ -5201,13 +5200,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) { @@ -5221,8 +5215,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 b0ee67a3557568bfd4adc9f254972ba047ac8947 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:12 +0000 Subject: [PATCH 04/34] 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 e7330842f..38b798052 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5409,22 +5409,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 a7ac396fd9f971c240a842d88e5c1162e120ea40 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:36 +0000 Subject: [PATCH 05/34] 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 38b798052..d3030831e 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5440,9 +5440,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 ddd04e13e087167bb3425dc3f256ea78836b18c7 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:47 +0000 Subject: [PATCH 06/34] 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 d3030831e..f91ca821c 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5450,12 +5450,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 152a487cc8df50b0ef612c24abd614000807d20d Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:58 +0000 Subject: [PATCH 07/34] 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 f91ca821c..3183cb7bc 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5464,12 +5464,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 e2defe78982562c09ba9e9a1b19511342dbe9b66 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:08 +0000 Subject: [PATCH 08/34] 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 3183cb7bc..9fb8098ba 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5478,12 +5478,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 1893c61fe29aae7e31925ba01849e482925adff2 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:17 +0000 Subject: [PATCH 09/34] 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 9fb8098ba..70fd14856 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5492,12 +5492,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 ed8022f53faaade7e8f5ebccf5d69f765f2351b0 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:38 +0000 Subject: [PATCH 10/34] 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 70fd14856..cfc841b9f 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5506,9 +5506,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 80b3efb3dabba0d8ef76b6014f622af943ba0906 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:51 +0000 Subject: [PATCH 11/34] 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 cfc841b9f..979f115be 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5516,9 +5516,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 0091d14e6d35cd7987195028b7bd56397cf52208 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:38:03 +0000 Subject: [PATCH 12/34] 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 979f115be..2647e4876 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5527,11 +5527,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 0281ed1458e5e43d845b031236b73bc435c47430 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 15:48:24 +0000 Subject: [PATCH 13/34] 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 2647e4876..a2e766a9b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5629,33 +5629,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 8e93f5f05..5bc60d1e9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1457,6 +1457,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 ce597dc38c8b47a2ba3a83460fdc2c0d8b4cfbda Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:59:57 +0000 Subject: [PATCH 14/34] 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 a2e766a9b..68cc596fc 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5633,11 +5633,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)); } @@ -5655,10 +5656,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; } @@ -5666,10 +5668,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 dd3940c8bb8a771e3d067c34d7e0f9b7a216f31d Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:39:31 +0000 Subject: [PATCH 15/34] 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 68cc596fc..4b27c95c2 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5540,12 +5540,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 39b89aae88e05a429f073b6a9b8e4824296b289e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:39:53 +0000 Subject: [PATCH 16/34] 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 4b27c95c2..a87161465 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5549,74 +5549,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 4ed25c05382d5fe481c992d1187b74a69998a6f5 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:08 +0000 Subject: [PATCH 17/34] 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 a87161465..2aa85f6fb 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5700,9 +5700,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 62cd3ddfb898d8c867a19fb6e19587e77f05f3fd Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:20 +0000 Subject: [PATCH 18/34] 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 2aa85f6fb..028f0e895 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5711,10 +5711,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 974b4dbe25c617dbef5c742f11258eecbbd8ed1e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:45 +0000 Subject: [PATCH 19/34] 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 028f0e895..5594df6e7 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5890,7 +5890,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 7394a2c59780ceb7ef73211ff5a162d7f0d7d3a5 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 10:30:03 +0000 Subject: [PATCH 20/34] 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 5594df6e7..cc3714948 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5907,6 +5907,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 5bc60d1e9..64e96ea53 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1477,7 +1477,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 92ea557979ff4acfaa8b81def29a37587895918b Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:07:02 +0000 Subject: [PATCH 21/34] 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 64e96ea53..3a21f898f 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1277,8 +1277,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 &; @@ -1324,26 +1323,43 @@ public: const_iterator it(spec, const_iterator::END); 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 a69d48dd19cb9f1b0f26795566b96969aba0d7eb Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:24:00 +0000 Subject: [PATCH 22/34] 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 cc3714948..634269d9d 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5345,23 +5345,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; @@ -5377,29 +5366,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 b612c1bb39aefea933241784ae1b69fb2c5b4deb Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:34:42 +0000 Subject: [PATCH 23/34] 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 634269d9d..c4a53ddd5 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5631,12 +5631,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 619f49eabe37650dd7ccbe49d26bf8afad8db242 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 13:42:53 +0000 Subject: [PATCH 24/34] 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 c4a53ddd5..8713f5755 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5259,8 +5259,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 aa4a0fe815b6c479dcac4643a3b28ff96ee3f9f1 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 14:13:46 +0000 Subject: [PATCH 25/34] 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 8713f5755..2a3c72c51 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4727,7 +4727,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); @@ -4791,8 +4791,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(); @@ -4826,7 +4826,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(); @@ -4851,7 +4851,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(); @@ -4886,7 +4886,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(); } @@ -4932,7 +4932,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(); } @@ -4960,7 +4960,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(); } @@ -4988,7 +4988,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(); } @@ -5013,7 +5013,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(); @@ -5021,19 +5021,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); } } @@ -5048,20 +5051,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(); @@ -5073,14 +5079,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(); } @@ -5135,7 +5143,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(); @@ -5147,7 +5155,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"); @@ -5190,10 +5198,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; } @@ -5220,7 +5228,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(); } @@ -5259,14 +5267,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); } @@ -5285,7 +5293,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"); } @@ -5314,7 +5322,7 @@ void RTLIL::SigSpec::check(Module *mod) const } w += chunk.width; } - log_assert(w == width_); + log_assert(w == size()); log_assert(bits_.empty()); } else @@ -5327,7 +5335,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()); } } @@ -5340,8 +5348,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()) { @@ -5361,7 +5369,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(); @@ -5384,7 +5392,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 @@ -5610,7 +5618,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; } @@ -5699,7 +5707,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++) @@ -5715,7 +5723,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()); @@ -5845,13 +5853,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; } @@ -5859,7 +5867,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; } @@ -5867,8 +5875,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 3a21f898f..85ef0f056 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1367,16 +1367,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(); @@ -1408,12 +1408,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)); } @@ -1436,7 +1436,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; @@ -1495,7 +1495,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 4939484840d50275aed247758bcdd4120f485a0a Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 15:03:47 +0000 Subject: [PATCH 26/34] 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 2a3c72c51..1291432c2 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4733,7 +4733,6 @@ void RTLIL::SigSpec::unpack() const that->bits_.emplace_back(c, i); that->chunks_.clear(); - that->hash_ = 0; } void RTLIL::SigSpec::updhash() const @@ -4765,6 +4764,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() @@ -4781,6 +4781,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) @@ -4812,6 +4813,7 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec other->bits_[j] = with.bits_[it->second]; } } + other->hash_ = 0; other->check(); } @@ -4837,6 +4839,7 @@ void RTLIL::SigSpec::replace(const dict &rules, RT if (it != rules.end()) other->bits_[i] = it->second; } + other->hash_ = 0; other->check(); } @@ -4862,6 +4865,7 @@ void RTLIL::SigSpec::replace(const std::map &rules if (it != rules.end()) other->bits_[i] = it->second; } + other->hash_ = 0; other->check(); } @@ -4888,6 +4892,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--) @@ -4907,6 +4912,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe break; } } + hash_ = 0; check(); } @@ -4934,6 +4940,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--) { @@ -4946,6 +4953,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec } } } + hash_ = 0; check(); } @@ -4962,6 +4970,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--) { @@ -4974,6 +4983,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS } } } + hash_ = 0; check(); } @@ -4990,6 +5000,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--) { @@ -5002,6 +5013,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * } } } + hash_ = 0; check(); } @@ -5089,6 +5101,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) bits_.at(offset + i) = bit; ++i; } + hash_ = 0; check(); } @@ -5132,6 +5145,7 @@ void RTLIL::SigSpec::remove_const() width_ = bits_.size(); } + hash_ = 0; check(); } @@ -5148,6 +5162,7 @@ void RTLIL::SigSpec::remove(int offset, int length) bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); width_ = bits_.size(); + hash_ = 0; check(); } @@ -5194,6 +5209,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) @@ -5229,6 +5245,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) } width_ += signal.size(); + hash_ = 0; check(); } @@ -5260,6 +5277,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) } width_++; + hash_ = 0; check(); } @@ -5277,7 +5295,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 85ef0f056..02b23a69a 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1369,7 +1369,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 e1169d03fe0e5c1dd9a5074c7444df25485f1a87 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 17:42:58 +0000 Subject: [PATCH 27/34] 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 1291432c2..6fccaf1d3 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5174,33 +5174,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 870ae18a2d069af6f953db5b9b825202d1a02c93 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 15:02:39 +0000 Subject: [PATCH 28/34] 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 6fccaf1d3..eda732619 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4456,9 +4456,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; @@ -4471,12 +4469,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(); } @@ -4485,12 +4482,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(); } @@ -4499,12 +4495,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(); } @@ -4513,12 +4508,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(); } @@ -4527,12 +4521,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(); } @@ -4541,12 +4534,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(); } @@ -4555,12 +4547,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(); } @@ -4568,10 +4559,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(); } @@ -4579,10 +4571,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(); } @@ -4591,14 +4584,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(); } @@ -4606,8 +4605,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(); @@ -4617,8 +4615,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(); @@ -4628,8 +4625,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(); @@ -4639,8 +4635,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(); @@ -4650,9 +4645,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(); } @@ -4681,58 +4675,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 @@ -4904,11 +4863,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; } } @@ -4946,11 +4902,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; @@ -4976,11 +4929,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; @@ -5006,11 +4956,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; @@ -5108,41 +5055,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; @@ -5160,7 +5093,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(); @@ -5199,10 +5131,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; } @@ -5218,60 +5161,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(); } @@ -5304,50 +5241,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 @@ -5721,7 +5644,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; @@ -5738,7 +5661,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 02b23a69a..436b8b440 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1234,29 +1234,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); @@ -1272,9 +1296,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) {} @@ -1286,14 +1331,12 @@ 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(); } enum End { END }; @@ -1303,15 +1346,14 @@ public: 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; } @@ -1366,7 +1408,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 745222fa3bf2ac570935ffd044c86fa2eb12d123 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 31 Oct 2025 10:06:13 +0000 Subject: [PATCH 29/34] 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 eda732619..95db45e64 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4675,23 +4675,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 @@ -4754,25 +4752,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(); } @@ -4790,15 +4785,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(); } @@ -4816,15 +4809,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(); } @@ -5578,23 +5569,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(); @@ -5630,22 +5623,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; } @@ -5654,15 +5648,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 436b8b440..fb184fe50 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1223,9 +1223,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++; } @@ -1251,8 +1252,8 @@ private: new (&bits_) std::vector; } - void unpack() const; - inline void inline_unpack() const { + void unpack(); + inline void inline_unpack() { if (rep_ == CHUNK) unpack(); } @@ -1406,13 +1407,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; } @@ -1456,6 +1466,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)); } @@ -1536,7 +1548,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; } @@ -2444,8 +2456,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 38d1d071a5db00e9cc60953fa3c1b00f2e8b29ee Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 31 Oct 2025 10:48:39 +0000 Subject: [PATCH 30/34] 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 95db45e64..46ed8287c 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4692,17 +4692,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); @@ -4711,9 +4706,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() @@ -4721,7 +4718,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() @@ -4738,7 +4735,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) @@ -4842,7 +4839,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--) @@ -4859,7 +4856,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe break; } } - hash_ = 0; + hash_.clear(); check(); } @@ -4887,7 +4884,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--) { @@ -4897,7 +4894,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -4914,7 +4911,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--) { @@ -4924,7 +4921,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -4941,7 +4938,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--) { @@ -4951,7 +4948,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -5039,7 +5036,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) bits_.at(offset + i) = bit; ++i; } - hash_ = 0; + hash_.clear(); check(); } @@ -5069,7 +5066,7 @@ void RTLIL::SigSpec::remove_const() bits_.swap(new_bits); } - hash_ = 0; + hash_.clear(); check(); } @@ -5085,7 +5082,7 @@ void RTLIL::SigSpec::remove(int offset, int length) bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); - hash_ = 0; + hash_.clear(); check(); } @@ -5137,7 +5134,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) @@ -5152,7 +5149,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()); @@ -5173,7 +5170,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 fb184fe50..c11e603fb 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1239,9 +1239,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 @@ -1258,7 +1288,7 @@ private: unpack(); } - void updhash() const; + Hasher::hash_t updhash() const; void destroy() { if (rep_ == CHUNK) chunk_.~SigChunk(); @@ -1410,9 +1440,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) @@ -1551,7 +1581,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; From 1cf3497d15070ce49bbc6258d1bee5d47b72ab81 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 7 Nov 2025 15:50:57 +0000 Subject: [PATCH 31/34] Repack SigSpecs when possible --- kernel/rtlil.cc | 139 +++++++++++++++++++++++++++++++++++++++++------- kernel/rtlil.h | 1 + 2 files changed, 122 insertions(+), 18 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 46ed8287c..a58487216 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4692,6 +4692,39 @@ void RTLIL::SigSpec::unpack() new (&bits_) std::vector(std::move(bits)); } +void RTLIL::SigSpec::try_repack() +{ + if (rep_ != BITS) + return; + + cover("kernel.rtlil.sigspec.convert.try_repack"); + + int bits_size = GetSize(bits_); + if (bits_size == 0) + return; + if (bits_[0].is_wire()) { + for (int i = 1; i < bits_size; i++) + if (bits_[0].wire != bits_[i].wire || bits_[0].offset + i != bits_[i].offset) + return; + SigChunk chunk(bits_[0].wire, bits_[0].offset, bits_size); + bits_.~vector(); + rep_ = CHUNK; + new (&chunk_) SigChunk(std::move(chunk)); + return; + } + std::vector bits; + bits.reserve(bits_size); + bits.push_back(bits_[0].data); + for (int i = 1; i < bits_size; i++) { + if (bits_[i].is_wire()) + return; + bits.push_back(bits_[i].data); + } + bits_.~vector(); + rep_ = CHUNK; + new (&chunk_) SigChunk(std::move(bits)); +} + Hasher::hash_t RTLIL::SigSpec::updhash() const { cover("kernel.rtlil.sigspec.hash"); @@ -4719,6 +4752,7 @@ void RTLIL::SigSpec::sort() cover("kernel.rtlil.sigspec.sort"); std::sort(bits_.begin(), bits_.end()); hash_.clear(); + try_repack(); } void RTLIL::SigSpec::sort_and_unify() @@ -4736,6 +4770,7 @@ void RTLIL::SigSpec::sort_and_unify() *this = unique_bits; hash_.clear(); + try_repack(); } void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) @@ -4759,13 +4794,17 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec } int this_size = size(); + bool other_modified = false; for (int j = 0; j < this_size; j++) { auto it = pattern_to_with.find((*this)[j]); if (it != pattern_to_with.end()) { + other_modified = true; (*other)[j] = with[it->second]; } } + if (other_modified) + other->try_repack(); other->check(); } @@ -4784,12 +4823,17 @@ void RTLIL::SigSpec::replace(const dict &rules, RT if (rules.empty()) return; int this_size = size(); + bool other_modified = false; for (int i = 0; i < this_size; i++) { auto it = rules.find((*this)[i]); - if (it != rules.end()) + if (it != rules.end()) { + other_modified = true; (*other)[i] = it->second; + } } + if (other_modified) + other->try_repack(); other->check(); } @@ -4808,12 +4852,17 @@ void RTLIL::SigSpec::replace(const std::map &rules if (rules.empty()) return; int this_size = size(); + bool other_modified = false; for (int i = 0; i < this_size; i++) { auto it = rules.find((*this)[i]); - if (it != rules.end()) + if (it != rules.end()) { + other_modified = true; (*other)[i] = it->second; + } } + if (other_modified) + other->try_repack(); other->check(); } @@ -4839,9 +4888,10 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_.clear(); } + bool modified = false; + bool other_modified = false; for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire == NULL) continue; @@ -4850,14 +4900,24 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe if (bits_[i].wire == pattern_chunk.wire && bits_[i].offset >= pattern_chunk.offset && bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) { + modified = true; bits_.erase(bits_.begin() + i); - if (other != NULL) + if (other != NULL) { + other_modified = true; other->bits_.erase(other->bits_.begin() + i); + } break; } } - hash_.clear(); + if (modified) { + hash_.clear(); + try_repack(); + } + if (other_modified) { + other->hash_.clear(); + other->try_repack(); + } check(); } @@ -4884,18 +4944,29 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_.clear(); } + bool modified = false; + bool other_modified = false; for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { + modified = true; bits_.erase(bits_.begin() + i); - if (other != NULL) + if (other != NULL) { + other_modified = true; other->bits_.erase(other->bits_.begin() + i); + } } } - hash_.clear(); + if (modified) { + hash_.clear(); + try_repack(); + } + if (other_modified) { + other->hash_.clear(); + other->try_repack(); + } check(); } @@ -4911,18 +4982,29 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_.clear(); } + bool modified = false; + bool other_modified = false; for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { + modified = true; bits_.erase(bits_.begin() + i); - if (other != NULL) + if (other != NULL) { + other_modified = true; other->bits_.erase(other->bits_.begin() + i); + } } } - hash_.clear(); + if (modified) { + hash_.clear(); + try_repack(); + } + if (other_modified) { + other->hash_.clear(); + other->try_repack(); + } check(); } @@ -4938,18 +5020,29 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_.clear(); } + bool modified = false; + bool other_modified = false; for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i].wire)) { + modified = true; bits_.erase(bits_.begin() + i); - if (other != NULL) + if (other != NULL) { + other_modified = true; other->bits_.erase(other->bits_.begin() + i); + } } } - hash_.clear(); + if (modified) { + hash_.clear(); + try_repack(); + } + if (other_modified) { + other->hash_.clear(); + other->try_repack(); + } check(); } @@ -5025,6 +5118,9 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) { cover("kernel.rtlil.sigspec.replace_pos"); + if (with.size() == 0) + return; + unpack(); log_assert(offset >= 0); @@ -5037,6 +5133,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) ++i; } hash_.clear(); + try_repack(); check(); } @@ -5050,6 +5147,7 @@ void RTLIL::SigSpec::remove_const() if (chunk_.wire == NULL) { chunk_.~SigChunk(); init_empty_bits(); + hash_.clear(); } } else @@ -5058,15 +5156,16 @@ void RTLIL::SigSpec::remove_const() std::vector new_bits; new_bits.reserve(bits_.size()); - for (auto &bit : bits_) if (bit.wire != NULL) new_bits.push_back(bit); - - bits_.swap(new_bits); + if (GetSize(new_bits) != GetSize(bits_)) { + bits_.swap(new_bits); + hash_.clear(); + try_repack(); + } } - hash_.clear(); check(); } @@ -5074,6 +5173,9 @@ void RTLIL::SigSpec::remove(int offset, int length) { cover("kernel.rtlil.sigspec.remove_pos"); + if (length == 0) + return; + unpack(); log_assert(offset >= 0); @@ -5083,6 +5185,7 @@ void RTLIL::SigSpec::remove(int offset, int length) bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); hash_.clear(); + try_repack(); check(); } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c11e603fb..98230ab1f 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1287,6 +1287,7 @@ private: if (rep_ == CHUNK) unpack(); } + void try_repack(); Hasher::hash_t updhash() const; void destroy() { From 0452955069e051d5916f0d1ab04bd0ca43f75697 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 12:02:21 +0100 Subject: [PATCH 32/34] rtlil: add explanatory note to SigSpec::Chunks --- kernel/rtlil.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 98230ab1f..f81cba38c 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1353,6 +1353,9 @@ public: return *this; } + // SigSpec::Chunks holds one reconstructed chunk at a time + // to provide the SigSpec::chunks() read-only chunks view + // since vector SigSpec::chunks_ has been removed struct Chunks { Chunks(const SigSpec &spec) : spec(spec) {} struct const_iterator { From ee5b8a97b9b6cbd0c22ee5555091b0094092d450 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 12:02:36 +0100 Subject: [PATCH 33/34] rtlil: avoid clang warning --- kernel/rtlil.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f81cba38c..79cc73e45 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1415,10 +1415,7 @@ public: return chunk_vector.size(); } int size() const { - int result = 0; - for (const SigChunk &_: *this) - ++result; - return result; + return std::distance(begin(), end()); } const SigChunk &at(int index) { ensure_chunk_vector(); From 4dac5cd1f85d9b90ba5dd86422213aeff1bcd951 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 12:08:35 +0100 Subject: [PATCH 34/34] rtlil: note SigSpec only has one chunk in internal docs --- .../yosys_internals/formats/rtlil_rep.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/source/yosys_internals/formats/rtlil_rep.rst b/docs/source/yosys_internals/formats/rtlil_rep.rst index b0cbfe3a5..dbd69c7e4 100644 --- a/docs/source/yosys_internals/formats/rtlil_rep.rst +++ b/docs/source/yosys_internals/formats/rtlil_rep.rst @@ -194,17 +194,18 @@ RTLIL::SigSpec A "signal" is everything that can be applied to a cell port. I.e. -- | Any constant value of arbitrary bit-width +- | A bit from a wire (``RTLIL::SigBit``) + | 1em For example: ``mywire[24]`` + +- | A range of bits from a wire (wire variant of ``RTLIL::SigChunk``) + | 1em For example: ``mywire, mywire[15:8]`` + +- | Any constant value of arbitrary bit-width (``std::vector>`` variant of ``RTLIL::SigChunk``) | 1em For example: ``1337, 16'b0000010100111001, 1'b1, 1'bx`` -- | All bits of a wire or a selection of bits from a wire - | 1em For example: ``mywire, mywire[24], mywire[15:8]`` - -- | Concatenations of the above - | 1em For example: ``{16'd1337, mywire[15:8]}`` - -The ``RTLIL::SigSpec`` data type is used to represent signals. The -``RTLIL::Cell`` object contains one ``RTLIL::SigSpec`` for each cell port. +The ``RTLIL::SigSpec`` data type is used to represent signals. +It contains a single ``RTLIL::SigChunk`` or a vector of ``RTLIL::SigBit``. +The ``RTLIL::Cell`` object contains one ``RTLIL::SigSpec`` for each cell port. In addition, connections between wires are represented using a pair of ``RTLIL::SigSpec`` objects. Such pairs are needed in different locations.