Consider:
struct B {
unsigned bit0 : 1;
unsigned bit1 : 1;
};
void
foo (struct B *b)
{
b->bit0 = b->bit0 | b->bit1;
}
./cc1 -O2 -fomit-frame-pointer -mregparm=3 generates
foo:
movb (%eax), %dl <- one load
movb %dl, %cl
shrb %cl
orl %edx, %ecx
andl $1, %ecx
movl (%eax), %edx <- another load from the same place
andl $-2, %edx
orl %ecx, %edx <- the second OR
movl %edx, (%eax)
ret
We could do something like
movb (%eax), %cl
movb %cl, %dl
shrb %dl
andl $1, %edx
orl %ecx, %edx
movb %dl, (%eax)
ret
or
movb (%eax), %dl
testb $2, %dl
je .L6
orl $1, %edx
movb %dl, (%eax)
.L6:
ret
expr.c actually has code intended to emit the second suggestion
(look for "Check for |= or &= of a bitfield" in expr.c), but it is
practically disabled because we get tree like this
b->bit0 = (<unnamed type>) (unsigned char)
((signed char) b->bit0 | (signed char) b->bit1)
whereas the code in expr.c expects
b->bit0 = b->bit0 | b->bit1;
The code is not triggered even in gcc-3.3. Probably it is practically
disabled for a long time.
--
Summary: OR of two single-bit bitfields is inefficient
Product: gcc
Version: unknown
Status: UNCONFIRMED
Keywords: missed-optimization
Severity: enhancement
Priority: P2
Component: middle-end
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: kazu at cs dot umass dot edu
CC: gcc-bugs at gcc dot gnu dot org
GCC target triplet: i686-pc-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18041