AK: Add support for some trivial math functions on aarch64

These all require just a single instruction each, we only have to
differentiate between register prefixes accordingly.
This commit is contained in:
Hendiadyoin1 2022-10-13 14:04:21 +02:00 committed by Linus Groh
parent 650d2fdc2d
commit eb5651870e
Notes: sideshowbarker 2024-07-17 05:58:44 +09:00

View file

@ -55,6 +55,24 @@ constexpr size_t product_odd() { return value * product_odd<value - 2>(); }
return __builtin_##function##f(args); \ return __builtin_##function##f(args); \
} }
#define AARCH64_INSTRUCTION(instruction, arg) \
if constexpr (IsSame<T, long double>) \
TODO(); \
if constexpr (IsSame<T, double>) { \
double res; \
asm(#instruction " %d0, %d1" \
: "=w"(res) \
: "w"(##arg)); \
return res; \
} \
if constexpr (IsSame<T, float>) { \
float res; \
asm(#instruction " %s0, %s1" \
: "=w"(res) \
: "w"(##arg)); \
return res; \
}
namespace Division { namespace Division {
template<FloatingPoint T> template<FloatingPoint T>
constexpr T fmod(T x, T y) constexpr T fmod(T x, T y)
@ -110,6 +128,8 @@ constexpr T sqrt(T x)
: "=t"(res) : "=t"(res)
: "0"(x)); : "0"(x));
return res; return res;
#elif ARCH(AARCH64)
AARCH64_INSTRUCTION(fsqrt, x);
#else #else
return __builtin_sqrt(x); return __builtin_sqrt(x);
#endif #endif
@ -118,6 +138,9 @@ constexpr T sqrt(T x)
template<FloatingPoint T> template<FloatingPoint T>
constexpr T rsqrt(T x) constexpr T rsqrt(T x)
{ {
#if ARCH(AARCH64)
AARCH64_INSTRUCTION(frsqrte, x);
#endif
return (T)1. / sqrt(x); return (T)1. / sqrt(x);
} }
@ -214,6 +237,8 @@ constexpr T fabs(T x)
"fabs" "fabs"
: "+t"(x)); : "+t"(x));
return x; return x;
#elif ARCH(AARCH64)
AARCH64_INSTRUCTION(abs, x);
#else #else
return __builtin_fabs(x); return __builtin_fabs(x);
#endif #endif
@ -581,6 +606,61 @@ ALWAYS_INLINE I round_to(P value)
: "st"); : "st");
} }
return static_cast<I>(ret); return static_cast<I>(ret);
#elif ARCH(AARCH64)
if constexpr (IsSigned<I>) {
if constexpr (sizeof(I) <= sizeof(i32)) {
i32 res;
if constexpr (IsSame<P, float>) {
asm("fcvtns %w0, %s1"
: "=r"(res), "w"(value));
} else if constexpr (IsSame<P, double>) {
asm("fcvtns %w0, %d1"
: "=r"(res), "w"(value));
} else if constexpr (IsSame<P, long double>) {
TODO();
}
return static_cast<I>(res);
}
static_cast<sizeof(I) == 8>; // either long or long long aka i64
i64 res;
if constexpr (IsSame<P, float>) {
asm("fcvtns %0, %s1"
: "=r"(res), "w"(value));
} else if constexpr (IsSame<P, double>) {
asm("fcvtns %0, %d1"
: "=r"(res), "w"(value));
} else if constexpr (IsSame<P, long double>) {
TODO();
}
return static_cast<I>(res);
}
if constexpr (sizeof(I) <= sizeof(u32)) {
u32 res;
if constexpr (IsSame<P, float>) {
asm("fcvtnu %w0, %s1"
: "=r"(res), "w"(value));
} else if constexpr (IsSame<P, double>) {
asm("fcvtnu %w0, %d1"
: "=r"(res), "w"(value));
} else if constexpr (IsSame<P, long double>) {
TODO();
}
return static_cast<I>(res);
}
static_cast<sizeof(I) == 8>; // either unsigned long or unsigned long long aka u64
u64 res;
if constexpr (IsSame<P, float>) {
asm("fcvtnu %0, %s1"
: "=r"(res), "w"(value));
} else if constexpr (IsSame<P, double>) {
asm("fcvtnu %0, %d1"
: "=r"(res), "w"(value));
} else if constexpr (IsSame<P, long double>) {
TODO();
}
return static_cast<I>(res);
#else #else
if constexpr (IsSame<P, long double>) if constexpr (IsSame<P, long double>)
return static_cast<I>(__builtin_llrintl(value)); return static_cast<I>(__builtin_llrintl(value));
@ -676,10 +756,15 @@ constexpr T ceil(T num)
? static_cast<i64>(num) ? static_cast<i64>(num)
: static_cast<i64>(num) + ((num > 0) ? 1 : 0); : static_cast<i64>(num) + ((num > 0) ? 1 : 0);
} }
#if ARCH(AARCH64)
AARCH64_INSTRUCTION(frintp, num);
#else
return __builtin_ceil(num); return __builtin_ceil(num);
#endif
} }
#undef CONSTEXPR_STATE #undef CONSTEXPR_STATE
#undef AARCH64_INSTRUCTION
} }
using AK::round_to; using AK::round_to;