https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54236

--- Comment #9 from Oleg Endo <olegendo at gcc dot gnu.org> ---
The following function compiled with -O2

unsigned int check (unsigned int x)
{
  return x == 0 ? 1 : x;
}

results in:
        tst     r4,r4
        bt/s    .L7
        mov     #1,r0
        mov     r4,r0
.L7:
        rts
        nop


Writing it as:
unsigned int check (unsigned int x)
{
  return x + (x == 0);
}

results in:
        tst     r4,r4
        mov     #0,r0
        rts
        addc    r4,r0

It seems that ifcvt is trying to utilize the 'add<mode>cc' standard name
pattern.  If the 2nd operand of the conditional addition is a constant 1 or -1
the addcc insn can be implemented via addc or subc without a branch.

If the comparison can't be done in one insn (e.g. x != 0) and requires T bit
negation/inversion:

unsigned int check (unsigned int x)
{
  return x + (x != 0);
}

results in (non-SH2A):
        tst     r4,r4
        mov     #-1,r0
        negc    r0,r0
        rts
        add     r4,r0

slightly better (one arith insn less):
        tst     r4,r4
        mov     #-1,r0
        subc    r0,r4    // r4 = r4 - (-1) - T = r4 + 1 - T
        rts
        mov     r4,r0

and on SH2A (already minimal):
        tst     r4,r4
        movrt   r0
        rts
        add     r4,r0



subc case:

unsigned int check (unsigned int x)
{
  return x - (x != 0);
}

non-SH2A:

        tst     r4,r4
        mov     #-1,r1
        mov     r4,r0
        negc    r1,r1
        rts
        sub     r1,r0    // r0 = r4 - (1 - T) = r4 - 1 + T

SH2A:
        tst     r4,r4
        movrt   r1
        mov     r4,r0
        rts
        sub     r1,r0

better (non-SH2A and SH2A):
        tst    r4,r4
        mov    #-1,r0
        rts
        addc   r4,r0     // r0 = -1 + r4 + T = r4 - 1 + T


The equivalent conditional version should result in the same (currently it
isn't):

unsigned int check (unsigned int x)
{
  return x != 0 ? (x - 1) : x;
}

Since ifcvt is also ran after combine, combine won't get the chance to combine
patterns such as:

(set (reg:SI 165 [ D.1635 ])
    (plus:SI (xor:SI (reg:SI 147 t)
            (const_int 1 [0x1]))
        (reg/v:SI 164 [ x ])))

which would occur after emitting a comparison, negating the result (T bit) and
then adding/subtracting the T bit via addc/subc.  If that happens, the combine
must be done manually in the split pass as it's done with some of the other
insns.

Reply via email to