From 594369121ac28a77e23e67fef4389884fccbe1fe Mon Sep 17 00:00:00 2001 From: Hediadyoin1 Date: Thu, 11 May 2023 12:09:47 +0200 Subject: [PATCH] AK: Add trunc and rint to AK/Math.h These are useful in some algorithms, which require specific rounding. --- AK/Math.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/AK/Math.h b/AK/Math.h index 8636e990c05..ef3b3a702f3 100644 --- a/AK/Math.h +++ b/AK/Math.h @@ -85,6 +85,7 @@ namespace Rounding { template constexpr T ceil(T num) { + // FIXME: SSE4.1 rounds[sd] num, res, 0b110 if (is_constant_evaluated()) { if (num < NumericLimits::min() || num > NumericLimits::max()) return num; @@ -102,6 +103,7 @@ constexpr T ceil(T num) template constexpr T floor(T num) { + // FIXME: SSE4.1 rounds[sd] num, res, 0b101 if (is_constant_evaluated()) { if (num < NumericLimits::min() || num > NumericLimits::max()) return num; @@ -116,6 +118,66 @@ constexpr T floor(T num) #endif } +template +constexpr T trunc(T num) +{ +#if ARCH(AARCH64) + if (is_constant_evaluated()) { + if (num < NumericLimits::min() || num > NumericLimits::max()) + return num; + return static_cast(static_cast(num)); + } + AARCH64_INSTRUCTION(frintz, num); +#endif + // FIXME: Use dedicated instruction in the non constexpr case + // SSE4.1: rounds[sd] %num, %res, 0b111 + if (num < NumericLimits::min() || num > NumericLimits::max()) + return num; + return static_cast(static_cast(num)); +} + +template +constexpr T rint(T x) +{ + CONSTEXPR_STATE(rint, x); + // Note: This does break tie to even + // But the behavior of frndint/rounds[ds]/frintx can be configured + // through the floating point control registers. + // FIXME: We should decide if we rename this to allow us to get away from + // the configurability "burden" rint has + // this would make us use `rounds[sd] %num, %res, 0b100` + // and `frintn` respectively, + // no such guaranteed round exists for x87 `frndint` +#if ARCH(X86_64) +# ifdef __SSE4_1__ + if constexpr (IsSame) { + T r; + asm( + "roundsd %1, %0" + : "=x"(r) + : "x"(x)); + return r; + } + if constexpr (IsSame) { + T r; + asm( + "roundss %1, %0" + : "=x"(r) + : "x"(x)); + return r; + } +# else + asm( + "frndint" + : "+t"(x)); + return x; +# endif +#elif ARCH(AARCH64) + AARCH64_INSTRUCTION(frintx, x); +#endif + TODO(); +} + template constexpr T round(T x) { @@ -286,8 +348,10 @@ ALWAYS_INLINE I round_to(P value) using Rounding::ceil; using Rounding::floor; +using Rounding::rint; using Rounding::round; using Rounding::round_to; +using Rounding::trunc; namespace Division { template