mirror of
https://github.com/FEX-Emu/FEX.git
synced 2024-11-23 14:40:14 +00:00
Fix FXTRACT for 0.0 and -0.0
Fixes fxtract by returning the correct values for 0.0 and -0.0. We moved the split of fxtract into _sig and _exp, to the opcode dispatcher, to ease some comparisons. Also removed the IR node F80XTRACTStack which is not needed anymore.
This commit is contained in:
parent
49087007be
commit
10ec6b63b6
@ -233,6 +233,10 @@ struct FEX_PACKED X80SoftFloat {
|
||||
|
||||
return Result;
|
||||
#else
|
||||
// Zero is a special case, the significand for +/- 0 is +/- zero.
|
||||
if (lhs.Exponent == 0x0 && lhs.Significand == 0x0) {
|
||||
return lhs;
|
||||
}
|
||||
X80SoftFloat Tmp = lhs;
|
||||
Tmp.Exponent = 0x3FFF;
|
||||
Tmp.Sign = lhs.Sign;
|
||||
@ -256,6 +260,12 @@ struct FEX_PACKED X80SoftFloat {
|
||||
|
||||
return Result;
|
||||
#else
|
||||
// Zero is a special case, the exponent is always -inf
|
||||
if (lhs.Exponent == 0x0 && lhs.Significand == 0x0) {
|
||||
X80SoftFloat Result(1, 0x7FFFUL, 0x8000'0000'0000'0000UL);
|
||||
return Result;
|
||||
}
|
||||
|
||||
int32_t TrueExp = lhs.Exponent - ExponentBias;
|
||||
return i32_to_extF80(TrueExp);
|
||||
#endif
|
||||
|
@ -5535,7 +5535,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87FYL2X, false>},
|
||||
{OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80PTANSTACK, true>},
|
||||
{OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80ATANSTACK, false>},
|
||||
{OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80XTRACTSTACK, false>},
|
||||
{OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::X87FXTRACTF64},
|
||||
{OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80FPREM1STACK, true>},
|
||||
{OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, false>},
|
||||
{OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, true>},
|
||||
@ -5765,7 +5765,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87FYL2X, false>},
|
||||
{OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80PTANSTACK, true>},
|
||||
{OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80ATANSTACK, false>},
|
||||
{OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80XTRACTSTACK, false>},
|
||||
{OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::X87FXTRACT},
|
||||
{OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80FPREM1STACK, true>},
|
||||
{OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, false>},
|
||||
{OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, true>},
|
||||
|
@ -735,6 +735,7 @@ public:
|
||||
void X87FNSAVE(OpcodeArgs);
|
||||
void X87FRSTOR(OpcodeArgs);
|
||||
void X87FXAM(OpcodeArgs);
|
||||
void X87FXTRACT(OpcodeArgs);
|
||||
void X87FCMOV(OpcodeArgs);
|
||||
void X87EMMS(OpcodeArgs);
|
||||
void X87FFREE(OpcodeArgs);
|
||||
@ -768,7 +769,6 @@ public:
|
||||
void FABSF64(OpcodeArgs);
|
||||
void FTSTF64(OpcodeArgs);
|
||||
void FRNDINTF64(OpcodeArgs);
|
||||
void FXTRACTF64(OpcodeArgs);
|
||||
void FNINITF64(OpcodeArgs);
|
||||
void FSQRTF64(OpcodeArgs);
|
||||
void X87UnaryOpF64(OpcodeArgs, FEXCore::IR::IROps IROp);
|
||||
@ -780,6 +780,7 @@ public:
|
||||
void X87FNSAVEF64(OpcodeArgs);
|
||||
void X87FRSTORF64(OpcodeArgs);
|
||||
void X87FXAMF64(OpcodeArgs);
|
||||
void X87FXTRACTF64(OpcodeArgs);
|
||||
void X87LDENVF64(OpcodeArgs);
|
||||
|
||||
void FCOMIF64(OpcodeArgs, size_t width, bool Integer, FCOMIFlags whichflags, bool poptwice);
|
||||
|
@ -804,4 +804,14 @@ void OpDispatchBuilder::X87FXAM(OpcodeArgs) {
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C3_LOC>(C3);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87FXTRACT(OpcodeArgs) {
|
||||
auto Top = _ReadStackValue(0);
|
||||
|
||||
_PopStackDestroy();
|
||||
auto Exp = _F80XTRACT_EXP(Top);
|
||||
auto Sig = _F80XTRACT_SIG(Top);
|
||||
_PushStack(Exp, Exp, 80, true);
|
||||
_PushStack(Sig, Sig, 80, true);
|
||||
}
|
||||
|
||||
} // namespace FEXCore::IR
|
||||
|
@ -8,6 +8,7 @@ $end_info$
|
||||
|
||||
#include "Interface/Core/OpcodeDispatcher.h"
|
||||
#include "Interface/Core/X86Tables/X86Tables.h"
|
||||
#include "Interface/IR/IR.h"
|
||||
|
||||
#include <FEXCore/Core/CoreState.h>
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
@ -519,4 +520,37 @@ void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) {
|
||||
_StoreContextIndexed(Reg, Top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87FXTRACTF64(OpcodeArgs) {
|
||||
// Split node into SIG and EXP while handling the special zero case.
|
||||
// i.e. if val == 0.0, then sig = 0.0, exp = -inf
|
||||
// if val == -0.0, then sig = -0.0, exp = -inf
|
||||
// otherwise we just extract the 64-bit sig and exp as normal.
|
||||
Ref Node = _ReadStackValue(0);
|
||||
|
||||
Ref Gpr = _VExtractToGPR(8, 8, Node, 0);
|
||||
|
||||
// zero case
|
||||
Ref ExpZV = _VCastFromGPR(8, 8, _Constant(0xfff0'0000'0000'0000UL));
|
||||
Ref SigZV = Node;
|
||||
|
||||
// non zero case
|
||||
Ref ExpNZ = _Bfe(OpSize::i64Bit, 11, 52, Gpr);
|
||||
ExpNZ = _Sub(OpSize::i64Bit, ExpNZ, _Constant(1023));
|
||||
Ref ExpNZV = _Float_FromGPR_S(8, 8, ExpNZ);
|
||||
|
||||
Ref SigNZ = _And(OpSize::i64Bit, Gpr, _Constant(0x800f'ffff'ffff'ffffLL));
|
||||
SigNZ = _Or(OpSize::i64Bit, SigNZ, _Constant(0x3ff0'0000'0000'0000LL));
|
||||
Ref SigNZV = _VCastFromGPR(8, 8, SigNZ);
|
||||
|
||||
// Comparison and select to push onto stack
|
||||
SaveNZCV();
|
||||
_TestNZ(OpSize::i64Bit, Gpr, _Constant(0x7fff'ffff'ffff'ffffUL));
|
||||
|
||||
Ref Sig = _NZCVSelectV(8, {COND_EQ}, SigZV, SigNZV);
|
||||
Ref Exp = _NZCVSelectV(8, {COND_EQ}, ExpZV, ExpNZV);
|
||||
|
||||
_PopStackDestroy();
|
||||
_PushStack(Exp, Exp, 64, true);
|
||||
_PushStack(Sig, Sig, 64, true);
|
||||
}
|
||||
} // namespace FEXCore::IR
|
||||
|
@ -3051,10 +3051,6 @@
|
||||
"DestSize": "16",
|
||||
"JITDispatch": false
|
||||
},
|
||||
"F80XTRACTStack": {
|
||||
"X87": true,
|
||||
"HasSideEffects": true
|
||||
},
|
||||
"FPR = F80XTRACT_EXP FPR:$X80Src": {
|
||||
"DestSize": "16",
|
||||
"JITDispatch": false
|
||||
|
@ -156,7 +156,6 @@ private:
|
||||
bool ReducedPrecisionMode;
|
||||
|
||||
// Helpers
|
||||
std::tuple<Ref, Ref> SplitF64SigExp(Ref Node);
|
||||
Ref RotateRight8(uint32_t V, Ref Amount);
|
||||
|
||||
// Handles a Unary operation.
|
||||
@ -518,20 +517,6 @@ Ref X87StackOptimization::SynchronizeStackValues() {
|
||||
return TopValue;
|
||||
}
|
||||
|
||||
std::tuple<Ref, Ref> X87StackOptimization::SplitF64SigExp(Ref Node) {
|
||||
Ref Gpr = IREmit->_VExtractToGPR(8, 8, Node, 0);
|
||||
|
||||
Ref Exp = IREmit->_And(OpSize::i64Bit, Gpr, GetConstant(0x7ff0000000000000LL));
|
||||
Exp = IREmit->_Lshr(OpSize::i64Bit, Exp, GetConstant(52));
|
||||
Exp = IREmit->_Sub(OpSize::i64Bit, Exp, GetConstant(1023));
|
||||
Exp = IREmit->_Float_FromGPR_S(8, 8, Exp);
|
||||
Ref Sig = IREmit->_And(OpSize::i64Bit, Gpr, GetConstant(0x800fffffffffffffLL));
|
||||
Sig = IREmit->_Or(OpSize::i64Bit, Sig, GetConstant(0x3ff0000000000000LL));
|
||||
Sig = IREmit->_VCastFromGPR(8, 8, Sig);
|
||||
|
||||
return std::tuple {Exp, Sig};
|
||||
}
|
||||
|
||||
void X87StackOptimization::Run(IREmitter* Emit) {
|
||||
FEXCORE_PROFILE_SCOPED("PassManager::x87StackOpt");
|
||||
|
||||
@ -964,30 +949,6 @@ void X87StackOptimization::Run(IREmitter* Emit) {
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_F80XTRACTSTACK: {
|
||||
Ref St0 = LoadStackValue();
|
||||
|
||||
Ref Exp {};
|
||||
Ref Sig {};
|
||||
if (ReducedPrecisionMode) {
|
||||
std::tie(Exp, Sig) = SplitF64SigExp(St0);
|
||||
} else {
|
||||
Exp = IREmit->_F80XTRACT_EXP(St0);
|
||||
Sig = IREmit->_F80XTRACT_SIG(St0);
|
||||
}
|
||||
|
||||
if (SlowPath) {
|
||||
// Write exp to top, update top for a push and set sig at new top.
|
||||
StoreStackValueAtOffset_Slow(Exp, 0, false);
|
||||
UpdateTopForPush_Slow();
|
||||
StoreStackValueAtOffset_Slow(Sig);
|
||||
} else {
|
||||
StackData.setTop(StackMemberInfo {Exp});
|
||||
StackData.push(StackMemberInfo {Sig});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_SYNCSTACKTOSLOW: {
|
||||
// This synchronizes stack values but doesn't necessarily moves us off the FastPath!
|
||||
Ref NewTop = SynchronizeStackValues();
|
||||
|
Loading…
Reference in New Issue
Block a user