Skip to content

Commit

Permalink
Add functions to compute minimum number of bits required to store int…
Browse files Browse the repository at this point in the history
…eger 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).
  • Loading branch information
daglem committed Mar 6, 2024
1 parent 8882f95 commit 9e8dd90
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 0 deletions.
39 changes: 39 additions & 0 deletions kernel/yosys.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
#include <limits.h>
#include <errno.h>

#if __cplusplus >= 202002L
# include <bit>
#endif

#include "libs/json11/json11.hpp"

YOSYS_NAMESPACE_BEGIN
Expand Down Expand Up @@ -175,6 +179,41 @@ 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.
int min_bit_width(int x)
{
int sgn = 0;
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 the most negative number,
// whose two's complement is equal to itself, i.e. MSB is set.
sgn += (x >= 0);
}
return sgn + min_bit_width((unsigned)x);
}

int readsome(std::istream &f, char *s, int n)
{
int rc = int(f.readsome(s, n));
Expand Down
2 changes: 2 additions & 0 deletions kernel/yosys.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit 9e8dd90

Please sign in to comment.