Skip to content

Commit ccabea0

Browse files
committed
Fix bug on has_single_bit
1 parent 528b7ce commit ccabea0

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

libc/src/__support/UInt.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -971,10 +971,15 @@ bit_cast(const UInt<Bits> &from) {
971971
template <typename T>
972972
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_big_int_v<T>, bool>
973973
has_single_bit(T value) {
974-
for (auto word : value.val)
975-
if (cpp::has_single_bit(word))
976-
return true;
977-
return false;
974+
int bits = 0;
975+
for (auto word : value.val) {
976+
if (word == 0)
977+
continue;
978+
bits += count_ones(word);
979+
if (bits > 1)
980+
return false;
981+
}
982+
return bits == 1;
978983
}
979984

980985
// Specialization of cpp::countr_zero ('bit.h') for BigInt.

libc/test/src/__support/CPP/bit_test.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include <stdint.h>
1414

15+
#include <iostream>
16+
1517
namespace LIBC_NAMESPACE::cpp {
1618

1719
using UnsignedTypes =
@@ -23,10 +25,25 @@ using UnsignedTypes =
2325
cpp::UInt<128>>;
2426

2527
TYPED_TEST(LlvmLibcBitTest, HasSingleBit, UnsignedTypes) {
26-
EXPECT_FALSE(has_single_bit<T>(T(0)));
27-
EXPECT_FALSE(has_single_bit<T>(~T(0)));
28+
constexpr auto ZERO = T(0);
29+
constexpr auto ALL_ONES = T(~ZERO);
30+
EXPECT_FALSE(has_single_bit<T>(ZERO));
31+
EXPECT_FALSE(has_single_bit<T>(ALL_ONES));
32+
2833
for (T value = 1; value; value <<= 1)
2934
EXPECT_TRUE(has_single_bit<T>(value));
35+
36+
// We test that if two bits are set has_single_bit returns false.
37+
// We do this by setting the highest or lowest bit depending or where the
38+
// current bit is. This is a bit convoluted but it helps catch a bug on BigInt
39+
// where we have to work on an element-by-element basis.
40+
constexpr auto MIDPOINT = T(ALL_ONES / 2);
41+
constexpr auto LSB = T(1);
42+
constexpr auto MSB = T(~(ALL_ONES >> 1));
43+
for (T value = 1; value; value <<= 1) {
44+
auto two_bits_value = value | ((value <= MIDPOINT) ? MSB : LSB);
45+
EXPECT_FALSE(has_single_bit<T>(two_bits_value));
46+
}
3047
}
3148

3249
TYPED_TEST(LlvmLibcBitTest, CountLZero, UnsignedTypes) {

0 commit comments

Comments
 (0)