https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127381
Bug ID: 127381
Summary: Missed vector optimization: ((x >> 31) == 1) & 1 is
not folded to x >> 31
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: mikaseianatsu at proton dot me
Target Milestone: ---
The following function extracts the highest bit of each unsigned 32-bit vector
lane, compares it with one, and converts the comparison mask back to zero or
one. The result is exactly x >> 31, but GCC retains the comparison and mask
operation.
Compiler:
GCC 17.0.0 20260827 (experimental)
Target: x86_64-pc-linux-gnu
GCC source: d38b7b34f4dc69f896e1fbd984b859365f3dd282
Configure options: --enable-languages=c,c++ --disable-bootstrap
--disable-multilib --enable-checking=release
Testcase:
typedef unsigned int v8u32 __attribute__((vector_size(32)));
v8u32
f (v8u32 x)
{
v8u32 bit = x >> 31;
v8u32 one = { 1, 1, 1, 1, 1, 1, 1, 1 };
return (v8u32) (bit == one) & one;
}
Compile with:
gcc -O2 -mavx2 -S -fdump-tree-optimized testcase.c -o testcase.s
Expected result:
For each unsigned 32-bit lane, bit = x >> 31 is either zero or one. Therefore
(bit == 1) & 1 produces exactly bit, so the function can be simplified to:
v8u32
f (v8u32 x)
{
return x >> 31;
}
Current result:
The optimized GIMPLE retains the comparison and mask conversion:
bit_3 = x_2(D) >> 31;
_1 = bit_3 == { 1, 1, 1, 1, 1, 1, 1, 1 };
_6 = VIEW_CONVERT_EXPR(_1);
_4 = _6 & { 1, 1, 1, 1, 1, 1, 1, 1 };
return _4;
The generated code contains five vector instructions instead of one:
f:
vpcmpeqd %ymm1, %ymm1, %ymm1
vpsrld $31, %ymm0, %ymm0
vpsrld $31, %ymm1, %ymm1
vpcmpeqd %ymm1, %ymm0, %ymm0
vpand %ymm1, %ymm0, %ymm0
ret
This appears to be a missed vector simplification for a value known to be
either zero or one. The equivalent scalar expression is already simplified by
GCC.