diff --git a/src/base/intmath.hh b/src/base/intmath.hh index 308c33f269..7acb8893cb 100644 --- a/src/base/intmath.hh +++ b/src/base/intmath.hh @@ -135,7 +135,6 @@ mulSigned(std::make_signed_t &high, std::make_signed_t &low, }; /** - * @ingroup api_base_utils * Multiply two values with place value p. * * (A * p + a) * (B * p + b) = @@ -150,8 +149,8 @@ mulSigned(std::make_signed_t &high, std::make_signed_t &low, */ template static constexpr std::enable_if_t -mulUnsigned(std::make_unsigned_t &high, std::make_unsigned_t &low, - std::make_unsigned_t val_a, std::make_unsigned_t val_b) +mulUnsignedManual(std::make_unsigned_t &high, std::make_unsigned_t &low, + std::make_unsigned_t val_a, std::make_unsigned_t val_b) { low = val_a * val_b; @@ -178,8 +177,22 @@ mulUnsigned(std::make_unsigned_t &high, std::make_unsigned_t &low, */ template static constexpr std::enable_if_t -mulSigned(std::make_signed_t &high, std::make_signed_t &low, - std::make_signed_t val_a, std::make_signed_t val_b) +mulUnsigned(std::make_unsigned_t &high, std::make_unsigned_t &low, + std::make_unsigned_t val_a, std::make_unsigned_t val_b) +{ +#ifdef __SIZEOF_INT128__ + __uint128_t val = (__uint128_t)val_a * (__uint128_t)val_b; + low = val; + high = (val >> 64); +#else + mulUnsignedManual(high, low, val_a, val_b); +#endif +} + +template +static constexpr std::enable_if_t +mulSignedManual(std::make_signed_t &high, std::make_signed_t &low, + std::make_signed_t val_a, std::make_signed_t val_b) { uint64_t u_high = 0, u_low = 0; mulUnsigned(u_high, u_low, val_a, val_b); @@ -193,6 +206,23 @@ mulSigned(std::make_signed_t &high, std::make_signed_t &low, low = u_low; } +/** + * @ingroup api_base_utils + */ +template +static constexpr std::enable_if_t +mulSigned(std::make_signed_t &high, std::make_signed_t &low, + std::make_signed_t val_a, std::make_signed_t val_b) +{ +#ifdef __SIZEOF_INT128__ + __int128_t val = (__int128_t)val_a * (__int128_t)val_b; + low = val; + high = (val >> 64); +#else + mulSignedManual(high, low, val_a, val_b); +#endif +} + /** * This function is used to align addresses in memory. * diff --git a/src/base/intmath.test.cc b/src/base/intmath.test.cc index 4eb8aaf163..b7fb34aebc 100644 --- a/src/base/intmath.test.cc +++ b/src/base/intmath.test.cc @@ -214,6 +214,12 @@ TEST(IntmathTest, mulUnsignedWide) EXPECT_EQ(hi, 0x1); EXPECT_EQ(low, 0xfffffffffffffffe); + hi = 0; + low = 0; + mulUnsignedManual(hi, low, a, b); + EXPECT_EQ(hi, 0x1); + EXPECT_EQ(low, 0xfffffffffffffffe); + a = 0; b = 0x5555555555555555; mulUnsigned(hi, low, a, b); @@ -231,6 +237,12 @@ TEST(IntmathTest, mulSignedWide) EXPECT_EQ(hi, 0x3fffffffffffffff); EXPECT_EQ(low, -0x8000000000000000); + hi = 0; + low = 0; + mulSignedManual(hi, low, a, b); + EXPECT_EQ(hi, 0x3fffffffffffffff); + EXPECT_EQ(low, -0x8000000000000000); + a = 0; b = -0x5555555555555555; mulSigned(hi, low, a, b);