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
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ They are most useful for writing code that has to adapt to what the platform pro
#endif
----

- `BOOST_INT128_HAS_INT128`: This is defined when compiling on a platform that has builtin `pass:[__int128]` or `pass:[unsigned __int128]` types (e.g. `pass:[__x86_64__]`).
- `BOOST_INT128_HAS_INT128`: This is defined when compiling on a platform that has builtin `pass:[__int128]` or `pass:[unsigned __int128]` types (e.g. `pass:[__x86_64__]`), and not user disabled by `BOOST_INT128_NO_BUILTIN_INT128`.

- `BOOST_INT128_ENDIAN_LITTLE_BYTE`: This is defined to `1` when compiling on a little endian architecture, otherwise `0`.

Expand Down
2 changes: 2 additions & 0 deletions examples/math_and_random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wundef"
#pragma clang diagnostic ignored "-Wstring-conversion"
#pragma clang diagnostic ignored "-Wsign-conversion"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif

// end::exclude[]
Expand Down
4 changes: 2 additions & 2 deletions include/boost/int128/bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int popcount(const uint12

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

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

if (BOOST_INT128_IS_CONSTANT_EVALUATED(x))
{
Expand All @@ -163,7 +163,7 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int popcount(const uint12
#endif
}

#elif defined(_M_IX86) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION)
#elif defined(_M_IX86) && !defined(__GNUC__) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION)

if (BOOST_INT128_IS_CONSTANT_EVALUATED(x))
{
Expand Down
8 changes: 4 additions & 4 deletions include/boost/int128/cstdlib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ BOOST_INT128_EXPORT struct i128div_t

BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr u128div_t div(const uint128 x, const uint128 y) noexcept
{
if (BOOST_INT128_UNLIKELY(x == 0U || y == 0U))
if (y == 0U)
{
return u128div_t{0U, 0U};
BOOST_INT128_UNREACHABLE;
}

if (x < y)
Expand Down Expand Up @@ -56,9 +56,9 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr u128div_t div(const uint1

BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr i128div_t div(const int128 x, const int128 y) noexcept
{
if (BOOST_INT128_UNLIKELY(x == 0 || y == 0))
if (y == 0)
{
return i128div_t{0, 0};
BOOST_INT128_UNREACHABLE;
}

const auto abs_lhs {static_cast<uint128>(abs(x))};
Expand Down
4 changes: 2 additions & 2 deletions include/boost/int128/detail/clz.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ constexpr int countl_impl(unsigned long long x) noexcept
return x ? __builtin_clzll(x) : std::numeric_limits<unsigned long long>::digits;
}

#elif (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION) && !(defined(__CUDACC__) && defined(BOOST_INT128_ENABLE_CUDA))
#elif (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(__GNUC__) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION) && !(defined(__CUDACC__) && defined(BOOST_INT128_ENABLE_CUDA))

constexpr int countl_impl(std::uint32_t x) noexcept
{
Expand Down Expand Up @@ -166,7 +166,7 @@ constexpr int countl_impl(std::uint64_t x) noexcept
}
}

#elif defined(_M_IX86) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION)
#elif defined(_M_IX86) && !defined(__GNUC__) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION)

constexpr int countl_impl(std::uint32_t x) noexcept
{
Expand Down
2 changes: 1 addition & 1 deletion include/boost/int128/detail/common_mul.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ BOOST_INT128_HOST_DEVICE BOOST_INT128_FORCE_INLINE constexpr std::uint64_t umul(

return _umul128(a, b, &hi);

#elif defined(_M_ARM64) && !defined(__CUDA_ARCH__) && !defined(__SYCL_DEVICE_ONLY__)
#elif defined(_M_ARM64) && !defined(__GNUC__) && !defined(__CUDA_ARCH__) && !defined(__SYCL_DEVICE_ONLY__)

hi = __umulh(a, b);
return a * b;
Expand Down
6 changes: 5 additions & 1 deletion include/boost/int128/detail/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
// Use 128-bit integers.
// The SYCL device target (spir64) has no native 128-bit integer, so on the device pass
// we fall back to the portable path (the same one used on platforms without __int128).
#if (defined(BOOST_HAS_INT128) || (defined(__SIZEOF_INT128__) && !defined(_MSC_VER)) && !defined(BOOST_INT128_NO_BUILTIN_INT128)) && !defined(__SYCL_DEVICE_ONLY__)
#if (defined(BOOST_HAS_INT128) || (defined(__SIZEOF_INT128__) && !defined(_MSC_VER))) && !defined(__SYCL_DEVICE_ONLY__) && !defined(BOOST_INT128_NO_BUILTIN_INT128)

#define BOOST_INT128_HAS_INT128

Expand Down Expand Up @@ -157,6 +157,10 @@ BOOST_int128EST_EXPORT using builtin_u128 = std::_Unsigned128;
# define BOOST_INT128_FORCE_INLINE inline
#endif

// MinGW defines the MSVC platform macros (_M_AMD64, _M_IX86, _M_ARM64) for source
// compatibility, but it provides the GNU intrinsics rather than the MSVC ones. Every
// guard selecting an MSVC-only intrinsic (__shiftleft128, _umul128, __umulh, _BitScan*,
// __popcnt*, ...) therefore has to exclude GNU-mode compilers with !defined(__GNUC__).
#ifdef __x86_64__

#ifndef BOOST_INT128_BUILD_MODULE
Expand Down
10 changes: 10 additions & 0 deletions include/boost/int128/detail/conversions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ BOOST_INT128_HOST_DEVICE constexpr bool operator>=(const T lhs, const U rhs) noe
return static_cast<uint128>(lhs) >= static_cast<uint128>(rhs);
}

#ifdef BOOST_INT128_HAS_SPACESHIP_OPERATOR

template <typename T, typename U, std::enable_if_t<detail::is_valid_overload_v<T> && detail::is_valid_overload_v<U> && !std::is_same<T, U>::value, bool> = true>
BOOST_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const T lhs, const U rhs) noexcept
{
return static_cast<uint128>(lhs) <=> static_cast<uint128>(rhs);
}

#endif

//=====================================
// Arithmetic Operators
//=====================================
Expand Down
2 changes: 1 addition & 1 deletion include/boost/int128/detail/ctz.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ BOOST_INT128_HOST_DEVICE constexpr int countr_impl(std::uint32_t x) noexcept

#endif

#if (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_INT128_HAS_BUILTIN(__builtin_ctz) && !(defined(__CUDACC__) && defined(BOOST_INT128_ENABLE_CUDA))
#if (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(__GNUC__) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_INT128_HAS_BUILTIN(__builtin_ctz) && !(defined(__CUDACC__) && defined(BOOST_INT128_ENABLE_CUDA))

constexpr int countr_impl(std::uint64_t x) noexcept
{
Expand Down
31 changes: 27 additions & 4 deletions include/boost/int128/detail/int128_imp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,27 @@ int128
template <BOOST_INT128_DEFAULTED_SIGNED_INTEGER_CONCEPT>
BOOST_INT128_HOST_DEVICE constexpr operator SignedInteger() const noexcept { return static_cast<SignedInteger>(low); }

#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4127)
#endif

template <BOOST_INT128_DEFAULTED_UNSIGNED_INTEGER_CONCEPT>
BOOST_INT128_HOST_DEVICE constexpr operator UnsignedInteger() const noexcept { return static_cast<UnsignedInteger>(low); }
BOOST_INT128_HOST_DEVICE constexpr operator UnsignedInteger() const noexcept
{
BOOST_INT128_IF_CONSTEXPR (std::is_same<UnsignedInteger, bool>::value)
{
return low || high;
}
else
{
return static_cast<UnsignedInteger>(low);
}
}

#ifdef _MSC_VER
# pragma warning(pop)
#endif

#if defined(BOOST_INT128_HAS_INT128) || defined(BOOST_INT128_HAS_MSVC_INT128)

Expand Down Expand Up @@ -1300,7 +1319,7 @@ BOOST_INT128_HOST_DEVICE int128 intrinsic_ls_impl(const int128 lhs, const Intege

# endif

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

if (rhs >= 64)
{
Expand Down Expand Up @@ -1497,7 +1516,7 @@ BOOST_INT128_HOST_DEVICE int128 intrinsic_rs_impl(const int128 lhs, const Intege

# endif

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

if (rhs >= 64)
{
Expand Down Expand Up @@ -1752,7 +1771,7 @@ BOOST_INT128_HOST_DEVICE BOOST_INT128_FORCE_INLINE constexpr int128 default_sub(

return detail::from_bits(result_high, result_low);

#elif defined(__aarch64__) && !defined(__APPLE__)
#elif defined(__aarch64__) && !defined(__APPLE__) && defined(BOOST_INT128_HAS_INT128)

// Unsigned wrap for consistent two's-complement semantics
return int128{static_cast<detail::builtin_u128>(lhs) - static_cast<detail::builtin_u128>(rhs)};
Expand Down Expand Up @@ -2311,6 +2330,10 @@ BOOST_INT128_HOST_DEVICE constexpr int128 operator/(const SignedInteger lhs, con
}
}

#if defined(__clang__)
# pragma clang diagnostic pop
#endif

#ifdef _MSC_VER
# pragma warning(pop)
#endif
Expand Down
35 changes: 30 additions & 5 deletions include/boost/int128/detail/uint128_imp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,27 @@ uint128
template <BOOST_INT128_DEFAULTED_SIGNED_INTEGER_CONCEPT>
BOOST_INT128_HOST_DEVICE constexpr operator SignedInteger() const noexcept { return static_cast<SignedInteger>(low); }

#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4127)
#endif

template <BOOST_INT128_DEFAULTED_UNSIGNED_INTEGER_CONCEPT>
BOOST_INT128_HOST_DEVICE constexpr operator UnsignedInteger() const noexcept { return static_cast<UnsignedInteger>(low); }
BOOST_INT128_HOST_DEVICE constexpr operator UnsignedInteger() const noexcept
{
BOOST_INT128_IF_CONSTEXPR (std::is_same<UnsignedInteger, bool>::value)
{
return low || high;
}
else
{
return static_cast<UnsignedInteger>(low);
}
}

#ifdef _MSC_VER
# pragma warning(pop)
#endif

#if defined(BOOST_INT128_HAS_INT128) || defined(BOOST_INT128_HAS_MSVC_INT128)

Expand Down Expand Up @@ -439,7 +458,7 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr bool operator==(const uin

return lhs.low == rhs.low && lhs.high == rhs.high;

#elif defined (__x86_64__) && !defined(BOOST_INT128_NO_BUILTIN_INT128)
#elif defined(__x86_64__) && defined(BOOST_INT128_HAS_INT128)

return static_cast<detail::builtin_u128>(lhs) == static_cast<detail::builtin_u128>(rhs);

Expand Down Expand Up @@ -535,7 +554,7 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr bool operator!=(const uin

return lhs.low != rhs.low || lhs.high != rhs.high;

#elif defined(__x86_64__) && !defined(BOOST_INT128_NO_BUILTIN_INT128)
#elif defined(__x86_64__) && defined(BOOST_INT128_HAS_INT128)

return static_cast<detail::builtin_u128>(lhs) != static_cast<detail::builtin_u128>(rhs);

Expand Down Expand Up @@ -2135,7 +2154,7 @@ BOOST_INT128_HOST_DEVICE BOOST_INT128_FORCE_INLINE uint128 msvc_mul(const uint12
return result;
}

#elif defined(_M_ARM64)
#elif defined(_M_ARM64) && !defined(__GNUC__)

BOOST_INT128_HOST_DEVICE BOOST_INT128_FORCE_INLINE uint128 msvc_mul(const uint128 lhs, const uint128 rhs) noexcept
{
Expand Down Expand Up @@ -2202,7 +2221,7 @@ BOOST_INT128_HOST_DEVICE BOOST_INT128_FORCE_INLINE constexpr uint128 default_mul
// s390x intentionally falls through to the synthetic low_word_mul below. Casting to builtin_u128
// makes GCC reconstruct the value through a vector-unit stack round-trip that is several times
// slower, and the memcpy path is unsafe for the narrow (scalar rhs) overloads on big-endian.
#elif ((defined(_M_AMD64) && !defined(__GNUC__)) || defined(_M_ARM64)) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION)
#elif (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(__GNUC__) && !defined(BOOST_INT128_NO_CONSTEVAL_DETECTION)

if (!BOOST_INT128_IS_CONSTANT_EVALUATED(lhs))
{
Expand Down Expand Up @@ -2506,6 +2525,12 @@ BOOST_INT128_HOST_DEVICE inline uint128& uint128::operator/=(const Integer rhs)

#endif // BOOST_INT128_HAS_MSVC_INT128

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

//=====================================
// Modulo Operator
//=====================================
Expand Down
2 changes: 1 addition & 1 deletion include/boost/int128/format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#ifndef BOOST_INT128_FORMAT_HPP
#define BOOST_INT128_FORMAT_HPP

#if __has_include(<format>) && defined(__cpp_lib_format) && __cpp_lib_format >= 201907L && !defined(BOOST_DECIMAL_DISABLE_CLIB)
#if __has_include(<format>) && defined(__cpp_lib_format) && __cpp_lib_format >= 201907L

#include <boost/int128/detail/mini_to_chars.hpp>
#include <boost/int128/detail/config.hpp>
Expand Down
28 changes: 7 additions & 21 deletions include/boost/int128/numeric.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <boost/int128/bit.hpp>
#include <boost/int128/cstdlib.hpp>
#include <boost/int128/detail/traits.hpp>
#include <boost/int128/utilities.hpp>

#ifndef BOOST_INT128_BUILD_MODULE

Expand Down Expand Up @@ -140,35 +141,20 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128 saturating_sub(con

BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr uint128 saturating_mul(const uint128 x, const uint128 y) noexcept
{
const auto x_bits {bit_width(x)};
const auto y_bits {bit_width(y)};

if ((x_bits + y_bits) > std::numeric_limits<uint128>::digits)
{
return (std::numeric_limits<uint128>::max)();
}

return x * y;
uint128 res {};
return ckd_mul(&res, x, y) ? (std::numeric_limits<uint128>::max)() : res;
}

BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128 saturating_mul(const int128 x, const int128 y) noexcept
{
const auto x_bits {bit_width(static_cast<uint128>(abs(x)))};
const auto y_bits {bit_width(static_cast<uint128>(abs(y)))};
int128 res {};
const auto overflowed {ckd_mul(&res, x, y)};

if ((x_bits + y_bits) > std::numeric_limits<int128>::digits)
if (overflowed)
{
if ((x < 0) != (y < 0))
{
return (std::numeric_limits<int128>::min)();
}
else
{
return (std::numeric_limits<int128>::max)();
}
return (x < 0) != (y < 0) ? (std::numeric_limits<int128>::min)() : (std::numeric_limits<int128>::max)();
}

const int128 res {x * y};
return res;
}

Expand Down
2 changes: 1 addition & 1 deletion include/boost/int128/random.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct make_unsigned<int128::uint128>
template <>
struct make_unsigned<int128::int128>
{
using type = int128::int128;
using type = int128::uint128;
};

template <class T, bool intrinsic>
Expand Down
3 changes: 3 additions & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ run github_issue_221.cpp ;
run github_issue_272.cpp ;
run github_issue_377.cpp ;
run github_issue_432.cpp ;
compile github_issue_477.cpp ;
run github_issue_479.cpp ;
compile github_issue_480.cpp ;

# Compilation of individual headers
compile compile_tests/int128_master_header_compile.cpp ;
Expand Down
34 changes: 34 additions & 0 deletions test/github_issue_477.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2026 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
//
// See: https://github.com/cppalliance/int128/issues/477

#include <boost/int128.hpp>

#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4459)
#endif

constexpr boost::int128::uint128 unsigned_value{1, 0};

constexpr bool a = unsigned_value;
static_assert(a, "Wrong value");

constexpr bool b(unsigned_value);
static_assert(b, "Wrong value");

constexpr bool c = static_cast<bool>(unsigned_value);
static_assert(c, "Wrong value");

constexpr boost::int128::int128 signed_value{1, 0};

constexpr bool d = signed_value;
static_assert(d, "Wrong value");

constexpr bool e(signed_value);
static_assert(e, "Wrong value");

constexpr bool f = static_cast<bool>(signed_value);
static_assert(f, "Wrong value");
Loading
Loading