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" } } */

Reply via email to