From 37e4c2e8f8759db52a5a5d05daf87455e9d44eed Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 15:46:36 +0000 Subject: [PATCH] Make SigSpec::chunks() return an object that can be iterated over without packing the SigSpec --- kernel/rtlil.cc | 25 +++++++++++++ kernel/rtlil.h | 77 ++++++++++++++++++++++++++++++++++++-- passes/cmds/show.cc | 7 ++-- passes/techmap/abc9_ops.cc | 4 +- 4 files changed, 104 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 21a466b42..d1b695dd0 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4648,6 +4648,31 @@ RTLIL::SigSpec::SigSpec(bool bit) check(); } +void RTLIL::SigSpec::Chunks::const_iterator::next_chunk_bits() +{ + int bits_size = GetSize(spec.bits_); + if (bit_index >= bits_size) + return; + int i = bit_index; + const SigBit &bit = spec.bits_[i++]; + chunk.wire = bit.wire; + chunk.data.clear(); + if (bit.is_wire()) { + chunk.offset = bit.offset; + while (i < bits_size && spec.bits_[i].wire == bit.wire && + spec.bits_[i].offset == bit.offset + i - bit_index) + ++i; + } else { + chunk.offset = 0; + chunk.data.push_back(bit.data); + while (i < bits_size && !spec.bits_[i].is_wire()) { + chunk.data.push_back(spec.bits_[i].data); + ++i; + } + } + chunk.width = i - bit_index; +} + void RTLIL::SigSpec::pack() const { RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index a2be435bd..31aff3245 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1275,7 +1275,75 @@ public: SigSpec &operator=(const SigSpec &rhs) = default; SigSpec &operator=(SigSpec &&rhs) = default; - inline const std::vector &chunks() const { pack(); return chunks_; } + struct Chunks { + const SigSpec &spec; + + struct const_iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const SigChunk &; + using difference_type = std::ptrdiff_t; + using pointer = const SigChunk *; + using reference = const SigChunk &; + + const SigSpec &spec; + int chunk_index; + int bit_index; + SigChunk chunk; + + const_iterator(const SigSpec &spec) : spec(spec) { + chunk_index = 0; + bit_index = 0; + if (!spec.packed()) + next_chunk_bits(); + } + void next_chunk_bits(); + + const SigChunk &operator*() { + if (spec.packed()) + return spec.chunks_[chunk_index]; + return chunk; + }; + const SigChunk *operator->() { return &**this; } + const_iterator &operator++() { + bit_index += (**this).width; + ++chunk_index; + if (!spec.packed()) + next_chunk_bits(); + return *this; + } + bool operator==(const const_iterator &rhs) const { return bit_index == rhs.bit_index; } + bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); } + }; + const_iterator begin() const { return const_iterator(spec); } + const_iterator end() const { + const_iterator it(spec); + it.bit_index = spec.size(); + return it; + } + std::vector::const_reverse_iterator rbegin() const { + spec.pack(); + return spec.chunks_.rbegin(); + } + std::vector::const_reverse_iterator rend() const { + spec.pack(); + return spec.chunks_.rend(); + } + int size() const { + spec.pack(); + return spec.chunks_.size(); + } + const SigChunk &at(int index) const { + spec.pack(); + return spec.chunks_.at(index); + } + operator const std::vector&() const { + spec.pack(); + return spec.chunks_; + } + }; + friend struct Chunks::const_iterator; + + inline Chunks chunks() const { return {*this}; } inline const std::vector &bits() const { inline_unpack(); return bits_; } inline int size() const { return width_; } @@ -1402,7 +1470,7 @@ public: static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str); static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); - operator std::vector() const { return chunks(); } + operator std::vector() const { pack(); return chunks_; } operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } @@ -2315,8 +2383,9 @@ inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const { } inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) { - log_assert(sig.size() == 1 && sig.chunks().size() == 1); - *this = SigBit(sig.chunks().front()); + log_assert(sig.size() == 1); + auto it = sig.chunks().begin(); + *this = SigBit(*it); } template diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index d0d9c0f85..14a251c41 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -278,11 +278,12 @@ struct ShowWorker std::vector label_pieces; int bitpos = sig.size()-1; - for (int rep, chunk_idx = ((int) sig.chunks().size()) - 1; chunk_idx >= 0; chunk_idx -= rep) { - const RTLIL::SigChunk &c = sig.chunks().at(chunk_idx); + RTLIL::SigSpec::Chunks sig_chunks = sig.chunks(); + for (int rep, chunk_idx = ((int) sig_chunks.size()) - 1; chunk_idx >= 0; chunk_idx -= rep) { + const RTLIL::SigChunk &c = sig_chunks.at(chunk_idx); // Find the number of times this chunk is repeating - for (rep = 1; chunk_idx - rep >= 0 && c == sig.chunks().at(chunk_idx - rep); rep++); + for (rep = 1; chunk_idx - rep >= 0 && c == sig_chunks.at(chunk_idx - rep); rep++); int cl, cr; cl = c.offset + c.width - 1; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 373d5d15e..8d3869ece 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1428,13 +1428,13 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) // Copy connections (and rename) from mapped_mod to module for (auto conn : mapped_mod->connections()) { if (!conn.first.is_fully_const()) { - auto chunks = conn.first.chunks(); + std::vector chunks = conn.first.chunks(); for (auto &c : chunks) c.wire = module->wires_.at(remap_name(c.wire->name)); conn.first = std::move(chunks); } if (!conn.second.is_fully_const()) { - auto chunks = conn.second.chunks(); + std::vector chunks = conn.second.chunks(); for (auto &c : chunks) if (c.wire) c.wire = module->wires_.at(remap_name(c.wire->name));