Menu

#541 fesetenv was broken

v1.0 (example)
open
None
6
2016-09-15
2016-05-25
Zidane
No

fesetenv doesn't set new fpu mode, because it's overwrited by current fpu mode:
fenv_t env = envp; <--- save new state to env localy in stack for fldenv
int _mxcsr;
asm ("fnstenv %0\n" <--- overwrites env by current state
"stmxcsr %1" : "=m" (
&env), "=m" (&_mxcsr));
/
_mxcsr = ((int)envp->unused0 << 16) | (int)envp->__unused1; // mxcsr low and high */
env.__unused0 = 0xffff;
env.__unused1 = 0xffff;
__asm
volatile ("fldenv %0" : : "m" (env) <<<---- load current state (WHAT THE HECK)

commit added this bug:
https://sourceforge.net/p/mingw-w64/mingw-w64/ci/e98d8084dde3e3aba43736ee78dd7b35541df00b/

Discussion

  • Zidane

    Zidane - 2016-05-25

    example:

    #include <stdio.h>
    #include <fenv.h>
    
    int main(void)
    {
        /* Compute 1.0/3.0 in default FPU mode */
        volatile float somefloat = 1.0;
        somefloat /= 3.0;
    
        /* Output it in float and hex formats */
        printf("%.9g\thex: %x\n", somefloat, *(int *)&somefloat);
    
    
        fenv_t a, b;
    
        fegetenv(&a); /* Save fpu env */
    
        fesetround(FE_TOWARDZERO);  /* Set round mode */
    
        fesetenv(&a); /* Restore fpu env (round mode must also be restored) */
    
        fegetenv(&b); /* Get current fpu env */
    
        /* Compute 1.0/3.0 after changing and restoring fpu env */
        volatile float somefloat2 = 1.0;
        somefloat2 /= 3.0;
    
        /* Output it in float and hex formats */
        printf("%.9g\thex: %x\n", somefloat2, *(int *)&somefloat2);
    
        /* Output FPU control words */
        printf ("FPU control words: %x, %x\n", a.__control_word, b.__control_word);
    
        return 0;
    }
    

    Output of binary compiled by mingw :
    0.333333343 hex: 3eaaaaab
    0.333333313 hex: 3eaaaaaa
    FPU control words: 37f, f7f

    Output of binary compiled by linux gcc :
    0.333333343 hex: 3eaaaaab
    0.333333343 hex: 3eaaaaab
    FPU control words: 37f, 37f

     

    Last edit: Zidane 2016-05-25
  • Eugene Sandulenko

    Let me clarify.

    In 2013 (the commit by Kai Tiez pointed above) apparently because of some bug hunting a code was introduced which affects FPU state. Particularly it could prevent a user code to set up rounding, etc.

    This leads to incorrect computation which are seen only in the programs compiled with MinGW64. That is incorrect and is a bug in the compiler.

    Particularly, the first comment in this thread provides a minimal program which demosntrated the effect. The program wants to set up rounding mode, but fsetenv() in MinGW64 prevents it from doing it.

    The code from the commit needs to be revisited, and if it is really required, then it should be narrowed to a special case it was originally intended for.

     

    Last edit: Eugene Sandulenko 2016-05-25
  • Ozkan Sezer

    Ozkan Sezer - 2016-05-25

    So it is broken strating with mingw-w64-v4x..

     
  • WinPORTS

    WinPORTS - 2016-05-26

    We have compiled and run the above source code using MinGW (GCC 6.1.0) and got the following:

    0.333333343 hex: 3eaaaaab
    0.333333343 hex: 3eaaaaab
    FPU control words: 37f, 37f

    We can assist with testing if needed.

    Cheers.

     
    • Zidane

      Zidane - 2016-05-26

      may you get binary you compiled for me?

       
      • WinPORTS

        WinPORTS - 2016-05-26
         
  • Mateusz Mikuła

    Mateusz Mikuła - 2016-09-15

    MSYS2 both GCC 6.1 and 6.2

    0.333333343     hex: 3eaaaaab
    0.333333313     hex: 3eaaaaaa
    FPU control words: 37f, f7f
    
     

Log in to post a comment.