-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
About FPU control word settings in 32-bit environment #12125
Comments
As I understood, the problem occurs because SQLite introduced a faster algorithm that uses We can't change this precision because this may cause fragmentation between x86 and other systems. x86_64 uses SSE2 for I suppose we have to use @iluuu1994 could you please take a look |
I am of the same understanding. It seems I didn't convey it well, sorry. According to the sqlite forum,
|
Disclaimer that my knowledge of both IEEE 754 and SQLite is limited. Reading https://www.sqlite.org/forum/forumpost/023baad0fdacea43 it sounds like SQLite does not expect FPU precision to be changed, nor would they like to support it, as they consider it a bug on our side (https://www.sqlite.org/forum/forumpost/abc65bec19475130). I'm not sure how to fix that, other than 1. not changing the FPU mode which would lead to inconsistent results in PHP, 2. switching back for every call into SQLite. Also worth noting, they say:
But Edit: Also, thank you @SakiTakamachi for your extensive analysis. 🙂 |
Yeah, it seems like the attitude is that they won't accept anything other than the highest precision that the CPU can handle. I think the only practical way is to temporarily change the precision before and after using the sqlite API. This is probably the same as idea 2. |
@SakiTakamachi Maybe they will reconsider if aware that there is an API on all major platforms? Maybe let them know in the thread you opened. And it would be great if you could verify in your short reproducer. |
OK, I'll post it in the thread. |
@SakiTakamachi Thank you! You should mention |
@iluuu1994 |
Although it is not definitive as the final conclusion has not yet been reached, it appears from the timeline that a fix for this issue has been adopted. |
@SakiTakamachi That's great, thank you! /cc @andypost |
Thank you! it means it just need to wait for new sqlite release) btw I got some reflection of x86 FPU because few tests still fail on x86 (32 bit) https://gitlab.alpinelinux.org/alpine/aports/-/issues/11645#note_104896 There was an attempt https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/28340/diffs |
@andypost In which php version does the test fail? In some cases, it may be easier to understand by opening a new issue. |
@SakiTakamachi it fails few years, probably starting from 7.4... can't recall exactly - I just disable this 32-bit tests long ago as it became clear that issue not in musl( I gonna enable them to get fresh run, IIRC few math tests was broken on s390x but over time they already fixed |
Ah, I see now. I'll take a look. |
I took a look, and it seems that Perhaps |
First, I took a closer look at test code:
alpine 32bit result:
debian 32bit (i386/debian:trixie-slim) result:
From these results, I infer that the problem lies in alpine's |
As I see the issue is in
|
Maybe 32-bit just need something like #5621 |
What's wrong with this?
|
then why without math the last number displayed 2 at the end |
Do you mean it's strange to round After rounding, display the "nearest decimal number" at the end. Most floating point numbers have guaranteed precision to the upper 15 digits. The remaining two digits are visible but unreliable. As I wrote above, the IEEE754 representation of these three values is It may appear that In fact, I don't think any rounding is being performed, because no matter how I change the rounding mode under FPU control, the result is the same. |
Thank you a lot for elaboration! I mentioned musl maintainer about this issue and examples |
I suspect the problem is with math.h and its related implementation of cos(). I'm very interested in this issue, so if you have any progress, please let me know. |
Probably it could be better to write to musl mailing list but maybe @richfelker can comment here |
Calling any function from the std library without satisfying the ABI (that fpu control word is in a state that gives conforming IEEE floating point semantics) yields undefined behavior. I believe I reported this bug in PHP a long time ago but it was ignored... |
Yes, it was fixed only for x86_64 |
btw I applied patch and all this tests passed https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/52108/diffs |
AFAICT that's just disabling the use of custom fpu control word, undermining whatever php was trying to achieve with it. While that use is almost certainly wrong (probably trying to use the low-precisions modes, that don't actually behave like IEEE types, and which induce some nasty UB-like effects), getting rid of it might produce new failures elsewhere. The "right" thing to do is to only switch into the nonconforming mode for execution of your own code that expects the fpu in this state, and to always switch back before returning to (or calling into) code that expects the ABI requirements to be met. |
In any case, all of the remaining issues in this thread are not caused by php. We can open a new issue if we want, so I close this issue. |
@SakiTakamachi issue is caused by PHP which is using control in a wrong way, so I have to disable FPU usage to pass tests |
Same as https://bugs.php.net/bug.php?id=79595 it just hide the problem |
It seems that alpine relies on long double behavior. I don't think it's a php issue. |
What do you think? |
Here's PR #12368 to backport the fix for 32-bits, at least it allows to pass tests |
I confirmed that the problem was resolved with SQLite3.43.2! |
@SakiTakamachi Great! Thank you for confirming! |
This issue cannot be "resolved" by changing the sqlite version. If the symptom went away, that just means it's re-buried, not resolved. It will not be resolved until PHP either stops fiddling with the FPU control word, or swaps the janky control word value in and out every time it switches between running its own code and calling external library (including libc) code. |
It makes sense to control the FPU if the OS supports that feature. However, I personally think that in-line ASM may be controversial.
Honestly, I don't think it's realistic because such places exist everywhere in PHP. |
It does not make sense on at least two levels, one deeply conceptual, and one very practical. On the very high conceptual level, making calls with the FPU control word set to something contrary to the ABI requirements voids all contracts you're expecting to be satisfied by the functions you're calling. Everything has undefined behavior. It might sometimes appear to work, or "mostly work", but you have no promises from anyone that anything will work. If you do this and rely on it working, you're doing coding by trial and error on particular versions of particular platforms you think you understand, and it may break at any time. On the practical level, setting the FPU control word is not doing what you think it is. Folks set it the way PHP is setting it in hopes of getting IEEE double behavior on the x87 fpu. Unfortunately, this is not possible. The "double" mode the x87 has is not actually IEEE double, but carries extra exponent range and extra bits of precision on denormals that should not be there, that will get lost in a hidden double-rounding step whenever an intermediate is spilled to memory rather than being kept in a register. This kind of inconsistent value breaks the assumptions compiler optimizations are built on and can produce all the standard UB effects. But even if nothing does blow up, it's not giving you the exact same results you'd get on a machine with actual IEEE doubles, which is presumably what whoever did this wanted.
The OS does not support that feature when calling library functions that have not given you a contract that they'll accept it. It supports letting you set it for your own code, but the compiler doesn't actually support this (see above), so you will get UB-like results sometimes.
As far as I'm concerned, being inline assembly is completely non-controversial. Assembly is really the only way you can make use of this feature without bad interactions with the compiler.
I don't think you are prepared to evaluate that unless you understand what it's used for and where it's wanted. |
Do you know what the FPU control word is currently used for and what will happen if it is abolished? As far as I know, it is described in the following RFC for round. |
We use SSE floating point instruction on X86_64 and regular FPU in x86 (32-bit). SSE precision is limited to 64-bit doubles while FPU may use 80-bit long double. |
Thank you. I studied it and was able to understand it to some extent. |
As I tried to explain above, the behavior is not actually unified. The x87 "64-bit precision" mode is not actually 64-bit and doesn't match IEEE double behavior. The in-register form has 53 mantissa bits like double, but 15 exponent bits like 80-bit extended. So to begin with, this is a different type with different results. When these frankenstein floats are spilled to memory, however, things get even more messy. The excess exponent range is collapsed at store time by another rounding operation, producing an inconsistent value depending on whether intermediates are kept in registers or need to be saved to the stack and reloaded (e.g. across function calls or if there's too much register pressure). There is really no good way to get safe and standard double precision evaluation on x86 without either requiring SSE2+ or using soft-float or some complex hybrid soft/hard method that patches up each result. It probably makes sense to try to figure out what properties you're actually trying to rely on. If there's a hosted-application-facing reason you're trying to match IEEE double semantics perfectly, you're not doing that now, and fixing it is really hard and costly. But if you're just trying to make tests come out as "pass" without arch-specific result expectations, the answer is probably just "don't do that". You get the safest behavior by processing expressions as |
First of all, let me state that these are my personal opinions. I personally think that FP is mainly used in two places, the output system and the calculation system. Since the output system is "closed" within php, there is probably no need to consider it in this case, and the use of external libraries in the calculation system may be the subject of this discussion. If the calculation system uses an external library and is a 32-bit architecture, it may be relatively easy to temporarily restore FPU control. However, I don't know exactly what the side effects of such a change would be. Such a change would likely require an RFC, but I have no idea how well it would be received. Really FPU issues bother us. There is no doubt about that. |
Description
It was discovered in this issue:
#12076
Here is the sqlite forum conversation:
https://www.sqlite.org/forum/forumpost/abbb95376ec6cd5f
In summary, even in an environment where the CPU can handle extended double-precision floating point numbers, in-line assembly may limit the use of normal double-precision numbers.
Here is the code:
php-src/Zend/zend_float.h
Line 356 in e2189e5
I think it should be fixed, but should this be fixed in a patch version, or should it be in a minor version and accompanied by an RFC?
Thank you.
PHP Version
php8.2.9
Operating System
i386/alpine docker image
The text was updated successfully, but these errors were encountered: