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.

Reply via email to