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

commit r17-5322-gd17bb98c82b708a7e65b02842456097104bf54ff
Author: Mariam Arutunian <[email protected]>
Date:   Thu Oct 15 20:25:40 2026 +0530

    i386: Implement pclmul expander for efficient CRC computation
    
    This patch introduces pclmul expanders for the i386 backend,
    dedicated to generating optimized code for CRC computations.
    
    Expander 1: Bit-Forward CRC (crc<SWI248x:mode><SWI24:mode>4)
    For targets that support pclmulqdq instruction (TARGET_PCLMUL),
    the expander will generate code that uses the pclmulqdq instruction for CRC
    computation.
    
    Expander 2: Bit-Reversed CRC (crc_rev<SWI1248x:mode><SWI24:mode>4)
    If the target does not support crc32 but supports pclmulqdq, it then uses
    the pclmulqdq instruction for bit-reversed CRC computation.
    
    This makes the x86 backend similar to aarch64 which uses pmull.
    Only CRC-16 with 16-bit data and CRC-32 with 16-bit and 32-bit data
    are covered. 8-bit data is omitted since it needs more instructions than
    the table based approach.
    
    gcc/ChangeLog:
    
            * config/i386/i386-expand.cc (ix86_expand_crc_using_pclmul): New
            function that implements pclmul expansion for Bit-Forward CRC
            computation.
            (ix86_expand_reversed_crc_using_pclmul): New function that
            implements pclmul expansion for Bit-Reversed CRC computation.
            * config/i386/i386-protos.h (ix86_expand_crc_using_pclmul): New
            extern function declaration.
            (ix86_expand_reversed_crc_using_pclmul): Likewise.
            * config/i386/i386.md (crc_rev<SWI124:mode>si4): Removed older
            expansion for Bit-Reversed CRC.
            (crc<SWI248x:mode><SWI24:mode>4): Added new expander for
            Bit-Forward CRC.
            (crc_rev<SWI1248x:mode><SWI24:mode>4): Added new expander for
            Bit-Reversed CRC which extends previous CRC32 expansion.
    
    gcc/testsuite/ChangeLog:
    
            * lib/target-supports.exp: Added new pclmul check function.
            * gcc.target/i386/crc-1-pclmul.c: New test.
            * gcc.target/i386/crc-10-pclmul.c: New test.
            * gcc.target/i386/crc-12-pclmul.c: New test.
            * gcc.target/i386/crc-13-pclmul.c: New test.
            * gcc.target/i386/crc-14-pclmul.c: New test.
            * gcc.target/i386/crc-17-pclmul.c: New test.
            * gcc.target/i386/crc-18-pclmul.c: New test.
            * gcc.target/i386/crc-21-pclmul.c: New test.
            * gcc.target/i386/crc-22-pclmul.c: New test.
            * gcc.target/i386/crc-23-pclmul.c: New test.
            * gcc.target/i386/crc-4-pclmul.c: New test.
            * gcc.target/i386/crc-5-pclmul.c: New test.
            * gcc.target/i386/crc-6-pclmul.c: New test.
            * gcc.target/i386/crc-7-pclmul.c: New test.
            * gcc.target/i386/crc-8-pclmul.c: New test.
            * gcc.target/i386/crc-9-pclmul.c: New test.
            * gcc.target/i386/crc-CCIT-data16-pclmul.c: New test.
            * gcc.target/i386/crc-CCIT-data8-pclmul.c: New test.
            * gcc.target/i386/crc-coremark-16bitdata-pclmul.c: New test.
            * gcc.target/i386/crc-crc32-data16.c: New test.
            * gcc.target/i386/crc-crc32-data32.c: New test.
            * gcc.target/i386/crc-crc32-data8.c: New test.
    
    Co-authored-by: Shreesh Adiga <[email protected]>
    Signed-off-by: Mariam Arutunian <[email protected]>
    Signed-off-by: Shreesh Adiga <[email protected]>

Diff:
---
 gcc/config/i386/i386-expand.cc                     | 133 +++++++++++++++++++++
 gcc/config/i386/i386-protos.h                      |   3 +
 gcc/config/i386/i386.md                            |  49 ++++++--
 gcc/testsuite/gcc.target/i386/crc-1-pclmul.c       |   9 ++
 gcc/testsuite/gcc.target/i386/crc-10-pclmul.c      |   9 ++
 gcc/testsuite/gcc.target/i386/crc-12-pclmul.c      |  10 ++
 gcc/testsuite/gcc.target/i386/crc-13-pclmul.c      |   9 ++
 gcc/testsuite/gcc.target/i386/crc-14-pclmul.c      |   9 ++
 gcc/testsuite/gcc.target/i386/crc-17-pclmul.c      |   9 ++
 gcc/testsuite/gcc.target/i386/crc-18-pclmul.c      |   9 ++
 gcc/testsuite/gcc.target/i386/crc-21-pclmul.c      |   9 ++
 gcc/testsuite/gcc.target/i386/crc-22-pclmul.c      |   9 ++
 gcc/testsuite/gcc.target/i386/crc-23-pclmul.c      |   9 ++
 gcc/testsuite/gcc.target/i386/crc-4-pclmul.c       |   9 ++
 gcc/testsuite/gcc.target/i386/crc-5-pclmul.c       |  10 ++
 gcc/testsuite/gcc.target/i386/crc-6-pclmul.c       |   9 ++
 gcc/testsuite/gcc.target/i386/crc-7-pclmul.c       |   9 ++
 gcc/testsuite/gcc.target/i386/crc-8-pclmul.c       |   9 ++
 gcc/testsuite/gcc.target/i386/crc-9-pclmul.c       |   9 ++
 .../gcc.target/i386/crc-CCIT-data16-pclmul.c       |  10 ++
 .../gcc.target/i386/crc-CCIT-data8-pclmul.c        |  10 ++
 .../i386/crc-coremark-16bitdata-pclmul.c           |  10 ++
 gcc/testsuite/gcc.target/i386/crc-crc32-data16.c   |  53 ++++++++
 gcc/testsuite/gcc.target/i386/crc-crc32-data32.c   |  53 ++++++++
 gcc/testsuite/gcc.target/i386/crc-crc32-data8.c    |  53 ++++++++
 gcc/testsuite/lib/target-supports.exp              |  35 ++++++
 26 files changed, 542 insertions(+), 13 deletions(-)

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 75bb79c08ba4..5d3e038adc6e 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -30804,4 +30804,137 @@ ix86_expand_lcp_stall_peephole (rtx_insn *insn, rtx 
*operands,
   emit_insn (set);
 }
 
+/* Generate assembly to calculate CRC using pclmulqdq instruction.
+   OPERANDS[1] is input CRC,
+   OPERANDS[2] is data (message),
+   OPERANDS[3] is the polynomial without the leading 1.  */
+
+void
+ix86_expand_crc_using_pclmul (scalar_mode crc_mode,
+                             scalar_mode data_mode,
+                             rtx *operands)
+{
+  /* Check and keep arguments.  */
+  gcc_assert (!CONST_INT_P (operands[0]));
+  gcc_assert (CONST_INT_P (operands[3]));
+  rtx crc = operands[1];
+  rtx data = operands[2];
+  rtx polynomial = operands[3];
+
+  unsigned HOST_WIDE_INT crc_size = GET_MODE_BITSIZE (crc_mode);
+  unsigned HOST_WIDE_INT data_size = GET_MODE_BITSIZE (data_mode);
+  gcc_assert (crc_size <= 32);
+  gcc_assert (data_size <= crc_size);
+
+  /* Calculate the quotient.  */
+  unsigned HOST_WIDE_INT
+      q = gf2n_poly_long_div_quotient (UINTVAL (polynomial), crc_size);
+
+  if (crc_size > data_size)
+    crc = expand_shift (RSHIFT_EXPR, SImode, crc, crc_size - data_size,
+                       NULL_RTX, 1);
+
+  /* Keep the quotient and polynomial in V2DImode.  */
+  rtvec q_poly_constants = gen_rtvec (2, gen_int_mode (q, DImode),
+                                     gen_int_mode (UINTVAL (polynomial),
+                                                   DImode));
+  rtx constants_v2di = gen_rtx_CONST_VECTOR (V2DImode, q_poly_constants);
+  rtx constants_reg = gen_reg_rtx (V2DImode);
+  emit_move_insn (constants_reg, constants_v2di);
+
+  /* crc ^ data and keep in V2DImode.  */
+  rtx cd_xor = expand_binop (SImode, xor_optab, crc, data, NULL_RTX, 1,
+                            OPTAB_WIDEN);
+  rtx res = gen_reg_rtx (V4SImode);
+  emit_insn (gen_vec_setv4si_0 (res, CONST0_RTX (V4SImode), cd_xor));
+  res = gen_lowpart (V2DImode, res);
+  /* Perform carry-less multiplication with quotient.  */
+  emit_insn (gen_pclmulqdq (res, res, constants_reg, const0_rtx));
+
+  res = expand_shift (RSHIFT_EXPR, V2DImode, res, crc_size, NULL_RTX, 1);
+
+  /* Perform carry-less multiplication with polynomial and get low part.  */
+  emit_insn (gen_pclmulqdq (res, res, constants_reg,
+                           gen_int_mode (0x10, SImode)));
+  rtx crc_part = gen_reg_rtx (SImode);
+  res = gen_lowpart (V4SImode, res);
+  emit_insn (gen_vec_extractv4sisi (crc_part, res, const0_rtx));
+
+  if (crc_size > data_size)
+    {
+      rtx shift = expand_shift (LSHIFT_EXPR, SImode, operands[1], data_size,
+                               NULL_RTX, 1);
+      crc_part = expand_binop (SImode, xor_optab, crc_part, shift, NULL_RTX, 1,
+                              OPTAB_DIRECT);
+    }
+  emit_move_insn (operands[0], gen_lowpart (crc_mode, crc_part));
+}
+
+/* Generate assembly to calculate reversed CRC using pclmulqdq instruction.
+   OPERANDS[1] is input CRC,
+   OPERANDS[2] is data (message),
+   OPERANDS[3] is the polynomial without the leading 1.  */
+
+void
+ix86_expand_reversed_crc_using_pclmul (scalar_mode crc_mode,
+                                      scalar_mode data_mode,
+                                      rtx *operands)
+{
+  /* Check and keep arguments.  */
+  gcc_assert (!CONST_INT_P (operands[0]));
+  gcc_assert (CONST_INT_P (operands[3]));
+  rtx crc = operands[1];
+  rtx data = operands[2];
+  rtx polynomial = operands[3];
+
+  unsigned HOST_WIDE_INT crc_size = GET_MODE_BITSIZE (crc_mode);
+  unsigned HOST_WIDE_INT data_size = GET_MODE_BITSIZE (data_mode);
+  gcc_assert (crc_size <= 32);
+  gcc_assert (data_size <= crc_size);
+
+  /* Calculate the quotient.  */
+  unsigned HOST_WIDE_INT
+      q = gf2n_poly_long_div_quotient (UINTVAL (polynomial), crc_size);
+  /* Reflect the calculated quotient.  */
+  q = reflect_hwi (q, crc_size + 1);
+
+  unsigned HOST_WIDE_INT reflected_op3 = reflect_hwi (UINTVAL (polynomial),
+                                                     crc_size);
+  /* Keep the quotient and reflected polynomial in V2DImode.  */
+  rtvec q_poly_constants = gen_rtvec (2, gen_int_mode (q, DImode),
+                                     gen_int_mode (reflected_op3 << 1,
+                                                   DImode));
+  rtx constants_v2di = gen_rtx_CONST_VECTOR (V2DImode, q_poly_constants);
+  rtx constants_reg = gen_reg_rtx (V2DImode);
+  emit_move_insn (constants_reg, constants_v2di);
+
+  /* crc ^ data and keep in V2DImode.  */
+  rtx cd_xor = expand_binop (SImode, xor_optab, crc, data, NULL_RTX, 1,
+                            OPTAB_WIDEN);
+
+  /* Perform carry-less multiplication with quotient.  */
+  rtx res = gen_reg_rtx (V4SImode);
+  emit_insn (gen_vec_setv4si_0 (res, CONST0_RTX (V4SImode), cd_xor));
+  res = gen_lowpart (V2DImode, res);
+  emit_insn (gen_pclmulqdq (res, res, constants_reg, const0_rtx));
+
+  res = expand_shift (LSHIFT_EXPR, V2DImode, res, 64 - data_size, NULL_RTX, 0);
+
+  /* Perform carry-less multiplication with polynomial and get high part.  */
+  emit_insn (gen_pclmulqdq (res, res, constants_reg,
+                           gen_int_mode (0x10, SImode)));
+  rtx res_high = gen_reg_rtx (SImode);
+  res = gen_lowpart (V4SImode, res);
+  emit_insn (gen_vec_extractv4sisi (res_high, res, const2_rtx));
+
+  if (crc_size > data_size)
+    {
+      rtx shift = expand_shift (RSHIFT_EXPR, SImode, crc, data_size,
+                               NULL_RTX, 1);
+      res_high = expand_binop (SImode, xor_optab, res_high, shift, NULL_RTX, 1,
+                              OPTAB_DIRECT);
+    }
+  emit_move_insn (operands[0], gen_lowpart (crc_mode, res_high));
+}
+
 #include "gt-i386-expand.h"
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index e969e3c58af8..949f6296462b 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -451,3 +451,6 @@ extern void ix86_set_handled_components (sbitmap);
 bool ix86_check_builtin_isa_match (unsigned int, HOST_WIDE_INT*,
                                   HOST_WIDE_INT*);
 rtx ix86_vgf2p8affine_shift_matrix (rtx, rtx, enum rtx_code);
+extern void ix86_expand_crc_using_pclmul (scalar_mode, scalar_mode, rtx *);
+extern void ix86_expand_reversed_crc_using_pclmul (scalar_mode, scalar_mode,
+                                                  rtx *);
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index ec93122cc347..81e6b59eaaec 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -30711,19 +30711,42 @@
    (set_attr "prefix_extra" "1")
    (set_attr "mode" "DI")])
 
-(define_expand "crc_rev<SWI124:mode>si4"
-  [(match_operand:SI 0 "register_operand")
-   (match_operand:SI 1 "register_operand")
-   (match_operand:SWI124 2 "nonimmediate_operand")
-   (match_operand:SI 3 "const_int_operand")]
-  "TARGET_CRC32"
-{
-  /* crc32 uses iSCSI polynomial */
-  if (INTVAL (operands[3]) == 0x1EDC6F41)
-    emit_insn (gen_sse4_2_crc32<mode> (operands[0], operands[1], operands[2]));
-  else
-    expand_reversed_crc_table_based (operands[0], operands[1], operands[2],
-                                    operands[3], <SWI124:MODE>mode);
+;; Bit-forward CRC
+(define_expand "crc<SWI248x:mode><SWI24:mode>4"
+  [(match_operand:SWI24   0 "register_operand")     ;; return value (CRC)
+   (match_operand:SWI24   1 "register_operand")     ;; initial CRC
+   (match_operand:SWI248x 2 "nonimmediate_operand") ;; data
+   (match_operand:SWI24   3 "const_int_operand")]   ;; polynomial
+  "TARGET_PCLMUL && <SWI24:MODE>mode >= <SWI248x:MODE>mode"
+{
+   ix86_expand_crc_using_pclmul (<SWI24:MODE>mode, <SWI248x:MODE>mode,
+                                operands);
+   DONE;
+})
+
+;; Reversed CRC
+(define_expand "crc_rev<SWI1248x:mode><SWI24:mode>4"
+  [(match_operand:SWI24    0 "register_operand")      ;; return value (CRC)
+   (match_operand:SWI24    1 "register_operand")      ;; initial CRC
+   (match_operand:SWI1248x 2 "nonimmediate_operand")  ;; data
+   (match_operand:SWI24    3 "const_int_operand")]    ;; polynomial
+  "(TARGET_PCLMUL && <SWI24:MODE>mode >= <SWI1248x:MODE>mode
+      && <SWI1248x:MODE>mode != QImode)
+    || (TARGET_CRC32 && <SWI24:MODE>mode == SImode)"
+  {
+    /* If it is iSCSI polynomial (0x1EDC6F41), generate crc32 instruction.  */
+    if (TARGET_CRC32 && INTVAL (operands[3]) == 0x1EDC6F41
+       && <SWI24:MODE>mode == SImode)
+      emit_insn (gen_sse4_2_crc32<SWI1248x:mode> (operands[0], operands[1],
+                                                 operands[2]));
+    /* Generate pclmul expansion for 16-bit and 32-bit data.  */
+    else if (TARGET_PCLMUL && <SWI24:MODE>mode >= <SWI1248x:MODE>mode
+       && <SWI1248x:MODE>mode != QImode)
+      ix86_expand_reversed_crc_using_pclmul (<SWI24:MODE>mode,
+                                            <SWI1248x:MODE>mode, operands);
+    else
+      expand_reversed_crc_table_based (operands[0], operands[1], operands[2],
+                                      operands[3], <SWI1248x:MODE>mode);
   DONE;
 })
 
diff --git a/gcc/testsuite/gcc.target/i386/crc-1-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-1-pclmul.c
new file mode 100644
index 000000000000..9e24063e7b82
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-1-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc 
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+
+#include "../../gcc.dg/torture/crc-1.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 16-bit data CRC-16 expands with pclmul */
+/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-10-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-10-pclmul.c
new file mode 100644
index 000000000000..e23a17ef1cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-10-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-10.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-12-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-12-pclmul.c
new file mode 100644
index 000000000000..54760c09e39f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-12-pclmul.c
@@ -0,0 +1,10 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc 
-fdisable-tree-phiopt2 -fdisable-tree-phiopt3" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-12.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 16-bit data CRC-16 expands with pclmul */
+/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-13-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-13-pclmul.c
new file mode 100644
index 000000000000..1fdf7def7688
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-13-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-13.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-14-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-14-pclmul.c
new file mode 100644
index 000000000000..76aa4418ab1a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-14-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-14.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-17-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-17-pclmul.c
new file mode 100644
index 000000000000..ea761b7b25cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-17-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-17.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-18-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-18-pclmul.c
new file mode 100644
index 000000000000..9dab85db68c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-18-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-18.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-21-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-21-pclmul.c
new file mode 100644
index 000000000000..03653b31e65b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-21-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-21.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 32-bit data CRC-32 expands with pclmul */
+/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-22-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-22-pclmul.c
new file mode 100644
index 000000000000..88d98dc07d4b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-22-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-22.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 16-bit data CRC-16 expands with pclmul */
+/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-23-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-23-pclmul.c
new file mode 100644
index 000000000000..5c77d142c2f1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-23-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-23.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 16-bit data CRC-16 expands with pclmul */
+/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-4-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-4-pclmul.c
new file mode 100644
index 000000000000..4cc829c0cb6c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-4-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-4.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-5-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-5-pclmul.c
new file mode 100644
index 000000000000..8f2bc7bc3c2d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-5-pclmul.c
@@ -0,0 +1,10 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -w -fdump-rtl-dfinish -fdump-tree-crc" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-5.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-6-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-6-pclmul.c
new file mode 100644
index 000000000000..2141588079e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-6-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-6.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-7-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-7-pclmul.c
new file mode 100644
index 000000000000..c4eaa28d18ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-7-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-7.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-8-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-8-pclmul.c
new file mode 100644
index 000000000000..628f13628e30
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-8-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-8.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-9-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-9-pclmul.c
new file mode 100644
index 000000000000..fbda6d6ab819
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-9-pclmul.c
@@ -0,0 +1,9 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+
+#include "../../gcc.dg/torture/crc-9.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-CCIT-data16-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-CCIT-data16-pclmul.c
new file mode 100644
index 000000000000..5777e26d7799
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-CCIT-data16-pclmul.c
@@ -0,0 +1,10 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-w -mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-CCIT-data16.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 16-bit data CRC-16 expands with pclmul */
+/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-CCIT-data8-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-CCIT-data8-pclmul.c
new file mode 100644
index 000000000000..128e95d76a48
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-CCIT-data8-pclmul.c
@@ -0,0 +1,10 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-w -mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } } */
+
+#include "../../gcc.dg/torture/crc-CCIT-data8.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 8-bit data CRC doesn't expand with pclmul */
+/* { dg-final { scan-rtl-dump-not "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-coremark-16bitdata-pclmul.c 
b/gcc/testsuite/gcc.target/i386/crc-coremark-16bitdata-pclmul.c
new file mode 100644
index 000000000000..6b517c9010c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-coremark-16bitdata-pclmul.c
@@ -0,0 +1,10 @@
+/* { dg-do run { target { pclmul_runtime } } } */
+/* { dg-options "-w -mpclmul -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include "../../gcc.dg/torture/crc-coremark16-data16.c"
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* Check 16-bit data CRC-16 expands with pclmul */
+/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-crc32-data16.c 
b/gcc/testsuite/gcc.target/i386/crc-crc32-data16.c
new file mode 100644
index 000000000000..5d11d49b4a22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-crc32-data16.c
@@ -0,0 +1,53 @@
+/* { dg-do run { target { sse4_runtime } } } */
+/* { dg-options "-msse4.2 -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+__attribute__ ((noinline,optimize(0)))
+uint32_t _crc32_O0 (uint32_t crc, uint16_t data) {
+  int i;
+  crc = crc ^ data;
+
+  for (i = 0; i < 16; i++) {
+      if (crc & 1)
+       crc = (crc >> 1) ^ 0x82F63B78;
+      else
+       crc = (crc >> 1);
+    }
+
+  return crc;
+}
+
+uint32_t _crc32 (uint32_t crc, uint16_t data) {
+  int i;
+  crc = crc ^ data;
+
+  for (i = 0; i < 16; i++) {
+      if (crc & 1)
+       crc = (crc >> 1) ^ 0x82F63B78;
+      else
+       crc = (crc >> 1);
+    }
+
+  return crc;
+}
+
+int main ()
+{
+  uint32_t crc = 0x0D800D80;
+  for (uint16_t i = 0; i < 0xffff; i++)
+    {
+      uint32_t res1 = _crc32_O0 (crc, i);
+      uint32_t res2 = _crc32 (crc, i);
+      if (res1 != res2)
+       abort ();
+      crc = res1;
+    }
+}
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* { dg-final { scan-rtl-dump "UNSPEC_CRC32" "dfinish"} } */
+/* { dg-final { scan-rtl-dump-times "pclmulqdq" 0 "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-crc32-data32.c 
b/gcc/testsuite/gcc.target/i386/crc-crc32-data32.c
new file mode 100644
index 000000000000..1027d1f42d92
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-crc32-data32.c
@@ -0,0 +1,53 @@
+/* { dg-do run { target { sse4_runtime } } } */
+/* { dg-options "-msse4.2 -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+__attribute__ ((noinline,optimize(0)))
+uint32_t _crc32_O0 (uint32_t crc, uint32_t data) {
+  int i;
+  crc = crc ^ data;
+
+  for (i = 0; i < 32; i++) {
+      if (crc & 1)
+       crc = (crc >> 1) ^ 0x82F63B78;
+      else
+       crc = (crc >> 1);
+    }
+
+  return crc;
+}
+
+uint32_t _crc32 (uint32_t crc, uint32_t data) {
+  int i;
+  crc = crc ^ data;
+
+  for (i = 0; i < 32; i++) {
+      if (crc & 1)
+       crc = (crc >> 1) ^ 0x82F63B78;
+      else
+       crc = (crc >> 1);
+    }
+
+  return crc;
+}
+
+int main ()
+{
+  uint32_t crc = 0x0D800D80;
+  for (uint8_t i = 0; i < 0xff; i++)
+    {
+      uint32_t res1 = _crc32_O0 (crc, i);
+      uint32_t res2 = _crc32 (crc, i);
+      if (res1 != res2)
+       abort ();
+      crc = res1;
+    }
+}
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* { dg-final { scan-rtl-dump "UNSPEC_CRC32" "dfinish"} } */
+/* { dg-final { scan-rtl-dump-times "pclmulqdq" 0 "dfinish"} } */
diff --git a/gcc/testsuite/gcc.target/i386/crc-crc32-data8.c 
b/gcc/testsuite/gcc.target/i386/crc-crc32-data8.c
new file mode 100644
index 000000000000..e4744f911f1a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/crc-crc32-data8.c
@@ -0,0 +1,53 @@
+/* { dg-do run { target { sse4_runtime } } } */
+/* { dg-options "-msse4.2 -O2 -fdump-rtl-dfinish -fdump-tree-crc" } */
+/* { dg-skip-if "" { *-*-* } { "-flto"} } */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+__attribute__ ((noinline,optimize(0)))
+uint32_t _crc32_O0 (uint32_t crc, uint8_t data) {
+  int i;
+  crc = crc ^ data;
+
+  for (i = 0; i < 8; i++) {
+      if (crc & 1)
+       crc = (crc >> 1) ^ 0x82F63B78;
+      else
+       crc = (crc >> 1);
+    }
+
+  return crc;
+}
+
+uint32_t _crc32 (uint32_t crc, uint8_t data) {
+  int i;
+  crc = crc ^ data;
+
+  for (i = 0; i < 8; i++) {
+      if (crc & 1)
+       crc = (crc >> 1) ^ 0x82F63B78;
+      else
+       crc = (crc >> 1);
+    }
+
+  return crc;
+}
+
+int main ()
+{
+  uint32_t crc = 0x0D800D80;
+  for (uint8_t i = 0; i < 0xff; i++)
+    {
+      uint32_t res1 = _crc32_O0 (crc, i);
+      uint32_t res2 = _crc32 (crc, i);
+      if (res1 != res2)
+       abort ();
+      crc = res1;
+    }
+}
+
+/* { dg-final { scan-tree-dump "calculates CRC!" "crc"} } */
+/* { dg-final { scan-tree-dump-times "Couldn't generate faster CRC code." 0 
"crc"} } */
+/* { dg-final { scan-rtl-dump "UNSPEC_CRC32" "dfinish"} } */
+/* { dg-final { scan-rtl-dump-times "pclmulqdq" 0 "dfinish"} } */
diff --git a/gcc/testsuite/lib/target-supports.exp 
b/gcc/testsuite/lib/target-supports.exp
index ae04b6a8daa1..a75c2c51e7e4 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -2995,6 +2995,30 @@ proc check_sse4_hw_available { } {
     }]
 }
 
+# Return 1 if the target supports executing PCLMUL instructions, 0
+# otherwise.  Cache the result.
+
+proc check_pclmul_hw_available { } {
+    return [check_cached_effective_target pclmul_hw_available {
+       # If this is not the right target then we can skip the test.
+       if { ![check_effective_target_x86] } {
+           expr 0
+       } else {
+           check_runtime_nocache pclmul_hw_available {
+               #include "cpuid.h"
+               int main ()
+               {
+                 unsigned int eax, ebx, ecx, edx;
+                 if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+                   return 1;
+
+                 return !(ecx & bit_PCLMUL);
+               }
+           } ""
+       }
+    }]
+}
+
 # Return 1 if the target supports executing AVX instructions, 0
 # otherwise.  Cache the result.
 
@@ -3119,6 +3143,17 @@ proc check_effective_target_sse4_runtime { } {
     return 0
 }
 
+# Return 1 if the target supports running PCLMUL executables, 0 otherwise.
+
+proc check_effective_target_pclmul_runtime { } {
+    if { [check_effective_target_pclmul]
+        && [check_pclmul_hw_available]
+        && [check_sse_os_support_available] } {
+       return 1
+    }
+    return 0
+}
+
 # Return 1 if the target supports running AVX executables, 0 otherwise.
 
 proc check_effective_target_avx_runtime { } {

Reply via email to