@@ -1463,6 +1463,13 @@ BOOST_SAFE_NUMBERS_HOST_DEVICE constexpr auto signed_underflow_mul_msg() noexcep
14631463 }
14641464}
14651465
1466+ // clang lowers signed __builtin_mul_overflow on __int128 to __muloti4 (compiler-rt
1467+ // only), which is missing when linking libgcc on clang-13. Limit the fast path to
1468+ // GCC and clang >= 14; everything else uses signed_no_intrin_mul for int128.
1469+ #if BOOST_SAFE_NUMBERS_HAS_BUILTIN(__builtin_mul_overflow) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) && (!defined(__clang__) || __clang_major__ >= 14)
1470+ # define BOOST_SAFE_NUMBERS_HAS_INT128_SIGNED_INTRIN_MUL
1471+ #endif
1472+
14661473#if BOOST_SAFE_NUMBERS_HAS_BUILTIN(__builtin_mul_overflow)
14671474
14681475template <std::signed_integral T>
@@ -1476,6 +1483,24 @@ auto signed_intrin_mul(const T lhs, const T rhs, T& result) -> signed_overflow_s
14761483 return signed_overflow_status::no_error;
14771484}
14781485
1486+ #ifdef BOOST_SAFE_NUMBERS_HAS_INT128_SIGNED_INTRIN_MUL
1487+
1488+ inline auto signed_intrin_mul (const int128::int128_t lhs, const int128::int128_t rhs, int128::int128_t & result) -> signed_overflow_status
1489+ {
1490+ __int128_t builtin_result;
1491+ const auto overflow {__builtin_mul_overflow (static_cast <__int128_t >(lhs), static_cast <__int128_t >(rhs), &builtin_result)};
1492+ result = builtin_result;
1493+
1494+ if (overflow)
1495+ {
1496+ return (lhs >= 0 ) == (rhs >= 0 ) ? signed_overflow_status::overflow : signed_overflow_status::underflow;
1497+ }
1498+
1499+ return signed_overflow_status::no_error;
1500+ }
1501+
1502+ #endif // BOOST_SAFE_NUMBERS_HAS_INT128_SIGNED_INTRIN_MUL
1503+
14791504#elif defined(BOOST_SAFENUMBERS_HAS_WINDOWS_X64_INTRIN) || defined(BOOST_SAFENUMBERS_HAS_WINDOWS_X86_INTRIN)
14801505
14811506template <std::signed_integral T>
@@ -1765,7 +1790,11 @@ struct signed_mul_helper
17651790
17661791 #if BOOST_SAFE_NUMBERS_HAS_BUILTIN(__builtin_mul_overflow) || defined(BOOST_SAFENUMBERS_HAS_WINDOWS_X64_INTRIN) || defined(BOOST_SAFENUMBERS_HAS_WINDOWS_X86_INTRIN)
17671792
1793+ // Route int128 through the intrin path only where the signed 128-bit
1794+ // fast path links (GCC, clang >= 14); elsewhere it uses no_intrin.
1795+ #if !defined(BOOST_SAFE_NUMBERS_HAS_INT128_SIGNED_INTRIN_MUL)
17681796 if constexpr (!std::is_same_v<BasisType, int128::int128_t >)
1797+ #endif
17691798 {
17701799 #if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_ENABLE_CUDA))
17711800
@@ -1812,7 +1841,11 @@ struct signed_mul_helper<overflow_policy::overflow_tuple, BasisType>
18121841
18131842 #if BOOST_SAFE_NUMBERS_HAS_BUILTIN(__builtin_mul_overflow) || defined(BOOST_SAFENUMBERS_HAS_WINDOWS_X64_INTRIN) || defined(BOOST_SAFENUMBERS_HAS_WINDOWS_X86_INTRIN)
18141843
1844+ // Route int128 through the intrin path only where the signed 128-bit
1845+ // fast path links (GCC, clang >= 14); elsewhere it uses no_intrin.
1846+ #if !defined(BOOST_SAFE_NUMBERS_HAS_INT128_SIGNED_INTRIN_MUL)
18151847 if constexpr (!std::is_same_v<BasisType, int128::int128_t >)
1848+ #endif
18161849 {
18171850 #if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_ENABLE_CUDA))
18181851
@@ -1849,7 +1882,11 @@ struct signed_mul_helper<overflow_policy::checked, BasisType>
18491882
18501883 #if BOOST_SAFE_NUMBERS_HAS_BUILTIN(__builtin_mul_overflow) || defined(BOOST_SAFENUMBERS_HAS_WINDOWS_X64_INTRIN) || defined(BOOST_SAFENUMBERS_HAS_WINDOWS_X86_INTRIN)
18511884
1885+ // Route int128 through the intrin path only where the signed 128-bit
1886+ // fast path links (GCC, clang >= 14); elsewhere it uses no_intrin.
1887+ #if !defined(BOOST_SAFE_NUMBERS_HAS_INT128_SIGNED_INTRIN_MUL)
18521888 if constexpr (!std::is_same_v<BasisType, int128::int128_t >)
1889+ #endif
18531890 {
18541891 #if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_ENABLE_CUDA))
18551892
0 commit comments