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

Reply via email to