https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127405
Bug ID: 127405
Summary: [14/15/16 Regression] wrong code at -O3 with a reverse
loop over std::vector<struct-of-2-doubles>
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: zerocool_85 at hotmail dot de
Target Milestone: ---
Created attachment 65595
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65595&action=edit
Reproducer
Compiling the attached program with -O3 produces wrong output; -O0, -O1, and
-O2 all
produce correct output for the same source and the same target
(x86_64-linux-gnu).
The program is a minimized extract of a tridiagonal (Thomas-algorithm)
backward-
substitution step. It counts down from nDimension - 2 to 0 inclusive using
for (size_t index = nDimension - 2; index != static_cast<size_t>(-1);
--index)
At -O3, with nDimension == 4 (3 loop iterations), the compiled program silently
skips the loop's final iteration (index == 0): coeff[0].c is left at its
default-constructed 0.0 instead of the correct value.
See attached as repro.cpp
Build and compare:
g++ -std=c++17 -O2 -Wall -Wextra repro.cpp -o repro_O2 && ./repro_O2 #
correct
g++ -std=c++17 -O3 -Wall -Wextra repro.cpp -o repro_O3 && ./repro_O3 #
wrong
Expected output (-O0/-O1/-O2, all agree):
=== 3-point (expected to always work) ===
coefficients[0]: a=0.000000 b=0.000000 c=0.931109
coefficients[1]: a=-0.000000 b=0.000012 c=0.961311
coefficients[2]: a=0.000000 b=0.000000 c=1.049546
coefficients[0] is exactly zero (default-constructed / never written): no --
correct
=== 4-point (suspected to drop index 0) ===
coefficients[0]: a=-0.000000 b=0.000000 c=0.971449
coefficients[1]: a=0.000000 b=-0.000036 c=0.880631
coefficients[2]: a=-0.000000 b=0.000065 c=0.984889
coefficients[3]: a=0.000000 b=0.000000 c=1.238325
coefficients[0] is exactly zero (default-constructed / never written): no --
correct
Actual output at -O3:
=== 3-point (expected to always work) ===
coefficients[0]: a=0.000000 b=0.000000 c=0.931109
coefficients[1]: a=-0.000000 b=0.000012 c=0.961311
coefficients[2]: a=0.000000 b=0.000000 c=1.049546
coefficients[0] is exactly zero (default-constructed / never written): no --
correct
=== 4-point (suspected to drop index 0) ===
coefficients[0]: a=0.000000 b=0.000000 c=0.000000
coefficients[1]: a=0.000000 b=-0.000036 c=0.880631
coefficients[2]: a=-0.000000 b=0.000065 c=0.984889
coefficients[3]: a=0.000000 b=0.000000 c=1.238325
coefficients[0] is exactly zero (default-constructed / never written): YES --
BUG REPRODUCED
Rewriting only the loop's exit condition to the semantically identical
for (size_t index = nDimension - 1; index-- > 0;)
with no other code changes, produces correct output at -O3.
Confirmed present in GCC 14.x through 16.2 (release).
No longer reproduces on a recent trunk build. The bisection landed on commit
27b2a84e580ac14677821daf736b9190f7aa5fc0
("match.pd: Relax single_use for fold-to-zero comparisons").
Not sure if the this related but the root cause may still be in trunk. As of
2026-09-15 this has not been backported to releases/gcc-16, so 16.x, 15.x
releases would still be affected as things currently stand.
Thanks in advance
Chris