From 2998f970d87dd96f630ad592d3292401221d942d Mon Sep 17 00:00:00 2001 From: Junekey Jeon Date: Mon, 15 Apr 2024 19:03:36 -0700 Subject: [PATCH] Try to address https://github.com/jk-jeon/dragonbox/issues/61, and also add a path for ICC --- include/dragonbox/dragonbox.h | 69 +++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/include/dragonbox/dragonbox.h b/include/dragonbox/dragonbox.h index 935f7a6..63d5992 100644 --- a/include/dragonbox/dragonbox.h +++ b/include/dragonbox/dragonbox.h @@ -198,6 +198,8 @@ #if defined(_MSC_VER) #include +#elif defined(__INTEL_COMPILER) + #include #endif namespace jkj { @@ -618,24 +620,67 @@ namespace jkj { // To suppress warning. static_cast(generic_impl); + JKJ_IF_CONSTEXPR(value_bits::value > 64) { + generic_impl(); + return *this; + } + JKJ_IF_CONSTEVAL { generic_impl(); return *this; } -#if JKJ_HAS_BUILTIN(__builtin_addcll) - static_assert(stdr::is_same::value && - value_bits::value == 64, - ""); - unsigned long long carry{}; - low_ = __builtin_addcll(low_, n, 0, &carry); - high_ = __builtin_addcll(high_, 0, carry, &carry); -#elif JKJ_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) + + // See https://github.com/fmtlib/fmt/pull/2985. +#if JKJ_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) + JKJ_IF_CONSTEXPR( + stdr::is_same::value) { + unsigned long long carry{}; + low_ = stdr::uint_least64_t(__builtin_addcll(low_, n, 0, &carry)); + high_ = stdr::uint_least64_t(__builtin_addcll(high_, 0, carry, &carry)); + return *this; + } +#endif +#if JKJ_HAS_BUILTIN(__builtin_addcl) && !defined(__ibmxl__) + JKJ_IF_CONSTEXPR(stdr::is_same::value) { + unsigned long carry{}; + low_ = stdr::uint_least64_t( + __builtin_addcl(static_cast(low_), + static_cast(n), 0, &carry)); + high_ = stdr::uint_least64_t( + __builtin_addcl(static_cast(high_), 0, carry, &carry)); + return *this; + } +#endif +#if JKJ_HAS_BUILTIN(__builtin_addc) && !defined(__ibmxl__) + JKJ_IF_CONSTEXPR(stdr::is_same::value) { + unsigned int carry{}; + low_ = stdr::uint_least64_t(__builtin_addc(static_cast(low_), + static_cast(n), 0, + &carry)); + high_ = stdr::uint_least64_t( + __builtin_addc(static_cast(high_), 0, carry, &carry)); + return *this; + } +#endif + +#if JKJ_HAS_BUILTIN(__builtin_ia32_addcarry_u64) + // __builtin_ia32_addcarry_u64 is not documented, but it seems it takes unsigned + // long long arguments. unsigned long long result{}; - auto const carry = __builtin_ia32_addcarryx_u64(0, low_, n, &result); - low_ = result; - __builtin_ia32_addcarryx_u64(carry, high_, 0, &result); - high_ = result; + auto const carry = __builtin_ia32_addcarry_u64(0, low_, n, &result); + low_ = stdr::uint_least64_t(result); + __builtin_ia32_addcarry_u64(carry, high_, 0, &result); + high_ = stdr::uint_least64_t(result); #elif defined(_MSC_VER) && defined(_M_X64) + // On MSVC, uint_least64_t and __int64 must be unsigned long long; see + // https://learn.microsoft.com/en-us/cpp/c-runtime-library/standard-types + // and https://learn.microsoft.com/en-us/cpp/cpp/int8-int16-int32-int64. + static_assert(stdr::is_same::value, + ""); + auto const carry = _addcarry_u64(0, low_, n, &low_); + _addcarry_u64(carry, high_, 0, &high_); +#elif defined(__INTEL_COMPILER) && (defined(_M_X64) || defined(__x86_64)) + static_assert(std::is_same::value, ""); auto const carry = _addcarry_u64(0, low_, n, &low_); _addcarry_u64(carry, high_, 0, &high_); #else