Skip to content
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

How should we handle fenv? #480

Open
tgross35 opened this issue Jan 25, 2025 · 3 comments
Open

How should we handle fenv? #480

tgross35 opened this issue Jan 25, 2025 · 3 comments

Comments

@tgross35
Copy link
Contributor

I am not entirely sure how we should or shouldn't be handling and testing fenv. It would be nice to comply with what the C specification says, but on the other hand I am unsure if it makes much sense considering RFC3514 says Rust does not support fenv and, as I understand it, LLVM still does not fully support it (though my information may be out of date here).

On one hand it would be nice to just remove everything that handles rounding modes and exceptions in order to keep code cleaner. On the other hand we are beginning to port some high quality algorithms that do correctly handle rounding modes, so I am leaning toward figuring out some way to test this for specific routines rather than discarding valuable code. In any case, I just don't want to keep the relevant handling around if it remains untested. Ignoring rounding modes but keeping exceptions is also an option since that should be easier to test.

Anyway, I don't have any strong opinions here so I am opening this issue to see what others think.

@tgross35
Copy link
Contributor Author

Related question: are there more uses rounding modes? I only know of result bracketing.

@beetrees
Copy link
Contributor

beetrees commented Jan 25, 2025

As Rust doesn't support non-default fenv, there's no way to support using a non-default fenv from the extern "C" libm functions (without using #[naked] ASM function wrappers) at the moment (LLVM does support it AFAIK, but it requires using the Constrained Floating-Point Intrinsics instead of the regular ones that Rust uses). Like all undefined behaviour, Rust code might coincidentally give the expected result when using a non-default fenv, but there are LLVM optimisations that rely on the default rounding mode for soundness and LLVM is free to add/remove/modify floating point operations in ways that affect what fenv exceptions are raised.

If having a way to use different rounding modes and check floating point exceptions via the Rust crate is desired, libm could have functions like cbrt_rounded (name very bikesheddable) that explicitly take a rounding mode as an argument and return what exceptions were raised if desired, similar to rustc_apfloat. The main barrier to this would be that a custom implementation of the basic floating point operations would also have to be used (such as the ones in rustc_apfloat, modified versions of those in compiler_builtins, or custom ASM on targets with hardware support), as the Rust +/-/*// operators will always use round to nearest (and don't return which exceptions are raised). Of course, this would definitely add implementation complexity for a feature that isn't currently used by core/std.

If adding support for takes-rounding-mode-and-also-returns-exceptions functions is decided not to be worthwhile, and having untested code is to be avoided, I'd suggest just removing the fenv handling, leaving a comment in it's place mentioning you've done so. The original implementation can always be referenced if fenv-handling is needed in the future.

@hanna-kruppe
Copy link
Contributor

Yes, rustc emits LLVM IR that uses the default floating point environment and as long as that's the case, querying/modifying the dynamic rounding mode or even querying exception status is effectively Undefined Behavior. Trying to change the codegen (even for a limited, nightly-only feature) runs into a lot of hard language design issues very quickly, and trying to tip-toe around it is extremely difficult as @beetrees described, so I would also suggest not bothering at all.

Looking at the history of libm::math::fenv shows that at least calls to fesetround in ported routines are footguns that should be eliminated in the porting process as long as Rust doesn't actually support them. Other calls may be harmless but at best it's still dead code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants