https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127606

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |missed-optimization

--- Comment #6 from Richard Biener <rguenth at gcc dot gnu.org> ---
That is, there's a missed optimization that would hide the issue and it can be
fixed with something like the following:

diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 38c8abfe3e7..ccb80797ac8 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -4119,6 +4119,24 @@ simplify_context::simplify_binary_operation_1 (rtx_code
c
ode,
                                                        XEXP (op0, 1), mode),
                                    op1);

+      /* Similarly, convert (xor (ior A B) B) to (and (not B) A).  */
+
+      else if (GET_CODE (op0) == IOR
+              && rtx_equal_p (XEXP (op0, 1), op1)
+              && ! side_effects_p (op1))
+       return simplify_gen_binary (AND, mode,
+                                   simplify_gen_unary (NOT, mode,
+                                                       op1, mode),
+                                   XEXP (op0, 0));
+
+      else if (GET_CODE (op0) == IOR
+              && rtx_equal_p (XEXP (op0, 0), op1)
+              && ! side_effects_p (op1))
+       return simplify_gen_binary (AND, mode,
+                                   simplify_gen_unary (NOT, mode,
+                                                       op1, mode),
+                                   XEXP (op0, 1));
+
       /* Given (xor (ior (xor A B) C) D), where B, C and D are
         constants, simplify to (xor (ior A C) (B&~C)^D), canceling
         out bits inverted twice and not set by C.  Similarly, given

I asked to investigate the observed SIGFPE:

✦ How the Uninitialized Bits Cause Division by Zero (Actual Wrong-Code)

  In cu:

   1 void cu(char cn) {
   2   bb = cw(2050618351, -111, -1044328.0f, cn - 103, -72, -19, 136) +
     979061894;
   3   ba = 130280446 + bb;
   4   if (-2 * ba != -262668294)
   5     az = 1067210928 / ay;
   6 }
  ay is a static variable initialized to zero (int ay;). In correct execution,
  aq in cp evaluates to 30 on iteration 1 and 0 on iteration 2, ensuring that
  the conditional -2 * ba != -262668294 is false and no division by zero
occurs.

  However, during compilation, aq = (de ^ 30) & (de ^ 127) (where de =
  (subreg:SI (reg:QI dl) 0) & 127) was combined into:

   1 insn 218: r343:SI = (subreg:SI dl:QI 0) | 30
   2 insn 219: r146:SI = r343:SI ^ (subreg:SI dl:QI 0)
   3 insn 220: aq:SI = r146:SI

  The RTL semantics of a non-promoted paradoxical subreg (subreg:SI (reg:QI dl)
  0) dictate that its upper 24 bits are undefined. This means:
   1. (X | 30) ^ X only produces zero in bits 8..31 if the two uses of X have
      identical upper bits.
   2. Because dl was a 1-byte variable spilled to the stack (mem:QI 4(%rsp)),
      only 1 byte in that stack slot was ever written.
   3. In insn 218, LRA reloaded (subreg:SI dl:QI 0) using movzbl
(zero-extending
      bits 8..31 to 0).
   4. In insn 219, LRA simplified the subreg of memory into (mem:SI 4(%rsp))
      (xor 4(%rsp), %edx), reading 4 bytes from memory where bytes 1..3 were
      uninitialized stack garbage.

  Consequently, r146:SI computed 0 ^ stack_garbage = stack_garbage in bits
  8..31, and stored that garbage into the 32-bit global variable aq. When
  non-zero garbage was present on the stack:
   - aq did not evaluate to 30, but to (garbage << 8) | 30.
   - This corrupted cr passed to cq, which altered ar, u, and subsequently ba
in
     cu.
   - -2 * ba != -262668294 evaluated to true, executing az = 1067210928 / ay
and
     crashing with a floating-point exception (SIGFPE, division by zero).

and further

  Without this simplification:
   - Combine formed (xor:SI (ior:SI dl#0 30) dl#0). By expanding ~dl & 30 into
     (dl | 30) ^ dl, it created two separate uses of the paradoxical subreg
dl#0
     without a masking operation on the outer XOR. This assumed that the upper
     bits of both instances of dl#0 would be equal and cancel out, which is
     invalid for paradoxical subregs of spilled pseudos.

hinting at another, wrong, "simplification" done by
distribute_and_simplify_rtx.

Reply via email to