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.