https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127455
Bug ID: 127455
Summary: [missed optimization] Unsigned casts prevent folding
bit-mask MAX
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: ---
GCC misses a bit-mask MAX simplification when the compared values are converted
from int to unsigned. The equivalent signed form is optimized by the match.pd
rule introduced in commit a20efc8 (PR109878):
https://github.com/gcc-mirror/gcc/commit/a20efc87806dd0f9f75a69a65547cce0e5e13e5b
Testcase:
int
f (int a)
{
int b = a & 3;
int c = a & 1;
return (unsigned) b > (unsigned) c ? b : c;
}
Reproduced on GCC 17 trunk at -O1, -O2, and -O3. Command:
gcc -O2 -Wall -Wextra -S -fdump-tree-optimized testcase.c
Actual result:
GCC retains both masks and the MAX expression in optimized GIMPLE.
b_5 = a_4(D) & 3;
c_6 = a_4(D) & 1;
c.0_1 = (unsigned int) c_6;
b.1_2 = (unsigned int) b_5;
_3 = MAX_EXPR <c.0_1, b.1_2>;
_7 = (int) _3;
return _7;
On x86-64, GCC emits:
movl %edi, %eax
andl $3, %edi
andl $1, %eax
cmpl %edi, %eax
cmovb %edi, %eax
ret
Expected result:
For every a, (a & 3) >= (a & 1), because mask 1 is a subset of mask 3.Both
values are nonnegative, so the conversions to unsigned preserve their values
and ordering. The function can therefore be simplified to:
_2 = a_1(D) & 3;
return _2;
The directly simplified source produces the following x86-64 instructions:
movl %edi, %eax
andl $3, %eax
ret
The same-width signed-to-unsigned conversions obscure the existing match.pd
pattern. The final code unnecessarily retains an extra mask, a comparison, and
a conditional move.
Compiler:
gcc version 17.0.0 20260827 (experimental) (GCC)
Target: x86_64-pc-linux-gnu
GCC source: d38b7b3