From 5628dff0bd9f8eaa34d3ae80b845354a28bfd0f1 Mon Sep 17 00:00:00 2001 From: nella Date: Tue, 7 Jul 2026 15:04:57 +0200 Subject: [PATCH] Fix wide shift count fold. --- kernel/rtlil.cc | 2 +- tests/opt/opt_expr_shift.ys | 30 ++++++++++++++++++++++++++++++ tests/unit/kernel/rtlilTest.cc | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d7503d5e2..c20d1e791 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -588,7 +588,7 @@ bool RTLIL::Const::convertible_to_int(bool is_signed) const if (size == 32) { if (is_signed) return true; - return back() != State::S1; + return (*this)[size - 1] != State::S1; } return false; diff --git a/tests/opt/opt_expr_shift.ys b/tests/opt/opt_expr_shift.ys index 5a27562f6..4ceb215f8 100644 --- a/tests/opt/opt_expr_shift.ys +++ b/tests/opt/opt_expr_shift.ys @@ -114,6 +114,36 @@ select -assert-none t:$shiftx design -reset +read_verilog <> 33'h0ffffffff; + assign sshl = in <<< 33'h0ffffffff; + assign sshr = in >>> 33'h0ffffffff; +endmodule +EOT + +select -assert-count 1 t:$shl +select -assert-count 1 t:$shr +select -assert-count 1 t:$sshl +select -assert-count 1 t:$sshr + +equiv_opt -assert opt_expr + +design -load postopt +select -assert-none t:$shl +select -assert-none t:$shr +select -assert-none t:$sshl +select -assert-none t:$sshr + +design -reset + read_verilog < +#include #include "kernel/rtlil.h" YOSYS_NAMESPACE_BEGIN @@ -35,6 +36,39 @@ namespace RTLIL { EXPECT_FALSE(c2 < c3); } + TEST_F(KernelRtlilTest, ConstConvertibleToInt) { + // A Const whose minimal unsigned size is exactly 32 bits (bit 31 set) + // but whose full width is larger must not be reported as convertible + // to a (signed) int when treated as unsigned + { + // 33 bits: bits 0..31 = 1, bit 32 = 0 => value 0xffffffff + std::vector v(33, S1); + v[32] = S0; + Const c(v); + EXPECT_FALSE(c.convertible_to_int(false)); + EXPECT_EQ(c.as_int_saturating(false), std::numeric_limits::max()); + EXPECT_FALSE(c.convertible_to_int(true)); + EXPECT_EQ(c.as_int_saturating(true), std::numeric_limits::max()); + } + + { + // 32-bit unsigned 0x7fffffff fits in a signed int + std::vector v(32, S1); + v[31] = S0; + Const c(v); + EXPECT_TRUE(c.convertible_to_int(false)); + EXPECT_EQ(c.as_int(false), 0x7fffffff); + } + + { + // 32-bit unsigned 0xffffffff does not fit in a signed int + std::vector v(32, S1); + Const c(v); + EXPECT_FALSE(c.convertible_to_int(false)); + EXPECT_EQ(c.as_int_saturating(false), std::numeric_limits::max()); + } + } + TEST_F(KernelRtlilTest, ConstStr) { // We have multiple distinct sections since it's annoying // to list multiple testcases as friends of Const in kernel/rtlil.h