https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66933

            Bug ID: 66933
           Summary: [AVR] Shifted multiplication produces suboptimal asm
           Product: gcc
           Version: 5.2.0
            Status: UNCONFIRMED
          Severity: enhancement
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: a-gnu.org at 0au dot de
  Target Milestone: ---

The function

    uint8_t test(uint8_t a, uint8_t b) { return (a*b) >> 7; }

compiles into the following assembly, with e.g.

    avr-gcc -mmcu=atmega328 -S -O3 test.c

(or any other optimization flag)

    test:
        mul r24,r22
        movw r24,r0
        clr __zero_reg__
        lsl r24
        mov r24,r25
        rol r24
        sbc r25,r25
        ret

This has two obvious possible enhancements:
- It uses mul instead of fmul: fmul calculates (a*b)<<1,
  so the high byte is already the correct return value of
  the function
- After calculating the return value (wih "rol r24"),
  there's an instruction "sbc r25, r25" that puts a
  completely unneeded value in r25, if I'm not mistaken
  it's 255 if (a*b) & 0x8000, else 0.

A better version that uses 8 instead of 12 cycles would be

    test:
        fmul r24, r22
        mov r24, r1
        clr __zero_reg__
        ret

Reply via email to