Bug 149971 - arithmetic operation results using '-O2' option of gcc are different from '-O1' and no option.
arithmetic operation results using '-O2' option of gcc are different from '-O...
Status: CLOSED NOTABUG
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: gcc (Show other bugs)
4.0
ia64 Linux
medium Severity medium
: ---
: ---
Assigned To: Jakub Jelinek
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2005-02-28 21:14 EST by L3support
Modified: 2007-11-30 17:07 EST (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2005-03-01 03:28:47 EST
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:


Attachments (Terms of Use)

  None (edit)
Description L3support 2005-02-28 21:14:22 EST
Description of problem:
  if '-O2' is specified as gcc option, the result of arithmetic 
  operation using 'double' type is different from '-O1' and no option.

Version-Release number of selected component (if applicable):
gcc-3.4.3-9.EL4

How reproducible:
 always

Steps to Reproduce:
 1. # gcc -test1.c -o test1_o2 -O2
 2. # gcc -test1.c -o test1_o1 -O1
 3. # gcc -test1.c -o test1
 4. # ./test1_o2
 5. # ./test1_o1
 6. # ./test1
  
Actual results:
   # uname -a
   Linux xxxxx 2.6.9-5.0.3.EL #1 SMP Mon Feb 14 09:52:53 EST 2005 ia64
ia64 ia64 GNU/Linux
   # ./test1_o2
   
   fx.fract = 0x1
   fx.value = 0x0
   
   # ./test1_o1
   
   fx.fract = 0x74BC
   fx.value = 0x7B
   
   # ./test1
   
   fx.fract = 0x74BC
   fx.value = 0x7B

   ( the result of '-O2' is different from others. )
   
Expected results:
   # ./test1_o2
   
   fx.fract = 0x74BC
   fx.value = 0x7B
 
   ( the result of '-O2' is same as others. )

Additional info:
  - if we compile test1.c on RHEL4 GA for x86, the result of '-O2' 
    is same as otheres.
    
    # uname -a
    Linux xxxxx 2.6.9-5.ELsmp #1 SMP Wed Jan 5 19:30:39 EST 2005 i686
i686 i386 GNU/Linux
    # gcc test1.c -o test1_o2 -O2
    # ./test1_o2 
    
    fx.fract = 0x74BC
    fx.value = 0x7B

  - if we add printf(3) in fuction '__qgf_ttac_fixed_from_double()' 
    in test1.c, the results are different from its place.
    
    2) 1) add printf(3) before operation 'n = (int) (d * 65536L);'
       --------------------------------------------------------------
         :
       FIXED __qgf_ttac_fixed_from_double(double d)
       {
           int n;
   
           printf("\n");
           n = (int) (d * 65536L);
           return *(FIXED *)&n;
       }
         :
       --------------------------------------------------------------
       # gcc test2.c -o test2_o2 -O2
       # ./test2_o2
       
       
       fx.fract = 0x0
       fx.value = 0x0
    
    2) add printf(3) after operation 'n = (int) (d * 65536L);'
       --------------------------------------------------------------
         :
       FIXED __qgf_ttac_fixed_from_double(double d)
       {
           int n;
   
           n = (int) (d * 65536L);
           printf("\n");
           return *(FIXED *)&n;
       }
         :
       --------------------------------------------------------------
       # gcc test3.c -o test3_o2 -O2
       # ./test3_o2
       
       
       fx.fract = 0x74BC
       fx.value = 0x7B
Comment 1 L3support 2005-02-28 22:09:12 EST
I couldn't attach the testcase. The following is the testcase.

// *****  test1.c  ***** //
#include <stdio.h>

typedef struct _FIXED { 
    unsigned short  fract; 
    short  value; 
} FIXED, *LPFIXED;

FIXED __qgf_ttac_fixed_from_double(double);

FIXED
__qgf_ttac_fixed_from_double(double d)
{
        int n;
        
        n = (int) (d * 65536L);
        return *(FIXED *)&n;
}

int
main(int argc, char *argv[])
{
        FIXED fx;
        double db;

        db = 123.456;

        fx = __qgf_ttac_fixed_from_double(db);

        printf("\nfx.fract = 0x%X\n", fx.fract);
        printf("fx.value = 0x%X\n\n", fx.value);
}
Comment 2 Jakub Jelinek 2005-03-01 03:28:47 EST
This testcase violates ISO C99 6.5 aliasing rules and therefore triggers
undefined behaviour.
See either the standard, or info gcc on -fstrict-aliasing which is the default
for -O2 and above.
You can use a union to access the value through it, or to work around buggy
code you can build with -fno-strict-aliasing.

BTW, if you compile this testcase with -Wall, which you always should do,
the compiler warns about this:
/tmp/149971.c: In function `__qgf_ttac_fixed_from_double':
/tmp/149971.c:16: warning: dereferencing type-punned pointer will break
strict-aliasing rules
/tmp/149971.c: In function `main':
/tmp/149971.c:31: warning: control reaches end of non-void function

Note You need to log in before you can comment on or make changes to this bug.