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: Georg-Johann Lay
Subject: Re: [avr-gcc-list] Telling inline asm that input register is clobbered?
Date: Mon, 10 Dec 2012 17:34:36 +0100
User-agent: Thunderbird 2.0.0.24 (X11/20100302)

Paul Sokolovsky wrote:
> Hello,
> 
> Georg-Johann Lay wrote:
> 
>> Paul Sokolovsky wrote:
>>>
>>> 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.

In order to make it work with C and without optimization, you will need a
properly prototyped my_delay:

static inline __attribute__((always_inline))
void my_delay (const unsigned long delay)
{
  __builtin_avr_delay_cycles (delay);
}

int main (void)
{
  my_delay (10);
}

Notice that the optimization with -O0 is very limited, thus if you ever need a
non-const delay, consider writing your own delay function.

Besides that, using design-pattern "delay" for anything else than short delays
to wait for, say, parasitical capacities / inductivities, can be considered as
a design flaw.  But that's a different story...

> 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.

Sorry, I cannot help you with dreaded [tm] languages like 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.

Maybe __builtin_avr_delay_cycles is too limited with the const delays.  Using
variable delays is possible if the requirement of cycle-exactness is dropped.

> 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.

The question is why you use "M" in the first place and not "n"?

> 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"
>         );
>     }
> }

You may want to consider code like the following:

static __inline__ __attribute__((always_inline))
void delay1 (const unsigned d)
{
    unsigned d2;
    __asm volatile ("1:"      "\n\t"
                    "dec  %0" "\n\t"
                    "brne 1b"
                    : "=r" (d2) : "0" (d));
}

Notice that inlining is indicated because otherwise, the call overhead will
garbage your delay time.  Similarly, the "const" is no sugar with -O0: it is
needed so minimize the overhead at -O0.  Try it out!

Moreover, without "volatile" the asm may be optimized away because it has no
side effects then.

Finally, notice that AVR Libc has similar stuff in util/delay.h


Johann




reply via email to

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