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:
pstef
2026-08-16 00:11:47 +02:00
parent 8ee895a649
commit 85fb137bbc
7 changed files with 21 additions and 25 deletions
+1 -1
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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)
+6 -4
View File
@@ -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)
+1 -1
View File
@@ -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
+4 -9
View File
@@ -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
+4 -4
View File
@@ -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);
}
}