Re: AVR/GNU C Compiler 15 - Non efficient bit access
Henrik Holst via Gcc-help <[email protected]> Fri, 13 Feb 2026 16:10:25 +0100
| Newsgroups | gmane.comp.gcc.help |
|---|---|
| Message-ID | <CAGwK9dymNCuXRGVEyOE1sGPDOTy=HTLH695d=Rb01-eNUQO0dw@mail.gmail.com> |
ignore me, I missed the 5.0 generation... Den fre 13 feb. 2026 kl 16:09 skrev Henrik Holst < [email protected]>: > sorry since I am not 100% familiar with the AVR architecture but isn't the > generated code from GCC 15.2 1 cycle (2 vs 3) less than what 15.1 generates > and thus actually more efficient? > > /HH > > Den fre 13 feb. 2026 kl 15:47 skrev <[email protected]>: > >> I'm working on an embedded project using an AVR microcontroller. >> >> I've noticed that version 15 generates non-efficient access to registers >> that have single instruction opcodes available. >> >> >> >> The AVR Instruction Set provides opcodes for I/O direct addressing: >> SBIC: Skip if Bit in I/O Register Cleared >> >> SBIS: Skip if Bit in I/O Register Set >> >> >> >> This is a minimal example that generates the problem: >> >> >> >> >> typedef __UINT8_TYPE__ uint8_t; >> >> #define SFR (*(volatile uint8_t*) (1 + __AVR_SFR_OFFSET__)) >> >> char File1 (char angle, char scale); >> >> void File2 (void) >> >> { >> >> if (!(SFR & (1 << 4))) >> >> for (uint8_t i = 0; i < 3; ++i) >> >> File1 (i, 1); >> >> } >> >> >> >> Compile with: >> $ avr-gcc -mmcu=atmega8 -S -Os -dp x.c >> >> >> >> A work-around was suggested by SprinterSB at the avrfreaks forum: >> >> >> >> static inline __attribute__((__always_inline__)) >> >> uint8_t bit_is_clear (uint8_t val, uint8_t bitno) >> >> { >> >> return ! (val & (1u << bitno)); >> >> } >> >> static inline __attribute__((__always_inline__)) >> >> uint8_t bit_is_set (uint8_t val, uint8_t bitno) >> >> { >> >> return !! (val & (1u << bitno)); >> >> } >> >> >> >> This worked on some instances around my project, however, I tried in the >> example below and it didn't solve the non-efficient access: >> >> >> >> typedef __UINT8_TYPE__ uint8_t; >> >> #define SFR1 (*(volatile uint8_t*) (0x01 + __AVR_SFR_OFFSET__)) >> >> #define SFRC (*(volatile uint8_t*) (0x0C + __AVR_SFR_OFFSET__)) >> >> void Func1(char a, char *p); >> >> static inline __attribute__((__always_inline__)) >> >> uint8_t my_bit_is_clear (uint8_t val, uint8_t bitno) { >> >> return ! (val & (1u << bitno)); >> >> } >> >> static inline __attribute__((__always_inline__)) >> >> uint8_t my_bit_is_set (uint8_t val, uint8_t bitno) { >> >> return !! (val & (1u << bitno)); >> >> } >> >> static void Func3(void); >> >> void Func2(void) { >> >> do { >> >> Func1(0,0); >> >> if(my_bit_is_set(SFRC, 1)) Func1(0,0); >> >> else Func3(); >> >> if(my_bit_is_set(SFRC,0)) { >> >> SFRC = 1; >> >> } >> >> } while(my_bit_is_clear(SFRC, 2)); >> >> } >> >> void Func3(void) { >> >> if(my_bit_is_set(SFRC, 3)) { >> >> Func1(0,0); >> >> uint8_t Ones=SFR1, Tens=0; >> >> while (Ones>=10) { Tens++; Ones-=10; } >> >> Func1(5,(uint8_t *)Tens); >> >> Func1(5,(uint8_t *)Ones); >> >> } else { >> >> Func1(9,(uint8_t *)(100+SFRC)); >> >> SFRC = 118; >> >> uint8_t Ones=SFR1, Tens=0; >> >> while (Ones>=10) { Tens++; Ones-=10; } >> >> Func1(9,(uint8_t *)Tens); >> >> Func1(9,(uint8_t *)Ones); >> >> } >> >> } >> >> >> >> >> AVR/GNU C Compiler 5.4.0 generates the proper code access: >> >> >> >> SBIS 0x0C,1 Skip if bit in I/O register set >> >> RJMP PC+0x0005 Relative jump >> >> >> >> AVR/GNU C Compiler 15.1.0 generates: >> >> >> >> IN R24,0x0C In from I/O location >> >> BST R24,1 Bit store from register to T >> >> CLR R15 Clear Register >> >> BLD R15,1 Bit load from T to register >> >> SBRS R24,1 Skip if bit in register set >> >> >> >> AVR/GNU C Compiler 15.2.0 generates: >> >> >> >> IN R24,0x0C In from I/O location >> >> MOV R17,R24 Copy register >> >> ANDI R17,0x02 Logical AND with immediate >> >> SBRS R24,1 Skip if bit in register set >> >> >> >> Thank you for this great compiler and for making a positive impact on the >> world! >> >> Regards, >> >> Gabriel Anzziani >> >>