avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] Avr-gcc versions comparison.


From: Bruce D. Lightner
Subject: Re: [avr-gcc-list] Avr-gcc versions comparison.
Date: Wed, 21 Feb 2007 10:46:32 -0800
User-agent: Thunderbird 1.5.0.9 (Windows/20061207)

Dmitry K. wrote:
Hi.

I have compile CVS version avr-libc (2007-02-20)
with for different compilers.
  

Dmitry,

While you are "testing", have you checked the code quality for the I/O "bit test" logic in avr-gcc v4.1.2?

I reported the following "bad I/O code" awhile back with avr-gcc v3.4.6:

An example of why more people should be "watching" the "avr-gcc" code generator are these three simple C routines which test a bit in one of the AVR microcontroller I/O ports.  Because of the AVR instruction set's clever "sbic" and "sbis" instructions, the machine code for tests like these should be short...and very fast.

However, only "test3()" produces the expected (i.e., correct) AVR instructions:

#include <avr/io.h>

#define J1708_IN_PORT  PORTD
#define J1708_IN_DDR   DDRD
#define J1708_IN_PIN   PIND
#define J1708_IN_BIT   3

  int test1(void)
  {
    unsigned char bit = (J1708_IN_PIN & (1 << J1708_IN_BIT)) ? 1 : 0;
    return bit;
  }

  int test2(void) {
   if (!(J1708_IN_PIN & (1 << J1708_IN_BIT))) return 0;
   return 1;
  }

  int test3(void) {
   if (!(J1708_IN_PIN & (1 << J1708_IN_BIT))) return 1;
   return 0;
  }


...compiled with avr-gcc 3.4.6:

  C:/WinAVR_20060421/bin/avr-gcc -mmcu=atmega16 -Os \
          -mcall-prologues -Wall -c \
          -gstabs -Wa,-ahlmsd=x.lst -o test.o test.c

...gives us horrible code for all except "test3()":

  **** int test1(void)
  **** {
  ****     unsigned char bit = (J1708_IN_PIN & (1 << J1708_IN_BIT)) ? 1 : 0;
        test1:
                in r24,48-0x20
                clr r25
                ldi r18,3
        1:      lsr r25
                ror r24
                dec r18
                brne 1b
                andi r24,lo8(1)
  ****     return bit;
  **** }
                clr r25
                ret

  ****
  **** int test2(void) {
  ****    if (!(J1708_IN_PIN & (1 << J1708_IN_BIT))) return 0;
        test2:
                in r24,48-0x20
                clr r25
                movw r18,r24
                andi r18,lo8(8)
                andi r19,hi8(8)
                sbrc r24,3
                rjmp .L3
                movw r24,r18
                ret
        .L3:
  ****    return 1;
                ldi r24,lo8(1)
                ldi r25,hi8(1)
  **** }
                ret

  **** int test3(void) {
  ****    if (!(J1708_IN_PIN & (1 << J1708_IN_BIT))) return 1;
        test3:
                sbic 48-0x20,3
                rjmp .L5
                ldi r24,lo8(1)
                ldi r25,hi8(1)
                ret
        .L5:
  ****    return 0;
                ldi r24,lo8(0)
                ldi r25,hi8(0)
  **** }
                ret

The bit-shift "loop" code generated for "test1()" is really "special". :-)    (Yes, that's 5 clocks per bit shift!)

I was lucky that my application only referenced bit 3 in the I/O port.  If the hardware had used bit 6, the routine would take twice as long to execute...over 33 clocks for an I/O bit test that should have taken just a couple of clocks!

Note that the only difference between "test2()" and "test3()" is the return value (i.e., 0 vs. 1).  Experiments show that returning "0" is what triggers the "bad behavior".  This bad example takes 6 AVR instructions to do the work of one "sbic" instruction.

Best regards,

Bruce

-- 
 Bruce D. Lightner
 Lightner Engineering
 La Jolla, California
 Voice: +1-858-551-4011
 FAX: +1-858-551-0777
 Email: address@hidden
 URL: http://www.lightner.net/lightner/bruce/

reply via email to

[Prev in Thread] Current Thread [Next in Thread]