https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114111
Bug ID: 114111 Summary: [avr] Expensive code instead of conditional branch. Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: gjl at gcc dot gnu.org Target Milestone: --- Created attachment 57541 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=57541&action=edit addcc.c: C test case Compile the code with avr-gcc -S -Os -dp: int add_ge0 (int x, char c) { return x + (c >= 0); } int add_eq0 (int x, char c) { return x + (c == 0); } int add_le0 (int x, char c) { return x + (c <= 0); } int add_ge1 (int x, char c) { return x + (c >= 1); } int add_ltm3 (int x, char c) { return x + (c < -3); } int add_bit6 (int x, char c) { return x + !!(c & (1 << 6)); } int add_nbit6 (int x, char c) { return x + !(c & (1 << 6)); } All these could be performed by a test and the addition of x in an if-block. But what the compiler does is to extend the 8-bit value c to 16 bit, then complement it, then shift the MSB to the LSB: add_ge0: mov __tmp_reg__,r22 ; 23 [c=12 l=3] *extendqihi2/0 lsl r0 sbc r23,r23 com r22 ; 24 [c=8 l=2] *one_cmplhi2 com r23 bst r23,7 ; 31 [c=16 l=4] *lshrhi3_const/3 clr r22 clr r23 bld r22,0 add r24,r22 ; 26 [c=8 l=2] *addhi3/0 adc r25,r23 ret ; 29 [c=0 l=1] return Even when it does a conditional to set the addend, it should rather have the addition in the if-block (and moving x to R18 adds even more bloat): add_eq0: mov r18,r24 ; 44 [c=4 l=1] movqi_insn/0 mov r19,r25 ; 45 [c=4 l=1] movqi_insn/0 ldi r24,lo8(1) ; 46 [c=4 l=2] *movhi/4 ldi r25,0 cp r22, __zero_reg__ ; 47 [c=4 l=1] cmpqi3/0 breq .L3 ; 48 [c=4 l=1] branch ldi r24,0 ; 43 [c=4 l=2] *movhi/1 ldi r25,0 .L3: add r24,r18 ; 42 [c=8 l=2] *addhi3/0 adc r25,r19 ret ; 51 [c=0 l=1] return ... .ident "GCC: (GNU) 14.0.1 20240212 (experimental)" With avr-gcc 3.4.6 from around 2006, the generated code is as follows: add_ge0: sbrs r22,7 ; 38 *sbrx_branch [length = 2] adiw r24,1 ; 15 *addhi3/2 [length = 1] .L2: ret ; 37 return [length = 1] add_eq0: tst r22 ; 13 tstqi [length = 1] brne .L4 ; 14 branch [length = 1] adiw r24,1 ; 15 *addhi3/2 [length = 1] .L4: ret ; 35 return [length = 1] etc. So at some point in time GCC lost all that smartness. Appears to be around emit_stor_flag and friends; as far as I can see it doesn't even try to work out costs.