diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 66ab5f1..5f0c53d 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -637,6 +637,19 @@ fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t umul128(uint64_t ab, uint64_t cd, uint64_t &hi) noexcept { + if (is_constant_evaluated()) { + auto ab_shifted = static_cast(ab >> 32); + auto cd_shifted = static_cast(cd >> 32); + + auto ad = emulu(ab_shifted, static_cast(cd)); + auto bd = emulu(static_cast(ab), static_cast(cd)); + auto adbc = ad + emulu(static_cast(ab), cd_shifted); + auto adbc_carry = static_cast(adbc < ad) << 32; + auto lo = bd + (adbc << 32); + hi = emulu(ab_shifted, cd_shifted) + static_cast(adbc >> 32) + + adbc_carry + static_cast(lo < bd); + return lo; + } #if defined(_M_ARM64) && !defined(__MINGW32__) // ARM64 has native support for 64-bit multiplications, no need to emulate // But MinGW on ARM64 doesn't have native support for 64-bit multiplications @@ -644,19 +657,7 @@ umul128(uint64_t ab, uint64_t cd, uint64_t &hi) noexcept { return ab * cd; #elif (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64) && \ !defined(__GNUC__)) - return _umul128(ab, cd, &hi); // _umul128 not available on ARM64 -#else - auto ab_shifted = static_cast(ab >> 32); - auto cd_shifted = static_cast(cd >> 32); - - auto ad = emulu(ab_shifted, static_cast(cd)); - auto bd = emulu(static_cast(ab), static_cast(cd)); - auto adbc = ad + emulu(static_cast(ab), cd_shifted); - auto adbc_carry = static_cast(adbc < ad) << 32; - auto lo = bd + (adbc << 32); - hi = emulu(ab_shifted, cd_shifted) + static_cast(adbc >> 32) + - adbc_carry + static_cast(lo < bd); - return lo; +return _umul128(ab, cd, &hi); // _umul128 not available on ARM64 #endif }