Bug 39255 - bitfield alias generates incorrect assembly
Summary: bitfield alias generates incorrect assembly
Status: RESOLVED DUPLICATE of bug 21920
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.3.1
: P3 critical
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-02-20 23:45 UTC by John Worley
Modified: 2009-02-21 00:44 UTC (History)
30 users (show)

See Also:
Host: i686-linux-gnu
Target: ia64-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description John Worley 2009-02-20 23:45:29 UTC
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.
Comment 1 Andrew Pinski 2009-02-20 23:47:51 UTC
-O2 enables strict aliasing (type based aliasing).  You need to use -fno-strict-aliasing to disable that.
Comment 2 Andrew Pinski 2009-02-20 23:56:11 UTC

*** This bug has been marked as a duplicate of 21920 ***
Comment 3 Andrew Pinski 2009-02-20 23:59:30 UTC
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.
Comment 4 John Worley 2009-02-21 00:25:49 UTC
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.
Comment 5 Andrew Pinski 2009-02-21 00:44:12 UTC
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 ***