Re: AVR/GNU C Compiler 15 - Non efficient bit access
Henrik Holst via Gcc-help <[email protected]> Fri, 13 Feb 2026 16:09:43 +0100
| Newsgroups | gmane.comp.gcc.help |
|---|---|
| Message-ID | <CAGwK9dzCqa2O7Smi2bkifDoC0Vb0JegspLCS47JGMoeFOJ540A@mail.gmail.com> |
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 > >