avr-libc Version 1.4.0 - util/delay.h misses inline keyword (regression) ======================================================================== In Revision 1.11 on Tue Sep 6 21:08:25 2005 UTC the "always_inline" attribute for the delay functions was added and the "inline" keyword removed. The "inline" keyword is still necessary. The problem is visible only for optimization levels below -O2/-Os. Rationale: ---------- In my interpretation of GCC docs the "always_inline" attribute is not sufficient for function inlining. It is a hint only, that inlining should be made regardless of optimization level. This gcc behaviour is also visible on gcc (GCC) 3.4.4 [FreeBSD] 20050518. Quotes: "GCC does not inline any functions when not optimizing unless you specify the `always_inline' attribute for the function, like this: /* Prototype. */ inline void foo (const char) __attribute__((always_inline));" "`always_inline' Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level was specified." Examples: --------- #include #include volatile uint8_t t; static inline void my_delay_us(int16_t __us) { _delay_loop_1(((F_CPU) / 3e6) * __us); } void test(void) { while (1) { t = (uint8_t)1; my_delay_us((uint8_t)40); t = (uint8_t)2; my_delay_us((uint8_t)50); } } >avr-gcc --version avr-gcc (GCC) 3.4.3 >avr-gcc -Wall -c -mmcu=atmega8535 -DF_CPU=1000000UL -O1 -S tst.c tst.c: In function `test': .../avr/include/util/delay.h:103: sorry, unimplemented: inlining failed in call to '_delay_loop_1': function body not available tst.c:8: sorry, unimplemented: called from here .../avr/include/util/delay.h:103: sorry, unimplemented: inlining failed in call to '_delay_loop_1': function body not available tst.c:8: sorry, unimplemented: called from here The generated code is .file "tst.c" .arch atmega8535 __SREG__ = 0x3f __SP_H__ = 0x3e __SP_L__ = 0x3d __tmp_reg__ = 0 __zero_reg__ = 1 .global __do_copy_data .global __do_clear_bss .text .type _delay_loop_1, @function _delay_loop_1: /* prologue: frame size=0 */ /* prologue end (size=0) */ /* #APP */ 1: dec r24 brne 1b /* #NOAPP */ /* epilogue: frame size=0 */ ret /* epilogue end (size=1) */ /* function _delay_loop_1 size 5 (4) */ .size _delay_loop_1, .-_delay_loop_1 .type _delay_loop_2, @function _delay_loop_2: /* prologue: frame size=0 */ /* prologue end (size=0) */ /* #APP */ 1: sbiw r24,1 brne 1b /* #NOAPP */ /* epilogue: frame size=0 */ ret /* epilogue end (size=1) */ /* function _delay_loop_2 size 5 (4) */ .size _delay_loop_2, .-_delay_loop_2 .type _delay_us, @function _delay_us: /* prologue: frame size=0 */ push r14 push r15 push r16 push r17 /* prologue end (size=4) */ movw r26,r24 movw r24,r22 ldi r18,lo8(0x3eaaaaab) ldi r19,hi8(0x3eaaaaab) ldi r20,hlo8(0x3eaaaaab) ldi r21,hhi8(0x3eaaaaab) movw r22,r24 movw r24,r26 rcall __mulsf3 movw r14,r22 movw r16,r24 ldi r18,lo8(0x3f800000) ldi r19,hi8(0x3f800000) ldi r20,hlo8(0x3f800000) ldi r21,hhi8(0x3f800000) rcall __ltsf2 tst r24 brge .L4 ldi r24,lo8(1) rjmp .L6 .L4: ldi r18,lo8(0x437f0000) ldi r19,hi8(0x437f0000) ldi r20,hlo8(0x437f0000) ldi r21,hhi8(0x437f0000) movw r24,r16 movw r22,r14 rcall __gtsf2 cp __zero_reg__,r24 brge .L7 ldi r24,lo8(0) rjmp .L6 .L7: movw r24,r16 movw r22,r14 rcall __fixunssfsi movw r26,r24 movw r24,r22 .L6: rcall _delay_loop_1 /* epilogue: frame size=0 */ pop r17 pop r16 pop r15 pop r14 ret /* epilogue end (size=5) */ /* function _delay_us size 48 (39) */ .size _delay_us, .-_delay_us .type _delay_ms, @function _delay_ms: /* prologue: frame size=0 */ push r14 push r15 push r16 push r17 /* prologue end (size=4) */ movw r26,r24 movw r24,r22 ldi r18,lo8(0x437a0000) ldi r19,hi8(0x437a0000) ldi r20,hlo8(0x437a0000) ldi r21,hhi8(0x437a0000) movw r22,r24 movw r24,r26 rcall __mulsf3 movw r14,r22 movw r16,r24 ldi r18,lo8(0x3f800000) ldi r19,hi8(0x3f800000) ldi r20,hlo8(0x3f800000) ldi r21,hhi8(0x3f800000) rcall __ltsf2 tst r24 brge .L11 ldi r24,lo8(1) ldi r25,hi8(1) rjmp .L13 .L11: ldi r18,lo8(0x477fff00) ldi r19,hi8(0x477fff00) ldi r20,hlo8(0x477fff00) ldi r21,hhi8(0x477fff00) movw r24,r16 movw r22,r14 rcall __gtsf2 cp __zero_reg__,r24 brge .L14 ldi r24,lo8(0) ldi r25,hi8(0) rjmp .L13 .L14: movw r24,r16 movw r22,r14 rcall __fixunssfsi movw r26,r24 movw r24,r22 .L13: rcall _delay_loop_2 /* epilogue: frame size=0 */ pop r17 pop r16 pop r15 pop r14 ret /* epilogue end (size=5) */ /* function _delay_ms size 50 (41) */ .size _delay_ms, .-_delay_ms .comm t,1,1 /* File "tst.c": code 108 = 0x006c ( 88), prologues 8, epilogues 12 */ With "inline" keywords in delay.h there are no warnings and the generated code is: .file "tst.c" .arch atmega8535 __SREG__ = 0x3f __SP_H__ = 0x3e __SP_L__ = 0x3d __tmp_reg__ = 0 __zero_reg__ = 1 .global __do_copy_data .global __do_clear_bss .text .global test .type test, @function test: /* prologue: frame size=0 */ push r28 push r29 /* prologue end (size=2) */ ldi r22,lo8(1) ldi r26,lo8(13) ldi r27,hi8(13) ldi r28,hlo8(13) ldi r29,hhi8(13) ldi r25,lo8(2) ldi r18,lo8(16) ldi r19,hi8(16) ldi r20,hlo8(16) ldi r21,hhi8(16) .L2: sts t,r22 mov r24,r26 /* #APP */ 1: dec r24 brne 1b /* #NOAPP */ sts t,r25 mov r24,r18 /* #APP */ 1: dec r24 brne 1b /* #NOAPP */ rjmp .L2 /* epilogue: frame size=0 */ /* epilogue: noreturn */ /* epilogue end (size=0) */ /* function test size 27 (25) */ .size test, .-test .comm t,1,1 /* File "tst.c": code 27 = 0x001b ( 25), prologues 2, epilogues 0 */ The fixed version is --- util/delay.h.orig Sat Nov 19 23:05:34 2005 +++ util/delay.h Wed Dec 07 08:56:33 2005 @@ -81,10 +81,10 @@ */ #if !defined(__DOXYGEN__) -static void _delay_loop_1(uint8_t __count) __attribute__((always_inline)); -static void _delay_loop_2(uint16_t __count) __attribute__((always_inline)); -static void _delay_us(double __us) __attribute__((always_inline)); -static void _delay_ms(double __ms) __attribute__((always_inline)); +static inline void _delay_loop_1(uint8_t __count) __attribute__((always_inline)); +static inline void _delay_loop_2(uint16_t __count) __attribute__((always_inline)); +static inline void _delay_us(double __us) __attribute__((always_inline)); +static inline void _delay_ms(double __ms) __attribute__((always_inline)); #endif /** \ingroup util_delay