From a5cc905184f3a8112063742a13653a8be148a51b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:52:24 +1300 Subject: [PATCH 01/46] simplify.cc: Fix unsized const in params --- frontends/ast/simplify.cc | 10 +++++++--- tests/verilog/unbased_unsized.sv | 9 +++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 97abf7452..330e9ef12 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2231,9 +2231,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (children[0]->type == AST_CONSTANT) { if (width != int(children[0]->bits.size())) { - RTLIL::SigSpec sig(children[0]->bits); - sig.extend_u0(width, children[0]->is_signed); - children[0] = mkconst_bits(location, sig.as_const().to_bits(), is_signed); + RTLIL::Const val; + if (children[0]->is_unsized) { + val = children[0]->bitsAsUnsizedConst(width); + } else { + val = children[0]->bitsAsConst(width); + } + children[0] = mkconst_bits(location, val.to_bits(), is_signed); fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; diff --git a/tests/verilog/unbased_unsized.sv b/tests/verilog/unbased_unsized.sv index 1d0c5a72c..af932cb74 100644 --- a/tests/verilog/unbased_unsized.sv +++ b/tests/verilog/unbased_unsized.sv @@ -6,6 +6,11 @@ module pass_through( endmodule module top; + localparam logic [63:0] + l01 = '0, + l02 = '1, + l03 = 'x, + l04 = 'z; logic [63:0] o01, o02, o03, o04, o05, o06, o07, o08, @@ -36,5 +41,9 @@ module top; assert (o10 === {64 {1'b1}}); assert (o11 === {64 {1'bx}}); assert (o12 === {64 {1'bz}}); + assert (l01 === {64 {1'b0}}); + assert (l02 === {64 {1'b1}}); + assert (l03 === {64 {1'bx}}); + assert (l04 === {64 {1'bz}}); end endmodule From e4c5900acd5caeaaea6f4e3983fe3f2ad6ba0495 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:13:12 +1300 Subject: [PATCH 02/46] tests/verilog: Unsized params in cell Non-zero case fails with `read_verilog`, but passes with `verific` and `read_slang`. --- tests/verilog/unbased_unsized.sv | 16 ++++++++++++++++ tests/verilog/unbased_unsized.ys | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/verilog/unbased_unsized.sv b/tests/verilog/unbased_unsized.sv index af932cb74..62f7d41ff 100644 --- a/tests/verilog/unbased_unsized.sv +++ b/tests/verilog/unbased_unsized.sv @@ -5,6 +5,14 @@ module pass_through( assign out = inp; endmodule +module set_param #( + parameter logic [63:0] VALUE +) ( + output logic [63:0] out +); + assign out = VALUE; +endmodule + module top; localparam logic [63:0] l01 = '0, @@ -28,6 +36,10 @@ module top; pass_through pt10('1, o10); pass_through pt11('x, o11); pass_through pt12('z, o12); + set_param #('0) sp13(o13); + set_param #('1) sp14(o14); + set_param #('x) sp15(o15); + set_param #('z) sp16(o16); always @* begin assert (o01 === {64 {1'b0}}); assert (o02 === {64 {1'b1}}); @@ -45,5 +57,9 @@ module top; assert (l02 === {64 {1'b1}}); assert (l03 === {64 {1'bx}}); assert (l04 === {64 {1'bz}}); + assert (o13 === {64 {1'b0}}); + assert (o14 === {64 {1'b1}}); + assert (o15 === {64 {1'bx}}); + assert (o16 === {64 {1'bz}}); end endmodule diff --git a/tests/verilog/unbased_unsized.ys b/tests/verilog/unbased_unsized.ys index 3290650d5..851866140 100644 --- a/tests/verilog/unbased_unsized.ys +++ b/tests/verilog/unbased_unsized.ys @@ -1,5 +1,5 @@ read_verilog -sv unbased_unsized.sv -hierarchy +hierarchy -top top proc flatten opt -full From 7302bf9a66b5b7635403cc4f59575b0e2899d414 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:45:07 +1300 Subject: [PATCH 03/46] Add CONST_FLAG_UNSIZED In order to support unsized constants being used as parameters, the `const` struct needs to know if it is unsized (so that the parameter can be used to set the size). Add unsized flag to param value serialization and rtlil back-/front-end. Add cell params to `tests/rtlil/everything.v`. --- backends/rtlil/rtlil_backend.cc | 7 +++++-- frontends/ast/ast.cc | 9 +++++++-- frontends/rtlil/rtlil_frontend.cc | 5 +++++ kernel/rtlil.h | 9 +++++---- tests/rtlil/everything.v | 17 +++++++++++++++++ 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index d607be837..63f64d12d 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -61,7 +61,9 @@ void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi return; } } - f << stringf("%d'", width); + if ((data.flags & RTLIL::CONST_FLAG_UNSIZED) == 0) { + f << stringf("%d'", width); + } if (data.flags & RTLIL::CONST_FLAG_SIGNED) { f << stringf("s"); } @@ -172,9 +174,10 @@ void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL:: dump_attributes(f, indent, cell); f << stringf("%s" "cell %s %s\n", indent, cell->type, cell->name); for (const auto& [name, param] : reversed(cell->parameters)) { - f << stringf("%s parameter%s%s %s ", indent, + f << stringf("%s parameter%s%s%s %s ", indent, (param.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", (param.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "", + (param.flags & RTLIL::CONST_FLAG_UNSIZED) != 0 ? " unsized" : "", name); dump_const(f, param); f << stringf("\n"); diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 4a16abee9..984c4294c 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -993,6 +993,8 @@ RTLIL::Const AstNode::asParaConst() const RTLIL::Const val = asAttrConst(); if (is_signed) val.flags |= RTLIL::CONST_FLAG_SIGNED; + if (is_unsized) + val.flags |= RTLIL::CONST_FLAG_UNSIZED; return val; } @@ -1766,7 +1768,10 @@ static std::string serialize_param_value(const RTLIL::Const &val) { res.push_back('s'); if (val.flags & RTLIL::ConstFlags::CONST_FLAG_REAL) res.push_back('r'); - res += stringf("%d", GetSize(val)); + if (val.flags & RTLIL::ConstFlags::CONST_FLAG_UNSIZED) + res.push_back('u'); + else + res += stringf("%d", GetSize(val)); res.push_back('\''); res.append(val.as_string("?")); return res; @@ -1860,7 +1865,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictsecond.flags & RTLIL::CONST_FLAG_STRING) != 0) child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string()); else - child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0); + child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0, (it->second.flags & RTLIL::CONST_FLAG_UNSIZED) != 0); rewritten.insert(it->first); } diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 04d01fc93..271962725 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -567,10 +567,13 @@ struct RTLILFrontendWorker { if (try_parse_keyword("parameter")) { bool is_signed = false; bool is_real = false; + bool is_unsized = false; if (try_parse_keyword("signed")) { is_signed = true; } else if (try_parse_keyword("real")) { is_real = true; + } else if (try_parse_keyword("unsized")) { + is_unsized = true; } RTLIL::IdString param_name = parse_id(); RTLIL::Const val = parse_const(); @@ -578,6 +581,8 @@ struct RTLILFrontendWorker { val.flags |= RTLIL::CONST_FLAG_SIGNED; if (is_real) val.flags |= RTLIL::CONST_FLAG_REAL; + if (is_unsized) + val.flags |= RTLIL::CONST_FLAG_UNSIZED; cell->parameters.insert({std::move(param_name), std::move(val)}); expect_eol(); } else if (try_parse_keyword("connect")) { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 7e699b365..85ae70ef4 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -53,10 +53,11 @@ namespace RTLIL // Semantic metadata - how can this constant be interpreted? // Values may be generally non-exclusive enum ConstFlags : unsigned char { - CONST_FLAG_NONE = 0, - CONST_FLAG_STRING = 1, - CONST_FLAG_SIGNED = 2, // only used for parameters - CONST_FLAG_REAL = 4 // only used for parameters + CONST_FLAG_NONE = 0, + CONST_FLAG_STRING = 1, + CONST_FLAG_SIGNED = 2, // only used for parameters + CONST_FLAG_REAL = 4, // only used for parameters + CONST_FLAG_UNSIZED = 8, // only used for parameters }; enum SelectPartials : unsigned char { diff --git a/tests/rtlil/everything.v b/tests/rtlil/everything.v index 666d630c2..c4f8c348a 100644 --- a/tests/rtlil/everything.v +++ b/tests/rtlil/everything.v @@ -38,3 +38,20 @@ module foo( assign b = bb; assign y = a + bb; endmodule + +module set_param #( + parameter [3:0] VALUE = 1'bx +) ( + output logic [3:0] out +); + assign out = VALUE; +endmodule + +module use_param ( + output logic [3:0] a, b, c, d +); + set_param #($signed(1)) spa (a); + set_param #('1) spb (b); + set_param #(1.1) spc (c); + set_param #(1'b1) spd (d); +endmodule From 8d4f790951b237eeb4871f719d4f72ab385797ec Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 12:41:50 +0000 Subject: [PATCH 04/46] 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 05/46] 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 06/46] 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 07/46] 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 08/46] 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 09/46] 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 10/46] 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 11/46] 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 12/46] 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 13/46] 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 14/46] 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 15/46] 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 16/46] 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 17/46] 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 18/46] 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 19/46] 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 20/46] 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 21/46] 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 22/46] 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 23/46] 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 24/46] 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 25/46] 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 26/46] 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 27/46] 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 28/46] 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 29/46] 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 30/46] 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 31/46] 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 32/46] 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 33/46] 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 34/46] 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 224109151da988618ede22c284a218e9bb3f3c06 Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Sat, 8 Nov 2025 23:05:10 +0530 Subject: [PATCH 35/46] add specific package imports and tests --- frontends/ast/simplify.cc | 25 +++++++++++++- frontends/verilog/verilog_parser.y | 33 ++++++++++++++++++- tests/verilog/package_import_specific.sv | 14 ++++++++ tests/verilog/package_import_specific.ys | 5 +++ .../verilog/package_import_specific_module.sv | 16 +++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 tests/verilog/package_import_specific.sv create mode 100644 tests/verilog/package_import_specific.ys create mode 100644 tests/verilog/package_import_specific_module.sv diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 97abf7452..010f4e14f 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1123,16 +1123,39 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (package_node) { - // Import all names from the package into current scope + bool is_wildcard = child->children.empty(); + std::set import_items; + + // For specific imports, collect the list of items to import + if (!is_wildcard) { + for (auto& import_item : child->children) { + import_items.insert(import_item->str); + } + } + + // Import names from the package into current scope for (auto& pkg_child : package_node->children) { + // Check if this is a specific import and if this item should be imported + if (!is_wildcard && import_items.count(pkg_child->str) == 0) + continue; + if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM || pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION || pkg_child->type == AST_TASK || pkg_child->type == AST_ENUM) { + // For wildcard imports, check if item already exists (from specific import) + if (is_wildcard && current_scope.count(pkg_child->str) > 0) + continue; current_scope[pkg_child->str] = pkg_child.get(); } if (pkg_child->type == AST_ENUM) { for (auto& enode : pkg_child->children) { log_assert(enode->type==AST_ENUM_ITEM); + // Check if this enum item should be imported + if (!is_wildcard && import_items.count(enode->str) == 0) + continue; + // For wildcard imports, check if item already exists (from specific import) + if (is_wildcard && current_scope.count(enode->str) > 0) + continue; if (current_scope.count(enode->str) == 0) current_scope[enode->str] = enode.get(); else diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index ef8427679..e6c7f3672 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -428,6 +428,7 @@ #include #include #include + #include #include "frontends/verilog/verilog_frontend.h" struct specify_target { @@ -462,6 +463,7 @@ using string_t = std::unique_ptr; using ast_t = std::unique_ptr; + using ast_list_t = std::vector; using al_t = std::unique_ptr>>; using specify_target_ptr_t = std::unique_ptr; using specify_triple_ptr_t = std::unique_ptr; @@ -557,6 +559,8 @@ %type struct_union %type asgn_binop inc_or_dec_op %type genvar_identifier +%type import_item_list +%type import_item %type specify_target %type specify_triple specify_opt_triple @@ -830,10 +834,37 @@ package_body_stmt: import_stmt: TOK_IMPORT hierarchical_id TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL { - // Create an import node to track package imports + // Create an import node to track specific and wildcard package imports auto import_node = std::make_unique(@$, AST_IMPORT); import_node->str = *$2; extra->ast_stack.back()->children.push_back(std::move(import_node)); + } | + TOK_IMPORT hierarchical_id TOK_PACKAGESEP import_item_list TOK_SEMICOL { + // Create an import node to track specific package imports + auto import_node = std::make_unique(@$, AST_IMPORT); + import_node->str = *$2; + // Move children from import_item_list to import_node + import_node->children = std::move($4); + extra->ast_stack.back()->children.push_back(std::move(import_node)); + }; + +import_item_list: + import_item { + ast_list_t list; + list.push_back(std::move($1)); + $$ = std::move(list); + } | + import_item_list TOK_COMMA import_item { + $1.push_back(std::move($3)); + $$ = std::move($1); + }; + +import_item: + TOK_ID { + // Create a simple node to store the imported item name + auto item_node = std::make_unique(@$, AST_NONE); + item_node->str = *$1; + $$ = std::move(item_node); }; interface: diff --git a/tests/verilog/package_import_specific.sv b/tests/verilog/package_import_specific.sv new file mode 100644 index 000000000..97004ed56 --- /dev/null +++ b/tests/verilog/package_import_specific.sv @@ -0,0 +1,14 @@ +package package_import_specific; + + localparam integer + DATA_WIDTH = 8, + ADDR_WIDTH = 4; + + localparam logic [2:0] + IDLE = 3'b000, + START = 3'b001, + DATA = 3'b010, + STOP = 3'b100, + DONE = 3'b101; + +endpackage diff --git a/tests/verilog/package_import_specific.ys b/tests/verilog/package_import_specific.ys new file mode 100644 index 000000000..8b183aac4 --- /dev/null +++ b/tests/verilog/package_import_specific.ys @@ -0,0 +1,5 @@ +read_verilog -sv package_import_specific.sv +read_verilog -sv package_import_specific_module.sv +hierarchy -check +proc +opt -full diff --git a/tests/verilog/package_import_specific_module.sv b/tests/verilog/package_import_specific_module.sv new file mode 100644 index 000000000..a568af4d2 --- /dev/null +++ b/tests/verilog/package_import_specific_module.sv @@ -0,0 +1,16 @@ +import package_import_specific::DATA_WIDTH; +import package_import_specific::IDLE; + +module package_import_specific_module; + logic [DATA_WIDTH-1:0] data; + logic [3:0] addr; + logic [2:0] state; + + always_comb begin + case (state) + IDLE: data = 8'h00; + default: data = 8'hFF; + endcase + end + +endmodule From 54e5eb1c3c7dea139401e811564bbf2e9ca91f60 Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Sat, 8 Nov 2025 23:16:52 +0530 Subject: [PATCH 36/46] no use vector --- frontends/verilog/verilog_parser.y | 35 ++++++++++-------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e6c7f3672..684727d5b 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -428,7 +428,6 @@ #include #include #include - #include #include "frontends/verilog/verilog_frontend.h" struct specify_target { @@ -463,7 +462,6 @@ using string_t = std::unique_ptr; using ast_t = std::unique_ptr; - using ast_list_t = std::vector; using al_t = std::unique_ptr>>; using specify_target_ptr_t = std::unique_ptr; using specify_triple_ptr_t = std::unique_ptr; @@ -559,8 +557,6 @@ %type struct_union %type asgn_binop inc_or_dec_op %type genvar_identifier -%type import_item_list -%type import_item %type specify_target %type specify_triple specify_opt_triple @@ -833,38 +829,31 @@ package_body_stmt: typedef_decl | localparam_decl | param_decl | task_func_decl; import_stmt: - TOK_IMPORT hierarchical_id TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL { - // Create an import node to track specific and wildcard package imports + TOK_IMPORT TOK_ID TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL { + // Create an import node to track wildcard package imports auto import_node = std::make_unique(@$, AST_IMPORT); import_node->str = *$2; extra->ast_stack.back()->children.push_back(std::move(import_node)); } | - TOK_IMPORT hierarchical_id TOK_PACKAGESEP import_item_list TOK_SEMICOL { - // Create an import node to track specific package imports - auto import_node = std::make_unique(@$, AST_IMPORT); + TOK_IMPORT TOK_ID TOK_PACKAGESEP { + // Start a specific import: create and push the AST_IMPORT node + AstNode* import_node = extra->pushChild(std::make_unique(@$, AST_IMPORT)); import_node->str = *$2; - // Move children from import_item_list to import_node - import_node->children = std::move($4); - extra->ast_stack.back()->children.push_back(std::move(import_node)); + } import_item_list TOK_SEMICOL { + // Done collecting specific items, pop the AST_IMPORT node + extra->ast_stack.pop_back(); }; import_item_list: - import_item { - ast_list_t list; - list.push_back(std::move($1)); - $$ = std::move(list); - } | - import_item_list TOK_COMMA import_item { - $1.push_back(std::move($3)); - $$ = std::move($1); - }; + import_item | + import_item_list TOK_COMMA import_item ; import_item: TOK_ID { - // Create a simple node to store the imported item name + // Append this specific import name under the current AST_IMPORT auto item_node = std::make_unique(@$, AST_NONE); item_node->str = *$1; - $$ = std::move(item_node); + extra->ast_stack.back()->children.push_back(std::move(item_node)); }; interface: From 0452955069e051d5916f0d1ab04bd0ca43f75697 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 12:02:21 +0100 Subject: [PATCH 37/46] 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 38/46] 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 39/46] 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. From 8f53d21ea7eaec66ab93cb611f36fbf9e798935b Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 14:26:10 +0100 Subject: [PATCH 40/46] simplify: refactor specific package import --- frontends/ast/simplify.cc | 85 ++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 010f4e14f..308406591 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -889,6 +889,52 @@ static void check_auto_nosync(AstNode *node) check_auto_nosync(child.get()); } +class PackageImporter { + std::set import_items; + bool is_wildcard; + const AstNode* node; +public: + PackageImporter(const AstNode* n, const AstNode* child) : node(n) { + is_wildcard = child->children.empty(); + // For specific imports, collect the list of items to import + if (!is_wildcard) { + for (auto& item : child->children) { + import_items.insert(item->str); + } + } + } + + void import(std::map& scope, AstNode* to_import) const { + // Check if this is a specific import and if this item should be imported + if (!is_wildcard && import_items.count(to_import->str) == 0) + return; + + if (to_import->type == AST_PARAMETER || to_import->type == AST_LOCALPARAM || + to_import->type == AST_TYPEDEF || to_import->type == AST_FUNCTION || + to_import->type == AST_TASK || to_import->type == AST_ENUM) { + // For wildcard imports, check if item already exists (from specific import) + if (is_wildcard && scope.count(to_import->str) > 0) + return; + scope[to_import->str] = to_import; + } + if (to_import->type == AST_ENUM) { + for (auto& enode : to_import->children) { + log_assert(enode->type==AST_ENUM_ITEM); + // Check if this enum item should be imported + if (!is_wildcard && import_items.count(enode->str) == 0) + continue; + // For wildcard imports, check if item already exists (from specific import) + if (is_wildcard && scope.count(enode->str) > 0) + continue; + if (scope.count(enode->str) == 0) + scope[enode->str] = enode.get(); + else + node->input_error("enum item %s already exists in current scope\n", enode->str); + } + } + } +}; + // convert the AST into a simpler AST that has all parameters substituted by their // values, unrolled for-loops, expanded generate blocks, etc. when this function // is done with an AST it can be converted into RTLIL using genRTLIL(). @@ -1123,45 +1169,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (package_node) { - bool is_wildcard = child->children.empty(); - std::set import_items; - - // For specific imports, collect the list of items to import - if (!is_wildcard) { - for (auto& import_item : child->children) { - import_items.insert(import_item->str); - } - } - + PackageImporter importer(this, child); // Import names from the package into current scope for (auto& pkg_child : package_node->children) { - // Check if this is a specific import and if this item should be imported - if (!is_wildcard && import_items.count(pkg_child->str) == 0) - continue; - - if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM || - pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION || - pkg_child->type == AST_TASK || pkg_child->type == AST_ENUM) { - // For wildcard imports, check if item already exists (from specific import) - if (is_wildcard && current_scope.count(pkg_child->str) > 0) - continue; - current_scope[pkg_child->str] = pkg_child.get(); - } - if (pkg_child->type == AST_ENUM) { - for (auto& enode : pkg_child->children) { - log_assert(enode->type==AST_ENUM_ITEM); - // Check if this enum item should be imported - if (!is_wildcard && import_items.count(enode->str) == 0) - continue; - // For wildcard imports, check if item already exists (from specific import) - if (is_wildcard && current_scope.count(enode->str) > 0) - continue; - if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode.get(); - else - input_error("enum item %s already exists in current scope\n", enode->str); - } - } + importer.import(current_scope, pkg_child.get()); } // Remove the import node since it's been processed children.erase(children.begin() + i); From f7881ced9e8d2a1fdeef33ceb5a4021fb8eaaf24 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 00:25:20 +0000 Subject: [PATCH 41/46] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dd7a8c022..575d1a7f3 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+162 +YOSYS_VER := 0.58+202 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 03eb2206d7b8a830dd32d0e1673986318111a4c3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 11 Nov 2025 07:57:22 +0100 Subject: [PATCH 42/46] Release version 0.59 --- CHANGELOG | 17 ++++++++++++++++- Makefile | 4 ++-- docs/source/conf.py | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8ceefee41..d267a4826 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,23 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.58 .. Yosys 0.59-dev +Yosys 0.58 .. Yosys 0.59 -------------------------- + * Various + - Pyosys is rewritten using pybind11. + - alumacc: merge independent of sign. + - write_btor: Include $assert and $assume cells in -ywmap output. + - RTLIL parser rewritten for efficiency. + - Wildcards enabled for Liberty file consuming. + - timeest: Add top ports launching/sampling. + + * New commands and options + - Added "-apply_derived_type" option to "box_derive" pass. + - Added "-publish_icells" option to "chtype" pass. + - Added "-width" option to "sim" pass. + - Added "sort" pass for sorting the design objects. + - Merged "synth_ecp5" and "synth_nexus" into "synth_lattice" pass. + - Added "-strict-gw5a-dffs" and "-setundef" options to "synth_gowin" pass. Yosys 0.57 .. Yosys 0.58 -------------------------- diff --git a/Makefile b/Makefile index 575d1a7f3..2501a7ea0 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+202 +YOSYS_VER := 0.59 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -184,7 +184,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 157aabb.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 157aabb.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) diff --git a/docs/source/conf.py b/docs/source/conf.py index 6740fab83..fb106bddb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -6,7 +6,7 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' copyright ='2025 YosysHQ GmbH' -yosys_ver = "0.58" +yosys_ver = "0.59" # select HTML theme html_theme = 'furo-ys' From fd40418c102eb2fdc15ca5cd5c2276468fa7ddd0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 11 Nov 2025 09:26:05 +0100 Subject: [PATCH 43/46] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d267a4826..6cefcc3ac 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.59 .. Yosys 0.60-dev +-------------------------- + Yosys 0.58 .. Yosys 0.59 -------------------------- * Various diff --git a/Makefile b/Makefile index 2501a7ea0..09dcd0639 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.59 +YOSYS_VER := 0.59+0 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -184,7 +184,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 157aabb.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 03eb220.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From e29328ec99e6b8a3cc5bd60c169ebed47f1b279c Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 11 Nov 2025 13:48:35 +0200 Subject: [PATCH 44/46] hotfix: workaround for pyosys build failure temporarily exclude `SigSpec::chunks` from the interface until nested structs/classes are supported --- pyosys/generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyosys/generator.py b/pyosys/generator.py index 65d886cf0..0883a7ba4 100644 --- a/pyosys/generator.py +++ b/pyosys/generator.py @@ -192,7 +192,7 @@ pyosys_headers = [ ), PyosysClass("SigChunk"), PyosysClass("SigBit", hash_expr="s"), - PyosysClass("SigSpec", hash_expr="s"), + PyosysClass("SigSpec", hash_expr="s", denylist={"chunks"}), PyosysClass( "Cell", ref_only=True, From 967e91aa73e84d921591f2f3b34aa5cad5124f5c Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 11 Nov 2025 13:44:50 +0100 Subject: [PATCH 45/46] libparse: fix parsing and memory safety of quoted values --- passes/techmap/libparse.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 9e2556891..a9ae75c01 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -123,7 +123,9 @@ int LibertyInputStream::peek_cold(size_t offset) if (!extend_buffer_at_least(offset + 1)) return EOF; } - +#ifdef log_assert + log_assert(buf_pos + offset < buffer.size()); +#endif return buffer[buf_pos + offset]; } @@ -458,7 +460,6 @@ int LibertyParser::lexer_inner(std::string &str) // if it wasn't an identifer, number of array range, // maybe it's a string? if (c == '"') { - f.consume(1); size_t i = 0; while (true) { c = f.peek(i); @@ -469,14 +470,13 @@ int LibertyParser::lexer_inner(std::string &str) break; } str.clear(); - f.unget(); - str.append(f.buffered_data(), f.buffered_data() + i + 1); + str.append(f.buffered_data(), f.buffered_data() + i); // Usage in filterlib is expected to retain quotes // but yosys expects to get unquoted #ifdef FILTERLIB str = "\"" + str + "\""; #endif - f.consume(i + 2); + f.consume(i + 1); return 'v'; } From 5f76729cbbcc6fd98f1cacbcf4e598cd74f30857 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 00:24:49 +0000 Subject: [PATCH 46/46] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 09dcd0639..f29c15484 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.59+0 +YOSYS_VER := 0.59+9 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)