[Bug rtl-optimization/126914] New: [17 regressions] noce_try_shifted_store_flag pessimizes "if (c) x = x OP 2^n" on targets with cheap conditional moves

"liuhongt at gcc dot gnu.org via Gcc-bugs" <[email protected]>
Newsgroups gmane.comp.gcc.bugs
Message-ID <[email protected]/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126914

            Bug ID: 126914
           Summary: [17 regressions] noce_try_shifted_store_flag
                    pessimizes "if (c) x = x OP 2^n" on targets with cheap
                    conditional moves
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: liuhongt at gcc dot gnu.org
  Target Milestone: ---

Since r17-2519-ga33f26607eb4f3 ("Improve select across A/A OP C where C is
2^n",
PR target/125731), if-conversion prefers a store-flag + shift + OP sequence
over
a conditional move for "if (c) x = x OP C" when C is a power of two.  On x86_64
it takes 5 instructions than original 4 since setcc has a false dependence and
needs an extra xorl, also original instructions sequence seems to have less
port pressure.

Testcase (t.c):

  long fun_not1 (int a, long b) { if (!(a & 1)) b ^= 8; return b; }

  $ gcc -O2 -march=x86-64-v3 -S t.c

GCC 15 / GCC 16 (good), 4 insns / 15 bytes:

  fun_not1:
          movq    %rsi, %rax
          xorq    $8, %rax
          andl    $1, %edi
          cmovne  %rsi, %rax
          ret


GCC 17 trunk (bad), 5 insns / 16 bytes:

  fun_not1:
          xorl    %eax, %eax
          andl    $1, %edi
          sete    %al
          salq    $3, %rax
          xorq    %rsi, %rax
          ret


More regressed testcases:

  long xor_not (int a, long b) { if (!(a & 1)) b ^= 8;     return b; } 
regressed
  long ior_not (int a, long b) { if (!(a & 1)) b |= 64;    return b; } 
regressed
  long add_not (int a, long b) { if (!(a & 1)) b += 65536; return b; } 
regressed
  long shl_not (int a, long b) { if (!(a & 1)) b <<= 16;   return b; } 
regressed
  long xor_cmp (int a, long b) { if (a > 100)  b ^= 8;     return b; } 
regressed
  long add_cmp (int a, long b) { if (a > 100)  b += 256;   return b; } 
regressed
  long add_ne  (int a, long b) { if (a != 0)   b += 256;   return b; } 
regressed


It's even clearer for add_ne 3 insns vs 5 insns (-O2 -march=x86-64-v3):

  add_ne   GCC 16:  leaq 256(%rsi), %rax     3 insns, 14 bytes; the lea is off
                    testl %edi, %edi                  the critical path
                    cmove %rsi, %rax

           trunk:   xorl %eax, %eax          5 insns, 15 bytes
                    testl %edi, %edi
                    setne %al
                    salq $8, %rax
                    addq %rsi, %rax
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.