[LA64_DYNAREC] Improve x87 long double compare - #4142
Conversation
| v2 = x87_get_st(dyn, ninst, x1, x2, nextop & 7, X87_COMBINE(0, nextop & 7)); | ||
| MOVFR2GR_D(x6, v1); | ||
| MOVFR2GR_D(x7, v2); | ||
| x87_fcomi_fpu_ld(dyn, ninst, x1, x2, x3, x4, x5, x6, x7, nextop & 7); |
There was a problem hiding this comment.
same question here abotut having this optionnal?
|
@ksco what do you think about those x87 tests: should they be optionnal or is it ok to have them all the time? |
|
Absolutely optional. I need to find some time to review this PR, but not now, for sure. |
|
The change should take effect when FASTROUND=0. As for x87_clear_fpu_ld, the single branch is not responsible for maintaining ld, so it should indeed be removed. |
ksco
left a comment
There was a problem hiding this comment.
I haven't finished the review, but this already confuses me. Could you please explain how this works in detail and what it is for? The NumPy example did not convince me, because it's a simple example that just shows that Box64 does not support long double, which is known. Does adding the exact support for this crafted example help any real-world program?
(This question holds for the interpreter change #4107 too, since that was already merged, maybe @ptitSeb has opinions too?)
| MAYUSE(st); | ||
| MAYUSE(chs); | ||
|
|
||
| #ifndef HAVE_LD80BITS |
There was a problem hiding this comment.
These helper functions update the simulated raw 80-bit shadow layout when HAVE_LD80BITS is unavailable, for example:
fpu_ld_t.ld.l.lower / upper
fpu_ld_t.uref
When HAVE_LD80BITS is available, fpu_ld_t stores a raw long double type, and the shadow layout does not need to be manually updated.
There was a problem hiding this comment.
It makes no sense to enable HAVE_LD80BITS on a LoongArch build.
There was a problem hiding this comment.
It makes no sense to enable HAVE_LD80BITS on a LoongArch build.
=.= That's true.
| MAYUSE(a); | ||
| MAYUSE(b); | ||
|
|
||
| #ifndef HAVE_LD80BITS |
| ADDI_D(addr, addr, st - dyn->lsx.x87stack); | ||
| ANDI(addr, addr, 7); | ||
|
|
||
| MOV32w(tmp, sizeof(fpu_ld_t)); |
There was a problem hiding this comment.
This is a compile-time constant (64). Do we need to use MOV32 and MUL_D?
There was a problem hiding this comment.
SLLI_D(addr, addr, 6);
| ld80_get_addr(dyn, ninst, s1, s4, a); | ||
| ld80_get_addr(dyn, ninst, s2, s4, b); | ||
|
|
||
| for (int i = 0; i < sizeof(fpu_ld_t); i += 2) { |
There was a problem hiding this comment.
I don't understand, why the step here is 2?
There was a problem hiding this comment.
I'm concerned that fpu_ld_t is a packed struct of #pragma pack(push, 1), and the uint64_t field inside is not guaranteed to be 8-byte aligned. Using half-word load/store operations can avoid unaligned 64-bit accesses and is also less expensive than copying byte by byte.
| // swap the cache value, not the double value itself :p | ||
| x87_get_st(dyn, ninst, x1, x2, nextop & 7, X87_ST(nextop & 7)); | ||
| x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0); | ||
| x87_swap_fpu_ld(dyn, ninst, x1, x2, x3, x4, 0, nextop & 7); |
There was a problem hiding this comment.
Wouldn't this need to be optional too?
|
I wont merge this PR for current release anyway. This will wait for the next dev. cycle. |
The NumPy case does not require full long double arithmetic support, and this PR is not trying to add that. The concrete issue is that, on targets without HAVE_LD80BITS, Box64 already keeps an emulated raw x87 80-bit shadow for some x87/long-double state. In the LA64 dynarec path, some x87 stack/sign operations update the cached ST double value, but the raw 80-bit shadow can remain stale. Later x87 compare/classification instructions may then observe the stale raw shadow. This is visible in real NumPy APIs, not only in a crafted unit test. For example, longdouble classification/comparison paths such as np.isinf, np.isfinite, np.isnan, and longdouble division corner cases expect inf/NaN classification to be coherent. So far, NumPy is the only real-world workload where I have verified this directly. But the underlying issue is not NumPy-specific: it is a consistency problem between the LA64 dynarec cached ST value and Box64's existing emulated raw x87 80-bit shadow. I can update the PR description to make this scope clearer: it does not implement full long double support; it only keeps the existing raw x87 shadow coherent for the affected dynarec x87 operations. |
0f640d1 to
3ece8b6
Compare
Use Box64's existing raw x87 80-bit shadow for FCOMI/FUCOMI/ FCOMIP/FUCOMIP when BOX64_DYNAREC_FASTROUND=0, improving long double comparison accuracy. Keep the raw shadow coherent for FXCH and sign-only FABS/FCHS operations, fixing cases where values such as LDBL_MAX collapse to double infinity and break isinf/isfinite-style checks. Signed-off-by: Zewei Yang <yangzewei@loongson.cn>
Improved x87 long double comparisons on LA64 dynarec.
Fixed long double classification issues, such as NumPy's
isinf/isfiniteoperations onnp.longdoublevalues.before
after