Yeah, this would work with an "I know the floating point environment is some specific non-standard one" setting, though not with an "I don't know the floating point environment" setting.
In C, the standard FENV_ACCESS pragma is "I don't know the environment", but it seems there are some nonstandard command-line arguments for setting a specific environment: for example, GCC has -mfp-rounding-mode for rounding (but Clang doesn't), and Clang has -fdenormal-fp-math for denormal handling (but GCC doesn't).
In any case, it looks like LLVM IR supports both setting a specific rounding mode and exception behavior (using arguments to the constrained FP math intrinsics), and setting specific denormal behavior (using a function attribute). Or even if this was lacking in some way, we could always have rustc assume a specific environment, but tell LLVM to be agnostic. This would be suboptimal but safe.
Setting a specific floating point environment does have major advantages: in addition to avoiding issues with const as you mentioned, it also avoids nerfing the optimizer. I'm not sure if LLVM supports all the same optimizations with constrained floating point intrinsics as it does with regular floating point instructions, but at least in theory it could, as long as the rounding mode and denormal handling is known, and exceptions are off. (Having exceptions on, or potentially on, inherently hinders optimizations since it makes floating point operations side-effecting.)
On the other hand, being environment agnostic has its own advantages:
-
Avoids forcing the compiler to model every floating point environment someone might want to run code in. Right now, we don't even perfectly simulate the default FPU behavior across supported architectures, though this can be fixed. When it comes to obscure nonstandard environment settings (there are things more obscure than disabling denormals
), it may be easier to punt. -
Easier to write code that dynamically changes the environment. For example, in my actual use case (that I ended up writing in C), I'm just a shared library living in the same process as arbitrary other code and I want to be a good citizen. So my function changes the floating point environment, performs a batch of calculations (large enough that the penalty of changing isn't a big deal), then changes back before returning.
Since I'm telling C to be environment-agnostic, I can treat the environment change as just a function call. But if I were doing it in Rust and Rust only supported known environments, then at minimum I'd need functions with different environment settings in the same crate – an entry point function set to the default environment, and the bulk of the code set to denormals-disabled – and there would need to be some magic "call with changed environment" builtin to let an environment-A function call an environment-B function by changing the mode, calling the function, and changing back.
On the other hand, "call with changed environment" would also be useful with an agnostic setting, and critical if it were implemented as a per-function setting rather than a separate target.