Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions include/boost/decimal/detail/fenv_rounding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,12 +645,15 @@ BOOST_DECIMAL_CUDA_CONSTEXPR auto fenv_round(T& val, bool is_neg = false, bool s

#endif

#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4127)
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wsign-conversion"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-conversion"
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4127)
#endif

template <typename TargetDecimalType, typename T1, typename T2, typename T3>
Expand Down Expand Up @@ -743,10 +746,12 @@ BOOST_DECIMAL_CUDA_CONSTEXPR auto coefficient_rounding(T1& coeff, T2& exp, T3& b
return coeff_digits;
}

#ifdef _MSC_VER
# pragma warning(pop)
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#elif defined(_MSC_VER)
# pragma warning(pop)
#endif

} // namespace detail
Expand Down
184 changes: 127 additions & 57 deletions include/boost/decimal/detail/int128/bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,70 +13,106 @@
namespace boost {
namespace int128 {

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool has_single_bit(const uint128_t x) noexcept
namespace impl {

BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_zero_impl(const uint128 x) noexcept
{
return x && !(x & (x - 1U));
return x.high == 0 ? 64 + detail::countl_zero(x.low) : detail::countl_zero(x.high);
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_zero(const uint128_t x) noexcept
} // namespace impl

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_zero(const uint128 x) noexcept
{
return x.high == 0 ? 64 + detail::countl_zero(x.low) : detail::countl_zero(x.high);
#if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) && BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_clzg) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION)

if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x))
{
return impl::countl_zero_impl(x);
}

// The second argument is the result for x == 0, which is undefined without it
return __builtin_clzg(static_cast<detail::builtin_u128>(x), 128);

#else

return impl::countl_zero_impl(x);

#endif
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_one(const uint128_t x) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_one(const uint128 x) noexcept
{
return countl_zero(~x);
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int bit_width(const uint128_t x) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int bit_width(const uint128 x) noexcept
{
return x ? 128 - countl_zero(x) : 0;
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t bit_ceil(const uint128_t x) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128 bit_ceil(const uint128 x) noexcept
{
return x <= 1U ? static_cast<uint128_t>(1) : static_cast<uint128_t>(1) << bit_width(x - 1U);
// __builtin_stdc_bit_ceil not available, but this is equivalent
return x <= 1U ? static_cast<uint128>(1) : static_cast<uint128>(2) << (127 - countl_zero(x - 1));
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t bit_floor(const uint128_t x) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128 bit_floor(const uint128 x) noexcept
{
return x > 0U ? static_cast<uint128_t>(1) << (bit_width(x) - 1U) : static_cast<uint128_t>(0);
// __builtin_stdc_bit_floor not available, but this is equivalent
return x == 0U ? static_cast<uint128>(0) : static_cast<uint128>(1) << (127 - countl_zero(x));
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_zero(const uint128_t x) noexcept
namespace impl {

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_zero_impl(const uint128 x) noexcept
{
return x.low == 0 ? 64 + detail::countr_zero(x.high) : detail::countr_zero(x.low);
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_one(const uint128_t x) noexcept
} // namespace impl

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_zero(const uint128 x) noexcept
{
#if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) && BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctzg) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION)

if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x))
{
return impl::countr_zero_impl(x);
}

// The second argument is the result for x == 0, which is undefined without it
return __builtin_ctzg(static_cast<detail::builtin_u128>(x), 128);

#else

return impl::countr_zero_impl(x);

#endif
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_one(const uint128 x) noexcept
{
return countr_zero(~x);
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t rotl(const uint128_t x, const int s) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128 rotl(const uint128 x, const int s) noexcept
{
// __builtin_stdc_rotate_left not available
constexpr auto mask {127U};
return x << (static_cast<unsigned>(s) & mask) | x >> (static_cast<unsigned>(-s) & mask);
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t rotr(const uint128_t x, const int s) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128 rotr(const uint128 x, const int s) noexcept
{
// __builtin_stdc_rotate_right not available
constexpr auto mask {127U};
return x >> (static_cast<unsigned>(s) & mask) | x << (static_cast<unsigned>(-s) & mask);
}

#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA))

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128_t x) noexcept
{
return __builtin_popcountll(x.high) + __builtin_popcountll(x.low);
}

#endif

namespace impl {

BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount_impl(std::uint64_t x) noexcept
BOOST_int128EST_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount_impl(std::uint64_t x) noexcept
{
x = x - ((x >> 1U) & UINT64_C(0x5555555555555555));
x = (x & UINT64_C(0x3333333333333333)) + ((x >> 2U) & UINT64_C(0x3333333333333333));
Expand All @@ -85,15 +121,34 @@ BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount_impl(std::uint64_
return static_cast<int>((x * UINT64_C(0x0101010101010101)) >> 56U);
}

} // namespace impl
// The exact-match overload above is selected for the 64-bit halves
BOOST_int128EST_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount_impl(const uint128 x) noexcept
{
return popcount_impl(x.high) + popcount_impl(x.low);
}

#if defined(_M_AMD64) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll)
} // namespace impl

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128_t x) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128 x) noexcept
{
#if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) && BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountg) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION)

if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x))
{
return impl::popcount_impl(x.high) + impl::popcount_impl(x.low); // LCOV_EXCL_LINE
return impl::popcount_impl(x);
}

return __builtin_popcountg(static_cast<detail::builtin_u128>(x));

#elif BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA))

return __builtin_popcountll(x.high) + __builtin_popcountll(x.low);

#elif defined(_M_AMD64) && !defined(__GNUC__) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION)

if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x))
{
return impl::popcount_impl(x); // LCOV_EXCL_LINE
}
else
{
Expand All @@ -107,15 +162,12 @@ BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE const

#endif
}
}

#elif defined(_M_IX86) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll)
#elif defined(_M_IX86) && !defined(__GNUC__) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION)

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128_t x) noexcept
{
if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x))
{
return impl::popcount_impl(x.high) + impl::popcount_impl(x.low); // LCOV_EXCL_LINE
return impl::popcount_impl(x); // LCOV_EXCL_LINE
}
else
{
Expand All @@ -137,26 +189,14 @@ BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE const

#endif
}
}

#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) || (defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA))

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128_t x) noexcept
{
return impl::popcount_impl(x.high) + impl::popcount_impl(x.low);
}

#endif
#else

#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA))
return impl::popcount_impl(x);

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t byteswap(const uint128_t x) noexcept
{
return {__builtin_bswap64(x.low), __builtin_bswap64(x.high)};
#endif
}

#endif

namespace impl {

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::uint64_t byteswap_impl(const std::uint64_t x) noexcept
Expand All @@ -166,17 +206,45 @@ BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE const
return (step16 & UINT64_C(0x00FF00FF00FF00FF)) << 8U | (step16 & UINT64_C(0xFF00FF00FF00FF00)) >> 8U;
}

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t byteswap_impl(const uint128_t x) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128 byteswap_impl(const uint128 x) noexcept
{
return {byteswap_impl(x.low), byteswap_impl(x.high)};
}

} // namespace impl

#if defined(_MSC_VER) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64)

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t byteswap(const uint128_t x) noexcept
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128 byteswap(const uint128 x) noexcept
{
// The whole-width builtins are deliberately ranked below the paired 64-bit form.
// Measured today (7/29/2026) they are a regression: the 128-bit value blocks the loop vectorization
// the paired __builtin_bswap64 receives, costing up to 1.5x on arm64, and on x86-64 both
// forms emit identical code. Revisit if the codegen improves.
#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA))

return {__builtin_bswap64(x.low), __builtin_bswap64(x.high)};

// __builtin_bswapg is clang-only (LLVM 22.1) and __builtin_bswap128 is GCC-only (GCC 11),
// so at most one of the two whole-width branches is ever live
#elif defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) && BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswapg) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION)

if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x))
{
return impl::byteswap_impl(x);
}

return static_cast<uint128>(__builtin_bswapg(static_cast<detail::builtin_u128>(x)));

#elif defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) && BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap128) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION)

if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x))
{
return impl::byteswap_impl(x);
}

return static_cast<uint128>(__builtin_bswap128(static_cast<detail::builtin_u128>(x)));

#elif defined(_MSC_VER) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION)

if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x))
{
return impl::byteswap_impl(x); // LCOV_EXCL_LINE
Expand All @@ -185,16 +253,18 @@ BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE const
{
return {_byteswap_uint64(x.low), _byteswap_uint64(x.high)};
}
}

#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64) || (defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA))
#else

BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t byteswap(const uint128_t x) noexcept
{
return impl::byteswap_impl(x);

#endif
}

#endif
BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool has_single_bit(const uint128 x) noexcept
{
return popcount(x) == 1;
}

} // namespace int128
} // namespace boost
Expand Down
Loading
Loading