[Bug middle-end/114111] New: [avr] Expensive code instead of conditional branch.
gjl at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Mon Feb 26 11:42:16 GMT 2024
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.
More information about the Gcc-bugs
mailing list