Created attachment 154139 [details] fmatest.cpp reproducer SUMMARY It seems the valgrind VM will always round down for the FMA instructions. So assuming the program didn't change the rounding mode, valgrind computes the wrong result: 0.0 + (- (0.0 * 1.0)) = -0.0 which should be 0.0 in all cases except _MM_ROUND_DOWN, which is not the default. STEPS TO REPRODUCE 1. Compile attached cpp with "g++ -O2 -mfma fmatest.cpp" 2. Run natively, observe no negative numbers 3. Run through valgrind with "valgrind --tool=none ./a.out" and observe the wrong results OBSERVED RESULT negative zero EXPECTED RESULT positive zero Even if not implementing switching rounding modes, the most common rounding mode should be chosen
Action is happening inside vex `dis_FMA` and `h_generic_calc_MAddF32` Rounding can be quite misleading but from my understanding the issue is that `dis_FMA` will (in case of vfnmadd used here) negate the result of `h_generic_calc_MAddF32`. But for this special case (zero) this is broken/wrong since it will negate the positive zero from `h_generic_calc_MAddF32`. The negation of the result should either be "conditional" or the MAddF32 implementation needs to be changed to propagate signs and return -0.0, which will then be changed to the correct value of +0.0. I'm not familiar with the valgrind codebase so it's hard for me to pinpoint a fix.
This also came up for multiple developers in FLINT. Please see our issue at https://github.com/flintlib/flint/issues/1366.
Codegen is 00000000004013e0 <_Z7naccFMAPfff>: 4013e0: c4 e2 71 ad 07 vfnmadd213ss (%rdi),%xmm1,%xmm0 4013e5: c5 fa 11 07 vmovss %xmm0,(%rdi) 4013e9: c3 ret 4013ea: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) Looking briefly at the code, it could be rounding but it could also be an error in the negation