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

            Bug ID: 128417
           Summary: [15 Regression] -foptimize-crc: bit-reflected CRC32
                    table loop replaced by __builtin_unreachable ()
           Product: gcc
           Version: 15.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: plantuml at gmail dot com
  Target Milestone: ---

With GCC 15.2.0 (x86_64-linux-gnu, Ubuntu 15.2.0-16ubuntu1) at -O2, a function
that fills a CRC32 table (bit-reflected, polynomial 0xEDB88320) in a loop is
replaced entirely by __builtin_unreachable (). GCC 13.3 and 14.3 compile it
correctly, and so does GCC 15 with -fno-optimize-crc, -fno-tree-vrp or -O1.

The loops have the shape that the TeaVM compiler generates (while (1) with
gotos); the same loops written with for/while (--k >= 0) are transformed by the
pass but the code stays correct.

Test case (no warning with -Wall -Wextra):

#include <stdint.h>

void init(int32_t *t) {
        int32_t i = 0;
        while (1) {
                if (!(i < 256)) break;
                int32_t k = 8;
                int32_t c = i;
                while (1) {
                        k = k - 1;
                        if (k < 0) goto done;
                        if (!(c & 1)) {
                                c = (int32_t) ((uint32_t) c >> 1);
                                goto next;
                        }
                        c = -306674912 ^ (int32_t) ((uint32_t) c >> 1);
                next:;
                }
        done:;
                t[i] = c;
                i = i + 1;
        }
}

$ gcc -O2 -c crc_v7.c -fdump-tree-optimized

Actual: the final tree is 11 lines and the function has no "ret" (the body is
__builtin_unreachable ()).
Expected: the table is filled and the function returns (64 lines of final tree
with -fno-optimize-crc).

-fdump-tree-crc-details shows that the pass finds the CRC ("Bit reversed", the
polynomial is found) and stops after "Checking 5 bit.".

If the table comes from a call before the loop (t = allocate (256); with
allocate declared extern), only the call is kept, followed by
__builtin_unreachable ().

Related: PR 127984 (same pass, another symptom: a loop of 24 iterations gives
the result of 32).

Found in the wild: the C generated by TeaVM 0.16.0 for java.util.zip.CRC32 has
the static initializer of its table cut after the call that allocates it, and
the program crashes at start-up. The whole story (177 generated files, CI
comparing gcc 13/14/15 and clang, delta debugging, scan of the -O2 options,
minimal cases): https://github.com/plantuml/gcc-2

Reply via email to