https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128484
Bug ID: 128484
Summary: loop-carried signed bit-field load and its sign
extract stay outside the cutoff test
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: Subodh.SunilHumne at amd dot com
Target Milestone: ---
GCC keeps a loop-carried load of a signed bit-field, and the shifts that
sign-extract it, on the path that runs on every iteration. The only
consumer is the range test inside a cutoff branch.
Target: x86_64-linux. Options: -O2.
struct Ext {
int id : 30;
unsigned atomFixed : 1;
unsigned groupFixed : 1;
};
__attribute__((noinline))
int filter (const struct Ext *ext, const double *r2, int n,
double cutoff, int lo, int hi, int *out)
{
int j = 0;
int id = ext[0].id;
for (int i = 0; i < n; ++i)
{
if (r2[i] < cutoff)
{
if (id >= lo && id <= hi)
out[j++] = i;
}
id = ext[i + 1].id;
}
return j;
}
The value tested on this iteration was loaded at the end of the previous
one. id = ext[i + 1].id is outside the cutoff, so a rejected pair still
loads and sign-extracts the next id.
GIMPLE carries the widened int. The load and the conversion sit in the
block that both the passing and failing edges reach:
<bb 3>:
# id_41 = PHI <id_33(latch), id_24(preheader)>
if (r2[i] < cutoff)
goto <bb 4>; // only use of id_41
<bb latch>:
_15 = ext[i + 1].id; // <unnamed-signed:30>
id_33 = (int) _15;
The (int) conversion is not where the x86 shifts come from. The 30-bit
temporary and int both use SImode, so the cast expands to a copy.
extract_bit_field sign-extracts while expanding the COMPONENT_REF, which
is sall $2 / sarl $2. Sinking the cast leaves the shifts on the load.
The phi is the widened int rather than the address, so there is no
pointer to reload under the cutoff. pass_sink_code runs on GIMPLE, and
no RTL pass moves the load and the extract under the branch.
x86-64 assembly of the loop, loads and shifts on the latch:
comisd (%rsi,%rcx,8), %xmm0
jbe .L7
cmpl %eax, %r11d
...
.L7:
movl (%rdi), %eax
addq $1, %rcx
addq $4, %rdi
sall $2, %eax
sarl $2, %eax
jne .L8
Desired placement: carry the address, and reload and sign-extract only
after the cutoff succeeds.
comisd (%rsi,%rcx,8), %xmm0
jbe .L7
movl (%rdi), %eax
sall $2, %eax
sarl $2, %eax
cmpl %eax, %lo
...
.L7:
addq $4, %rdi # next address only