From cb9bfed1699bd5c1ee0eed475e501c56383f62e7 Mon Sep 17 00:00:00 2001 From: nella Date: Thu, 25 Jun 2026 11:14:46 +0200 Subject: [PATCH 1/4] Tighten sig2bits. --- kernel/bitpattern.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index e2071436c..76c008b89 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -102,11 +102,19 @@ struct BitPatternPool bits_t bits; bits.bitdata = sig.as_const().to_bits(); for (auto &b : bits.bitdata) - if (b > RTLIL::State::S1) + if (b > RTLIL::State::S1 && b != RTLIL::State::Sx && b != RTLIL::State::Sz) b = RTLIL::State::Sa; return bits; } + static bool covers_nothing(const bits_t &bits) + { + for (auto &b : bits.bitdata) + if (b == RTLIL::State::Sx || b == RTLIL::State::Sz) + return true; + return false; + } + /** * Two cubes match if their intersection is non-empty. */ @@ -132,6 +140,8 @@ struct BitPatternPool bool has_any(RTLIL::SigSpec sig) { bits_t bits = sig2bits(sig); + if (covers_nothing(bits)) + return false; for (auto &it : database) if (match(it, bits)) return true; @@ -150,6 +160,8 @@ struct BitPatternPool bool has_all(RTLIL::SigSpec sig) { bits_t bits = sig2bits(sig); + if (covers_nothing(bits)) + return true; for (auto &it : database) if (match(it, bits)) { for (int i = 0; i < width; i++) @@ -171,6 +183,8 @@ struct BitPatternPool { bool status = false; bits_t bits = sig2bits(sig); + if (covers_nothing(bits)) + return false; for (auto it = database.begin(); it != database.end();) if (match(*it, bits)) { for (int i = 0; i < width; i++) { From 6a45e7b29086f9c285f17a1248fa4ee5e410c953 Mon Sep 17 00:00:00 2001 From: nella Date: Thu, 25 Jun 2026 11:14:54 +0200 Subject: [PATCH 2/4] Add tests. --- tests/proc/rmdead_case_x.ys | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/proc/rmdead_case_x.ys diff --git a/tests/proc/rmdead_case_x.ys b/tests/proc/rmdead_case_x.ys new file mode 100644 index 000000000..6a44ec462 --- /dev/null +++ b/tests/proc/rmdead_case_x.ys @@ -0,0 +1,40 @@ +# https://github.com/YosysHQ/yosys/issues/5979 + +read_verilog -sv << EOF +module top ( + input wire [1:0] sel, + input wire [3:0] a, + input wire [3:0] b, + output reg [3:0] y +); + always @* begin + case (sel) + 2'b1x: y = a; + 2'b10: y = b; + default: y = a; + endcase + end +endmodule + +module gold ( + input wire [1:0] sel, + input wire [3:0] a, + input wire [3:0] b, + output reg [3:0] y +); + always @* begin + if (sel == 2'b10) y = b; + else y = a; + end +endmodule +EOF + +proc +opt -full + +select -assert-count 1 top/o:y %ci* top/i:b %i + +equiv_make gold top equiv +cd equiv +equiv_simple +equiv_status -assert From 2b4ec9d57a51800b78f9e5fa224c5dd7131d219e Mon Sep 17 00:00:00 2001 From: nella Date: Mon, 6 Jul 2026 13:26:00 +0200 Subject: [PATCH 3/4] Fix covers_nothing. --- kernel/bitpattern.h | 24 +++++++++------ tests/unit/kernel/bitpatternTest.cc | 10 ++++++ tests/verilog/temp/issue4402_syn.v | 48 +++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 tests/verilog/temp/issue4402_syn.v diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index 76c008b89..848a753a5 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -102,15 +102,19 @@ struct BitPatternPool bits_t bits; bits.bitdata = sig.as_const().to_bits(); for (auto &b : bits.bitdata) - if (b > RTLIL::State::S1 && b != RTLIL::State::Sx && b != RTLIL::State::Sz) + if (b > RTLIL::State::S1) b = RTLIL::State::Sa; return bits; } - static bool covers_nothing(const bits_t &bits) + /** + * A literal x/z bit can never match a 2-valued selector, so a pattern containing + * one covers nothing. + */ + static bool covers_nothing(RTLIL::SigSpec sig) { - for (auto &b : bits.bitdata) - if (b == RTLIL::State::Sx || b == RTLIL::State::Sz) + for (auto bit : sig) + if (bit.wire == NULL && (bit.data == RTLIL::State::Sx || bit.data == RTLIL::State::Sz)) return true; return false; } @@ -139,9 +143,9 @@ struct BitPatternPool */ bool has_any(RTLIL::SigSpec sig) { - bits_t bits = sig2bits(sig); - if (covers_nothing(bits)) + if (covers_nothing(sig)) return false; + bits_t bits = sig2bits(sig); for (auto &it : database) if (match(it, bits)) return true; @@ -159,9 +163,9 @@ struct BitPatternPool */ bool has_all(RTLIL::SigSpec sig) { - bits_t bits = sig2bits(sig); - if (covers_nothing(bits)) + if (covers_nothing(sig)) return true; + bits_t bits = sig2bits(sig); for (auto &it : database) if (match(it, bits)) { for (int i = 0; i < width; i++) @@ -182,9 +186,9 @@ struct BitPatternPool bool take(RTLIL::SigSpec sig) { bool status = false; - bits_t bits = sig2bits(sig); - if (covers_nothing(bits)) + if (covers_nothing(sig)) return false; + bits_t bits = sig2bits(sig); for (auto it = database.begin(); it != database.end();) if (match(*it, bits)) { for (int i = 0; i < width; i++) { diff --git a/tests/unit/kernel/bitpatternTest.cc b/tests/unit/kernel/bitpatternTest.cc index 001d47060..a641b85a3 100644 --- a/tests/unit/kernel/bitpatternTest.cc +++ b/tests/unit/kernel/bitpatternTest.cc @@ -11,6 +11,8 @@ TEST(BitpatternTest, has) SigSpec _01a = {RTLIL::S0, RTLIL::S1, RTLIL::Sa}; SigSpec _011 = {RTLIL::S0, RTLIL::S1, RTLIL::S1}; SigSpec _111 = {RTLIL::S1, RTLIL::S1, RTLIL::S1}; + SigSpec _01x = {RTLIL::S0, RTLIL::S1, RTLIL::Sx}; + SigSpec _01z = {RTLIL::S0, RTLIL::S1, RTLIL::Sz}; EXPECT_TRUE(BitPatternPool(_aaa).has_any(_01a)); EXPECT_TRUE(BitPatternPool(_01a).has_any(_01a)); @@ -19,6 +21,10 @@ TEST(BitpatternTest, has) // overlap is symmetric EXPECT_TRUE(BitPatternPool(_01a).has_any(_011)); EXPECT_FALSE(BitPatternPool(_111).has_any(_01a)); + // overlaps nothing + EXPECT_FALSE(BitPatternPool(_011).has_any(_01x)); + EXPECT_FALSE(BitPatternPool(_011).has_any(_01z)); + EXPECT_FALSE(BitPatternPool(_aaa).has_any(_01x)); EXPECT_TRUE(BitPatternPool(_aaa).has_all(_01a)); EXPECT_TRUE(BitPatternPool(_01a).has_all(_01a)); @@ -27,6 +33,10 @@ TEST(BitpatternTest, has) // 01a is not covered by 011 EXPECT_FALSE(BitPatternPool(_011).has_all(_01a)); EXPECT_FALSE(BitPatternPool(_111).has_all(_01a)); + // trivially covered by any pool + EXPECT_TRUE(BitPatternPool(_011).has_all(_01x)); + EXPECT_TRUE(BitPatternPool(_011).has_all(_01z)); + EXPECT_TRUE(BitPatternPool(_111).has_all(_01x)); } YOSYS_NAMESPACE_END diff --git a/tests/verilog/temp/issue4402_syn.v b/tests/verilog/temp/issue4402_syn.v new file mode 100644 index 000000000..b098b8d6f --- /dev/null +++ b/tests/verilog/temp/issue4402_syn.v @@ -0,0 +1,48 @@ +/* Generated by Yosys 0.66+154 (git sha1 23aadd92a-dirty, Release, Clang /nix/store/mw4gasdvwgscgpxpzihjgchfhs3hhqhn-clang-wrapper-21.1.8/bin/clang++ 21.1.8) [git@github.com:YosysHQ/yosys at nella/x-wildcard] */ + +(* top = 1 *) +(* src = "< Date: Tue, 7 Jul 2026 04:03:17 +0200 Subject: [PATCH 4/4] Rm. --- tests/verilog/temp/issue4402_syn.v | 48 ------------------------------ 1 file changed, 48 deletions(-) delete mode 100644 tests/verilog/temp/issue4402_syn.v diff --git a/tests/verilog/temp/issue4402_syn.v b/tests/verilog/temp/issue4402_syn.v deleted file mode 100644 index b098b8d6f..000000000 --- a/tests/verilog/temp/issue4402_syn.v +++ /dev/null @@ -1,48 +0,0 @@ -/* Generated by Yosys 0.66+154 (git sha1 23aadd92a-dirty, Release, Clang /nix/store/mw4gasdvwgscgpxpzihjgchfhs3hhqhn-clang-wrapper-21.1.8/bin/clang++ 21.1.8) [git@github.com:YosysHQ/yosys at nella/x-wildcard] */ - -(* top = 1 *) -(* src = "<