From 9a0559c4e33e1173c24494a3b594f16598b50807 Mon Sep 17 00:00:00 2001 From: Dag Lem Date: Wed, 6 Mar 2024 18:28:10 +0100 Subject: [PATCH] Add functions to compute minimum number of bits required to store integer values Separate functions are implemented for signed and unsigned integers. Note that the current use of ceil_log2(x) for x >= 0 may be incorrect in some cases; the minimum number of bits required to store x is really ceil_log2(x + 1). --- kernel/yosys.cc | 38 ++++++++++++++++++++++++++++++++++++++ kernel/yosys.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index c7f5bebdab7..c851221796e 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -73,6 +73,10 @@ #include #include +#if __cplusplus >= 202002L +# include +#endif + #include "libs/json11/json11.hpp" YOSYS_NAMESPACE_BEGIN @@ -175,6 +179,40 @@ int ceil_log2(int x) #endif } +// Calculate the minimum number of bits required to store an unsigned integer value. +// Note that min_bit_width(0u) == 0. +int min_bit_width(unsigned x) +{ +#if __cplusplus >= 202002L + return std::bit_width(x); +#else + int width = 0; + while (x) { + width += 1; + x >>= 1; + } + return width; +#endif +} + +// Calculate the minimum number of bits required to store a signed integer value, +// using two's complement representation for negative values. +// Note that the sign bit is included in the width for all values except 0. +int min_bit_width(int x) +{ + if (x < 0) { + // Compute two's complement of negative value. + // Negative numbers are represented in two's complement form + // in SystemVerilog, and this is also guaranteed by C++20. + // C++20 also makes integral conversion of unsigned integers + // to signed integers well defined. + x = -(unsigned)x; + } + // Add a bit for sign, except for 0 and the most negative number, whose + // two's complement is equal to itself, i.e. the sign bit is still set. + return (x > 0) + min_bit_width((unsigned)x); +} + int readsome(std::istream &f, char *s, int n) { int rc = int(f.readsome(s, n)); diff --git a/kernel/yosys.h b/kernel/yosys.h index 0a4641d1819..43cd756b56f 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -274,6 +274,8 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); int ceil_log2(int x) YS_ATTRIBUTE(const); +int min_bit_width(unsigned x); +int min_bit_width(int x); inline std::string vstringf(const char *fmt, va_list ap) {