[Top][All Lists]
[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