mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-09-13 01:55:57 -04:00
add native aarch64 (arm64) support
use -mcpu=native on arm64 targets build-appimage.sh kernel architecture detection
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -38,16 +39,26 @@ inline uint32_t PpcStorePsqFloatBitsInline(uint32_t value)
|
||||
|
||||
inline uint64_t PpcLoadPairPsqFloatBitsPackedInline(uint64_t value)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
const __m128i lanes = _mm_cvtsi64_si128(static_cast<long long>(value));
|
||||
const __m128i magnitude = _mm_and_si128(lanes, _mm_set1_epi32(0x7FFFFFFF));
|
||||
const __m128i nanMask = _mm_cmpgt_epi32(magnitude, _mm_set1_epi32(0x7F800000));
|
||||
const __m128i result = _mm_or_si128(
|
||||
lanes, _mm_and_si128(nanMask, _mm_set1_epi32(0x00400000)));
|
||||
return static_cast<uint64_t>(_mm_cvtsi128_si64(result));
|
||||
#elif defined(__aarch64__)
|
||||
// Equivalent to applying PpcLoadPsqFloatBitsInline to each 32-bit lane: the
|
||||
// x86 body above only ever acts on these same two lanes (the upper 64 bits
|
||||
// _mm_cvtsi64_si128 zero-fills never survive the final truncating extract).
|
||||
const uint32_t lo = PpcLoadPsqFloatBitsInline(static_cast<uint32_t>(value));
|
||||
const uint32_t hi = PpcLoadPsqFloatBitsInline(static_cast<uint32_t>(value >> 32));
|
||||
return (static_cast<uint64_t>(hi) << 32) | lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint64_t PpcStorePairPsqFloatBitsPackedInline(uint64_t value)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
const __m128i lanes = _mm_cvtsi64_si128(static_cast<long long>(value));
|
||||
const __m128i magnitude = _mm_and_si128(lanes, _mm_set1_epi32(0x7FFFFFFF));
|
||||
const __m128i subnormalMask = _mm_cmplt_epi32(magnitude, _mm_set1_epi32(0x00800000));
|
||||
@@ -60,8 +71,16 @@ inline uint64_t PpcStorePairPsqFloatBitsPackedInline(uint64_t value)
|
||||
_mm_and_si128(subnormalMask, signedZero),
|
||||
_mm_andnot_si128(subnormalMask, quieted));
|
||||
return static_cast<uint64_t>(_mm_cvtsi128_si64(result));
|
||||
#elif defined(__aarch64__)
|
||||
// Equivalent to applying PpcStorePsqFloatBitsInline to each 32-bit lane;
|
||||
// same reasoning as the load-side port above.
|
||||
const uint32_t lo = PpcStorePsqFloatBitsInline(static_cast<uint32_t>(value));
|
||||
const uint32_t hi = PpcStorePsqFloatBitsInline(static_cast<uint32_t>(value >> 32));
|
||||
return (static_cast<uint64_t>(hi) << 32) | lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
inline __m128i PpcPsqSwapPairBytesInline(__m128i lanes)
|
||||
{
|
||||
const __m128i order = _mm_setr_epi8(
|
||||
@@ -95,21 +114,42 @@ inline __m128i PpcStorePairPsqFloatBitsLanesInline(__m128i lanes)
|
||||
_mm_and_si128(subnormalMask, signedZero),
|
||||
_mm_andnot_si128(subnormalMask, quieted));
|
||||
}
|
||||
#endif // defined(__x86_64__)
|
||||
|
||||
// host -> packed FPR double, guard already proven by the caller.
|
||||
inline double PpcLoadPairPsqFloatFromHostInline(const uint8_t* host)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
const __m128i raw = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(host));
|
||||
return PpcM128ToPsInline(_mm_castsi128_ps(
|
||||
PpcLoadPairPsqFloatBitsLanesInline(PpcPsqSwapPairBytesInline(raw))));
|
||||
#elif defined(__aarch64__)
|
||||
// The x86 path's full 8-byte pshufb reversal plus a same-endian load is,
|
||||
// taken together, exactly a 64-bit byteswap of a plain little-endian load:
|
||||
// it turns the on-disk [ps0 big-endian][ps1 big-endian] byte layout into a
|
||||
// native uint64 with low 32 bits = ps1, high 32 bits = ps0 (this file's
|
||||
// documented packed-double lane convention).
|
||||
uint64_t raw = 0;
|
||||
std::memcpy(&raw, host, sizeof(raw));
|
||||
const uint64_t swapped = __builtin_bswap64(raw);
|
||||
return PpcBitCastToDoubleInline(PpcLoadPairPsqFloatBitsPackedInline(swapped));
|
||||
#endif
|
||||
}
|
||||
|
||||
// packed FPR double -> host, guard already proven by the caller.
|
||||
inline void PpcStorePairPsqFloatToHostInline(uint8_t* host, double value)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
const __m128i lanes = PpcStorePairPsqFloatBitsLanesInline(
|
||||
_mm_castps_si128(PpcPsToM128Inline(value)));
|
||||
_mm_storel_epi64(reinterpret_cast<__m128i*>(host), PpcPsqSwapPairBytesInline(lanes));
|
||||
#elif defined(__aarch64__)
|
||||
// Inverse of the load path above: bswap64 is its own inverse, so applying
|
||||
// it to the quieted packed value reproduces the on-disk big-endian bytes.
|
||||
const uint64_t quieted = PpcStorePairPsqFloatBitsPackedInline(PpcBitCastToU64Inline(value));
|
||||
const uint64_t swapped = __builtin_bswap64(quieted);
|
||||
std::memcpy(host, &swapped, sizeof(swapped));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename SignedType>
|
||||
@@ -329,6 +369,7 @@ inline uint8_t PpcQuantizePsqU8Scale61Inline(float value)
|
||||
// matching PpcQuantizePsqU8Scale61Inline's !(scaled > 0) rule.
|
||||
inline uint16_t PpcQuantizePairPsqU8Scale61PackedInline(double value)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
const __m128 scaled = _mm_mul_ps(PpcPsToM128Inline(value), _mm_set1_ps(0.125f));
|
||||
const __m128 nonNegative = _mm_max_ps(scaled, _mm_setzero_ps());
|
||||
const __m128 clamped = _mm_min_ps(nonNegative, _mm_set1_ps(255.0f));
|
||||
@@ -338,6 +379,17 @@ inline uint16_t PpcQuantizePairPsqU8Scale61PackedInline(double value)
|
||||
// Native lane 0 is ps1 and lane 1 is ps0. Packing to the low uint16_t
|
||||
// therefore produces the guest-order numeric value (ps0 << 8) | ps1.
|
||||
return static_cast<uint16_t>(_mm_cvtsi128_si32(lanes8));
|
||||
#elif defined(__aarch64__)
|
||||
// Equivalent to two calls of the already-portable scalar quantizer above
|
||||
// (its own !(scaled > 0) rule maps NaN to 0, matching what MAXPS-with-zero
|
||||
// does on the x86 path per the comment there), packed the same way the
|
||||
// fallback path just below already does for the non-SIMD case.
|
||||
PPC_FPR fpr{};
|
||||
fpr.d = value;
|
||||
const uint8_t q0 = PpcQuantizePsqU8Scale61Inline(fpr.paired.ps0);
|
||||
const uint8_t q1 = PpcQuantizePsqU8Scale61Inline(fpr.paired.ps1);
|
||||
return static_cast<uint16_t>((static_cast<uint16_t>(q0) << 8) | static_cast<uint16_t>(q1));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Preserve the complete memory/MMIO/executable-write behavior off the leaf
|
||||
|
||||
Reference in New Issue
Block a user