https://gcc.gnu.org/g:f403d5f08ae92b30fac43bb89ef9c9dad25a79ec
commit r15-11262-gf403d5f08ae92b30fac43bb89ef9c9dad25a79ec Author: Tamar Christina <[email protected]> Date: Fri Apr 17 07:46:07 2026 +0100 middle-end: disable CRC pass when -Os and the target does not have CRC optabs [PR124900] The example #include <stdint.h> #include <stddef.h> uint32_t crc32(const uint8_t *data, size_t length) { uint8_t i; uint32_t crc = 0xffffffff; // Initial value while (length--) { crc ^= (uint32_t)(*data++) << 24; #pragma GCC unroll 0 for (i = 0; i < 8; ++i) { if (crc & 0x80000000) crc = (crc << 1) ^ 0x04C11DB7; else crc <<= 1; } } return crc; } when compiled with -Os -march=armv8-a increases the codesize significantly because it generates a loop that's as big as the original but adds a lookup table of 255 * 4 bytes. This means it's actively making codesize bigger and introduces a codesize regression from before the pass was added. This patch disables the CRC table based expansion when compiling for size. gcc/ChangeLog: PR middle-end/124900 * gimple-crc-optimization.cc (crc_optimization::optimize_crc_loop): Do not expand to table when compiling for size. (class crc_optimization): Update prototype of optimize_crc_loop to include loop. (crc_optimization::execute): Pass loop to optimize_crc_loop. gcc/testsuite/ChangeLog: PR middle-end/124900 * gcc.target/aarch64/crc-1.c: New test. * gcc.target/aarch64/crc-2.c: New test. * gcc.target/aarch64/crc-3.c: New test. * gcc.target/aarch64/crc-4.c: New test. (cherry picked from commit 26e88fe809de0f1a1812c99e2e0106afb03257b3) Diff: --- gcc/gimple-crc-optimization.cc | 24 +++++++++++++++++++----- gcc/testsuite/gcc.target/aarch64/crc-1.c | 24 ++++++++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/crc-2.c | 24 ++++++++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/crc-3.c | 24 ++++++++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/crc-4.c | 24 ++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 5 deletions(-) diff --git a/gcc/gimple-crc-optimization.cc b/gcc/gimple-crc-optimization.cc index 1751be9bc97f..6710ddf14d3b 100644 --- a/gcc/gimple-crc-optimization.cc +++ b/gcc/gimple-crc-optimization.cc @@ -32,6 +32,8 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "tree-scalar-evolution.h" #include "crc-verification.h" +#include "internal-fn.h" +#include "predict.h" class crc_optimization { private: @@ -225,10 +227,10 @@ class crc_optimization { /* Returns phi statement which may hold the calculated CRC. */ gphi *get_output_phi (); - /* Attempts to optimize a CRC calculation loop by replacing it with a call to - an internal function (IFN_CRC or IFN_CRC_REV). + /* Attempts to optimize a CRC calculation calculated by LOOP by replacing it + with a call to an internal function (IFN_CRC or IFN_CRC_REV). Returns true if replacement succeeded, otherwise false. */ - bool optimize_crc_loop (gphi *output_crc); + bool optimize_crc_loop (class loop *loop, gphi *output_crc); public: crc_optimization () : m_visited_stmts (BITMAP_ALLOC (NULL)), @@ -1221,7 +1223,7 @@ crc_optimization::get_output_phi () Returns true if replacement succeeded, otherwise false. */ bool -crc_optimization::optimize_crc_loop (gphi *output_crc) +crc_optimization::optimize_crc_loop (class loop *loop, gphi *output_crc) { if (!output_crc) { @@ -1260,6 +1262,18 @@ crc_optimization::optimize_crc_loop (gphi *output_crc) location_t loc; loc = EXPR_LOCATION (phi_result); + /* If the target does not have an expansion for CRC optimally then the table + based lookup will need at least 255-bytes of RODATA and won't be smaller + than the original code itself. */ + if (!optimize_loop_for_speed_p (loop)) + { + tree data_type = TREE_TYPE (m_data_arg); + tree result_type = TREE_TYPE (phi_result); + auto ty_pair = tree_pair (data_type, result_type); + if (!direct_internal_fn_supported_p (ifn, ty_pair, OPTIMIZE_FOR_BOTH)) + return false; + } + /* Add IFN call and write the return value in the phi_result. */ gcall *call = gimple_build_call_internal (ifn, 3, m_crc_arg, m_data_arg, polynomial_arg); @@ -1337,7 +1351,7 @@ crc_optimization::execute (function *fun) fprintf (dump_file, "The loop with %d header BB index " "calculates CRC!\n", m_crc_loop->header->index); - if (!optimize_crc_loop (output_crc)) + if (!optimize_crc_loop (loop, output_crc)) { if (dump_file) fprintf (dump_file, "Couldn't generate faster CRC code.\n"); diff --git a/gcc/testsuite/gcc.target/aarch64/crc-1.c b/gcc/testsuite/gcc.target/aarch64/crc-1.c new file mode 100644 index 000000000000..e47b73d02b74 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/crc-1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Os -march=armv8-a -fdump-tree-crc -std=c99" } */ + +#include <stdint.h> +#include <stddef.h> + +uint32_t crc32(const uint8_t *data, size_t length) +{ + uint8_t i; + uint32_t crc = 0xffffffff; // Initial value + while (length--) { + crc ^= (uint32_t)(*data++) << 24; +#pragma GCC unroll 0 + for (i = 0; i < 8; ++i) { + if (crc & 0x80000000) + crc = (crc << 1) ^ 0x04C11DB7; + else + crc <<= 1; + } + } + return crc; +} + +/* { dg-final { scan-tree-dump-not {\.CRC } "crc" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/crc-2.c b/gcc/testsuite/gcc.target/aarch64/crc-2.c new file mode 100644 index 000000000000..5cef000c9a67 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/crc-2.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Os -march=armv8-a+crypto -fdump-tree-crc -std=c99" } */ + +#include <stdint.h> +#include <stddef.h> + +uint32_t crc32(const uint8_t *data, size_t length) +{ + uint8_t i; + uint32_t crc = 0xffffffff; // Initial value + while (length--) { + crc ^= (uint32_t)(*data++) << 24; +#pragma GCC unroll 0 + for (i = 0; i < 8; ++i) { + if (crc & 0x80000000) + crc = (crc << 1) ^ 0x04C11DB7; + else + crc <<= 1; + } + } + return crc; +} + +/* { dg-final { scan-tree-dump-times {\.CRC } 1 "crc" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/crc-3.c b/gcc/testsuite/gcc.target/aarch64/crc-3.c new file mode 100644 index 000000000000..6f9900525d3f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/crc-3.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O3 -march=armv8-a -fdump-tree-crc -std=c99" } */ + +#include <stdint.h> +#include <stddef.h> + +uint32_t crc32(const uint8_t *data, size_t length) +{ + uint8_t i; + uint32_t crc = 0xffffffff; // Initial value + while (length--) { + crc ^= (uint32_t)(*data++) << 24; +#pragma GCC unroll 0 + for (i = 0; i < 8; ++i) { + if (crc & 0x80000000) + crc = (crc << 1) ^ 0x04C11DB7; + else + crc <<= 1; + } + } + return crc; +} + +/* { dg-final { scan-tree-dump-times {\.CRC } 1 "crc" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/crc-4.c b/gcc/testsuite/gcc.target/aarch64/crc-4.c new file mode 100644 index 000000000000..9a51856f44c8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/crc-4.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O3 -march=armv8-a+crypto -fdump-tree-crc -std=c99" } */ + +#include <stdint.h> +#include <stddef.h> + +uint32_t crc32(const uint8_t *data, size_t length) +{ + uint8_t i; + uint32_t crc = 0xffffffff; // Initial value + while (length--) { + crc ^= (uint32_t)(*data++) << 24; +#pragma GCC unroll 0 + for (i = 0; i < 8; ++i) { + if (crc & 0x80000000) + crc = (crc << 1) ^ 0x04C11DB7; + else + crc <<= 1; + } + } + return crc; +} + +/* { dg-final { scan-tree-dump-times {\.CRC } 1 "crc" } } */
