https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127606
Richard Biener <rguenth at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |ASSIGNED
Assignee|unassigned at gcc dot gnu.org |rguenth at gcc dot
gnu.org
Keywords| |needs-bisection
Last reconfirmed| |2026-09-25
Ever confirmed|0 |1
--- Comment #5 from Richard Biener <rguenth at gcc dot gnu.org> ---
✦ Root Cause Analysis
In cp in obj/gcc/t.c, the variable dl is defined as char (8-bit QImode). In
the loop, de and aq are computed as:
1 de = (long)dl << 40 >> 40;
2 aq = (30 ^ de) & (127 ^ de);
At the RTL expansion level:
- dl is stored in pseudo reg:QI 160.
- Because dl is non-negative (0 and 127), de is represented as (reg:SI 169)
=
(and:SI (subreg:SI (reg:QI 160) 0) 127).
- The expression for aq (reg:SI 146) is computed by:
1 insn 217: r342:SI = r169:SI ^ 30
2 insn 218: r343:SI = r169:SI ^ 127
3 insn 219: r146:SI = r342:SI & r343:SI
During the combine pass:
1. combine combines instructions 216, 218, 217 into 219.
2. In distribute_and_simplify_rtx (gcc/combine.cc), the special-case rule
for
(and (xor B C) (not A)) transforms the expression into (xor (ior A B)
(ior
A C)). With A = (subreg:SI (reg:QI 160) 0), B = (A & 127), and C = 30:
- new_op0 = A | (A & 127) = A.
- new_op1 = A | 30.
- tmp = (xor:SI (ior:SI A 30) A).
3. In Boolean algebra: (A | B) ^ A == (~A) & B. However, while gcc/match.pd
(line 2329) simplifies this for GIMPLE:
1 /* (X | Y) ^ X -> Y & ~ X*/
2 (simplify
3 (bit_xor:c (convert1? (bit_ior:c @@0 @1)) (convert2? @0))
4 ...)
and gcc/simplify-rtx.cc has the dual rule for AND:
1 /* Convert (xor (and A B) B) to (and (not A) B). */
simplify-rtx.cc lacked the corresponding rule for IOR: (xor (ior A B) B)
->
(and (not B) A).
4. As a result, the expression was left in the expanded form:
1 insn 218: r343:SI = (subreg:SI (reg:QI 160) 0) | 30
2 insn 219: r146:SI = r343:SI ^ (subreg:SI (reg:QI 160) 0)
which introduced two unmasked uses of the paradoxical subreg (subreg:SI
(reg:QI 160) 0).
5. Under high register pressure across calls, reg:QI 160 was spilled to a
stack slot. Because reg:QI 160 is QImode, only 1 byte was ever stored to
the stack slot.
6. When reloading the operands:
- For insn 218, LRA reloaded operand 0 using zero-extension (movzbl
4(%rsp), %esi), zeroing bits 8..31.
- For insn 219, LRA simplified the memory subreg into a 32-bit SImode
load
directly from 4(%rsp) (xor 4(%rsp), %edx).
7. This read 3 bytes of uninitialized stack memory into bits 8..31 of aq,
which propagated through cq and cm to cause the uninitialized memory
errors reported by Valgrind.
I'm going to fix it.