#pragma once #include "ppc_isa_config.h" #include "ppc_isa_context.h" #include "ppc_isa_float.h" #include "big_endian.h" #include "ppc_isa_memory.h" #include #include #include #include #include #include #include inline uint32_t PpcLoadPsqFloatBitsInline(uint32_t value) { const uint32_t magnitude = value & 0x7FFFFFFFu; if (magnitude > 0x7F800000u) return value | 0x00400000u; return value; } inline uint32_t PpcStorePsqFloatBitsInline(uint32_t value) { const uint32_t magnitude = value & 0x7FFFFFFFu; if (magnitude < 0x00800000u) return value & 0x80000000u; if (magnitude > 0x7F800000u) return value | 0x00400000u; return value; } inline uint64_t PpcLoadPairPsqFloatBitsPackedInline(uint64_t value) { const __m128i lanes = _mm_cvtsi64_si128(static_cast(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(_mm_cvtsi128_si64(result)); } inline uint64_t PpcStorePairPsqFloatBitsPackedInline(uint64_t value) { const __m128i lanes = _mm_cvtsi64_si128(static_cast(value)); const __m128i magnitude = _mm_and_si128(lanes, _mm_set1_epi32(0x7FFFFFFF)); const __m128i subnormalMask = _mm_cmplt_epi32(magnitude, _mm_set1_epi32(0x00800000)); const __m128i nanMask = _mm_cmpgt_epi32(magnitude, _mm_set1_epi32(0x7F800000)); const __m128i quieted = _mm_or_si128( lanes, _mm_and_si128(nanMask, _mm_set1_epi32(0x00400000))); const __m128i signedZero = _mm_and_si128( lanes, _mm_set1_epi32(std::numeric_limits::min())); const __m128i result = _mm_or_si128( _mm_and_si128(subnormalMask, signedZero), _mm_andnot_si128(subnormalMask, quieted)); return static_cast(_mm_cvtsi128_si64(result)); } inline __m128i PpcPsqSwapPairBytesInline(__m128i lanes) { const __m128i order = _mm_setr_epi8( static_cast(7), static_cast(6), static_cast(5), static_cast(4), static_cast(3), static_cast(2), static_cast(1), static_cast(0), static_cast(0x80), static_cast(0x80), static_cast(0x80), static_cast(0x80), static_cast(0x80), static_cast(0x80), static_cast(0x80), static_cast(0x80)); return _mm_shuffle_epi8(lanes, order); } // Lane-local sNaN quieting; identical rule to PpcLoadPairPsqFloatBitsPackedInline. inline __m128i PpcLoadPairPsqFloatBitsLanesInline(__m128i lanes) { const __m128i magnitude = _mm_and_si128(lanes, _mm_set1_epi32(0x7FFFFFFF)); const __m128i nanMask = _mm_cmpgt_epi32(magnitude, _mm_set1_epi32(0x7F800000)); return _mm_or_si128(lanes, _mm_and_si128(nanMask, _mm_set1_epi32(0x00400000))); } // Lane-local denormal flush + sNaN quieting; identical rule to // PpcStorePairPsqFloatBitsPackedInline. inline __m128i PpcStorePairPsqFloatBitsLanesInline(__m128i lanes) { const __m128i magnitude = _mm_and_si128(lanes, _mm_set1_epi32(0x7FFFFFFF)); const __m128i subnormalMask = _mm_cmplt_epi32(magnitude, _mm_set1_epi32(0x00800000)); const __m128i nanMask = _mm_cmpgt_epi32(magnitude, _mm_set1_epi32(0x7F800000)); const __m128i quieted = _mm_or_si128( lanes, _mm_and_si128(nanMask, _mm_set1_epi32(0x00400000))); const __m128i signedZero = _mm_and_si128( lanes, _mm_set1_epi32(std::numeric_limits::min())); return _mm_or_si128( _mm_and_si128(subnormalMask, signedZero), _mm_andnot_si128(subnormalMask, quieted)); } // host -> packed FPR double, guard already proven by the caller. inline double PpcLoadPairPsqFloatFromHostInline(const uint8_t* host) { const __m128i raw = _mm_loadl_epi64(reinterpret_cast(host)); return PpcM128ToPsInline(_mm_castsi128_ps( PpcLoadPairPsqFloatBitsLanesInline(PpcPsqSwapPairBytesInline(raw)))); } // packed FPR double -> host, guard already proven by the caller. inline void PpcStorePairPsqFloatToHostInline(uint8_t* host, double value) { const __m128i lanes = PpcStorePairPsqFloatBitsLanesInline( _mm_castps_si128(PpcPsToM128Inline(value))); _mm_storel_epi64(reinterpret_cast<__m128i*>(host), PpcPsqSwapPairBytesInline(lanes)); } template inline SignedType PpcScaleAndClampPsqInline(float value, uint32_t scale) { if (scale == 0u) { constexpr float kMin = static_cast(std::numeric_limits::min()); constexpr float kMax = static_cast(std::numeric_limits::max()); return static_cast(std::clamp(value, kMin, kMax)); } const float factor = scale < 32u ? std::ldexp(1.0f, static_cast(scale)) : std::ldexp(1.0f, -(64 - static_cast(scale))); const float scaled = value * factor; constexpr float kMin = static_cast(std::numeric_limits::min()); constexpr float kMax = static_cast(std::numeric_limits::max()); return static_cast(std::clamp(scaled, kMin, kMax)); } template inline float PpcDequantizePsqInline(SignedType value, uint32_t scale) { if (scale == 0u) { return static_cast(value); } const float factor = scale < 32u ? std::ldexp(1.0f, -static_cast(scale)) : std::ldexp(1.0f, static_cast(64u - scale)); return static_cast(value) * factor; } template inline T PpcReadUnpairedPsqInline(uint32_t addr) { if constexpr (sizeof(T) == 1) { return static_cast(Memory::Read8(addr)); } else if constexpr (sizeof(T) == 2) { return static_cast(Memory::Read16(addr)); } else { return static_cast(Memory::Read32(addr)); } } template inline std::pair PpcReadPairPsqInline(uint32_t addr) { if constexpr (sizeof(T) == 1) { const uint16_t packed = Memory::Read16(addr); return { static_cast(packed >> 8), static_cast(packed) }; } else if constexpr (sizeof(T) == 2) { const uint32_t packed = Memory::Read32(addr); return { static_cast(packed >> 16), static_cast(packed) }; } else { const uint64_t packed = Memory::Read64(addr); return { static_cast(packed >> 32), static_cast(packed) }; } } template inline void PpcWriteUnpairedPsqInline(uint32_t addr, T value) { if constexpr (sizeof(T) == 1) { Memory::Write8(addr, static_cast(value)); } else if constexpr (sizeof(T) == 2) { Memory::Write16(addr, static_cast(value)); } else { Memory::Write32(addr, static_cast(value)); } } template inline void PpcWritePairPsqInline(uint32_t addr, T first, T second) { if constexpr (sizeof(T) == 1) { const uint16_t packed = (static_cast(first) << 8) | static_cast(second); Memory::Write16(addr, packed); } else if constexpr (sizeof(T) == 2) { const uint32_t packed = (static_cast(first) << 16) | static_cast(second); Memory::Write32(addr, packed); } else { const uint64_t packed = (static_cast(first) << 32) | static_cast(second); Memory::Write64(addr, packed); } } // The flat reservation makes every 32-bit guest address a host address; a pending-deferred // (EFB) page is PAGE_NOACCESS so the load faults through the vectored handler instead of // reading stale bytes, and unmapped pages commit on demand, same as MemoryInline::Flat* loads. MKW_PPC_FORCE_INLINE const uint8_t* PpcTryGetPsqReadableHostInline(uint32_t addr) { return MKW_FLAT_GUEST_BASE + addr; } // Same reduction for stores. Still refuses a 32-bit address wrap (one host access can't // reproduce it) and keeps MMIO write policy inline, since a fault record can't carry the // stored value and a null result must preserve the cold GX FIFO dispatch path byte for byte. // The old 1 MiB page-cross refusal is gone since the whole 4 GiB is now contiguous; deferred, // executable, and unmapped pages still trap. MKW_PPC_FORCE_INLINE uint8_t* PpcTryGetPsqWritableHostInline(uint32_t addr) { if (addr > UINT32_MAX - 7u) [[unlikely]] return nullptr; if (MemoryInline::FlatWriteNeedsPolicy(addr) || MemoryInline::FlatWriteNeedsPolicy(addr + 7u)) [[unlikely]] return nullptr; return MKW_FLAT_GUEST_BASE + addr; } inline double PpcLoadPairPsqFloatFastInline(uint32_t addr) { const uint8_t* host = PpcTryGetPsqReadableHostInline(addr); if (host != nullptr) [[likely]] { return PpcLoadPairPsqFloatFromHostInline(host); } return PpcBitCastToDoubleInline( PpcLoadPairPsqFloatBitsPackedInline(MemoryInline::Read64Slow(addr))); } inline double PpcLoadSinglePsqFloatFastInline(uint32_t addr) { const uint32_t raw = PpcReadUnpairedPsqInline(addr); return PpcMakePairedResultInline( PpcBitCastToFloatInline(raw), 1.0f).d; } template inline double PpcLoadPairPsqIntegerFastInline(uint32_t addr, uint32_t scale = 0u) { if constexpr (sizeof(ValueType) == 1) { const uint16_t packed = Memory::Read16(addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 8), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } else if constexpr (sizeof(ValueType) == 2) { const uint32_t packed = Memory::Read32(addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 16), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } else { const uint64_t packed = Memory::Read64(addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 32), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } } template inline double PpcLoadSinglePsqQuantizedFastInline(uint32_t addr, uint32_t scale) { using UnsignedType = std::make_unsigned_t; const UnsignedType value = PpcReadUnpairedPsqInline(addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(value), scale), 1.0f).d; } inline void PpcStorePairPsqFloatFastInline(uint32_t addr, double value) { uint8_t* host = PpcTryGetPsqWritableHostInline(addr); if (host != nullptr) [[likely]] { PpcStorePairPsqFloatToHostInline(host, value); return; } MemoryInline::Write64Slow( addr, PpcStorePairPsqFloatBitsPackedInline(PpcBitCastToU64Inline(value))); } inline uint8_t PpcQuantizePsqU8Scale61Inline(float value) { const float scaled = value * 0.125f; if (!(scaled > 0.0f)) { return 0; } if (scaled >= 255.0f) { return 255; } return static_cast(scaled); } // GQR U8 scale 61 is common in paired stores. Quantize both payload lanes as // one native vector so the normal finite path does not branch once per lane. // MAXPS with zero as the second operand also maps either NaN lane to zero, // matching PpcQuantizePsqU8Scale61Inline's !(scaled > 0) rule. inline uint16_t PpcQuantizePairPsqU8Scale61PackedInline(double value) { 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)); const __m128i lanes32 = _mm_cvttps_epi32(clamped); const __m128i lanes16 = _mm_packs_epi32(lanes32, lanes32); const __m128i lanes8 = _mm_packus_epi16(lanes16, lanes16); // 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(_mm_cvtsi128_si32(lanes8)); } // Preserve the complete memory/MMIO/executable-write behavior off the leaf // path. Keeping this out of line prevents those uncommon checks from being // replicated at every compile-time-known PSQ store. MKW_PPC_NO_INLINE inline void PpcStorePairPsqU8Scale61Fallback( uint32_t addr, double value) { PPC_FPR fpr{}; fpr.d = value; const uint16_t packed = static_cast( (static_cast(PpcQuantizePsqU8Scale61Inline(fpr.paired.ps0)) << 8) | static_cast(PpcQuantizePsqU8Scale61Inline(fpr.paired.ps1))); Memory::Write16(addr, packed); } // The full-writable bias is already the runtime proof that this two-byte store // is mapped, in range, debug-compatible, and cannot touch executable guest // code. Check that proof before doing any conversion work, then perform the // endian-aware native store directly. A zero entry takes the exact cold path. MKW_PPC_FORCE_INLINE void PpcStorePairPsqU8Scale61FastInline( uint32_t addr, double value) { uint8_t* host = nullptr; if (!MemoryInline::TryGetWritablePointerFast(addr, sizeof(uint16_t), host)) { PpcStorePairPsqU8Scale61Fallback(addr, value); return; } const uint16_t packed = PpcQuantizePairPsqU8Scale61PackedInline(value); BigEndian::Write16(host, packed); } MKW_PPC_FORCE_INLINE void PpcStorePairPsqU8Scale61ResolvedInline( uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value) { if (!resolvedHost) { PpcStorePairPsqU8Scale61Fallback(addr, value); return; } const uint16_t packed = PpcQuantizePairPsqU8Scale61PackedInline(value); BigEndian::Write16(resolvedHost + offset, packed); } template inline void PpcStorePairPsqQuantizedFastInline(uint32_t addr, double value, uint32_t scale) { PPC_FPR fpr{}; fpr.d = value; if constexpr (std::is_same_v) { if (scale == 61u) { PpcStorePairPsqU8Scale61FastInline(addr, value); return; } } if constexpr (std::is_signed_v) { const auto first = static_cast>( static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale))); const auto second = static_cast>( static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps1, scale))); PpcWritePairPsqInline(addr, first, second); } else { const auto first = static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale)); const auto second = static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps1, scale)); PpcWritePairPsqInline(addr, first, second); } } inline void PpcStoreSinglePsqFloatFastInline(uint32_t addr, double value) { const uint32_t first = PpcConvertToSingleFTZInline( PpcBitCastToU64Inline(static_cast(PpcGetPs0Inline(value)))); PpcWriteUnpairedPsqInline(addr, first); } template inline void PpcStoreSinglePsqQuantizedFastInline(uint32_t addr, double value, uint32_t scale) { PPC_FPR fpr{}; fpr.d = value; if constexpr (std::is_signed_v) { const auto first = static_cast>( static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale))); PpcWriteUnpairedPsqInline(addr, first); } else { const auto first = static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale)); PpcWriteUnpairedPsqInline(addr, first); } } inline double PpcLoadPairPsqFloatResolvedInline(uint8_t* resolvedHost, uint32_t offset, uint32_t addr) { // A resolved range is already the proof; MemoryInline::ReadResolved64 only // falls back when the host pointer is null. if (resolvedHost != nullptr) [[likely]] return PpcLoadPairPsqFloatFromHostInline(resolvedHost + offset); return PpcBitCastToDoubleInline(PpcLoadPairPsqFloatBitsPackedInline( MemoryInline::ReadResolvedFallback(addr))); } inline double PpcLoadSinglePsqFloatResolvedInline(uint8_t* resolvedHost, uint32_t offset, uint32_t addr) { const uint32_t raw = MemoryInline::ReadResolved32(resolvedHost, offset, addr); return PpcMakePairedResultInline(PpcBitCastToFloatInline(raw), 1.0f).d; } template inline double PpcLoadPairPsqIntegerResolvedInline(uint8_t* resolvedHost, uint32_t offset, uint32_t addr, uint32_t scale = 0u) { if constexpr (sizeof(ValueType) == 1) { const uint16_t packed = MemoryInline::ReadResolved16(resolvedHost, offset, addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 8), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } else if constexpr (sizeof(ValueType) == 2) { const uint32_t packed = MemoryInline::ReadResolved32(resolvedHost, offset, addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 16), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } else { const uint64_t packed = MemoryInline::ReadResolved64(resolvedHost, offset, addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 32), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } } template inline double PpcLoadSinglePsqQuantizedResolvedInline(uint8_t* resolvedHost, uint32_t offset, uint32_t addr, uint32_t scale) { using UnsignedType = std::make_unsigned_t; UnsignedType value; if constexpr (sizeof(UnsignedType) == 1) value = MemoryInline::ReadResolved8(resolvedHost, offset, addr); else if constexpr (sizeof(UnsignedType) == 2) value = MemoryInline::ReadResolved16(resolvedHost, offset, addr); else value = MemoryInline::ReadResolved32(resolvedHost, offset, addr); return PpcMakePairedResultInline(PpcDequantizePsqInline(static_cast(value), scale), 1.0f).d; } inline void PpcStorePairPsqFloatResolvedInline(uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value) { // Mirrors MemoryInline::WriteResolved64: the resolved range is the proof, // and only a null host takes the original-address fallback. if (resolvedHost != nullptr) [[likely]] { PpcStorePairPsqFloatToHostInline(resolvedHost + offset, value); return; } MemoryInline::WriteResolvedFallback( addr, PpcStorePairPsqFloatBitsPackedInline(PpcBitCastToU64Inline(value))); } template inline void PpcStorePairPsqQuantizedResolvedInline(uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value, uint32_t scale) { PPC_FPR fpr{}; fpr.d = value; if constexpr (std::is_same_v) { if (scale == 61u) { PpcStorePairPsqU8Scale61ResolvedInline(resolvedHost, offset, addr, value); return; } } using Unsigned = std::make_unsigned_t; const auto quantize = [scale](float lane) -> Unsigned { return static_cast(static_cast(PpcScaleAndClampPsqInline(lane, scale))); }; const Unsigned first = quantize(fpr.paired.ps0); const Unsigned second = quantize(fpr.paired.ps1); if constexpr (sizeof(QuantizedType) == 1) MemoryInline::WriteResolved16(resolvedHost, offset, addr, (static_cast(first) << 8) | second); else if constexpr (sizeof(QuantizedType) == 2) MemoryInline::WriteResolved32(resolvedHost, offset, addr, (static_cast(first) << 16) | second); else MemoryInline::WriteResolved64(resolvedHost, offset, addr, (static_cast(first) << 32) | second); } inline void PpcStoreSinglePsqFloatResolvedInline(uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value) { const uint32_t first = PpcConvertToSingleFTZInline(PpcBitCastToU64Inline(static_cast(PpcGetPs0Inline(value)))); MemoryInline::WriteResolved32(resolvedHost, offset, addr, first); } template inline void PpcStoreSinglePsqQuantizedResolvedInline(uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value, uint32_t scale) { PPC_FPR fpr{}; fpr.d = value; using Unsigned = std::make_unsigned_t; const Unsigned first = static_cast(static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale))); if constexpr (sizeof(QuantizedType) == 1) MemoryInline::WriteResolved8(resolvedHost, offset, addr, first); else if constexpr (sizeof(QuantizedType) == 2) MemoryInline::WriteResolved16(resolvedHost, offset, addr, first); else MemoryInline::WriteResolved32(resolvedHost, offset, addr, first); } template inline T PpcReadUnpairedPsqStackInline(uint32_t addr) { if constexpr (sizeof(T) == 1) { return static_cast(MemoryInline::ReadStack8(addr)); } else if constexpr (sizeof(T) == 2) { return static_cast(MemoryInline::ReadStack16(addr)); } else { return static_cast(MemoryInline::ReadStack32(addr)); } } template inline void PpcWriteUnpairedPsqStackInline(uint32_t addr, T value) { if constexpr (sizeof(T) == 1) { MemoryInline::WriteStack8(addr, static_cast(value)); } else if constexpr (sizeof(T) == 2) { MemoryInline::WriteStack16(addr, static_cast(value)); } else { MemoryInline::WriteStack32(addr, static_cast(value)); } } template inline void PpcWritePairPsqStackInline(uint32_t addr, T first, T second) { if constexpr (sizeof(T) == 1) { const uint16_t packed = (static_cast(first) << 8) | static_cast(second); MemoryInline::WriteStack16(addr, packed); } else if constexpr (sizeof(T) == 2) { const uint32_t packed = (static_cast(first) << 16) | static_cast(second); MemoryInline::WriteStack32(addr, packed); } else { const uint64_t packed = (static_cast(first) << 32) | static_cast(second); MemoryInline::WriteStack64(addr, packed); } } inline double PpcLoadPairPsqFloatStackInline(uint32_t addr) { // MemoryInline::ReadStack64's exact proof (TryGetPointerFast), then the // same Memory::Read64 fallback it uses on a miss. uint8_t* host = nullptr; if (MemoryInline::TryGetPointerFast(addr, sizeof(uint64_t), host)) [[likely]] return PpcLoadPairPsqFloatFromHostInline(host); return PpcBitCastToDoubleInline(PpcLoadPairPsqFloatBitsPackedInline(Memory::Read64(addr))); } inline double PpcLoadSinglePsqFloatStackInline(uint32_t addr) { const uint32_t raw = PpcReadUnpairedPsqStackInline(addr); return PpcMakePairedResultInline(PpcBitCastToFloatInline(raw), 1.0f).d; } template inline double PpcLoadPairPsqIntegerStackInline(uint32_t addr, uint32_t scale = 0u) { if constexpr (sizeof(ValueType) == 1) { const uint16_t packed = MemoryInline::ReadStack16(addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 8), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } else if constexpr (sizeof(ValueType) == 2) { const uint32_t packed = MemoryInline::ReadStack32(addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 16), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } else { const uint64_t packed = MemoryInline::ReadStack64(addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(packed >> 32), scale), PpcDequantizePsqInline(static_cast(packed), scale)).d; } } template inline double PpcLoadSinglePsqQuantizedStackInline(uint32_t addr, uint32_t scale) { using UnsignedType = std::make_unsigned_t; const UnsignedType value = PpcReadUnpairedPsqStackInline(addr); return PpcMakePairedResultInline( PpcDequantizePsqInline(static_cast(value), scale), 1.0f).d; } inline void PpcStorePairPsqFloatStackInline(uint32_t addr, double value) { // MemoryInline::WriteStack64's exact proof (WriteStackScalarFast -> // TryGetPointerFast), then the same Memory::Write64 fallback on a miss. uint8_t* host = nullptr; if (MemoryInline::TryGetPointerFast(addr, sizeof(uint64_t), host)) [[likely]] { PpcStorePairPsqFloatToHostInline(host, value); return; } Memory::Write64(addr, PpcStorePairPsqFloatBitsPackedInline(PpcBitCastToU64Inline(value))); } template inline void PpcStorePairPsqQuantizedStackInline(uint32_t addr, double value, uint32_t scale) { PPC_FPR fpr{}; fpr.d = value; if constexpr (std::is_same_v) { if (scale == 61u) { const uint16_t packed = PpcQuantizePairPsqU8Scale61PackedInline(value); MemoryInline::WriteStack16(addr, packed); return; } } if constexpr (std::is_signed_v) { const auto first = static_cast>( static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale))); const auto second = static_cast>( static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps1, scale))); PpcWritePairPsqStackInline(addr, first, second); } else { const auto first = static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale)); const auto second = static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps1, scale)); PpcWritePairPsqStackInline(addr, first, second); } } inline void PpcStoreSinglePsqFloatStackInline(uint32_t addr, double value) { const uint32_t first = PpcConvertToSingleFTZInline( PpcBitCastToU64Inline(static_cast(PpcGetPs0Inline(value)))); PpcWriteUnpairedPsqStackInline(addr, first); } template inline void PpcStoreSinglePsqQuantizedStackInline(uint32_t addr, double value, uint32_t scale) { PPC_FPR fpr{}; fpr.d = value; if constexpr (std::is_signed_v) { const auto first = static_cast>( static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale))); PpcWriteUnpairedPsqStackInline(addr, first); } else { const auto first = static_cast(PpcScaleAndClampPsqInline(fpr.paired.ps0, scale)); PpcWriteUnpairedPsqStackInline(addr, first); } } // Paired-Single helpers (psq_l / psq_st). w=0 loads/stores both ps0/ps1 (paired), w=1 only // ps0 (scalar); i is the GQR index (0-7) for quantization type and scale. extern "C" double PPC_PsqL(uint32_t addr, uint32_t w, uint32_t i); extern "C" void PPC_PsqSt(uint32_t addr, double value, uint32_t w, uint32_t i); // Cold generic body for psq_l. The complete quantization switch lives in one // out-of-line copy so PPC_PsqLInline's float fast path can be force-inlined at // guest call sites without spilling live registers around a call. template MKW_PPC_NO_INLINE MKW_PPC_COLD inline double PPC_PsqLGeneric(uint32_t gqr, uint32_t addr) { static_assert(W <= 1u, "psq load W must be 0 or 1"); static_assert(I < 8u, "psq load GQR index must be 0..7"); if constexpr (W == 0u) { switch (gqr & 0xFFFF0000u) { case 0x00000000u: return PpcLoadPairPsqFloatFastInline(addr); case 0x00040000u: return PpcLoadPairPsqIntegerFastInline(addr); case 0x00050000u: return PpcLoadPairPsqIntegerFastInline(addr); case 0x00060000u: return PpcLoadPairPsqIntegerFastInline(addr); case 0x00070000u: return PpcLoadPairPsqIntegerFastInline(addr); default: break; } } else { const uint32_t type = (gqr >> 16) & 0x7u; const uint32_t scale = (gqr >> 24) & 0x3Fu; switch (type) { case 0u: return PpcLoadSinglePsqFloatFastInline(addr); case 4u: return PpcLoadSinglePsqQuantizedFastInline(addr, scale); case 5u: return PpcLoadSinglePsqQuantizedFastInline(addr, scale); case 6u: return PpcLoadSinglePsqQuantizedFastInline(addr, scale); case 7u: return PpcLoadSinglePsqQuantizedFastInline(addr, scale); default: break; } } return PPC_PsqL(addr, W, I); } // Hot wrapper: the float encoding (quantization type 0) is what the SDK leaves // in the GQRs for the overwhelming majority of psq_l sites, so it is tested with // one compare and handled inline. Every other encoding, including the reserved // ones that must reach PPC_PsqL, tail-calls the cold generic body above. template MKW_PPC_FORCE_INLINE double PPC_PsqLInline(CpuContext* cpu, uint32_t addr) { static_assert(W <= 1u, "psq load W must be 0 or 1"); static_assert(I < 8u, "psq load GQR index must be 0..7"); if (!cpu) [[unlikely]] { std::abort(); } const uint32_t gqr = cpu->gqr[I]; if constexpr (W == 0u) { // Paired float requires type 0 *and* load scale 0 (the pair path in the // generic body dispatches on the whole load halfword for that reason). if ((gqr & 0xFFFF0000u) == 0x00000000u) [[likely]] { return PpcLoadPairPsqFloatFastInline(addr); } } else { // Scalar float ignores the load scale, exactly like the generic switch. if (((gqr >> 16) & 0x7u) == 0u) [[likely]] { return PpcLoadSinglePsqFloatFastInline(addr); } } return PPC_PsqLGeneric(gqr, addr); } template MKW_PPC_FORCE_INLINE double PPC_PsqLInline(uint32_t addr) { return PPC_PsqLInline(TryGetCpuContext(), addr); } // GQR-hoisting entry points (audit T-GQR). Identical bodies to PPC_PsqLInline/PPC_PsqStInline // above, but the GQR value arrives as an argument instead of being reloaded from ctx->gqr[I] // at every access, since pointer indirection otherwise forces a reload after every intervening // store. I is only consulted for reserved encodings that tail-call PPC_PsqL/PPC_PsqSt. template MKW_PPC_FORCE_INLINE double PPC_PsqLGqrInline(uint32_t gqrValue, uint32_t addr) { static_assert(W <= 1u, "psq load W must be 0 or 1"); static_assert(I < 8u, "psq load GQR index must be 0..7"); if constexpr (W == 0u) { // Paired float requires type 0 *and* load scale 0 (the pair path in the // generic body dispatches on the whole load halfword for that reason). if ((gqrValue & 0xFFFF0000u) == 0x00000000u) [[likely]] { return PpcLoadPairPsqFloatFastInline(addr); } } else { // Scalar float ignores the load scale, exactly like the generic switch. if (((gqrValue >> 16) & 0x7u) == 0u) [[likely]] { return PpcLoadSinglePsqFloatFastInline(addr); } } return PPC_PsqLGeneric(gqrValue, addr); } // Context-carrying form, for emission sites that still hand the CpuContext to // every helper. The context is not read; the null check is retained so a broken // call site fails the same way the ctx->gqr[I] form does. template MKW_PPC_FORCE_INLINE double PPC_PsqLGqrInline(CpuContext* cpu, uint32_t gqrValue, uint32_t addr) { if (!cpu) [[unlikely]] { std::abort(); } return PPC_PsqLGqrInline(gqrValue, addr); } template MKW_PPC_FORCE_INLINE double PPC_PsqLKnownInline(CpuContext*, uint32_t addr) { static_assert(W <= 1u, "psq load W must be 0 or 1"); static_assert(I < 8u, "psq load GQR index must be 0..7"); constexpr uint32_t type = (GQR >> 16) & 0x7u; constexpr uint32_t scale = (GQR >> 24) & 0x3Fu; if constexpr (type == 0u) { if constexpr (W == 0u) return PpcLoadPairPsqFloatFastInline(addr); else return PpcLoadSinglePsqFloatFastInline(addr); } else if constexpr (type == 4u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerFastInline(addr, scale); else return PpcLoadSinglePsqQuantizedFastInline(addr, scale); } else if constexpr (type == 5u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerFastInline(addr, scale); else return PpcLoadSinglePsqQuantizedFastInline(addr, scale); } else if constexpr (type == 6u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerFastInline(addr, scale); else return PpcLoadSinglePsqQuantizedFastInline(addr, scale); } else if constexpr (type == 7u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerFastInline(addr, scale); else return PpcLoadSinglePsqQuantizedFastInline(addr, scale); } else { return PPC_PsqL(addr, W, I); } } // Cold generic body for the stack-form psq_l, mirroring PPC_PsqLGeneric: the // complete quantization switch lives in one out-of-line copy so the hot // wrapper's float path can be force-inlined at guest call sites without // spilling live registers around a call. template MKW_PPC_NO_INLINE MKW_PPC_COLD inline double PPC_PsqLStackGeneric(uint32_t gqr, uint32_t addr) { static_assert(W <= 1u, "psq stack load W must be 0 or 1"); static_assert(I < 8u, "psq stack load GQR index must be 0..7"); if constexpr (W == 0u) { switch (gqr & 0xFFFF0000u) { case 0x00000000u: return PpcLoadPairPsqFloatStackInline(addr); case 0x00040000u: return PpcLoadPairPsqIntegerStackInline(addr); case 0x00050000u: return PpcLoadPairPsqIntegerStackInline(addr); case 0x00060000u: return PpcLoadPairPsqIntegerStackInline(addr); case 0x00070000u: return PpcLoadPairPsqIntegerStackInline(addr); default: break; } } else { const uint32_t type = (gqr >> 16) & 0x7u; const uint32_t scale = (gqr >> 24) & 0x3Fu; switch (type) { case 0u: return PpcLoadSinglePsqFloatStackInline(addr); case 4u: return PpcLoadSinglePsqQuantizedStackInline(addr, scale); case 5u: return PpcLoadSinglePsqQuantizedStackInline(addr, scale); case 6u: return PpcLoadSinglePsqQuantizedStackInline(addr, scale); case 7u: return PpcLoadSinglePsqQuantizedStackInline(addr, scale); default: break; } } return PPC_PsqL(addr, W, I); } // Hot wrapper: the float encoding (quantization type 0) is what the SDK leaves // in the GQRs for the overwhelming majority of psq_l sites, so it is tested with // one compare and handled inline. Every other encoding, including the reserved // ones that must reach PPC_PsqL, tail-calls the cold generic body above. template MKW_PPC_FORCE_INLINE double PPC_PsqLStackInline(CpuContext* cpu, uint32_t addr) { static_assert(W <= 1u, "psq stack load W must be 0 or 1"); static_assert(I < 8u, "psq stack load GQR index must be 0..7"); if (!cpu) [[unlikely]] { std::abort(); } const uint32_t gqr = cpu->gqr[I]; if constexpr (W == 0u) { // Paired float requires type 0 *and* load scale 0 (the pair path in the // generic body dispatches on the whole load halfword for that reason). if ((gqr & 0xFFFF0000u) == 0x00000000u) [[likely]] { return PpcLoadPairPsqFloatStackInline(addr); } } else { // Scalar float ignores the load scale, exactly like the generic switch. if (((gqr >> 16) & 0x7u) == 0u) [[likely]] { return PpcLoadSinglePsqFloatStackInline(addr); } } return PPC_PsqLStackGeneric(gqr, addr); } template MKW_PPC_FORCE_INLINE double PPC_PsqLStackInline(uint32_t addr) { return PPC_PsqLStackInline(TryGetCpuContext(), addr); } template MKW_PPC_FORCE_INLINE double PPC_PsqLKnownStackInline(CpuContext*, uint32_t addr) { static_assert(W <= 1u, "psq stack load W must be 0 or 1"); static_assert(I < 8u, "psq stack load GQR index must be 0..7"); constexpr uint32_t type = (GQR >> 16) & 0x7u; constexpr uint32_t scale = (GQR >> 24) & 0x3Fu; if constexpr (type == 0u) { if constexpr (W == 0u) return PpcLoadPairPsqFloatStackInline(addr); else return PpcLoadSinglePsqFloatStackInline(addr); } else if constexpr (type == 4u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerStackInline(addr, scale); else return PpcLoadSinglePsqQuantizedStackInline(addr, scale); } else if constexpr (type == 5u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerStackInline(addr, scale); else return PpcLoadSinglePsqQuantizedStackInline(addr, scale); } else if constexpr (type == 6u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerStackInline(addr, scale); else return PpcLoadSinglePsqQuantizedStackInline(addr, scale); } else if constexpr (type == 7u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerStackInline(addr, scale); else return PpcLoadSinglePsqQuantizedStackInline(addr, scale); } else { return PPC_PsqL(addr, W, I); } } // Cold generic body for psq_st. See PPC_PsqLGeneric: the full switch stays out // of line so the float fast path in PPC_PsqStInline can be force-inlined. template MKW_PPC_NO_INLINE MKW_PPC_COLD inline void PPC_PsqStGeneric(uint32_t gqr, uint32_t addr, double value) { static_assert(W <= 1u, "psq store W must be 0 or 1"); static_assert(I < 8u, "psq store GQR index must be 0..7"); if constexpr (W == 0u) { switch (gqr & 0x0000FFFFu) { case 0x0000u: PpcStorePairPsqFloatFastInline(addr, value); return; case 0x0004u: PpcStorePairPsqQuantizedFastInline(addr, value, 0u); return; case 0x0005u: PpcStorePairPsqQuantizedFastInline(addr, value, 0u); return; case 0x0006u: PpcStorePairPsqQuantizedFastInline(addr, value, 0u); return; case 0x0007u: PpcStorePairPsqQuantizedFastInline(addr, value, 0u); return; case 0x3D04u: PpcStorePairPsqQuantizedFastInline(addr, value, 61u); return; default: break; } } else { const uint32_t type = gqr & 0x7u; const uint32_t scale = (gqr >> 8) & 0x3Fu; switch (type) { case 0u: PpcStoreSinglePsqFloatFastInline(addr, value); return; case 4u: PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); return; case 5u: PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); return; case 6u: PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); return; case 7u: PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); return; default: break; } } PPC_PsqSt(addr, value, W, I); } // Hot wrapper: store type 0 (float) is the common GQR setup, tested with a // single compare and handled inline. Quantized encodings (including the U8 // scale-61 pair case) and reserved encodings go to the cold generic body. template MKW_PPC_FORCE_INLINE void PPC_PsqStInline(CpuContext* cpu, uint32_t addr, double value) { static_assert(W <= 1u, "psq store W must be 0 or 1"); static_assert(I < 8u, "psq store GQR index must be 0..7"); if (!cpu) [[unlikely]] { std::abort(); } const uint32_t gqr = cpu->gqr[I]; if constexpr (W == 0u) { // Paired float requires store type 0 *and* store scale 0, matching the // generic body's dispatch on the whole store halfword. if ((gqr & 0x0000FFFFu) == 0x0000u) [[likely]] { PpcStorePairPsqFloatFastInline(addr, value); return; } } else { // Scalar float ignores the store scale, exactly like the generic switch. if ((gqr & 0x7u) == 0u) [[likely]] { PpcStoreSinglePsqFloatFastInline(addr, value); return; } } PPC_PsqStGeneric(gqr, addr, value); } template MKW_PPC_FORCE_INLINE void PPC_PsqStInline(uint32_t addr, double value) { PPC_PsqStInline(TryGetCpuContext(), addr, value); } // GQR-hoisting store entry points. See PPC_PsqLGqrInline above for why the GQR // value is passed in and what the template parameters still mean. template MKW_PPC_FORCE_INLINE void PPC_PsqStGqrInline(uint32_t gqrValue, uint32_t addr, double value) { static_assert(W <= 1u, "psq store W must be 0 or 1"); static_assert(I < 8u, "psq store GQR index must be 0..7"); if constexpr (W == 0u) { // Paired float requires store type 0 *and* store scale 0, matching the // generic body's dispatch on the whole store halfword. if ((gqrValue & 0x0000FFFFu) == 0x0000u) [[likely]] { PpcStorePairPsqFloatFastInline(addr, value); return; } } else { // Scalar float ignores the store scale, exactly like the generic switch. if ((gqrValue & 0x7u) == 0u) [[likely]] { PpcStoreSinglePsqFloatFastInline(addr, value); return; } } PPC_PsqStGeneric(gqrValue, addr, value); } template MKW_PPC_FORCE_INLINE void PPC_PsqStGqrInline(CpuContext* cpu, uint32_t gqrValue, uint32_t addr, double value) { if (!cpu) [[unlikely]] { std::abort(); } PPC_PsqStGqrInline(gqrValue, addr, value); } template MKW_PPC_FORCE_INLINE void PPC_PsqStKnownInline(CpuContext*, uint32_t addr, double value) { static_assert(W <= 1u, "psq store W must be 0 or 1"); static_assert(I < 8u, "psq store GQR index must be 0..7"); constexpr uint32_t type = GQR & 0x7u; constexpr uint32_t scale = (GQR >> 8) & 0x3Fu; if constexpr (type == 0u) { if constexpr (W == 0u) PpcStorePairPsqFloatFastInline(addr, value); else PpcStoreSinglePsqFloatFastInline(addr, value); } else if constexpr (type == 4u) { if constexpr (W == 0u && scale == 61u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedFastInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); } else { if constexpr (W == 0u) PpcStorePairPsqQuantizedFastInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); } } else if constexpr (type == 5u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedFastInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); } else if constexpr (type == 6u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedFastInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); } else if constexpr (type == 7u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedFastInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); } else { PPC_PsqSt(addr, value, W, I); } } // Cold generic body for the stack-form psq_st. See PPC_PsqStGeneric: the full // switch stays out of line so the float fast path in the hot wrapper below can // be force-inlined. template MKW_PPC_NO_INLINE MKW_PPC_COLD inline void PPC_PsqStStackGeneric(uint32_t gqr, uint32_t addr, double value) { static_assert(W <= 1u, "psq stack store W must be 0 or 1"); static_assert(I < 8u, "psq stack store GQR index must be 0..7"); if constexpr (W == 0u) { switch (gqr & 0x0000FFFFu) { case 0x0000u: PpcStorePairPsqFloatStackInline(addr, value); return; case 0x0004u: PpcStorePairPsqQuantizedStackInline(addr, value, 0u); return; case 0x0005u: PpcStorePairPsqQuantizedStackInline(addr, value, 0u); return; case 0x0006u: PpcStorePairPsqQuantizedStackInline(addr, value, 0u); return; case 0x0007u: PpcStorePairPsqQuantizedStackInline(addr, value, 0u); return; case 0x3D04u: PpcStorePairPsqQuantizedStackInline(addr, value, 61u); return; default: break; } } else { const uint32_t type = gqr & 0x7u; const uint32_t scale = (gqr >> 8) & 0x3Fu; switch (type) { case 0u: PpcStoreSinglePsqFloatStackInline(addr, value); return; case 4u: PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); return; case 5u: PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); return; case 6u: PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); return; case 7u: PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); return; default: break; } } PPC_PsqSt(addr, value, W, I); } // Hot wrapper: store type 0 (float) is the common GQR setup, tested with a // single compare and handled inline. Quantized encodings (including the U8 // scale-61 pair case) and reserved encodings go to the cold generic body. template MKW_PPC_FORCE_INLINE void PPC_PsqStStackInline(CpuContext* cpu, uint32_t addr, double value) { static_assert(W <= 1u, "psq stack store W must be 0 or 1"); static_assert(I < 8u, "psq stack store GQR index must be 0..7"); if (!cpu) [[unlikely]] { std::abort(); } const uint32_t gqr = cpu->gqr[I]; if constexpr (W == 0u) { // Paired float requires store type 0 *and* store scale 0, matching the // generic body's dispatch on the whole store halfword. if ((gqr & 0x0000FFFFu) == 0x0000u) [[likely]] { PpcStorePairPsqFloatStackInline(addr, value); return; } } else { // Scalar float ignores the store scale, exactly like the generic switch. if ((gqr & 0x7u) == 0u) [[likely]] { PpcStoreSinglePsqFloatStackInline(addr, value); return; } } PPC_PsqStStackGeneric(gqr, addr, value); } template MKW_PPC_FORCE_INLINE void PPC_PsqStStackInline(uint32_t addr, double value) { PPC_PsqStStackInline(TryGetCpuContext(), addr, value); } // Context-free PSQ entries for translated regions which own GQR state as an // ordinary native value. All architecturally valid quantization encodings are // handled directly; reserved encodings retain the generic helper's abort. template MKW_PPC_NO_INLINE MKW_PPC_COLD inline double PPC_PsqLStateFallback(uint32_t gqr, uint32_t addr) { static_assert(W <= 1u && I < 8u); const uint32_t type = (gqr >> 16) & 0x7u; const uint32_t scale = (gqr >> 24) & 0x3Fu; if constexpr (W == 0u) { switch (type) { case 0u: return Stack ? PpcLoadPairPsqFloatStackInline(addr) : PpcLoadPairPsqFloatFastInline(addr); case 4u: return Stack ? PpcLoadPairPsqIntegerStackInline(addr, scale) : PpcLoadPairPsqIntegerFastInline(addr, scale); case 5u: return Stack ? PpcLoadPairPsqIntegerStackInline(addr, scale) : PpcLoadPairPsqIntegerFastInline(addr, scale); case 6u: return Stack ? PpcLoadPairPsqIntegerStackInline(addr, scale) : PpcLoadPairPsqIntegerFastInline(addr, scale); case 7u: return Stack ? PpcLoadPairPsqIntegerStackInline(addr, scale) : PpcLoadPairPsqIntegerFastInline(addr, scale); default: std::abort(); } } else { switch (type) { case 0u: return Stack ? PpcLoadSinglePsqFloatStackInline(addr) : PpcLoadSinglePsqFloatFastInline(addr); case 4u: return Stack ? PpcLoadSinglePsqQuantizedStackInline(addr, scale) : PpcLoadSinglePsqQuantizedFastInline(addr, scale); case 5u: return Stack ? PpcLoadSinglePsqQuantizedStackInline(addr, scale) : PpcLoadSinglePsqQuantizedFastInline(addr, scale); case 6u: return Stack ? PpcLoadSinglePsqQuantizedStackInline(addr, scale) : PpcLoadSinglePsqQuantizedFastInline(addr, scale); case 7u: return Stack ? PpcLoadSinglePsqQuantizedStackInline(addr, scale) : PpcLoadSinglePsqQuantizedFastInline(addr, scale); default: std::abort(); } } } // Keep the normal explicit-state path small and directly optimizable. Exact // unscaled encodings cover the SDK's common GQR setup; scaled and reserved // encodings retain the complete implementation in one cold outlined body. template MKW_PPC_FORCE_INLINE double PPC_PsqLStateInline(uint32_t gqr, uint32_t addr) { static_assert(W <= 1u && I < 8u); switch (gqr & 0xFFFF0000u) { case 0x00000000u: if constexpr (W == 0u) return Stack ? PpcLoadPairPsqFloatStackInline(addr) : PpcLoadPairPsqFloatFastInline(addr); else return Stack ? PpcLoadSinglePsqFloatStackInline(addr) : PpcLoadSinglePsqFloatFastInline(addr); case 0x00040000u: if constexpr (W == 0u) return Stack ? PpcLoadPairPsqIntegerStackInline(addr, 0u) : PpcLoadPairPsqIntegerFastInline(addr, 0u); else return Stack ? PpcLoadSinglePsqQuantizedStackInline(addr, 0u) : PpcLoadSinglePsqQuantizedFastInline(addr, 0u); case 0x00050000u: if constexpr (W == 0u) return Stack ? PpcLoadPairPsqIntegerStackInline(addr, 0u) : PpcLoadPairPsqIntegerFastInline(addr, 0u); else return Stack ? PpcLoadSinglePsqQuantizedStackInline(addr, 0u) : PpcLoadSinglePsqQuantizedFastInline(addr, 0u); case 0x00060000u: if constexpr (W == 0u) return Stack ? PpcLoadPairPsqIntegerStackInline(addr, 0u) : PpcLoadPairPsqIntegerFastInline(addr, 0u); else return Stack ? PpcLoadSinglePsqQuantizedStackInline(addr, 0u) : PpcLoadSinglePsqQuantizedFastInline(addr, 0u); case 0x00070000u: if constexpr (W == 0u) return Stack ? PpcLoadPairPsqIntegerStackInline(addr, 0u) : PpcLoadPairPsqIntegerFastInline(addr, 0u); else return Stack ? PpcLoadSinglePsqQuantizedStackInline(addr, 0u) : PpcLoadSinglePsqQuantizedFastInline(addr, 0u); default: return PPC_PsqLStateFallback(gqr, addr); } } template MKW_PPC_NO_INLINE MKW_PPC_COLD inline void PPC_PsqStStateFallback(uint32_t gqr, uint32_t addr, double value) { static_assert(W <= 1u && I < 8u); const uint32_t type = gqr & 0x7u; const uint32_t scale = (gqr >> 8) & 0x3Fu; if constexpr (W == 0u) { switch (type) { case 0u: Stack ? PpcStorePairPsqFloatStackInline(addr, value) : PpcStorePairPsqFloatFastInline(addr, value); return; case 4u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStorePairPsqQuantizedFastInline(addr, value, scale); return; case 5u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStorePairPsqQuantizedFastInline(addr, value, scale); return; case 6u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStorePairPsqQuantizedFastInline(addr, value, scale); return; case 7u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStorePairPsqQuantizedFastInline(addr, value, scale); return; default: std::abort(); } } else { switch (type) { case 0u: if constexpr (Stack) PpcStoreSinglePsqFloatStackInline(addr, value); else PpcStoreSinglePsqFloatFastInline(addr, value); return; case 4u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); return; case 5u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); return; case 6u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); return; case 7u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline(addr, value, scale); return; default: std::abort(); } } } template MKW_PPC_FORCE_INLINE void PPC_PsqStStateInline(uint32_t gqr, uint32_t addr, double value) { static_assert(W <= 1u && I < 8u); switch (gqr & 0xFFFFu) { case 0x0000u: if constexpr (W == 0u) Stack ? PpcStorePairPsqFloatStackInline(addr, value) : PpcStorePairPsqFloatFastInline(addr, value); else Stack ? PpcStoreSinglePsqFloatStackInline(addr, value) : PpcStoreSinglePsqFloatFastInline(addr, value); return; case 0x0004u: if constexpr (W == 0u) { if constexpr (Stack) PpcStorePairPsqQuantizedStackInline(addr, value, 0u); else PpcStorePairPsqQuantizedFastInline(addr, value, 0u); } else { if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline(addr, value, 0u); else PpcStoreSinglePsqQuantizedFastInline(addr, value, 0u); } return; case 0x0005u: if constexpr (W == 0u) { if constexpr (Stack) PpcStorePairPsqQuantizedStackInline(addr, value, 0u); else PpcStorePairPsqQuantizedFastInline(addr, value, 0u); } else { if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline(addr, value, 0u); else PpcStoreSinglePsqQuantizedFastInline(addr, value, 0u); } return; case 0x0006u: if constexpr (W == 0u) { if constexpr (Stack) PpcStorePairPsqQuantizedStackInline(addr, value, 0u); else PpcStorePairPsqQuantizedFastInline(addr, value, 0u); } else { if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline(addr, value, 0u); else PpcStoreSinglePsqQuantizedFastInline(addr, value, 0u); } return; case 0x0007u: if constexpr (W == 0u) { if constexpr (Stack) PpcStorePairPsqQuantizedStackInline(addr, value, 0u); else PpcStorePairPsqQuantizedFastInline(addr, value, 0u); } else { if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline(addr, value, 0u); else PpcStoreSinglePsqQuantizedFastInline(addr, value, 0u); } return; default: PPC_PsqStStateFallback(gqr, addr, value); return; } } template MKW_PPC_FORCE_INLINE double PPC_PsqLResolvedStateInline( uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr) { static_assert(W <= 1u && I < 8u); if (!resolvedHost) [[unlikely]] return PPC_PsqLStateInline(gqr, addr); const uint32_t type = (gqr >> 16) & 0x7u; const uint32_t scale = (gqr >> 24) & 0x3Fu; if constexpr (W == 0u) { switch (type) { case 0u: return PpcLoadPairPsqFloatResolvedInline(resolvedHost, offset, addr); case 4u: return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr, scale); case 5u: return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr, scale); case 6u: return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr, scale); case 7u: return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr, scale); default: std::abort(); } } else { switch (type) { case 0u: return PpcLoadSinglePsqFloatResolvedInline(resolvedHost, offset, addr); case 4u: return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); case 5u: return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); case 6u: return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); case 7u: return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); default: std::abort(); } } } template MKW_PPC_FORCE_INLINE void PPC_PsqStResolvedStateInline( uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value) { static_assert(W <= 1u && I < 8u); if (!resolvedHost) [[unlikely]] { PPC_PsqStStateInline(gqr, addr, value); return; } const uint32_t type = gqr & 0x7u; const uint32_t scale = (gqr >> 8) & 0x3Fu; if constexpr (W == 0u) { switch (type) { case 0u: PpcStorePairPsqFloatResolvedInline(resolvedHost, offset, addr, value); return; case 4u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 5u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 6u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 7u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; default: std::abort(); } } else { switch (type) { case 0u: PpcStoreSinglePsqFloatResolvedInline(resolvedHost, offset, addr, value); return; case 4u: PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 5u: PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 6u: PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 7u: PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; default: std::abort(); } } } template MKW_PPC_FORCE_INLINE void PPC_PsqStKnownStackInline(CpuContext*, uint32_t addr, double value) { static_assert(W <= 1u, "psq stack store W must be 0 or 1"); static_assert(I < 8u, "psq stack store GQR index must be 0..7"); constexpr uint32_t type = GQR & 0x7u; constexpr uint32_t scale = (GQR >> 8) & 0x3Fu; if constexpr (type == 0u) { if constexpr (W == 0u) PpcStorePairPsqFloatStackInline(addr, value); else PpcStoreSinglePsqFloatStackInline(addr, value); } else if constexpr (type == 4u) { if constexpr (W == 0u && scale == 61u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); } else { if constexpr (W == 0u) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); } } else if constexpr (type == 5u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); } else if constexpr (type == 6u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); } else if constexpr (type == 7u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedStackInline(addr, value, scale); else PpcStoreSinglePsqQuantizedStackInline(addr, value, scale); } else { PPC_PsqSt(addr, value, W, I); } } // Cold generic body for the resolved-host psq_l. Only reached with a non-null // resolvedHost; the null case keeps its original PPC_PsqL behaviour in the // force-inlined wrapper below. template MKW_PPC_NO_INLINE MKW_PPC_COLD inline double PPC_PsqLResolvedGeneric( uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr) { if constexpr (W == 0u) { switch (gqr & 0xFFFF0000u) { case 0x00000000u: return PpcLoadPairPsqFloatResolvedInline(resolvedHost, offset, addr); case 0x00040000u: return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr); case 0x00050000u: return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr); case 0x00060000u: return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr); case 0x00070000u: return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr); default: return PPC_PsqL(addr, W, I); } } else { const uint32_t type = (gqr >> 16) & 7u; const uint32_t scale = (gqr >> 24) & 0x3Fu; switch (type) { case 0u: return PpcLoadSinglePsqFloatResolvedInline(resolvedHost, offset, addr); case 4u: return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); case 5u: return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); case 6u: return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); case 7u: return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); default: return PPC_PsqL(addr, W, I); } } } // Hot wrapper: resolved host pointer plus the float GQR encoding is the case // that dominates translated code, so it is a compare and a direct byteswapped // access. Null host and every non-float encoding stay out of line. template MKW_PPC_FORCE_INLINE double PPC_PsqLResolvedInline(CpuContext* cpu, uint8_t* resolvedHost, uint32_t offset, uint32_t addr) { if (!resolvedHost) [[unlikely]] return PPC_PsqL(addr, W, I); const uint32_t gqr = cpu->gqr[I]; if constexpr (W == 0u) { // Paired float: load type 0 with load scale 0. if ((gqr & 0xFFFF0000u) == 0x00000000u) [[likely]] return PpcLoadPairPsqFloatResolvedInline(resolvedHost, offset, addr); } else { // Scalar float ignores the load scale. if (((gqr >> 16) & 7u) == 0u) [[likely]] return PpcLoadSinglePsqFloatResolvedInline(resolvedHost, offset, addr); } return PPC_PsqLResolvedGeneric(gqr, resolvedHost, offset, addr); } template MKW_PPC_NO_INLINE MKW_PPC_COLD inline double PPC_PsqLKnownResolvedFallback( uint32_t addr) { return PPC_PsqLKnownInline(nullptr, addr); } template MKW_PPC_FORCE_INLINE double PPC_PsqLKnownResolvedInline(CpuContext* cpu, uint8_t* resolvedHost, uint32_t offset, uint32_t addr) { if (!resolvedHost) [[unlikely]] return PPC_PsqLKnownResolvedFallback(addr); static_assert(W <= 1u, "psq resolved load W must be 0 or 1"); static_assert(I < 8u, "psq resolved load GQR index must be 0..7"); constexpr uint32_t type = (GQR >> 16) & 0x7u; constexpr uint32_t scale = (GQR >> 24) & 0x3Fu; if constexpr (type == 0u) { if constexpr (W == 0u) return PpcLoadPairPsqFloatResolvedInline(resolvedHost, offset, addr); else return PpcLoadSinglePsqFloatResolvedInline(resolvedHost, offset, addr); } else if constexpr (type == 4u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr, scale); else return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); } else if constexpr (type == 5u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr, scale); else return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); } else if constexpr (type == 6u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr, scale); else return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); } else if constexpr (type == 7u) { if constexpr (W == 0u) return PpcLoadPairPsqIntegerResolvedInline(resolvedHost, offset, addr, scale); else return PpcLoadSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, scale); } else { return PPC_PsqL(addr, W, I); } } // Cold generic body for the resolved-host psq_st. Only reached with a non-null // resolvedHost; the null case keeps its original PPC_PsqSt behaviour in the // force-inlined wrapper below. template MKW_PPC_NO_INLINE MKW_PPC_COLD inline void PPC_PsqStResolvedGeneric( uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value) { if constexpr (W == 0u) { switch (gqr & 0xFFFFu) { case 0x0000u: PpcStorePairPsqFloatResolvedInline(resolvedHost, offset, addr, value); return; case 0x0004u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, 0u); return; case 0x0005u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, 0u); return; case 0x0006u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, 0u); return; case 0x0007u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, 0u); return; case 0x3D04u: PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, 61u); return; default: PPC_PsqSt(addr, value, W, I); return; } } else { const uint32_t type = gqr & 7u; const uint32_t scale = (gqr >> 8) & 0x3Fu; switch (type) { case 0u: PpcStoreSinglePsqFloatResolvedInline(resolvedHost, offset, addr, value); return; case 4u: PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 5u: PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 6u: PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; case 7u: PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); return; default: PPC_PsqSt(addr, value, W, I); return; } } } // Hot wrapper: resolved host pointer plus the float GQR encoding becomes a // compare and a direct byteswapped store. Null host and every non-float // encoding (including U8 scale 61) stay out of line. template MKW_PPC_FORCE_INLINE void PPC_PsqStResolvedInline(CpuContext* cpu, uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value) { if (!resolvedHost) [[unlikely]] { PPC_PsqSt(addr, value, W, I); return; } const uint32_t gqr = cpu->gqr[I]; if constexpr (W == 0u) { // Paired float: store type 0 with store scale 0. if ((gqr & 0xFFFFu) == 0x0000u) [[likely]] { PpcStorePairPsqFloatResolvedInline(resolvedHost, offset, addr, value); return; } } else { // Scalar float ignores the store scale. if ((gqr & 7u) == 0u) [[likely]] { PpcStoreSinglePsqFloatResolvedInline(resolvedHost, offset, addr, value); return; } } PPC_PsqStResolvedGeneric(gqr, resolvedHost, offset, addr, value); } template MKW_PPC_NO_INLINE MKW_PPC_COLD inline void PPC_PsqStKnownResolvedFallback( uint32_t addr, double value) { PPC_PsqStKnownInline(nullptr, addr, value); } template MKW_PPC_FORCE_INLINE void PPC_PsqStKnownResolvedInline(CpuContext* cpu, uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value) { if (!resolvedHost) [[unlikely]] { PPC_PsqStKnownResolvedFallback(addr, value); return; } static_assert(W <= 1u, "psq resolved store W must be 0 or 1"); static_assert(I < 8u, "psq resolved store GQR index must be 0..7"); constexpr uint32_t type = GQR & 0x7u; constexpr uint32_t scale = (GQR >> 8) & 0x3Fu; if constexpr (type == 0u) { if constexpr (W == 0u) PpcStorePairPsqFloatResolvedInline(resolvedHost, offset, addr, value); else PpcStoreSinglePsqFloatResolvedInline(resolvedHost, offset, addr, value); } else if constexpr (type == 4u) { if constexpr (W == 0u && scale == 61u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); else PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); } else { if constexpr (W == 0u) PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); else PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); } } else if constexpr (type == 5u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); else PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); } else if constexpr (type == 6u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); else PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); } else if constexpr (type == 7u) { if constexpr (W == 0u) PpcStorePairPsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); else PpcStoreSinglePsqQuantizedResolvedInline(resolvedHost, offset, addr, value, scale); } else { PPC_PsqSt(addr, value, W, I); } }