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

            Bug ID: 84673
           Summary: Overcomplicated code generation for a chain of
                    mutually exclusive conditions
           Product: gcc
           Version: 7.3.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: zackw at panix dot com
  Target Milestone: ---

This function

int has_bad_chars(unsigned char *str, __SIZE_TYPE__ len)
{
  for (unsigned char *c = str; c < str + len; c++)
    {
      unsigned char x = *c;
      if (__builtin_expect (x <= 0x1f || x == 0x5c || x == 0x7f,
                            0))
        return 1;
    }
  return 0;
}

compiles with GCC 7.3.1 at -Os -march=native on a current-generation x86-64 to

has_bad_chars:
        addq    %rdi, %rsi
.L2:
        cmpq    %rsi, %rdi
        jnb     .L7
        movb    (%rdi), %al
        cmpb    $31, %al
        setbe   %cl
        cmpb    $92, %al
        sete    %dl
        orb     %dl, %cl
        jne     .L5
        cmpb    $127, %al
        je      .L5
        incq    %rdi
        jmp     .L2
.L7:
        xorl    %eax, %eax
        ret
.L5:
        movl    $1, %eax
        ret

It is six bytes shorter, and also I think more efficient, to generate this
instead:

has_bad_chars:
.LFB0:
        .cfi_startproc
        addq    %rdi, %rsi
.L2:
        cmpq    %rsi, %rdi
        jnb     .L7
        movb    (%rdi), %al
        cmpb    $31, %al
        jbe     .L5
        cmpb    $92, %al
        je      .L5
        cmpb    $127, %al
        je      .L5
        incq    %rdi
        jmp     .L2
.L7:
        xorl    %eax, %eax
        ret
.L5:
        movl    $1, %eax
        ret

The same thing happens at -O2, but also a chunk of the loop body gets
pointlessly duplicated above the loop (it looks like it tried to unroll the
loop and got stuck halfway).

Reply via email to