8/16bit oddities on avr-gcc

Michael Kukat michael@unixiron.org
Fri Mar 2 12:06:00 GMT 2007


i'm programming a lot of AVR firmware since a while, first in pure
assembler, as gcc 3.x didn't produce code i liked very much. But the
4.1.1 i'm currently using produces quite good code if you sometimes
try around to get the best results (as in "i would write nearly the
same in assembler").

But now, i found one strange thing where i currently can't find a
workaround i really like. It's about a quite simple loop here:

This is my perftest.c file:
#include <avr/io.h>
#include < inttypes.h>

volatile uint8_t xx;

void test() {
        uint8_t ctr;

        ctr = 0;
        do {
                xx = ctr;
        } while(++ctr < 64);

quite simple. If i compile this like the following:

avr-gcc -mmcu=atmega644 -O3 -S -o - perftest.c

i see that ctr is used in 16bit:

        ldi r24,lo8(0)
        ldi r25,hi8(0)
        sts xx,r24
        adiw r24,1
        cpi r24,64
        cpc r25,__zero_reg__
        brne .L2
/* epilogue: frame size=0 */

Now i tried around a bit and see the following situation:

if i replace the "xx = ctr" by an __asm__("nop"), the counter is 8
bit, as it should be. If i use ctr = 64 before the loop and do
while(--ctr);, the counter also is 8 bit (with xx = ctr in the loop).
All experiments trying < (uint8_t) 64 and so didn't work, also !=
instead of < doesn't work, i can't find a "nice" way to force the
counter being 8 bit when using the value within the loop. I need that
loop in this way, that's why i don't use --ctr.

But i found one operation, which does the same like (++ctr < 64) in my
case, but doesn't create the counter in 16bit but in 8bit, as desired:
(++ctr % 64). With this, the result is exactly what i want:

         ldi r24,lo8(0)
        sts xx,r24
        subi r24,lo8(-(1))
        cpi r24,lo8(64)
        brne .L2
/* epilogue: frame size=0 */

Is there any reason for this strange 16bit behaviour? To me, it looks
like the assignemt xx = ctr seems to trigger some signed flags for the
comparison, because ((++ctr & 0x7f) < 64) also produces the desired
8bit version. Might be okay in this loop, but isn't so fine if i need,
say, 200 as the counter top value.

What do you think about this?


More information about the Gcc-help mailing list