Consider the following code: typedef struct { unsigned long A:16; unsigned long B:48; } bits; int wrong(unsigned long y) { bits *p = (bits *) &y; if (y == 0 || p->A >= 512) { return (1); } return (0); } int right(unsigned long y) { bits *p = (bits *) &y; if (y == 0 || p->A >= 512) { return (-1); } return (0); } The *only* difference between right() and wrong() is the return value in the IF clause. With -O2, the function right() compiles to correct, if suboptimal, code. The function wrong(), however, generates the following: wrong: .prologue .body .mmi cmp.ne p6, p7 = 0, r32 nop 0 addl r14 = 511, r0 .mmi ld2 r15 = [r12] <<<<<< HUH? st8 [r12] = r32 <<<<<< HUH? addl r8 = 1, r0 .mib nop 0 nop 0 (p7) br.ret.dpnt.many rp ;; .mmi cmp4.gtu p6, p7 = r15, r14 ;;wrong: .prologue .body .mmi cmp.ne p6, p7 = 0, r32 nop 0 addl r14 = 511, r0 .mmi ld2 r15 = [r12] st8 [r12] = r32 addl r8 = 1, r0 .mib nop 0 nop 0 (p7) br.ret.dpnt.many rp ;; .mmi cmp4.gtu p6, p7 = r15, r14 ;; (p6) addl r14 = 1, r0 (p7) mov r14 = r0 ;; .mib nop 0 mov r8 = r14 br.ret.sptk.many rp .endp wrong# (p6) addl r14 = 1, r0 (p7) mov r14 = r0 ;; .mib nop 0 mov r8 = r14 br.ret.sptk.many rp .endp wrong# It is clearly wrong to perform the load from the stack before the proper value (r32) has been stored. When run, the value of p->A is the low 16 bits of whatever was stored on the stack before.
-O2 enables strict aliasing (type based aliasing). You need to use -fno-strict-aliasing to disable that.
*** This bug has been marked as a duplicate of 21920 ***
Note in 4.4 and above, GCC generates "correct" even with strict aliasing enabled and it generates better code, it does not store on the stack at all.
Whether or not this is just an aliasing bug, I'd like to understand why changing the return value from 1 to -1 makes the compiler generate correct code.
Because of different optimizations happen. When having 1, it basically creates: if (y == 0) return p->A >= 512; return 0; with -1, it keeps the branch. This is normal with aliasing violations really. Anyways the code is undefined so the compiler technically could do anything. *** This bug has been marked as a duplicate of 21920 ***