mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-29 04:01:27 +01:00
JIT-inline F64ATAN and F64FYL2X for reduced precision x87 path
This commit is contained in:
1 parent
59755ec115
commit
db50b04663
5 files changed
+359
-2
No files matched your search
@@ -551,6 +551,8 @@ void Dispatcher::EmitDispatcher() {
|
||||
EmitF64Tan();
|
||||
EmitF64F2XM1();
|
||||
EmitF64Scale();
|
||||
EmitF64Atan();
|
||||
EmitF64FYL2X();
|
||||
|
||||
// Interpreter fallbacks
|
||||
{
|
||||
@@ -1421,6 +1423,322 @@ void Dispatcher::EmitF64F2XM1() {
|
||||
dc64(0x3D78'1619'3166'D0F5ULL);
|
||||
}
|
||||
|
||||
// JIT-inlined double-precision atan2 for the F64 reduced precision x87 path.
|
||||
// Input: VTMP1 = y, VTMP2 = x. Output: VTMP1 = atan2(y, x).
|
||||
// Algorithm: 20-term Horner polynomial from ARM optimized-routines atan_data.c.
|
||||
// atan(z) = z + z^3 * P(z^2), with range reduction to [0,1] and quadrant adjustment.
|
||||
void Dispatcher::EmitF64Atan() {
|
||||
F64AtanHandlerAddress = GetCursorAddress<uint64_t>();
|
||||
|
||||
constexpr auto Accum = ARMEmitter::VReg::v2;
|
||||
|
||||
ARMEmitter::ForwardLabel Fallback;
|
||||
ARMEmitter::ForwardLabel NoSwap, PosX, NegY;
|
||||
ARMEmitter::ForwardLabel PiOver2Label, PiLabel;
|
||||
ARMEmitter::ForwardLabel C0Label, C1Label, C2Label, C3Label, C4Label, C5Label, C6Label;
|
||||
ARMEmitter::ForwardLabel C7Label, C8Label, C9Label, C10Label, C11Label, C12Label, C13Label;
|
||||
ARMEmitter::ForwardLabel C14Label, C15Label, C16Label, C17Label, C18Label, C19Label;
|
||||
|
||||
// Stack layout: [sp] = q2 (16B), [sp+16] = y bits (8B), [sp+24] = x bits (8B).
|
||||
str<ARMEmitter::IndexType::PRE>(ARMEmitter::QReg::q2, ARMEmitter::Reg::rsp, -32);
|
||||
|
||||
mrs(TMP1, ARMEmitter::SystemRegister::NZCV);
|
||||
str(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
|
||||
fmov(ARMEmitter::Size::i64Bit, TMP1, VTMP2.D());
|
||||
fmov(ARMEmitter::Size::i64Bit, TMP2, VTMP1.D());
|
||||
str(TMP2, ARMEmitter::Reg::rsp, 16);
|
||||
str(TMP1, ARMEmitter::Reg::rsp, 24);
|
||||
|
||||
// Compute |x|, |y|, pack sign/swap flags into TMP1 = (sign_x<<2)|(sign_y<<1)|swap.
|
||||
fabs(Accum.D(), VTMP2.D());
|
||||
fabs(VTMP2.D(), VTMP1.D());
|
||||
|
||||
fcmp(VTMP2.D(), Accum.D());
|
||||
lsr(ARMEmitter::Size::i64Bit, TMP1, TMP1, 63);
|
||||
lsr(ARMEmitter::Size::i64Bit, TMP2, TMP2, 63);
|
||||
cset(ARMEmitter::Size::i64Bit, TMP3, ARMEmitter::Condition::CC_HI);
|
||||
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP1, TMP1, 2);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP1, TMP1, TMP2, ARMEmitter::ShiftType::LSL, 1);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP1, TMP1, TMP3);
|
||||
|
||||
// z = min(|y|,|x|) / max(|y|,|x|); NaN guard catches 0/0, inf/inf, NaN inputs.
|
||||
fcsel(ARMEmitter::ScalarRegSize::i64Bit, VTMP1, Accum, VTMP2, ARMEmitter::Condition::CC_HI);
|
||||
fcsel(ARMEmitter::ScalarRegSize::i64Bit, Accum, VTMP2, Accum, ARMEmitter::Condition::CC_HI);
|
||||
fdiv(VTMP2.D(), VTMP1.D(), Accum.D());
|
||||
fcmp(VTMP2.D(), VTMP2.D());
|
||||
(void)b(ARMEmitter::Condition::CC_VS, &Fallback);
|
||||
|
||||
// P(z^2) via 20-term Horner.
|
||||
fmul(Accum.D(), VTMP2.D(), VTMP2.D());
|
||||
fmov(ARMEmitter::Size::i64Bit, TMP3, VTMP2.D());
|
||||
|
||||
ldr(VTMP1.D(), &C19Label);
|
||||
ldr(VTMP2.D(), &C18Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C17Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C16Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C15Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C14Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C13Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C12Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C11Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C10Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C9Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C8Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C7Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C6Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C5Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C4Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C3Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C2Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C1Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &C0Label);
|
||||
fmadd(VTMP1.D(), Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
|
||||
// atan_abs = z + z^3 * P(z^2).
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP2.D(), TMP3);
|
||||
fmul(VTMP1.D(), Accum.D(), VTMP1.D());
|
||||
fmadd(VTMP1.D(), VTMP2.D(), VTMP1.D(), VTMP2.D());
|
||||
|
||||
// Quadrant adjustment driven by packed flags in TMP1.
|
||||
(void)tbz(TMP1, 0, &NoSwap);
|
||||
ldr(VTMP2.D(), &PiOver2Label);
|
||||
fsub(VTMP1.D(), VTMP2.D(), VTMP1.D());
|
||||
(void)Bind(&NoSwap);
|
||||
|
||||
(void)tbz(TMP1, 2, &PosX);
|
||||
ldr(VTMP2.D(), &PiLabel);
|
||||
fsub(VTMP1.D(), VTMP2.D(), VTMP1.D());
|
||||
(void)Bind(&PosX);
|
||||
|
||||
(void)tbz(TMP1, 1, &NegY);
|
||||
fneg(VTMP1.D(), VTMP1.D());
|
||||
(void)Bind(&NegY);
|
||||
|
||||
ldr(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TMP1);
|
||||
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::QReg::q2, ARMEmitter::Reg::rsp, 32);
|
||||
ret();
|
||||
|
||||
// Fallback path: restore original inputs from stack stash and dispatch the ABI handler.
|
||||
(void)Bind(&Fallback);
|
||||
ldr(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TMP1);
|
||||
ldr(TMP2, ARMEmitter::Reg::rsp, 16);
|
||||
ldr(TMP1, ARMEmitter::Reg::rsp, 24);
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::QReg::q2, ARMEmitter::Reg::rsp, 32);
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP2);
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP2.D(), TMP1);
|
||||
str<ARMEmitter::IndexType::PRE>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16);
|
||||
ldr(TMP1, STATE_PTR(CpuStateFrame, Pointers.FallbackHandlerPointers[FEXCore::Core::OPINDEX_F64ATAN].ABIHandler));
|
||||
ldr(TMP4, STATE_PTR(CpuStateFrame, Pointers.FallbackHandlerPointers[FEXCore::Core::OPINDEX_F64ATAN].Func));
|
||||
blr(TMP1);
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16);
|
||||
ret();
|
||||
|
||||
Align(16);
|
||||
(void)Bind(&C19Label);
|
||||
dc64(0x3EF3'5885'1160'A528ULL);
|
||||
(void)Bind(&C18Label);
|
||||
dc64(0xBF2A'B24D'A7BE'7402ULL);
|
||||
(void)Bind(&C17Label);
|
||||
dc64(0x3F51'7739'E210'171AULL);
|
||||
(void)Bind(&C16Label);
|
||||
dc64(0xBF6D'0062'B42F'E3BFULL);
|
||||
(void)Bind(&C15Label);
|
||||
dc64(0x3F81'4E9D'C19A'4A4EULL);
|
||||
(void)Bind(&C14Label);
|
||||
dc64(0xBF90'0513'8172'2A59ULL);
|
||||
(void)Bind(&C13Label);
|
||||
dc64(0x3F98'6089'7B29'E5EFULL);
|
||||
(void)Bind(&C12Label);
|
||||
dc64(0xBFA0'0E6E'ECE7'DE80ULL);
|
||||
(void)Bind(&C11Label);
|
||||
dc64(0x3FA3'38E3'1EB2'FBBCULL);
|
||||
(void)Bind(&C10Label);
|
||||
dc64(0xBFA5'D301'40AE'5E99ULL);
|
||||
(void)Bind(&C9Label);
|
||||
dc64(0x3FA8'42DB'E9B0'D916ULL);
|
||||
(void)Bind(&C8Label);
|
||||
dc64(0xBFAA'EBFE'7B41'8581ULL);
|
||||
(void)Bind(&C7Label);
|
||||
dc64(0x3FAE'1D0F'9696'F63BULL);
|
||||
(void)Bind(&C6Label);
|
||||
dc64(0xBFB1'1100'EE08'4227ULL);
|
||||
(void)Bind(&C5Label);
|
||||
dc64(0x3FB3'B139'B6A8'8BA1ULL);
|
||||
(void)Bind(&C4Label);
|
||||
dc64(0xBFB7'45D1'60A7'E368ULL);
|
||||
(void)Bind(&C3Label);
|
||||
dc64(0x3FBC'71C7'1BC3'951CULL);
|
||||
(void)Bind(&C2Label);
|
||||
dc64(0xBFC2'4924'9247'8F88ULL);
|
||||
(void)Bind(&C1Label);
|
||||
dc64(0x3FC9'9999'9999'96C1ULL);
|
||||
(void)Bind(&C0Label);
|
||||
dc64(0xBFD5'5555'5555'5555ULL);
|
||||
(void)Bind(&PiOver2Label);
|
||||
dc64(0x3FF9'21FB'5444'2D18ULL);
|
||||
(void)Bind(&PiLabel);
|
||||
dc64(0x4009'21FB'5444'2D18ULL);
|
||||
}
|
||||
|
||||
// JIT-inlined double-precision y * log2(x) for the F64 reduced precision x87 path.
|
||||
// Input: VTMP1 = x, VTMP2 = y. Output: VTMP1 = y * log2(x).
|
||||
// Algorithm: atanh-based log via s = f/(2+f) with 9-term polynomial, scaled by 1/ln(2),
|
||||
// then multiplied by y.
|
||||
void Dispatcher::EmitF64FYL2X() {
|
||||
F64FYL2XHandlerAddress = GetCursorAddress<uint64_t>();
|
||||
|
||||
constexpr auto Accum = ARMEmitter::VReg::v2;
|
||||
|
||||
ARMEmitter::ForwardLabel Fallback;
|
||||
ARMEmitter::ForwardLabel NoNorm;
|
||||
ARMEmitter::ForwardLabel Sqrt2Label, Log2eLabel;
|
||||
ARMEmitter::ForwardLabel BiasLabel;
|
||||
ARMEmitter::ForwardLabel P0Label, P1Label, P2Label, P3Label, P4Label, P5Label, P6Label, P7Label, P8Label;
|
||||
|
||||
str<ARMEmitter::IndexType::PRE>(ARMEmitter::QReg::q2, ARMEmitter::Reg::rsp, -16);
|
||||
|
||||
mrs(TMP1, ARMEmitter::SystemRegister::NZCV);
|
||||
str(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
|
||||
// Reject x <= 0, subnormal, inf and NaN before any FPR is clobbered,
|
||||
// so VTMP1/VTMP2 still hold the original inputs at the fallback.
|
||||
fmov(ARMEmitter::Size::i64Bit, TMP1, VTMP1.D());
|
||||
(void)tbnz(TMP1, 63, &Fallback);
|
||||
lsr(ARMEmitter::Size::i64Bit, TMP2, TMP1, 52);
|
||||
(void)cbz(ARMEmitter::Size::i64Bit, TMP2, &Fallback);
|
||||
cmp(ARMEmitter::Size::i64Bit, TMP2, 0x7FF);
|
||||
(void)b(ARMEmitter::Condition::CC_EQ, &Fallback);
|
||||
fmov(ARMEmitter::Size::i64Bit, TMP3, VTMP2.D());
|
||||
|
||||
// Extract k and normalize mantissa m into [1.0, 2.0).
|
||||
sub(ARMEmitter::Size::i64Bit, TMP2, TMP2, 1023);
|
||||
ubfx(ARMEmitter::Size::i64Bit, TMP1, TMP1, 0, 52);
|
||||
ldr(TMP4, &BiasLabel);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP1, TMP1, TMP4);
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP1);
|
||||
|
||||
// If m > sqrt(2), halve m and increment k.
|
||||
ldr(VTMP2.D(), &Sqrt2Label);
|
||||
fcmp(VTMP1.D(), VTMP2.D());
|
||||
(void)b(ARMEmitter::Condition::CC_LE, &NoNorm);
|
||||
fmov(ARMEmitter::ScalarRegSize::i64Bit, VTMP2, 0.5f);
|
||||
fmul(VTMP1.D(), VTMP1.D(), VTMP2.D());
|
||||
add(ARMEmitter::Size::i64Bit, TMP2, TMP2, 1);
|
||||
(void)Bind(&NoNorm);
|
||||
|
||||
// f = m - 1; s = f / (2 + f); TMP1 stashes s, VTMP1 holds s^2.
|
||||
fmov(ARMEmitter::ScalarRegSize::i64Bit, VTMP2, 1.0f);
|
||||
fsub(VTMP1.D(), VTMP1.D(), VTMP2.D());
|
||||
fmov(ARMEmitter::ScalarRegSize::i64Bit, VTMP2, 2.0f);
|
||||
fadd(VTMP2.D(), VTMP1.D(), VTMP2.D());
|
||||
fdiv(Accum.D(), VTMP1.D(), VTMP2.D());
|
||||
fmul(VTMP1.D(), Accum.D(), Accum.D());
|
||||
fmov(ARMEmitter::Size::i64Bit, TMP1, Accum.D());
|
||||
|
||||
// 9-term Horner from 1/19 down to 1/3.
|
||||
ldr(Accum.D(), &P8Label);
|
||||
ldr(VTMP2.D(), &P7Label);
|
||||
fmadd(Accum.D(), VTMP1.D(), Accum.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &P6Label);
|
||||
fmadd(Accum.D(), VTMP1.D(), Accum.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &P5Label);
|
||||
fmadd(Accum.D(), VTMP1.D(), Accum.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &P4Label);
|
||||
fmadd(Accum.D(), VTMP1.D(), Accum.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &P3Label);
|
||||
fmadd(Accum.D(), VTMP1.D(), Accum.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &P2Label);
|
||||
fmadd(Accum.D(), VTMP1.D(), Accum.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &P1Label);
|
||||
fmadd(Accum.D(), VTMP1.D(), Accum.D(), VTMP2.D());
|
||||
ldr(VTMP2.D(), &P0Label);
|
||||
fmadd(Accum.D(), VTMP1.D(), Accum.D(), VTMP2.D());
|
||||
|
||||
// ln(1+f) = 2 * s * (1 + s^2 * P(s^2)).
|
||||
fmul(Accum.D(), VTMP1.D(), Accum.D());
|
||||
fmov(ARMEmitter::ScalarRegSize::i64Bit, VTMP2, 1.0f);
|
||||
fadd(Accum.D(), Accum.D(), VTMP2.D());
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP2.D(), TMP1);
|
||||
fmul(Accum.D(), VTMP2.D(), Accum.D());
|
||||
fadd(Accum.D(), Accum.D(), Accum.D());
|
||||
|
||||
// log2(x) = k + ln(1+f)/ln(2); multiply by y.
|
||||
ldr(VTMP1.D(), &Log2eLabel);
|
||||
fmul(VTMP1.D(), Accum.D(), VTMP1.D());
|
||||
scvtf(ARMEmitter::Size::i64Bit, VTMP2.D(), TMP2);
|
||||
fadd(VTMP1.D(), VTMP1.D(), VTMP2.D());
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP2.D(), TMP3);
|
||||
fmul(VTMP1.D(), VTMP1.D(), VTMP2.D());
|
||||
|
||||
ldr(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TMP1);
|
||||
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::QReg::q2, ARMEmitter::Reg::rsp, 16);
|
||||
ret();
|
||||
|
||||
// Fallback path: VTMP1/VTMP2 still hold the original x/y.
|
||||
(void)Bind(&Fallback);
|
||||
ldr(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TMP1);
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::QReg::q2, ARMEmitter::Reg::rsp, 16);
|
||||
str<ARMEmitter::IndexType::PRE>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16);
|
||||
ldr(TMP1, STATE_PTR(CpuStateFrame, Pointers.FallbackHandlerPointers[FEXCore::Core::OPINDEX_F64FYL2X].ABIHandler));
|
||||
ldr(TMP4, STATE_PTR(CpuStateFrame, Pointers.FallbackHandlerPointers[FEXCore::Core::OPINDEX_F64FYL2X].Func));
|
||||
blr(TMP1);
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16);
|
||||
ret();
|
||||
|
||||
// Constant pool: bias=1.0, sqrt(2), log2(e)=1/ln(2), P8..P0 = 1/19, 1/17, 1/15, ..., 1/3.
|
||||
Align(16);
|
||||
(void)Bind(&BiasLabel);
|
||||
dc64(0x3FF0'0000'0000'0000ULL);
|
||||
(void)Bind(&Sqrt2Label);
|
||||
dc64(0x3FF6'A09E'667F'3BCDULL);
|
||||
(void)Bind(&Log2eLabel);
|
||||
dc64(0x3FF7'1547'652B'82FEULL);
|
||||
(void)Bind(&P8Label);
|
||||
dc64(0x3FAA'F286'BCA1'AF28ULL);
|
||||
(void)Bind(&P7Label);
|
||||
dc64(0x3FAE'1E1E'1E1E'1E1EULL);
|
||||
(void)Bind(&P6Label);
|
||||
dc64(0x3FB1'1111'1111'1111ULL);
|
||||
(void)Bind(&P5Label);
|
||||
dc64(0x3FB3'B13B'13B1'3B14ULL);
|
||||
(void)Bind(&P4Label);
|
||||
dc64(0x3FB7'45D1'745D'1746ULL);
|
||||
(void)Bind(&P3Label);
|
||||
dc64(0x3FBC'71C7'1C71'C71CULL);
|
||||
(void)Bind(&P2Label);
|
||||
dc64(0x3FC2'4924'9249'2492ULL);
|
||||
(void)Bind(&P1Label);
|
||||
dc64(0x3FC9'9999'9999'999AULL);
|
||||
(void)Bind(&P0Label);
|
||||
dc64(0x3FD5'5555'5555'5555ULL);
|
||||
}
|
||||
|
||||
uint64_t Dispatcher::GenerateABICall(FallbackABI ABI) {
|
||||
auto Address = GetCursorAddress<uint64_t>();
|
||||
constexpr static auto FallbackPointerReg = TMP4;
|
||||
@@ -1870,6 +2188,8 @@ void Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState* Thread)
|
||||
Ptrs.F64TanHandler = F64TanHandlerAddress;
|
||||
Ptrs.F64F2XM1Handler = F64F2XM1HandlerAddress;
|
||||
Ptrs.F64ScaleHandler = F64ScaleHandlerAddress;
|
||||
Ptrs.F64AtanHandler = F64AtanHandlerAddress;
|
||||
Ptrs.F64FYL2XHandler = F64FYL2XHandlerAddress;
|
||||
|
||||
// Fill in the fallback handlers
|
||||
InterpreterOps::FillFallbackIndexPointers(Ptrs.FallbackHandlerPointers, &ABIPointers[0]);
|
||||
|
||||
@@ -105,6 +105,8 @@ private:
|
||||
uint64_t F64TanHandlerAddress {};
|
||||
uint64_t F64F2XM1HandlerAddress {};
|
||||
uint64_t F64ScaleHandlerAddress {};
|
||||
uint64_t F64AtanHandlerAddress {};
|
||||
uint64_t F64FYL2XHandlerAddress {};
|
||||
|
||||
void EmitDispatcher();
|
||||
uint64_t GenerateABICall(FallbackABI ABI);
|
||||
@@ -121,6 +123,8 @@ private:
|
||||
void EmitF64Tan();
|
||||
void EmitF64F2XM1();
|
||||
void EmitF64Scale();
|
||||
void EmitF64Atan();
|
||||
void EmitF64FYL2X();
|
||||
|
||||
FEX_CONFIG_OPT(DisableL2Cache, DISABLEL2CACHE);
|
||||
};
|
||||
|
||||
@@ -4650,6 +4650,37 @@ DEF_OP(F64TAN) {
|
||||
fmov(Dst.D(), VTMP1.D());
|
||||
}
|
||||
|
||||
// Src1=y(ST1), Src2=x(ST0). Marshal into VTMP1/VTMP2 and dispatch the shared handler.
|
||||
DEF_OP(F64ATAN) {
|
||||
const auto Op = IROp->C<IR::IROp_F64ATAN>();
|
||||
const auto Src1 = GetVReg(Op->Src1);
|
||||
const auto Src2 = GetVReg(Op->Src2);
|
||||
const auto Dst = GetVReg(Node);
|
||||
|
||||
fmov(VTMP1.D(), Src1.D());
|
||||
fmov(VTMP2.D(), Src2.D());
|
||||
ldr(TMP1, STATE_PTR(CpuStateFrame, Pointers.F64AtanHandler));
|
||||
str<ARMEmitter::IndexType::PRE>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16);
|
||||
blr(TMP1);
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16);
|
||||
fmov(Dst.D(), VTMP1.D());
|
||||
}
|
||||
|
||||
// Src=x(ST0), Src2=y(ST1). Marshal into VTMP1/VTMP2 and dispatch the shared handler.
|
||||
DEF_OP(F64FYL2X) {
|
||||
const auto Op = IROp->C<IR::IROp_F64FYL2X>();
|
||||
const auto Src = GetVReg(Op->Src);
|
||||
const auto Src2 = GetVReg(Op->Src2);
|
||||
const auto Dst = GetVReg(Node);
|
||||
|
||||
fmov(VTMP1.D(), Src.D());
|
||||
fmov(VTMP2.D(), Src2.D());
|
||||
ldr(TMP1, STATE_PTR(CpuStateFrame, Pointers.F64FYL2XHandler));
|
||||
str<ARMEmitter::IndexType::PRE>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, -16);
|
||||
blr(TMP1);
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16);
|
||||
fmov(Dst.D(), VTMP1.D());
|
||||
}
|
||||
|
||||
DEF_OP(F64SCALE) {
|
||||
const auto Op = IROp->C<IR::IROp_F64SCALE>();
|
||||
|
||||
@@ -2758,7 +2758,7 @@
|
||||
"F64": {
|
||||
"FPR = F64ATAN FPR:$Src1, FPR:$Src2": {
|
||||
"DestSize": "OpSize::i64Bit",
|
||||
"JITDispatch": false
|
||||
"JITDispatch": true
|
||||
},
|
||||
"FPR = F64FPREM FPR:$Src1, FPR:$Src2": {
|
||||
"DestSize": "OpSize::i64Bit",
|
||||
@@ -2778,7 +2778,7 @@
|
||||
},
|
||||
"FPR = F64FYL2X FPR:$Src, FPR:$Src2": {
|
||||
"DestSize": "OpSize::i64Bit",
|
||||
"JITDispatch": false
|
||||
"JITDispatch": true
|
||||
},
|
||||
"FPR = F64TAN FPR:$Src": {
|
||||
"DestSize": "OpSize::i64Bit",
|
||||
|
||||
@@ -381,6 +381,8 @@ struct JITPointers {
|
||||
uint64_t F64TanHandler {};
|
||||
uint64_t F64F2XM1Handler {};
|
||||
uint64_t F64ScaleHandler {};
|
||||
uint64_t F64AtanHandler {};
|
||||
uint64_t F64FYL2XHandler {};
|
||||
/** @} */
|
||||
|
||||
// Copy of process-wide named vector constants data.
|
||||
|
||||
Reference in new issue
Block a user