https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67644
Bug ID: 67644 Summary: [SH] double load on volatile bitfield mem Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: olegendo at gcc dot gnu.org Target Milestone: --- Target: sh*-*-* The following: struct USRSTR { union { unsigned char BYTE; struct { unsigned char BIT7:1; unsigned char BIT6:1; unsigned char BIT5:1; unsigned char BIT4:1; unsigned char BIT3:1; unsigned char BIT2:1; unsigned char BIT1:1; unsigned char BIT0:1; } BIT; } ICR0; }; void test_1 (volatile USRSTR* x) { x->ICR0.BIT.BIT5 |= 1; } compiled with -O2 -m4 -ml results in: mov.b @r4,r1 mov.b @r4,r0 or #4,r0 mov.b r0,@r4 rts nop The double load looks wrong. With normal memory it might do no harm, but when accessing hardware registers this might result in wrong behavior. For instance, sometimes hardware register reads clear status bits etc. It seems this happens only when the bitfield is read and written back. If it's only read, there is only one load: int test_2 (volatile USRSTR* x) { return x->ICR0.BIT.BIT5; } mov.b @r4,r0 tst #4,r0 mov #-1,r0 rts negc r0,r0 And it happens only when there are bitfields involved: void test_3 (volatile unsigned char* x) { x[0] |= 4; } mov.b @r4,r0 extu.b r0,r0 or #4,r0 mov.b r0,@r4 rts nop The problem is present on trunk and GCC 5.