diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 635c867ae..c9ddb815f 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -430,12 +430,12 @@ struct value : public expr_base> { // Detect shifts definitely large than Bits early. for (size_t n = 1; n < amount.chunks; n++) if (amount.data[n] != 0) - return {}; + return (Signed && is_neg()) ? value().bit_not() : value(); // Past this point we can use the least significant chunk as the shift size. size_t shift_chunks = amount.data[0] / chunk::bits; size_t shift_bits = amount.data[0] % chunk::bits; if (shift_chunks >= chunks) - return {}; + return (Signed && is_neg()) ? value().bit_not() : value(); value result; chunk::type carry = 0; for (size_t n = 0; n < chunks - shift_chunks; n++) { @@ -444,12 +444,13 @@ struct value : public expr_base> { : data[chunks - 1 - n] << (chunk::bits - shift_bits); } if (Signed && is_neg()) { - size_t top_chunk_idx = (Bits - shift_bits) / chunk::bits; - size_t top_chunk_bits = (Bits - shift_bits) % chunk::bits; + size_t top_chunk_idx = amount.data[0] > Bits ? 0 : (Bits - amount.data[0]) / chunk::bits; + size_t top_chunk_bits = amount.data[0] > Bits ? 0 : (Bits - amount.data[0]) % chunk::bits; for (size_t n = top_chunk_idx + 1; n < chunks; n++) result.data[n] = chunk::mask; - if (shift_bits != 0) + if (amount.data[0] != 0) result.data[top_chunk_idx] |= chunk::mask << top_chunk_bits; + result.data[result.chunks - 1] &= result.msb_mask; } return result; } diff --git a/tests/cxxrtl/test_value.cc b/tests/cxxrtl/test_value.cc index ca05b89ab..c553f6112 100644 --- a/tests/cxxrtl/test_value.cc +++ b/tests/cxxrtl/test_value.cc @@ -12,4 +12,28 @@ int main() cxxrtl::value<6> c = a.shl(b); assert(c.get() == 0); } + + { + // sshr of unreasonably large size should sign extend correctly + cxxrtl::value<64> a(0u, 0x80000000u); + cxxrtl::value<64> b(0u, 1u); + cxxrtl::value<64> c = a.sshr(b); + assert(c.get() == 0xffffffffffffffffu); + } + + { + // sshr of exteeding Bits should sign extend correctly + cxxrtl::value<8> a(0x80u); + cxxrtl::value<8> b(10u); + cxxrtl::value<8> c = a.sshr(b); + assert(c.get() == 0xffu); + } + + { + // Sign extension should occur correctly + cxxrtl::value<64> a(0x23456789u, 0x8abcdef1u); + cxxrtl::value<8> b(32u); + cxxrtl::value<64> c = a.sshr(b); + assert(c.get() == 0xffffffff8abcdef1u); + } } \ No newline at end of file