https://gcc.gnu.org/g:cda67a9c08276ab8123bbffee32637df89dc37a5

commit r17-5643-gcda67a9c08276ab8123bbffee32637df89dc37a5
Author: Shreesh Adiga <[email protected]>
Date:   Tue Oct 27 16:44:45 2026 +0100

    i386: Support 64-bit CRC-32C expansion on ia32
    
    Allow CRC-32C expansion for 64-bit data on ia32 targets.
    When the CRC64 polynomial is the iSCSI polynomial shifted by 32
    (0x1EDC6F4100000000), compute the CRC by chaining
    two crc32l instructions to process the low and high 32-bit
    halves of the XORed operands, avoiding a DImode XOR.
    
    Retain the existing crc32q expansion on x86-64 and extend
    the CRC-32C tests to cover both ia32 and x86-64 targets.
    
    gcc/ChangeLog:
    
            * config/i386/i386.md (crc_rev<SWI1248x:mode><SWI248x:mode>4):
            Allow CRC-32C expansion for 64-bit data on ia32 targets.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/i386/crc-crc32-data64-negative.c: Run tests on ia32
            and x86-64; check for the appropriate CRC32 instruction.
            * gcc.target/i386/crc-crc32-data64.c: Likewise.
    
    Signed-off-by: Shreesh Adiga <[email protected]>

Diff:
---
 gcc/config/i386/i386.md                            | 31 +++++++++++++++++-----
 .../gcc.target/i386/crc-crc32-data64-negative.c    |  6 ++---
 gcc/testsuite/gcc.target/i386/crc-crc32-data64.c   |  7 ++---
 3 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index ce47379c1746..c7fcaf1739ec 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -30736,9 +30736,7 @@
    (match_operand:SWI248x  3 "const_int_operand")]    ;; polynomial
   "<SWI1248x:MODE_SIZE> <= <SWI248x:MODE_SIZE>
    && ((TARGET_PCLMUL && <SWI1248x:MODE>mode != QImode)
-       || (TARGET_CRC32
-          && <SWI248x:MODE_SIZE> >= GET_MODE_SIZE (SImode)
-          && <SWI248x:MODE_SIZE> <= UNITS_PER_WORD))"
+       || (TARGET_CRC32 && <SWI248x:MODE_SIZE> >= GET_MODE_SIZE (SImode)))"
 {
   if (TARGET_CRC32 && <SWI248x:MODE>mode == SImode
       && INTVAL (operands[3]) == 0x1EDC6F41)
@@ -30746,14 +30744,33 @@
                                                operands[2]));
   /* 0x1EDC6F4100000000 is x^32 times the iSCSI polynomial, so the result
      is CRC-32C of crc ^ data in the low 32 bits, with upper bits zero.  */
-  else if (TARGET_64BIT && TARGET_CRC32 && <SWI248x:MODE>mode == DImode
+  else if (TARGET_CRC32 && <SWI248x:MODE>mode == DImode
           && <SWI1248x:MODE>mode == DImode
           && INTVAL (operands[3]) == HOST_WIDE_INT_C (0x1EDC6F4100000000))
     {
-      rtx cd_xor = expand_binop (DImode, xor_optab, operands[1], operands[2],
+      if (TARGET_64BIT)
+       {
+         rtx cd_xor = expand_binop (DImode, xor_optab, operands[1],
+                                    operands[2], NULL_RTX, 1, OPTAB_DIRECT);
+         rtx zero = force_reg (SImode, const0_rtx);
+         emit_insn (gen_sse4_2_crc32di (operands[0], zero, cd_xor));
+       }
+      else
+       {
+         /* crc32l computes CRC-32C of dest ^ src, so chaining two of them
+            processes the low and high halves of crc ^ data without a
+            separate DImode xor.  */
+         rtx tmp = gen_reg_rtx (SImode);
+         emit_insn (gen_sse4_2_crc32si (tmp, gen_lowpart (SImode, operands[1]),
+                                        gen_lowpart (SImode, operands[2])));
+         rtx hi = expand_binop (SImode, xor_optab, tmp,
+                                gen_highpart (SImode, operands[1]),
                                 NULL_RTX, 1, OPTAB_DIRECT);
-      rtx zero = force_reg (SImode, const0_rtx);
-      emit_insn (gen_sse4_2_crc32di (operands[0], zero, cd_xor));
+         rtx res = gen_reg_rtx (SImode);
+         emit_insn (gen_sse4_2_crc32si (res, hi,
+                                        gen_highpart (SImode, operands[2])));
+         emit_move_insn (operands[0], convert_to_mode (DImode, res, 1));
+       }
     }
   /* Generate pclmul expansion for 16-bit, 32-bit and 64-bit data.  */
   else if (TARGET_PCLMUL && <SWI1248x:MODE>mode != QImode)
diff --git a/gcc/testsuite/gcc.target/i386/crc-crc32-data64-negative.c 
b/gcc/testsuite/gcc.target/i386/crc-crc32-data64-negative.c
index 07200dc89917..7981a79a5329 100644
--- a/gcc/testsuite/gcc.target/i386/crc-crc32-data64-negative.c
+++ b/gcc/testsuite/gcc.target/i386/crc-crc32-data64-negative.c
@@ -1,5 +1,5 @@
-/* { dg-do run { target { { sse4_runtime && pclmul_runtime } && { ! ia32 } } } 
} */
-/* { dg-options "-msse4.2 -mpclmul -O2 -save-temps -fdump-rtl-dfinish 
-fdump-tree-crc" } */
+/* { dg-do run { target { sse4_runtime && pclmul_runtime } } } */
+/* { dg-options "-O2 -msse4.2 -mpclmul -masm=att -save-temps" } */
 /* { dg-skip-if "" { *-*-* } { "-flto"} } */
 
 #include <stdint.h>
@@ -50,5 +50,5 @@ int main ()
     }
 }
 
-/* { dg-final { scan-assembler-not "crc32q"} } */
+/* { dg-final { scan-assembler-not "crc32(l|q)"} } */
 /* { dg-final { scan-assembler "pclmul"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-crc32-data64.c 
b/gcc/testsuite/gcc.target/i386/crc-crc32-data64.c
index 02f6fcc9fbfe..a2aa8df82582 100644
--- a/gcc/testsuite/gcc.target/i386/crc-crc32-data64.c
+++ b/gcc/testsuite/gcc.target/i386/crc-crc32-data64.c
@@ -1,5 +1,5 @@
-/* { dg-do run { target { { sse4_runtime && pclmul_runtime } && { ! ia32 } } } 
} */
-/* { dg-options "-msse4.2 -mpclmul -O2 -save-temps -fdump-rtl-dfinish 
-fdump-tree-crc" } */
+/* { dg-do run { target { sse4_runtime && pclmul_runtime } } } */
+/* { dg-options "-O2 -msse4.2 -mpclmul -masm=att -save-temps" } */
 /* { dg-skip-if "" { *-*-* } { "-flto"} } */
 
 #include <stdint.h>
@@ -50,5 +50,6 @@ int main ()
     }
 }
 
-/* { dg-final { scan-assembler "crc32q"} } */
+/* { dg-final { scan-assembler "crc32q" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "crc32l" { target ia32 } } } */
 /* { dg-final { scan-assembler-not "pclmul"} } */

Reply via email to