I am working on a Rust crate which changes the rounding mode (+inf, -inf, nearest, or truncate).
The functions that change the rounding mode are written using inline assembly:
fn upward() {
let cw: u32 = 0;
unsafe {
asm!("stmxcsr $0;
mov $0, %eax;
or $$0x4000, %eax;
mov %eax, $0;
ldmxcsr $0;"
: "=*m"(&cw)
: "*m"(&cw)
: "{eax}"
);
}
}
When I compile the code in debug mode it works as intended, I get 0.3333333333337 for one-third when rounding toward positive infinity, but when I compile in release mode I get the same result no matter what rounding mode I set. I guess this behavior is due to the optimizations that the LLVM backend does.
If I knew which LLVM passes are responsible for this optimization, I can disable them as I don't see any other workaround at the moment.
Basically, you can't do this. LLVM assumes that all floating point operations use the default rounding mode, and that the floating-point control register is never read or modified.
There's been some discussion of this issue recently on the LLVM-dev mailing list, if you're interested.
In the meantime, the only reliable workaround is to use inline assembly, like asm!("addsd $0, $1"
.
Rust's standard library also assumes that you don't modify the rounding mode (in particular, the code for converting between floating-point and strings is sensitive to this).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With