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

            Bug ID: 65317
           Summary: [SH] Shifts used instead of and with const_int
           Product: gcc
           Version: 5.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: olegendo at gcc dot gnu.org
            Target: sh*-*-*

int
test_01 (int a, int b)
{
  int r = a < 0;
  return r << 31;
}

compiled with -O2 -m4:
        shll    r4
        movt    r0
        and     #1,r0
        rts
        rotr    r0

could be:
        mov.l   .Lconst,r0
        rts
        and     r4,r0
.Lconst:
        .long 0x80000000


combine says:
Failed to match this instruction:
(set (reg:SI 168 [ D.1470 ])
    (and:SI (reg:SI 4 r4 [ a ])
        (const_int -2147483648 [0xffffffff80000000])))

Notice that this

int
test_02 (int a)
{
  return a & 0x80000000;
}

compiles as expected:
        mov.l   .L18,r0
        rts    
        and     r4,r0
.L19:
        .align 2
.L18:
        .long   -2147483648


If code size is important, or constant loads should be avoided (because it's
not shared etc), a shorter (in code size) version would be:
        shll     r4
        movt     r0
        rts
        rotr     r0


Another case:

int foo3(int *x)
{
  int i,y;
  int a[40];
  int b[40] __attribute__ ((aligned(32)));
  int c[40] __attribute__ ((aligned(128)));

  for (i = 0; i < 40; i++)
    a[i] = *x++;
  for (i = 0; i < 40; i++)
    b[i] = *x++;
  for (i = 0; i < 40; i++)
    c[i] = *x++;

  y = -99;
  for (i = 0; i < 40; i++)
    y = y + a[i] + b[i] + c[i];

  return y;
}

compiles to:
        mov.l   r14,@-r15
        mov     #-5,r3
        add     #-80,r15
        mov.w   .L11,r2
        add     #-80,r15
        add     r15,r2
        mov     r15,r14
        mov     r2,r15
        mov     r15,r7
        add     #31,r7
        mov     #5,r1
        shld    r3,r7     <<<<
        shld    r1,r7     <<<<
        mov     #0,r0
        mov     #40,r1
        .align 2
.L2:
        mov.l   @(r0,r4),r2
        ....

The shifts used to mask out lower bits can be replaced with a much simpler and
with a constant.
Combine says:

Failed to match this instruction:
(set (reg/f:SI 217)
    (and:SI (reg/f:SI 214)
        (const_int -32 [0xffffffffffffffe0])))

It seems that it's better to allow any constant for the *andsi_compact pattern
and split out the constant load if it doesn't fit into K08.  An and with
constant 0x80000000 could be treated as a special case to emit the shorter
sequence:
        shll     r4
        movt     r0
        rts
        rotr     r0

If constant calculation optimization is done (PR 65069), it would automatically
be converted to:
        mov     #1,r0
        rotr    r0
        rts
        and     r4,r0

which is equivalent and maybe even better because the input is not mutated.

Reply via email to