mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
EE/FPU: name the clamp modes the slot format actually follows
eeFprSyncSlotFormat keys on CHECK_FPU_FULL, so the relocated file is what both of iFPUd's rungs compute over, not mode 3 alone. The comments that name a mode where they mean the tier are renamed to the tier.
This commit is contained in:
+1
-1
@@ -58,7 +58,7 @@ __fi static u32 eeFprNarrow(double stored)
|
||||
}
|
||||
|
||||
/* Whether the FPR file is in this domain right now. It follows the EE FPU's
|
||||
clamp mode: only the mode-3 recompiler computes here, and modes 0-2 leave the
|
||||
clamp mode: only iFPUd computes here, and modes 0 to 2 leave the
|
||||
architectural word in the slot's low half. Read it through
|
||||
FPRreg::Word()/SetWord().
|
||||
*/
|
||||
|
||||
+4
-5
@@ -151,11 +151,10 @@ union GPR_reg64 {
|
||||
s8 SC[8];
|
||||
};
|
||||
|
||||
/* One EE FPR. The architectural register is 32 bits and the slot is 64, so the
|
||||
word is not the slot and there is no u32 view of it: it is read through
|
||||
Word() and written through SetWord(), and how a slot encodes it is those two
|
||||
functions' business. In eeClampMode 3 it is the relocation of EeFpuFormat.h,
|
||||
and otherwise the low half.
|
||||
/* One EE FPR. The architectural register is 32 bits and the slot is 64: read
|
||||
the word through Word(), write it through SetWord(). From eeClampMode 3 up a
|
||||
slot holds the relocation of EeFpuFormat.h, below that the word in its low
|
||||
half.
|
||||
*/
|
||||
union FPRreg {
|
||||
double d;
|
||||
|
||||
@@ -301,7 +301,7 @@ __fi static void armEmitEeFprStoreSlotWord(const vixl::aarch64::MemOperand& slot
|
||||
}
|
||||
|
||||
// Bridge for emitters holding a result as the architectural single in an S
|
||||
// register while the slot they store it to holds the stored double: the mode-3
|
||||
// register while the slot they store it to holds the stored double: iFPUd's
|
||||
// bodies, the fast path's SQRT, and LWC1's fastmem load. Clobbers `tmp`.
|
||||
__fi static void armEmitEeFprFromS(const vixl::aarch64::VRegister& slot,
|
||||
const vixl::aarch64::VRegister& src, const vixl::aarch64::Register& tmp)
|
||||
|
||||
@@ -633,7 +633,8 @@ static void emitFpuMul(const a64::VRegister& dst, const a64::VRegister& s, const
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// "Full" / DOUBLE-precision emitters (iFPUd-arm64.cpp), selected per-op when
|
||||
// CHECK_FPU_FULL (GameDB eeClampMode:3). Default config uses the fast paths.
|
||||
// CHECK_FPU_FULL (GameDB eeClampMode 3 and up). Default config uses the fast
|
||||
// paths.
|
||||
// MOV.S is a raw bit-copy in BOTH modes (x86 DOUBLE::recMOV_S_xmm == the fast
|
||||
// body), so it has no DOUBLE selection.
|
||||
namespace DOUBLE {
|
||||
@@ -1459,7 +1460,8 @@ void recMSUBA_S()
|
||||
// CVT.S: fd = (float)int_bits_of(fpr[fs])
|
||||
// Single NEON-scalar SCVTF Sd,Sn — the int32 bits are already in the V file;
|
||||
// the old Fmov-to-GPR bounce cost an extra insn + cross-file hazard (GE-02).
|
||||
// A relocated slot puts them back out of reach, so mode 3 pays the bounce.
|
||||
// A relocated slot puts them back out of reach, so the double tier pays the
|
||||
// bounce.
|
||||
static void recCVT_S_xmm(int info)
|
||||
{
|
||||
if (!CHECK_FPU_FULL)
|
||||
@@ -1485,8 +1487,8 @@ void recCVT_S()
|
||||
// NaN by sign — positive NaN → 0x7fffffff, negative NaN → 0x80000000. Fix up
|
||||
// the NaN case only (cold branch over the source-sign select).
|
||||
//
|
||||
// A relocated slot holds no NaN, so mode 3 unscales into the value and converts,
|
||||
// and Fcvtzs's own saturation covers it.
|
||||
// A relocated slot holds no NaN, so the double tier unscales into the value and
|
||||
// converts, and Fcvtzs's own saturation covers it.
|
||||
static void recCVT_W_xmm(int info)
|
||||
{
|
||||
if (CHECK_FPU_FULL)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// widens each single to IEEE double, performs the op in double, then narrows
|
||||
// back to a PS2 single with the hardware's overflow/underflow/clamp semantics.
|
||||
// It is selected when CHECK_FPU_FULL (EmuConfig.Cpu.Recompiler.fpuFullMode, the
|
||||
// GameDB `eeClampMode:3` path — FFX, Max Payne, Dark Cloud 2, Klonoa 2 …).
|
||||
// GameDB eeClampMode 3 and up — FFX, Max Payne, Dark Cloud 2, Klonoa 2 …).
|
||||
// Default config runs the single-precision fast path in iFPU-arm64.cpp.
|
||||
//
|
||||
// It serves eeClampMode 3 and 4, which differ at emitDefectiveFmul and at
|
||||
|
||||
@@ -323,13 +323,8 @@ static const void* _DynGen_EnterRecompiledCode()
|
||||
armAsm->Ldr(a64::s9, -FLT_MAX);
|
||||
|
||||
// Same convention, three registers along: d11 = 2^kEeFprScaleExp, which
|
||||
// turns a slot into the value it denotes (NEON_RESERVED_EEFPU_UNSCALE; the
|
||||
// contract is on the constant, the consumers are in iFPUd-arm64.cpp).
|
||||
// Parking it here is what makes a mode-3 widening one instruction instead
|
||||
// of eleven — every consumer reads it, none materializes it, and because
|
||||
// the low 64 bits of d8-d15 are callee-saved there is no C-call seam,
|
||||
// branch fork, superblock side exit or backpatched fastmem thunk that can
|
||||
// invalidate it.
|
||||
// turns a slot into the value it denotes. The contract is on
|
||||
// NEON_RESERVED_EEFPU_UNSCALE; iFPUd-arm64.cpp is the consumer.
|
||||
//
|
||||
// Emitted unconditionally rather than under CHECK_FPU_FULL: two
|
||||
// instructions once per JIT entry are not worth a dispatcher that goes
|
||||
@@ -533,8 +528,8 @@ void iFlushCall(int flushtype)
|
||||
// GE-15: FPR-class slots (NEONTYPE_FPREG/FPACC) in the callee-saved
|
||||
// q10-q15 range survive plain C-helper seams — AAPCS64 preserves the
|
||||
// LOWER 64 bits of v8-v15, and this class only ever reads/writes lane 0,
|
||||
// at S width or (eeClampMode 3, where the slot is a relocated double) D
|
||||
// width. Both fit inside the preserved half, and _writebackNEONreg stores
|
||||
// at S width, or at D width where eeClampMode 3 and up put a relocated
|
||||
// double in the slot. Both fit the preserved half, and _writebackNEONreg stores
|
||||
// the same width it filled, so post-call garbage above it is never
|
||||
// observed. Writeback if
|
||||
// dirty but KEEP mapped — 4248's writeback-dirty-but-keep passes, whose
|
||||
|
||||
@@ -1049,10 +1049,10 @@ void recLWC1()
|
||||
vtlbFastmemReadFPR32(9, ftreg);
|
||||
if (CHECK_FPU_FULL)
|
||||
{
|
||||
// The load lands the architectural word; in mode 3 the slot holds
|
||||
// it relocated. Emitted after the backpatch site, so it runs on the
|
||||
// thunk's return path too (the slow path ends in the same
|
||||
// Fmov S<n>, w0).
|
||||
// The load lands the architectural word; on the double tier the
|
||||
// slot holds it relocated. Emitted after the backpatch site so it
|
||||
// runs on the thunk's return path too (the slow path ends in the
|
||||
// same Fmov S<n>, w0).
|
||||
armEmitEeFprFromS(armDRegister(ftreg), armSRegister(ftreg), RXSCRATCH);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user