Skip to content

Commit b88a1dd

Browse files
authored
[libc] Make BigInt bitwise shift consistent with regular integral semantics. (#87874)
This patch removes the test for cases where the shift operand is greater or equal to the bit width of the number. This is done for two reasons, first it makes `BigInt` consistent with regular integral bitwise shift semantics, and second it makes the shift operation faster. The shift operation is on the critical path for `exp` and `log` operations, see #86137 (comment).
1 parent fc7087b commit b88a1dd

File tree

3 files changed

+9
-17
lines changed

3 files changed

+9
-17
lines changed

libc/src/__support/FPUtil/dyadic_float.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,17 @@ template <size_t Bits> struct DyadicFloat {
122122

123123
int exp_lo = exp_hi - static_cast<int>(PRECISION) - 1;
124124

125-
MantissaType m_hi(mantissa >> shift);
125+
MantissaType m_hi =
126+
shift >= MantissaType::BITS ? MantissaType(0) : mantissa >> shift;
126127

127128
T d_hi = FPBits<T>::create_value(
128129
sign, exp_hi,
129130
(static_cast<output_bits_t>(m_hi) & FPBits<T>::SIG_MASK) |
130131
IMPLICIT_MASK)
131132
.get_val();
132133

133-
MantissaType round_mask = MantissaType(1) << (shift - 1);
134+
MantissaType round_mask =
135+
shift > MantissaType::BITS ? 0 : MantissaType(1) << (shift - 1);
134136
MantissaType sticky_mask = round_mask - MantissaType(1);
135137

136138
bool round_bit = !(mantissa & round_mask).is_zero();

libc/src/__support/big_int.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,18 +249,14 @@ LIBC_INLINE constexpr bool is_negative(cpp::array<word, N> &array) {
249249
enum Direction { LEFT, RIGHT };
250250

251251
// A bitwise shift on an array of elements.
252-
// TODO: Make the result UB when 'offset' is greater or equal to the number of
253-
// bits in 'array'. This will allow for better code performance.
252+
// 'offset' must be less than TOTAL_BITS (i.e., sizeof(word) * CHAR_BIT * N)
253+
// otherwise the behavior is undefined.
254254
template <Direction direction, bool is_signed, typename word, size_t N>
255255
LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
256256
size_t offset) {
257257
static_assert(direction == LEFT || direction == RIGHT);
258258
constexpr size_t WORD_BITS = cpp::numeric_limits<word>::digits;
259259
constexpr size_t TOTAL_BITS = N * WORD_BITS;
260-
if (LIBC_UNLIKELY(offset == 0))
261-
return array;
262-
if (LIBC_UNLIKELY(offset >= TOTAL_BITS))
263-
return {};
264260
#ifdef LIBC_TYPES_HAS_INT128
265261
if constexpr (TOTAL_BITS == 128) {
266262
using type = cpp::conditional_t<is_signed, __int128_t, __uint128_t>;
@@ -272,6 +268,8 @@ LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
272268
return cpp::bit_cast<cpp::array<word, N>>(tmp);
273269
}
274270
#endif
271+
if (LIBC_UNLIKELY(offset == 0))
272+
return array;
275273
const bool is_neg = is_signed && is_negative(array);
276274
constexpr auto at = [](size_t index) -> int {
277275
// reverse iteration when direction == LEFT.

libc/test/src/__support/big_int_test.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ TYPED_TEST(LlvmLibcUIntClassTest, Masks, Types) {
192192

193193
TYPED_TEST(LlvmLibcUIntClassTest, CountBits, Types) {
194194
if constexpr (!T::SIGNED) {
195-
for (size_t i = 0; i <= T::BITS; ++i) {
195+
for (size_t i = 0; i < T::BITS; ++i) {
196196
const auto l_one = T::all_ones() << i; // 0b111...000
197197
const auto r_one = T::all_ones() >> i; // 0b000...111
198198
const int zeros = i;
@@ -559,10 +559,6 @@ TEST(LlvmLibcUIntClassTest, ShiftLeftTests) {
559559
LL_UInt128 result5({0, 0x2468ace000000000});
560560
EXPECT_EQ((val2 << 100), result5);
561561

562-
LL_UInt128 result6({0, 0});
563-
EXPECT_EQ((val2 << 128), result6);
564-
EXPECT_EQ((val2 << 256), result6);
565-
566562
LL_UInt192 val3({1, 0, 0});
567563
LL_UInt192 result7({0, 1, 0});
568564
EXPECT_EQ((val3 << 64), result7);
@@ -589,10 +585,6 @@ TEST(LlvmLibcUIntClassTest, ShiftRightTests) {
589585
LL_UInt128 result5({0x0000000001234567, 0});
590586
EXPECT_EQ((val2 >> 100), result5);
591587

592-
LL_UInt128 result6({0, 0});
593-
EXPECT_EQ((val2 >> 128), result6);
594-
EXPECT_EQ((val2 >> 256), result6);
595-
596588
LL_UInt128 v1({0x1111222233334444, 0xaaaabbbbccccdddd});
597589
LL_UInt128 r1({0xaaaabbbbccccdddd, 0});
598590
EXPECT_EQ((v1 >> 64), r1);

0 commit comments

Comments
 (0)