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

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

Re: [avr-gcc-list] Telling inline asm that input register is clobbered?


From: Paul Sokolovsky
Subject: Re: [avr-gcc-list] Telling inline asm that input register is clobbered?
Date: Mon, 10 Dec 2012 17:49:08 +0200

Hello,

On Mon, 10 Dec 2012 14:12:26 +0100
Georg-Johann Lay <address@hidden> wrote:

> Paul Sokolovsky wrote:
> > Hello,
> > 
> > I'd like to reimplement __builtin_avr_delay_cycles() function in
> > inline assembly. The reason is that __builtin_avr_delay_cycles() has
> > too-early operand checking, so for example
> > 
> > static __attribute__((__always_inline__)) my_delay(int cycles)
> > {
> >     __builtin_avr_delay_cycles(cycles);
> > }
> 
> Would you supply a test case?
> 
> > Will still complain that __builtin_avr_delay_cycles(cycles) is not
> > constant even for cases like my_delay(10).
> 
> Also consider to make the function inline and to make 'cycles' const.

Thanks for good hinting!

Yes, first of all gcc can const-expr optimize following code if
compiled with -O:

--------
static void my_delay(int delay)
{ __builtin_avr_delay_cycles(delay); }
int main()
{ my_delay(10); }
--------

I guess, by marking that always_inline, compile without explicit -O
would work too. What's crucial here is "static" however - without it,
gcc tries to produce non-inlined version, and that's where it fails.

However, my usecase is using that in C++ template lib, and I
need that to be in a method of class, which can't be "static" in the
same sense as static function in C.

But the case above reminded me - if you want to do this time of magic in
gcc (essentially, compile-time evaluation), you need to use
__builtin_constant_p() function. That's actually how I did it first for
msp430, but then found out there it works even without
__builtin_constant_p(), so I lazily commented it out (saves thinking
what to do for !__builtin_constant_p() case) and then forgot about.

So, I started another try on ldi-based approach, and just got lucky
that my test code had "good" value of literal integer constant. Because
it turned out that "M" asm constraint is very picky regarding value it
gets. One would think that casting to uint8_t would be the best way to
get a value suitable for it, but actually, that will throw "error:
impossible constraint in ‘asm’" for any value >=0x80. Fortunately, I
found that (& 0xff) does the trick, so mission accomplished.

That "M" behavior still looks like bug, so hope a testcase below may be
useful (not sure if attachments are allowed, so just pasting):

=========
#include <stdint.h>

int delay1(int d)
{
    if (__builtin_constant_p(d)) {
        asm(
            "ldi    r24, %0 \n"
            "1: \n"
            "subi   r24, 1 \n" //1
            "brne   1b \n"
            : : "M" ((uint8_t)d) : "r24"
        );
    }
}

int delay2(int d)
{
    if (__builtin_constant_p(d)) {
        asm(
            "ldi    r24, %0 \n"
            "1: \n"
            "subi   r24, 1 \n" //1
            "brne   1b \n"
            : : "M" (d & 0xff) : "r24"
        );
    }
}

int main()
{
// Compiled with avr-gcc 4.5.3 (as shipped with Ubuntu 12.04 Precise):
// avr-gcc -c -O2 avr-delay-asm.c
// -O2 is mandatory, to trigger function inlining,
// alternatively can be marked as inline explicitly
    delay1(0x7f);
    delay1(0x80); // This will fail with "error: impossible constraint in ‘asm’"
    delay2(0x7f);
    delay2(0x80);
}
=========


> 
> Johann



-- 
Best regards,
 Paul                          mailto:address@hidden



reply via email to

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