Correct the FpuMulHack comment: the constant is pi, not pi/2

0x40490fdb is 3.14159274, and 0.25 * that is pi/4 == 0x3f490fdb. The
comment called the multiplicand pi/2 and did not say what the patched
value 0x3f490fda is, which left it reading as an arbitrary magic number
lifted from x86.

It is not arbitrary: 0x3f490fda is pi/4 one ULP low, and one ULP low is
what the EE's multiplier returns here. Its Booth recoding drops one ULP
when ft's significand has an odd digit pair (ft & 0x2AA -- 0x490fdb & 0x2AA
== 0x28a, so it fires) and the exact product carries no tail below the
single ULP -- fs = 0.25 = 2^-2 has significand 2^23 exactly, so the product
is exact and the deficit reaches the result. The gamefix is a hardcoded
instance of a general defect, not a game-specific fudge.

Checked by executing the general widened model (cmtst/fmul/fcmeq/bic/add on
doubles under FZ|RZ) on both operand orders:

    model(0.25, pi) = 0x3f490fda    gamefix patches to 0x3f490fda
    model(pi, 0.25) = 0x3f490fdb    gamefix leaves alone (host value)

so the model agrees with the gamefix on the asymmetry too -- the predicate
reads ft's significand alone, and 0.25's is zero. That is the same
asymmetry the Cmp sequence below has, where s must be 0.25 and t must be pi.

Comment also records why the general model is not being pulled into this
fast path: here it costs ~9 instructions on every multiply in every game,
against 1 today. It belongs in iFPUd-arm64.cpp, where the operands are
already doubles and it costs 4 -- and where every eeClampMode:3 title gets
it, rather than the one title that needs the hack. Extending it to this
path needs its own measured case.

Comment-only change; no emitted code moves.

Idea by pstef.
This commit is contained in:
bmdhacks
2026-08-02 17:03:02 -07:00
committed by Brian Degenhardt
parent c5a6c7cb0a
commit fca3e9074b
+18 -6
View File
@@ -593,12 +593,24 @@ static void fpuEmitGuardedAddSub(const a64::VRegister& dst,
// FpuMulHack (Tales of Destiny Remake gamefix, EmuConfig.Gamefixes.FpuMulHack).
// x86 routes every FPU multiply (MUL/MULA/MADD/MSUB) through FPU_MUL, which —
// when the gamefix is on — patches the single specific product 0.25 * (π/2)
// (0x3e800000 * 0x40490fdb) to 0x3f490fda so the game stops hanging in one
// late-game room. Emit `dst = (hit) ? 0x3f490fda : s*t`; callers clamp/accumulate
// dst as they normally would (the magic value is an ordinary small float, so a
// following fpuClampResult is a no-op). In the default config (gamefix off) this
// is a bare Fmul — zero added cost.
// when the gamefix is on — patches the single specific product 0.25 * π
// (0x3e800000 * 0x40490fdb) from the correctly-rounded 0x3f490fdb to 0x3f490fda
// so the game stops hanging in one late-game room. Emit
// `dst = (hit) ? 0x3f490fda : s*t`; callers clamp/accumulate dst as they normally
// would (the magic value is an ordinary small float, so a following
// fpuClampResult is a no-op). In the default config (gamefix off) this is a bare
// Fmul — zero added cost.
//
// The patched value is not arbitrary: 0x3f490fda is π/4 one ULP low, which is
// what the EE's multiplier actually returns. Its Booth recoding drops one ULP
// when ft's significand has an odd digit pair (ft & 0x2AA) and the exact product
// has no tail below the single ULP — here fs = 2^-2, so the product is exact and
// the deficit reaches the result. The general model reproduces this pair (and
// leaves the swapped operand order alone, exactly as the check below does).
// It is NOT generalized here: in this fast path it costs ~9 instructions on every
// multiply in every game, against 1 today. Its home is iFPUd-arm64.cpp, where the
// double product already exists and it costs 4 — extending it to this path needs
// its own measured case.
static void emitFpuMul(const a64::VRegister& dst, const a64::VRegister& s, const a64::VRegister& t)
{
if (!CHECK_FPUMULHACK)