https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128322
Bug ID: 128322
Summary: [16/17 Regression] wrong code at -O1 since r17-4215:
push_partial_def pruning drops head padding of
non-constant partial def
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: lzy20000419 at outlook dot com
Target Milestone: ---
Created attachment 66048
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=66048&action=edit
testcase
struct A { unsigned long long lo : 32, y : 19, rest : 13; };
struct BF { unsigned long long x0:4, x1:8, x2:31, x3:3, x4:4, x5:14; };
union U { unsigned char b[8]; struct A a; struct BF bf; };
__attribute__((noipa)) unsigned f(union U *p, unsigned v) {
p->b[6] = 209;
p->a.y = v;
p->b[5] = 39;
return p->bf.x4;
}
int main(void) {
static union U x;
unsigned r = f(&x, 0x30000);
__builtin_printf("%u\n", r);
if (r != 12) __builtin_abort();
return 0;
}
$ gcc -O1 t.c && ./a.out
Aborted (f is folded to "return 4")
Expected 12. -O0 and -O1 -fno-tree-fre are fine. Also fails at -O2.
Fails with trunk and the current gcc-16 branch (16.2.1 20261030); 16.2 and
older are fine.
Started with r17-4215 (PR127377 fix), and r16-9671 on the 16 branch.
https://godbolt.org/z/xsnYfvsoo (x86-64, 16.2 vs trunk)
Big-endian is affected too: the same testcase on powerpc64 (BE) trunk -O1 folds
f to "li 3,15" (expected 12):
https://godbolt.org/z/jofGT6n1Y (16.1 vs trunk)
In vn_walk_cb_data::push_partial_def (tree-ssa-sccvn.cc), a non-constant
partial def is pruned by first rounding its start down to a byte, which leaves
head padding h = offseti - pd.offset (up to 7 bits). Then, when it goes past
the end of the load, the size is set to maxsizei + (tail % 8), which does not
count h. When tail % 8 < h the pruned def ends before the end of the load. Here
the load is bits 46..49 and the store to a.y is bits 32..50 (h = 6, tail = 1),
so it becomes [40,45) instead of [40,51), is dropped as shadowed by b[5] = 39,
and the walk goes on to b[6] = 209.
Maybe something like pd.size = (offseti + maxsizei - pd.offset) + tail % 8 (not
tested).
Disclaimer: This test case was generated by a fuzzer, and the report was
written with LLM assistance.