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

            Bug ID: 99089
           Summary: unnecessary zero extend before AND
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: wilson at gcc dot gnu.org
  Target Milestone: ---

Given this testcase extracted from newlib

struct s
{
  short s;
  int i;
};

extern void sub2 (void);
extern void sub3 (void);

int
sub (struct s* t)
{
  short i = t->s;
  if ((i & 0x8) == 0)
    t->s |= 0x800;
  if ((t->s & 0x3) == 0)
    sub3 ();
  t->i = i;
  return 0;
}

compiling for riscv32-elf with -O2 -S and looking at assembly code, I see two
places where we have

        slli    a5,a5,16
        srli    a5,a5,16
        andi    a5,a5,3

The zero extend before the AND is clearly unnecessary.

It seems a complex set of circumstances leads to here.  The tree level
optimizer extends the lifetime of the first zero extend into a phi, which means
the operation is split across basic blocks.  This also means no REG_DEAD note
and no combine.  It isn't until 309 bbro that the zero extend and AND end up
back in the same basic block again, and that is too late to optimize it as
nothing after 309 bbro can fix this.

So it appears we need a global rtl pass that can notice and fix redundant zero
extends feeding into AND operations across basic blocks.

Reply via email to