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