mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 10:00:16 +02:00
Revert "Fix quiet and signalling nan propagation"
This reverts commit e7a47a647c.
This commit is contained in:
1 parent
ed5774b88f
commit
bc6295a78d
9 files changed
+8
-169
No files matched your search
@@ -504,47 +504,6 @@ struct FEX_PACKED X80SoftFloat {
|
||||
return std::bit_cast<float>(Result);
|
||||
}
|
||||
|
||||
bool IsSignalingNaN() const {
|
||||
return (Exponent == 0x7FFF) && (Significand & 0x8000000000000000ULL) && !(Significand & 0x4000000000000000ULL) && // Bit 62 clear (signaling)
|
||||
(Significand & 0x3FFFFFFFFFFFFFFFULL);
|
||||
}
|
||||
|
||||
bool IsQuietNaN() const {
|
||||
return (Exponent == 0x7FFF) && (Significand & 0x8000000000000000ULL) && (Significand & 0x4000000000000000ULL); // Bit 62 set (quiet)
|
||||
}
|
||||
|
||||
// Helper to detect if this is any NaN
|
||||
bool IsNaN() const {
|
||||
return IsSignalingNaN() || IsQuietNaN();
|
||||
}
|
||||
|
||||
// X87 value to F64 while preserving signaling nan property
|
||||
double ToF64_PreserveNan(softfloat_state* state) const {
|
||||
if (IsSignalingNaN()) {
|
||||
// we keep it as a signaling nan in ieee754 in 64bits
|
||||
uint64_t sign_bit = Sign ? 0x8000000000000000ULL : 0;
|
||||
uint64_t exp_bits = 0x7FF0000000000000ULL;
|
||||
uint64_t x87_frac = Significand & 0x3FFFFFFFFFFFFFFFULL;
|
||||
uint64_t ieee_frac = (x87_frac >> 11) & 0x0007FFFFFFFFFFFFULL;
|
||||
|
||||
if (ieee_frac == 0) {
|
||||
ieee_frac = 1;
|
||||
}
|
||||
ieee_frac &= ~0x0008000000000000ULL;
|
||||
|
||||
uint64_t result_bits = sign_bit | exp_bits | ieee_frac;
|
||||
return std::bit_cast<double>(result_bits);
|
||||
} else if (IsQuietNaN()) {
|
||||
const float64_t Result = extF80_to_f64(state, *this);
|
||||
uint64_t result_bits = std::bit_cast<uint64_t>(Result);
|
||||
result_bits |= 0x0008000000000000ULL;
|
||||
return std::bit_cast<double>(result_bits);
|
||||
} else {
|
||||
const float64_t Result = extF80_to_f64(state, *this);
|
||||
return std::bit_cast<double>(Result);
|
||||
}
|
||||
}
|
||||
|
||||
double ToF64(softfloat_state* state) const {
|
||||
const float64_t Result = extF80_to_f64(state, *this);
|
||||
return std::bit_cast<double>(Result);
|
||||
@@ -625,39 +584,6 @@ struct FEX_PACKED X80SoftFloat {
|
||||
*this = f64_to_extF80(state, std::bit_cast<float64_t>(rhs));
|
||||
}
|
||||
|
||||
// Create X80SoftFloat from double while preserving NaN signaling properties
|
||||
static X80SoftFloat FromF64_PreserveNaN(softfloat_state* state, double value) {
|
||||
uint64_t bits = std::bit_cast<uint64_t>(value);
|
||||
|
||||
// Check if it's a nan
|
||||
if ((bits & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && (bits & 0x000FFFFFFFFFFFFFULL) != 0) {
|
||||
|
||||
X80SoftFloat result;
|
||||
result.Sign = (bits >> 63) & 1;
|
||||
result.Exponent = 0x7FFF;
|
||||
|
||||
bool is_signaling = !(bits & 0x0008000000000000ULL);
|
||||
uint64_t ieee_payload = bits & 0x0007FFFFFFFFFFFFULL;
|
||||
|
||||
// set bit 63 required for x87
|
||||
result.Significand = 0x8000000000000000ULL;
|
||||
|
||||
if (is_signaling) { // clear bit 62 for signaling nan
|
||||
result.Significand &= ~0x4000000000000000ULL;
|
||||
} else { // clear bit 62 for quiet nan
|
||||
result.Significand |= 0x4000000000000000ULL;
|
||||
}
|
||||
|
||||
// ieee754 51-bit payload -> x87 62-bit payload
|
||||
result.Significand |= (ieee_payload << 11) & 0x3FFFFFFFFFFFFFFFULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// For non-NaN values, use standard conversion
|
||||
return X80SoftFloat(state, value);
|
||||
}
|
||||
|
||||
X80SoftFloat(softfloat_state* state, BIGFLOAT rhs) {
|
||||
#if BIGFLOATSIZE == 16
|
||||
*this = f128_to_extF80(state, std::bit_cast<float128_t>(rhs));
|
||||
|
||||
@@ -407,14 +407,6 @@
|
||||
"Emulates X87 floating point using 64-bit precision. This reduces emulation accuracy and may result in rendering bugs."
|
||||
]
|
||||
},
|
||||
"X87StrictReducedPrecision": {
|
||||
"Type": "bool",
|
||||
"Default": "false",
|
||||
"Desc": [
|
||||
"Enables stricter X87 floating point behavior when X87ReducedPrecision is enabled.",
|
||||
"Adds additional checks and implementations like NaN propagation for better compatibility."
|
||||
]
|
||||
},
|
||||
"ABILocalFlags": {
|
||||
"Type": "bool",
|
||||
"Default": "false",
|
||||
|
||||
@@ -208,7 +208,6 @@ public:
|
||||
FEX_CONFIG_OPT(GDBSymbols, GDBSYMBOLS);
|
||||
FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO);
|
||||
FEX_CONFIG_OPT(x87ReducedPrecision, X87REDUCEDPRECISION);
|
||||
FEX_CONFIG_OPT(x87StrictReducedPrecision, X87STRICTREDUCEDPRECISION);
|
||||
FEX_CONFIG_OPT(DisableTelemetry, DISABLETELEMETRY);
|
||||
FEX_CONFIG_OPT(DisableVixlIndirectCalls, DISABLE_VIXL_INDIRECT_RUNTIME_CALLS);
|
||||
FEX_CONFIG_OPT(SmallTSCScale, SMALLTSCSCALE);
|
||||
@@ -324,13 +323,6 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateX87PrecisionConfig() {
|
||||
// If strict reduced precision is enabled, automatically enable reduced precision
|
||||
if (Config.x87StrictReducedPrecision() && !Config.x87ReducedPrecision()) {
|
||||
FEXCore::Config::Set(FEXCore::Config::CONFIG_X87REDUCEDPRECISION, "1");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Initializes the JIT compilers for the thread
|
||||
|
||||
@@ -57,13 +57,20 @@ $end_info$
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <fcntl.h>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <shared_mutex>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string_view>
|
||||
#include <sys/stat.h>
|
||||
#include <type_traits>
|
||||
#include <unistd.h>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <xxhash.h>
|
||||
|
||||
@@ -93,8 +100,6 @@ ContextImpl::ContextImpl(const FEXCore::HostFeatures& Features)
|
||||
|
||||
// Track atomic TSO emulation configuration.
|
||||
UpdateAtomicTSOEmulationConfig();
|
||||
// Ensure X87 precision constraints are respected.
|
||||
UpdateX87PrecisionConfig();
|
||||
}
|
||||
|
||||
struct GetFrameBlockInfoResult {
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
#pragma once
|
||||
#include "Common/SoftFloat.h"
|
||||
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/Core/Interpreter/Fallbacks/FallbackOpHandler.h"
|
||||
#include "Interface/IR/IR.h"
|
||||
|
||||
#include <FEXCore/Debug/InternalThreadState.h>
|
||||
#include <FEXCore/Utils/SHMStats.h>
|
||||
#include <FEXCore/Config/Config.h>
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
FEXCORE_PRESERVE_ALL_ATTR static softfloat_state SoftFloatStateFromFCW(uint16_t FCW, bool Force80BitPrecision = false) {
|
||||
@@ -79,12 +77,6 @@ struct OpHandlers<IR::OP_F80CVTTO> {
|
||||
FEXCORE_PRESERVE_ALL_ATTR static VectorRegType handle8(uint16_t FCW, double src, FEXCore::Core::CpuStateFrame* Frame) {
|
||||
FEXCORE_PROFILE_INSTANT_INCREMENT(Frame->Thread, AccumulatedFloatFallbackCount, 1);
|
||||
ScopedSoftFloatState State {FCW, Frame};
|
||||
auto Context = static_cast<Context::ContextImpl*>(Frame->Thread->CTX);
|
||||
auto ReducedPrecisionMode = Context->Config.x87ReducedPrecision;
|
||||
auto StrictReducedPrecisionMode = Context->Config.x87StrictReducedPrecision;
|
||||
if (!ReducedPrecisionMode || StrictReducedPrecisionMode) {
|
||||
return X80SoftFloat::FromF64_PreserveNaN(&State.State, src);
|
||||
}
|
||||
return X80SoftFloat(&State.State, src);
|
||||
}
|
||||
};
|
||||
@@ -123,12 +115,6 @@ struct OpHandlers<IR::OP_F80CVT> {
|
||||
FEXCORE_PRESERVE_ALL_ATTR static double handle8(uint16_t FCW, VectorRegType src, FEXCore::Core::CpuStateFrame* Frame) {
|
||||
FEXCORE_PROFILE_INSTANT_INCREMENT(Frame->Thread, AccumulatedFloatFallbackCount, 1);
|
||||
ScopedSoftFloatState State {FCW, Frame};
|
||||
auto Context = static_cast<Context::ContextImpl*>(Frame->Thread->CTX);
|
||||
auto ReducedPrecisionMode = Context->Config.x87ReducedPrecision;
|
||||
auto StrictReducedPrecisionMode = Context->Config.x87StrictReducedPrecision;
|
||||
if (!ReducedPrecisionMode || StrictReducedPrecisionMode) {
|
||||
return X80SoftFloat(src).ToF64_PreserveNan(&State.State);
|
||||
}
|
||||
return X80SoftFloat(src).ToF64(&State.State);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1330,7 +1330,6 @@ protected:
|
||||
|
||||
private:
|
||||
FEX_CONFIG_OPT(ReducedPrecisionMode, X87REDUCEDPRECISION);
|
||||
FEX_CONFIG_OPT(StrictReducedPrecisionMode, X87STRICTREDUCEDPRECISION);
|
||||
|
||||
struct JumpTargetInfo {
|
||||
Ref BlockEntry;
|
||||
|
||||
@@ -158,9 +158,7 @@ public:
|
||||
: Features(Features)
|
||||
, GPROpSize(GPROpSize) {
|
||||
FEX_CONFIG_OPT(ReducedPrecision, X87REDUCEDPRECISION);
|
||||
FEX_CONFIG_OPT(StrictReducedPrecision, X87STRICTREDUCEDPRECISION);
|
||||
ReducedPrecisionMode = ReducedPrecision;
|
||||
StrictReducedPrecisionMode = StrictReducedPrecision;
|
||||
}
|
||||
void Run(IREmitter* Emit) override;
|
||||
|
||||
@@ -168,12 +166,10 @@ private:
|
||||
const FEXCore::HostFeatures& Features;
|
||||
const OpSize GPROpSize;
|
||||
bool ReducedPrecisionMode;
|
||||
bool StrictReducedPrecisionMode;
|
||||
FEX_CONFIG_OPT(DisableVixlIndirectCalls, DISABLE_VIXL_INDIRECT_RUNTIME_CALLS);
|
||||
|
||||
// Helpers
|
||||
Ref RotateRight8(uint32_t V, Ref Amount);
|
||||
Ref SilenceNaN(Ref Value);
|
||||
|
||||
void F80SplitStore_Helper(const IROp_StoreStackMem* Op, Ref StackNode) {
|
||||
Ref AddrNode = IR->GetNode(Op->Addr);
|
||||
@@ -208,10 +204,7 @@ private:
|
||||
case OpSize::i32Bit:
|
||||
case OpSize::i64Bit: {
|
||||
StackNode = IREmit->_F80CVT(Op->StoreSize, StackNode);
|
||||
if (!ReducedPrecisionMode || StrictReducedPrecisionMode) {
|
||||
StackNode = SilenceNaN(StackNode);
|
||||
}
|
||||
IREmit->_StoreMemFPR(Op->StoreSize, StackNode, AddrNode, Offset, Align, OffsetType, OffsetScale);
|
||||
IREmit->_StoreMem(FPRClass, Op->StoreSize, StackNode, AddrNode, Offset, Align, OffsetType, OffsetScale);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -242,10 +235,6 @@ private:
|
||||
MemOffsetType OffsetType = Op->OffsetType;
|
||||
uint8_t OffsetScale = Op->OffsetScale;
|
||||
|
||||
if ((!ReducedPrecisionMode || StrictReducedPrecisionMode) && Op->StoreSize != OpSize::f80Bit) {
|
||||
StackNode = SilenceNaN(StackNode);
|
||||
}
|
||||
|
||||
switch (Op->StoreSize) {
|
||||
case OpSize::i32Bit: {
|
||||
StackNode = IREmit->_Float_FToF(OpSize::i32Bit, OpSize::i64Bit, StackNode);
|
||||
@@ -499,15 +488,6 @@ inline Ref X87StackOptimization::RotateRight8(uint32_t V, Ref Amount) {
|
||||
return IREmit->_Lshr(OpSize::i32Bit, GetConstant(V | (V << 8)), Amount);
|
||||
}
|
||||
|
||||
inline Ref X87StackOptimization::SilenceNaN(Ref Value) {
|
||||
Ref GPRValue = IREmit->_VExtractToGPR(OpSize::i64Bit, OpSize::i64Bit, Value, 0);
|
||||
|
||||
IREmit->_FCmp(OpSize::i64Bit, Value, Value); // Comparison with itself should set VS if nan
|
||||
Ref QuietNaNGPR = IREmit->_Or(OpSize::i64Bit, GPRValue, IREmit->_Constant(0x0008000000000000ULL));
|
||||
Ref SilencedValue = IREmit->_VCastFromGPR(OpSize::i64Bit, OpSize::i64Bit, QuietNaNGPR);
|
||||
return IREmit->_NZCVSelectV(OpSize::i64Bit, CondClass::VS, SilencedValue, Value);
|
||||
}
|
||||
|
||||
inline std::optional<X87StackOptimization::StackMemberInfo> X87StackOptimization::MigrateToSlowPath_IfInvalid(uint8_t Offset) {
|
||||
const auto& [Valid, StackMember] = StackData.top(Offset);
|
||||
MigrateToSlowPathIf(Valid != StackSlot::VALID);
|
||||
|
||||
@@ -721,17 +721,10 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
ConfigCheckBox {
|
||||
id: x87ReducedPrecisionCheckbox
|
||||
text: qsTr("Reduced x87 precision")
|
||||
config: "X87ReducedPrecision"
|
||||
}
|
||||
|
||||
ConfigCheckBox {
|
||||
text: qsTr("Strict reduced x87 precision")
|
||||
config: "X87StrictReducedPrecision"
|
||||
enabled: x87ReducedPrecisionCheckbox.checked
|
||||
}
|
||||
|
||||
ConfigCheckBox {
|
||||
text: qsTr("Unsafe local flags optimization")
|
||||
config: "ABILocalFlags"
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "6"
|
||||
},
|
||||
"Mode": "32BIT"
|
||||
}
|
||||
%endif
|
||||
|
||||
%include "nan_test_macros.inc"
|
||||
|
||||
mov esp, 0xe0000040
|
||||
|
||||
; Test x87 quiet NaN preservation in non-reduced precision mode (32-bit)
|
||||
; This test verifies that quiet NaNs remain quiet during conversion
|
||||
; Returns NaN triple: 6 (0b110) for quiet NaN
|
||||
|
||||
finit
|
||||
lea edx, [.data]
|
||||
fld tword [edx] ; load qnan 80bit
|
||||
fstp qword [edx + 16] ; store qnan as 64bit
|
||||
|
||||
; Check the stored 64-bit value using NaN triple macro
|
||||
lea edx, [.data + 16]
|
||||
movsd xmm0, [edx] ; Load 64-bit double into xmm0
|
||||
CHECK_NAN_TRIPLE_64
|
||||
|
||||
hlt
|
||||
|
||||
align 8
|
||||
.data:
|
||||
dq 0xc000000000000000 ; quiet NaN significand
|
||||
dw 0x7fff ; NaN exponent
|
||||
dq 0 ; space for 64-bit result
|
||||
Reference in new issue
Block a user