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