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.