Skip to content

Commit df2ed49

Browse files
committed
[libc] Make BigInt bitwise shift consistent with regular integral semantics.
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 llvm#86137 (comment).
1 parent 684f27d commit df2ed49

File tree

3 files changed

+14
-18
lines changed

3 files changed

+14
-18
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/uint_test.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,12 @@ TYPED_TEST(LlvmLibcUIntClassTest, Masks, Types) {
193193
TYPED_TEST(LlvmLibcUIntClassTest, CountBits, Types) {
194194
if constexpr (!T::SIGNED) {
195195
for (size_t i = 0; i <= T::BITS; ++i) {
196-
const auto l_one = T::all_ones() << i; // 0b111...000
197-
const auto r_one = T::all_ones() >> i; // 0b000...111
196+
const auto zero_or = [i](T value) {
197+
// Prevent UB when i == T::BITS.
198+
return i == T::BITS ? 0 : value;
199+
};
200+
const auto l_one = zero_or(T::all_ones() << i); // 0b111...000
201+
const auto r_one = zero_or(T::all_ones() >> i); // 0b000...111
198202
const int zeros = i;
199203
const int ones = T::BITS - zeros;
200204
ASSERT_EQ(cpp::countr_one(r_one), ones);
@@ -559,10 +563,6 @@ TEST(LlvmLibcUIntClassTest, ShiftLeftTests) {
559563
LL_UInt128 result5({0, 0x2468ace000000000});
560564
EXPECT_EQ((val2 << 100), result5);
561565

562-
LL_UInt128 result6({0, 0});
563-
EXPECT_EQ((val2 << 128), result6);
564-
EXPECT_EQ((val2 << 256), result6);
565-
566566
LL_UInt192 val3({1, 0, 0});
567567
LL_UInt192 result7({0, 1, 0});
568568
EXPECT_EQ((val3 << 64), result7);
@@ -589,10 +589,6 @@ TEST(LlvmLibcUIntClassTest, ShiftRightTests) {
589589
LL_UInt128 result5({0x0000000001234567, 0});
590590
EXPECT_EQ((val2 >> 100), result5);
591591

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

0 commit comments

Comments
 (0)