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.

Reply via email to