http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58017

            Bug ID: 58017
           Summary: [SH] Use shift and test for unsigned compare
           Product: gcc
           Version: 4.9.0
            Status: UNCONFIRMED
          Severity: enhancement
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: olegendo at gcc dot gnu.org
            Target: sh*-*-*

On SH unsigned int comparisons against some constants can be converted to shift
and test sequences to potentially save one register.
For example:

int test_00 (unsigned int a, int b, int c)
{
  if (a == 0 || a == 1)
    return 50;

  return 0;
}

compiled with -O2:

        mov     #1,r1
        cmp/hi  r1,r4  // T = r4 > r1 (unsigned)
        bf/s    .L7
        mov     #0,r0
        rts
        nop
.L7:
        rts
        mov     #50,r0


can also be written as:

        shlr    r4     // r4 >>= 1
        tst     r4,r4  // T = r4 == 0
        bt      .L7
        mov     #0,r0
        rts
        nop
.L7:
        rts
        mov     #50,r0

In this case it doesn't save much, but if register pressure is high and the
compared value is not used anywhere else, this can avoid using one register for
the comparison constant.  This is probably only going to be beneficial for
right shift patterns that can be done in 1 or 2 insns and if the inverted
comparison result can be handled by a following conditional branch.

If the comparison constant does not fit into an imm8 it will be loaded from the
constant pool:

        mov.l  .L7,r1
        cmp/hi  r1,r4
        bf     .L3
        mov     #50,r0
        rts
        nop
.L3:
        rts
        mov     #0,r0
.L8:
        .align 2
.L7:
        .long   65535

In this case it might always be beneficial to replace the comparison with

       shlr16   r4
       tst      r4,r4

especially if the compared reg is dead after the comparison.

Reply via email to