Skip to content

Commit f898ec5

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 cfb86ae commit f898ec5

File tree

3 files changed

+11
-18
lines changed

3 files changed

+11
-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/UInt.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: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,9 @@ 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) { return i == T::BITS ? 0 : value; };
197+
const auto l_one = zero_or(T::all_ones() << i); // 0b111...000
198+
const auto r_one = zero_or(T::all_ones() >> i); // 0b000...111
198199
const int zeros = i;
199200
const int ones = T::BITS - zeros;
200201
ASSERT_EQ(cpp::countr_one(r_one), ones);
@@ -559,10 +560,6 @@ TEST(LlvmLibcUIntClassTest, ShiftLeftTests) {
559560
LL_UInt128 result5({0, 0x2468ace000000000});
560561
EXPECT_EQ((val2 << 100), result5);
561562

562-
LL_UInt128 result6({0, 0});
563-
EXPECT_EQ((val2 << 128), result6);
564-
EXPECT_EQ((val2 << 256), result6);
565-
566563
LL_UInt192 val3({1, 0, 0});
567564
LL_UInt192 result7({0, 1, 0});
568565
EXPECT_EQ((val3 << 64), result7);
@@ -589,10 +586,6 @@ TEST(LlvmLibcUIntClassTest, ShiftRightTests) {
589586
LL_UInt128 result5({0x0000000001234567, 0});
590587
EXPECT_EQ((val2 >> 100), result5);
591588

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

0 commit comments

Comments
 (0)