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