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.

Reply via email to