Re: AVR/GNU C Compiler 15 - Non efficient bit access
Georg-Johann Lay via Gcc-help <[email protected]> Fri, 13 Feb 2026 18:37:02 +0100
| Newsgroups | gmane.comp.gcc.help |
|---|---|
| Message-ID | <[email protected]> |
Am 13.02.26 um 15:45 schrieb [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 The generated code is: File2: push r28 ; 40 [c=4 l=1] pushqi1/0 in r24,0x1 ; 37 [c=4 l=1] movqi_insn/3 mov r28,r24 ; 38 [c=4 l=2] *andqi3/3 andi r28,1<<4 sbrc r24,4 ; 39 [c=4 l=2] *sbrx_branchqi rjmp .L1 .L3: ldi r22,lo8(1) ; 32 [c=4 l=1] movqi_insn/1 mov r24,r28 ; 33 [c=4 l=1] movqi_insn/0 call File1 ; 12 [c=12 l=2] call_value_insn/1 subi r28,lo8(-(1)) ; 34 [c=4 l=1] *addqi3/1 cpi r28,lo8(3) ; 35 [c=4 l=1] cmpqi3/0 brne .L3 ; 36 [c=4 l=1] branch .L1: pop r28 ; 43 [c=4 l=1] popqi ret ; 44 [c=0 l=1] return_from_epilogue What happens is that in the calculation of SFR & (1 << 4) a value of zero may be produced, and that value is then used to initialize the loop variable i = 0. Insn combine combines a SBRC insn 39 as expected but doesn't look further, because is cannot combine the volatile load 37 as that load would still be around after a combination to SBIC, breaking volatile correctness. The pass that introduces the reuse of the zero value is .uncprop1, and indeed with -fno-tree-dominator-opts the code is as expected (that's just an observation and not a recommendation to use that option): File2: push r28 ; 39 [c=4 l=1] pushqi1/0 sbic 0x1,4 ; 38 [c=4 l=2] *sbix_branch rjmp .L1 ldi r28,0 ; 37 [c=4 l=1] movqi_insn/0 .L3: ldi r22,lo8(1) ; 32 [c=4 l=1] movqi_insn/1 mov r24,r28 ; 33 [c=4 l=1] movqi_insn/0 call File1 ; 13 [c=12 l=2] call_value_insn/1 subi r28,lo8(-(1)) ; 34 [c=4 l=1] *addqi3/1 cpi r28,lo8(3) ; 35 [c=4 l=1] cmpqi3/0 brne .L3 ; 36 [c=4 l=1] branch .L1: pop r28 ; 42 [c=4 l=1] popqi ret ; 43 [c=0 l=1] return_from_epilogue Now insn 38 is a SBIC on bit 4 of the SFR, and insn 37 just loads i = 0 in reg 28. The sequence is 2 instructions shorter. Johann