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