tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit d92b922fa3bcc892a679d885207e0aee915413d5
parent 65eef9a90d2d0543762d819042619bd72dfee9f0
Author: André Bargull <andre.bargull@gmail.com>
Date:   Sat, 15 Nov 2025 10:15:23 +0000

Bug 1998457 - Part 1: Extend ReciprocalMulConstants for Int64 division. r=spidermonkey-reviewers,iain

Clang and GCC support the non-standard types `__int128_t` and `__uint128_t` on
x64 and arm64 (and other 64-bit architectures, but not for 32-bit architectures).

Unfortunately there are some problems with using `__[u]int128_t` when using
clang-cl, see bug 1998457, comment #10. Therefore the `[U]Int128` classes added
for `Temporal` are used.

Differential Revision: https://phabricator.services.mozilla.com/D271436

Diffstat:
Mjs/src/jit/MacroAssembler.cpp | 3++-
Mjs/src/jit/ReciprocalMulConstants.cpp | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mjs/src/jit/ReciprocalMulConstants.h | 29+++++++++++++++++++++++------
3 files changed, 85 insertions(+), 18 deletions(-)

diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp @@ -2062,7 +2062,8 @@ void MacroAssembler::loadInt32ToStringWithBase( // "Unsigned Division by 7" for the case when |rmc.multiplier| exceeds // UINT32_MAX and we need to adjust the shift amount. - auto rmc = ReciprocalMulConstants::computeUnsignedDivisionConstants(base); + auto rmc = ReciprocalMulConstants::computeUnsignedDivisionConstants( + uint32_t(base)); // We first compute |q = (M * n) >> 32), where M = rmc.multiplier. mulHighUnsigned32(Imm32(rmc.multiplier), input, scratch1); diff --git a/js/src/jit/ReciprocalMulConstants.cpp b/js/src/jit/ReciprocalMulConstants.cpp @@ -8,14 +8,39 @@ #include "mozilla/Assertions.h" +#include <limits> + using namespace js::jit; -ReciprocalMulConstants ReciprocalMulConstants::computeDivisionConstants( - uint32_t d, int maxLog) { - MOZ_ASSERT(maxLog >= 2 && maxLog <= 32); +template <typename UintT> +struct TwiceLarger; + +template <> +struct TwiceLarger<uint32_t> { + using Type = uint64_t; + using SignedType = int64_t; +}; + +template <> +struct TwiceLarger<uint64_t> { + using Type = js::Uint128; + using SignedType = js::Int128; +}; + +template <typename DivConstants, typename UintT> +static auto ComputeDivisionConstants(UintT d, int maxLog) { + using UintT_Twice = typename TwiceLarger<UintT>::Type; + using IntT_Twice = typename TwiceLarger<UintT>::SignedType; + + MOZ_ASSERT(maxLog >= 2 && maxLog <= std::numeric_limits<UintT>::digits); + // In what follows, 0 < d < 2^maxLog and d is not a power of 2. - MOZ_ASSERT(d < (uint64_t(1) << maxLog) && (d & (d - 1)) != 0); + MOZ_ASSERT(UintT_Twice(d) < (UintT_Twice(1) << maxLog) && + !mozilla::IsPowerOfTwo(d)); + // NOTE: The following explanation assumes T = uint32_t, but + // T = uint64_t works similar. + // // Speeding up division by non power-of-2 constants is possible by // calculating, during compilation, a value M such that high-order // bits of M*n correspond to the result of the division of n by d. @@ -76,19 +101,43 @@ ReciprocalMulConstants ReciprocalMulConstants::computeDivisionConstants( // compute it as (2^p-1) % d + 1, where 2^p-1 can then be computed // without overflow as UINT64_MAX >> (64-p). - // We now compute the least p >= 32 with the property above... - int32_t p = 32; - while ((uint64_t(1) << (p - maxLog)) + (UINT64_MAX >> (64 - p)) % d + 1 < d) { - p++; + static constexpr auto UINT_BITS = std::numeric_limits<UintT>::digits; + static constexpr auto UINT_TWICE_BITS = + std::numeric_limits<UintT_Twice>::digits; + static constexpr auto UINT_TWICE_MAX = + std::numeric_limits<UintT_Twice>::max(); + + // We now compute the least p >= UINT_BITS with the property above... + int32_t p = UINT_BITS; + while (true) { + auto u = (UintT_Twice(1) << (p - maxLog)); + auto v = (UINT_TWICE_MAX >> (UINT_TWICE_BITS - p)); + if (u + (v % UintT_Twice(d)) + UintT_Twice(1) < UintT_Twice(d)) { + p++; + } else { + break; + } } // ...and the corresponding M. For either the signed (L=31) or the // unsigned (L=32) case, this value can be too large (cf. item a). // Codegen can still multiply by M by multiplying by (M - 2^L) and // adjusting the value afterwards, if this is the case. - ReciprocalMulConstants rmc; - rmc.multiplier = (UINT64_MAX >> (64 - p)) / d + 1; - rmc.shiftAmount = p - 32; + DivConstants rmc; + rmc.multiplier = static_cast<IntT_Twice>( + (UINT_TWICE_MAX >> (UINT_TWICE_BITS - p)) / UintT_Twice(d) + + UintT_Twice(1)); + rmc.shiftAmount = p - UINT_BITS; return rmc; } + +ReciprocalMulConstants::Div32Constants +ReciprocalMulConstants::computeDivisionConstants(uint32_t d, int maxLog) { + return ComputeDivisionConstants<Div32Constants>(d, maxLog); +} + +ReciprocalMulConstants::Div64Constants +ReciprocalMulConstants::computeDivisionConstants(uint64_t d, int maxLog) { + return ComputeDivisionConstants<Div64Constants>(d, maxLog); +} diff --git a/js/src/jit/ReciprocalMulConstants.h b/js/src/jit/ReciprocalMulConstants.h @@ -11,23 +11,40 @@ #include <stdint.h> +#include "vm/Int128.h" + namespace js::jit { struct ReciprocalMulConstants { - int64_t multiplier; - int32_t shiftAmount; + template <typename Multiplier, typename ShiftAmount> + struct DivConstants { + Multiplier multiplier; + ShiftAmount shiftAmount; + }; + + using Div32Constants = DivConstants<int64_t, int32_t>; - static ReciprocalMulConstants computeSignedDivisionConstants(int32_t d) { + static auto computeSignedDivisionConstants(int32_t d) { return computeDivisionConstants(mozilla::Abs(d), 31); } - static ReciprocalMulConstants computeUnsignedDivisionConstants(uint32_t d) { + static auto computeUnsignedDivisionConstants(uint32_t d) { return computeDivisionConstants(d, 32); } + using Div64Constants = DivConstants<Int128, int32_t>; + + static auto computeSignedDivisionConstants(int64_t d) { + return computeDivisionConstants(mozilla::Abs(d), 63); + } + + static auto computeUnsignedDivisionConstants(uint64_t d) { + return computeDivisionConstants(d, 64); + } + private: - static ReciprocalMulConstants computeDivisionConstants(uint32_t d, - int maxLog); + static Div32Constants computeDivisionConstants(uint32_t d, int maxLog); + static Div64Constants computeDivisionConstants(uint64_t d, int maxLog); }; } // namespace js::jit