http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52076
Bug #: 52076 Summary: bloated code for setting single bits in bitfields on m68k Classification: Unclassified Product: gcc Version: 4.7.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target AssignedTo: unassig...@gcc.gnu.org ReportedBy: mi...@it.uu.se While debugging an unrelated issue I noticed what appears to be fairly poor code for setting single-bit bitfields on m68k, and likewise for setting a single bit in an int-sized field. Test case: struct kobject { unsigned int b7:1; unsigned int :6; unsigned int b0:1; unsigned char x; unsigned int f; }; unsigned char fie(const struct kobject *kobj) { return kobj->x; } void foo(struct kobject *kobj) { kobj->b7 = 1; kobj->f |= 4; } void bar(struct kobject *kobj) { *(unsigned char*)kobj |= 128; *((unsigned char*)&kobj->f + 3) |= 4; } The procedures foo() and bar() have equivalent effect (ignoring strict-aliasing issues, imagine the appropriate unions there). Compiling this with gcc-4.7-20120128 -fomit-frame-pointer -Os -mcpu=68040 we get the following code: 00000000 <fie>: 0: 206f 0004 moveal %sp@(4),%a0 4: 1028 0001 moveb %a0@(1),%d0 8: 4e75 rts 0000000a <foo>: a: 206f 0004 moveal %sp@(4),%a0 e: 7001 moveq #1,%d0 10: efd0 0001 bfins %d0,%a0@,0,1 14: 103c 0004 moveb #4,%d0 18: 81a8 0002 orl %d0,%a0@(2) 1c: 4e75 rts 0000001e <bar>: 1e: 206f 0004 moveal %sp@(4),%a0 22: 0010 ff80 orib #-128,%a0@ 26: 0028 0004 0005 orib #4,%a0@(5) 2c: 4e75 rts 1. In foo(), why insert a 1-bit field with bfins and a temporary register? We could have used (a) bfset, (b) bset with an immediate bit number, or orib as bar() does. The latter two also work on all m68k generations, not just 020+. 2. In foo(), why use "moveb #4,%d0" to set %d0 to 4 (knowing that the high 24 bits of %d0 currently are zero) when moveq could have done the same without a word for the immediate or depending on the previous state of %d0? 3. Does the m68k have store-forwarding restrictions? I suspect not, and if so we can use smaller-than-long writes when writing few bits. So in foo()'s assignment "kobj->f |= 4" we don't need a scratch register and could use an orib or oriw with a one-word "#4" immediate instead.