diff --git a/AK/Math.h b/AK/Math.h index 09debce7cd..a382e55299 100644 --- a/AK/Math.h +++ b/AK/Math.h @@ -265,7 +265,7 @@ constexpr T tan(T angle) CONSTEXPR_STATE(tan, angle); #if ARCH(I386) || ARCH(X86_64) - double ret, one; + T ret, one; asm( "fptan" : "=t"(one), "=u"(ret) @@ -536,6 +536,89 @@ using Hyperbolic::cosh; using Hyperbolic::sinh; using Hyperbolic::tanh; +template +ALWAYS_INLINE I round_to(P value) +{ +#if ARCH(I386) || ARCH(X86_64) + // Note: fistps outputs into a signed integer location (i16, i32, i64), + // so lets be nice and tell the compiler that. + Conditional= sizeof(i16), MakeSigned, i16> ret; + if constexpr (sizeof(I) == sizeof(i64)) { + asm("fistpll %0" + : "=m"(ret) + : "t"(value) + : "st"); + } else if constexpr (sizeof(I) == sizeof(i32)) { + asm("fistpl %0" + : "=m"(ret) + : "t"(value) + : "st"); + } else { + asm("fistps %0" + : "=m"(ret) + : "t"(value) + : "st"); + } + return static_cast(ret); +#else + if constexpr (IsSame) + return static_cast(llrintl(value)); + if constexpr (IsSame) + return static_cast(llrint(value)); + if constexpr (IsSame) + return static_cast(llrintf(value)); +#endif +} + +#ifdef __SSE__ +template +ALWAYS_INLINE I round_to(float value) +{ + if constexpr (sizeof(I) == sizeof(i64)) { + // Note: Outputting into 64-bit registers or memory locations requires the + // REX prefix, so we have to fall back to long doubles on i686 +# if ARCH(X86_64) + i64 ret; + asm("cvtss2si %1, %0" + : "=r"(ret) + : "xm"(value)); + return static_cast(ret); +# else + return round_to(value); +# endif + } + i32 ret; + asm("cvtss2si %1, %0" + : "=r"(ret) + : "xm"(value)); + return static_cast(ret); +} +#endif +#ifdef __SSE2__ +template +ALWAYS_INLINE I round_to(double value) +{ + if constexpr (sizeof(I) == sizeof(i64)) { + // Note: Outputting into 64-bit registers or memory locations requires the + // REX prefix, so we have to fall back to long doubles on i686 +# if ARCH(X86_64) + i64 ret; + asm("cvtsd2si %1, %0" + : "=r"(ret) + : "xm"(value)); + return static_cast(ret); +# else + return round_to(value); +# endif + } + i32 ret; + asm("cvtsd2si %1, %0" + : "=r"(ret) + : "xm"(value)); + return static_cast(ret); +} +#endif + template constexpr T pow(T x, T y) { @@ -563,5 +646,6 @@ constexpr T pow(T x, T y) } #undef CONSTEXPR_STATE - } + +using AK::round_to;