AVR/GNU C Compiler 15 - Non efficient bit access

<[email protected]> Fri, 13 Feb 2026 09:45:29 -0500
Newsgroups gmane.comp.gcc.help
Message-ID <[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