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.

Reply via email to