On Wed, Oct 7, 2026 at 5:28 PM Shreesh Adiga
<[email protected]> wrote:
>
> On Tue, Sep 8, 2026 at 3:46 PM Mariam Arutunian <[email protected]>
> wrote:
>>
>> Thanks for the patch!
>>
>> I've had a quick look, and everything looks okay so far.
>
>
> Thanks Mariam for your review!
>
> GCC x86 maintainers: ping for review. Kindly assist with the next steps for
> this change.
> I'm interested in working on 64-bit CRC expansion as a follow up once this is
> merged.
>
> Thanks,
> Shreesh
>
>>
>> On Mon, Sep 7, 2026 at 1:56 PM Shreesh Adiga <[email protected]>
>> wrote:
>>>
>>> From: Mariam Arutunian <[email protected]>
>>>
>>> This patch introduces pclmul expanders for the i386 backend,
>>> dedicated to generating optimized code for CRC computations.
>>>
>>> Expander 1: Bit-Forward CRC (crc<SWI1248x:mode><SWI124:mode>4)
>>> For targets that support both pclmulqdq instruction (TARGET_PCLMUL) and are
>>> 64-bit (TARGET_64BIT),
>>> the expander will generate code that uses the pclmulqdq instruction for CRC
>>> computation.
>>>
>>> Expander 2: Bit-Reversed CRC (crc_rev<SWI1248x:mode><SWI124: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.
>>> This is based on earlier submitted patch which was not merged for x86:
>>> https://gcc.gnu.org/pipermail/gcc-patches/2024-November/668248.html
>>>
>>> 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<SWI1248x:mode><SWI124:mode>4): Added new expander for
>>> Bit-Forward CRC.
>>> (crc_rev<SWI1248x:mode><SWI124:mode>4): Added new expander for
>>> Bit-Reversed CRC which extends previous CRC32 expansion.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * 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: Shreesh Adiga <[email protected]>
Mariam's signoff is needed here.
>>> ---
>>> gcc/config/i386/i386-expand.cc | 133 ++++++++++++++++++
>>> gcc/config/i386/i386-protos.h | 3 +
>>> gcc/config/i386/i386.md | 53 +++++--
>>> gcc/testsuite/gcc.target/i386/crc-1-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-10-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-12-pclmul.c | 9 ++
>>> gcc/testsuite/gcc.target/i386/crc-13-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-14-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-17-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-18-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-21-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-22-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-23-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-4-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-5-pclmul.c | 9 ++
>>> gcc/testsuite/gcc.target/i386/crc-6-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-7-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-8-pclmul.c | 8 ++
>>> gcc/testsuite/gcc.target/i386/crc-9-pclmul.c | 8 ++
>>> .../gcc.target/i386/crc-CCIT-data16-pclmul.c | 9 ++
>>> .../gcc.target/i386/crc-CCIT-data8-pclmul.c | 9 ++
>>> .../i386/crc-coremark-16bitdata-pclmul.c | 9 ++
>>> .../gcc.target/i386/crc-crc32-data16.c | 53 +++++++
>>> .../gcc.target/i386/crc-crc32-data32.c | 53 +++++++
>>> .../gcc.target/i386/crc-crc32-data8.c | 53 +++++++
>>> 25 files changed, 492 insertions(+), 13 deletions(-)
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-1-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-10-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-12-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-13-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-14-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-17-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-18-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-21-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-22-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-23-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-4-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-5-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-6-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-7-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-8-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-9-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-CCIT-data16-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-CCIT-data8-pclmul.c
>>> create mode 100644
>>> gcc/testsuite/gcc.target/i386/crc-coremark-16bitdata-pclmul.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-crc32-data16.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-crc32-data32.c
>>> create mode 100644 gcc/testsuite/gcc.target/i386/crc-crc32-data8.c
>>>
>>> diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
>>> index fb4224af0da..6010892e3dc 100644
>>> --- a/gcc/config/i386/i386-expand.cc
>>> +++ b/gcc/config/i386/i386-expand.cc
>>> @@ -29917,4 +29917,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, DImode, crc, crc_size - data_size,
>>> + NULL_RTX, 1);
>>> +
>>> + /* Keep the quotient in V2DImode. */
>>> + rtx q_v2di = gen_reg_rtx (V2DImode);
>>> + rtx quotient = force_reg (DImode, gen_int_mode (q, DImode));
>>> + emit_insn (gen_vec_concatv2di (q_v2di, quotient, const0_rtx));
This will move the constant through GPR and will result in movabs (a
costly insn) and inter-unit movq. It is probably cheaper to have a
DImode constant in the constant pool and movq it from there. I assume
the compiler will move the memory load out of the loop by itself.
>>> + /* crc ^ data and keep in V2DImode. */
>>> + rtx cd_xor = expand_binop (DImode, xor_optab, crc, data, NULL_RTX, 1,
>>> + OPTAB_WIDEN);
>>> +
>>> + rtx res = gen_reg_rtx (V2DImode);
>>> + emit_insn (gen_vec_concatv2di (res, cd_xor, const0_rtx));
>>> + /* Perform carry-less multiplication. */
>>> + emit_insn (gen_pclmulqdq (res, res, q_v2di, gen_int_mode (0, SImode)));
const0_rtx
>>> +
>>> + res = expand_shift (RSHIFT_EXPR, V2DImode, res, crc_size, NULL_RTX, 1);
>>> +
>>> + /* Keep the polynomial in V2DImode. */
>>> + polynomial = simplify_gen_unary (ZERO_EXTEND, DImode, polynomial,
>>> + GET_MODE (polynomial));
>>> + rtx t1 = force_reg (DImode, polynomial);
>>> + rtx p_v2di = gen_reg_rtx (V2DImode);
>>> + emit_insn (gen_vec_concatv2di (p_v2di, t1, const0_rtx));
Here you should use movd from memory (sse2_loadld + some subreg magic).
>>> +
>>> + /* Perform carry-less multiplication and get low part. */
>>> + emit_insn (gen_pclmulqdq (res, res, p_v2di, gen_int_mode (0, SImode)));
>>> + rtx crc_part = gen_reg_rtx (DImode);
>>> + emit_insn (gen_vec_extractv2didi (crc_part, res, const0_rtx));
>>> +
>>> + if (crc_size > data_size)
>>> + {
>>> + rtx shift = expand_shift (LSHIFT_EXPR, DImode, operands[1],
>>> data_size,
>>> + NULL_RTX, 1);
>>> + crc_part = expand_binop (DImode, 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)
The same comments as above apply to this function, too.
>>> +{
>>> + /* 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);
>>> +
>>> + rtx q_v2di = gen_reg_rtx (V2DImode);
>>> + rtx quotient = force_reg (DImode, gen_int_mode (q, DImode));
>>> + emit_insn (gen_vec_concatv2di (q_v2di, quotient, const0_rtx));
>>> +
>>> + /* crc ^ data and keep in V2DImode. */
>>> + rtx cd_xor = expand_binop (DImode, xor_optab, crc, data, NULL_RTX, 1,
>>> + OPTAB_WIDEN);
>>> +
>>> + /* Perform carry-less multiplication. */
>>> + rtx res = gen_reg_rtx (V2DImode);
>>> + emit_insn (gen_vec_concatv2di (res, cd_xor, const0_rtx));
>>> + emit_insn (gen_pclmulqdq (res, res, q_v2di, gen_int_mode (0, SImode)));
>>> +
>>> + res = expand_shift (LSHIFT_EXPR, V2DImode, res, 64 - data_size,
>>> NULL_RTX, 0);
>>> +
>>> + /* Reflect the polynomial and keep in V2DImode. */
>>> + unsigned HOST_WIDE_INT reflected_op3 = reflect_hwi (UINTVAL (polynomial),
>>> + crc_size);
>>> + rtx ref_polynomial = force_reg (DImode,
>>> + gen_int_mode (reflected_op3 << 1,
>>> DImode));
>>> + rtx p_v2di = gen_reg_rtx (V2DImode);
>>> + emit_insn (gen_vec_concatv2di (p_v2di, ref_polynomial, const0_rtx));
>>> +
>>> + /* Perform carry-less multiplication and get high part. */
>>> + emit_insn (gen_pclmulqdq (res, res, p_v2di, gen_int_mode (0, SImode)));
>>> + rtx res_high = gen_reg_rtx (DImode);
>>> + emit_insn (gen_vec_extractv2didi (res_high, res, const1_rtx));
>>> +
>>> + if (crc_size > data_size)
>>> + {
>>> + rtx shift = expand_shift (RSHIFT_EXPR, DImode, crc, data_size,
>>> + NULL_RTX, 1);
>>> + res_high = expand_binop (DImode, 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 21994d3d498..d225a8fadc2 100644
>>> --- a/gcc/config/i386/i386-protos.h
>>> +++ b/gcc/config/i386/i386-protos.h
>>> @@ -449,3 +449,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 4e18797743f..7538b1f70f1 100644
>>> --- a/gcc/config/i386/i386.md
>>> +++ b/gcc/config/i386/i386.md
>>> @@ -30504,19 +30504,46 @@ (define_insn "sse4_2_crc32di"
>>> (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<SWI1248x:mode><SWI124:mode>4"
>>> + [;; return value (calculated CRC)
>>> + (match_operand:SWI124 0 "register_operand" "=r")
>>> + ;; initial CRC
>>> + (match_operand:SWI124 1 "register_operand" "r")
>>> + ;; data
>>> + (match_operand:SWI1248x 2 "register_operand" "r")
Please remove constraints, they are ignored in expanders. Also, please
place comments after operands, see e.g. atomic_compare_and_swap<mode>.
>>> + ;; polynomial without leading 1
>>> + (match_operand:SWI124 3 "const_int_operand")]
>>> + "TARGET_PCLMUL && TARGET_64BIT && <SWI124:MODE>mode >=
>>> <SWI1248x:MODE>mode"
Please write:
TARGET_64BIT && TARGET_PCLMUL
&& <SWI124...
Please mind the line length limit.
>>> +{
>>> + ix86_expand_crc_using_pclmul (<SWI124:MODE>mode, <SWI1248x:MODE>mode,
>>> + operands);
>>> + DONE;
>>> +})
>>> +
>>> +;; Reversed CRC
>>> +(define_expand "crc_rev<SWI1248x:mode><SWI124:mode>4"
>>> + [;; return value (calculated CRC)
>>> + (match_operand:SWI124 0 "register_operand" "=r")
>>> + ;; initial CRC
>>> + (match_operand:SWI124 1 "register_operand" "r")
>>> + ;; data
>>> + (match_operand:SWI1248x 2 "register_operand" "r")
>>> + ;; polynomial without leading 1
>>> + (match_operand:SWI124 3 "const_int_operand")]
Same here.
>>> + "<SWI124:MODE>mode >= <SWI1248x:MODE>mode"
>>> + {
>>> + /* If it is iSCSI polynomial (0x1EDC6F41), generate crc32 instruction.
>>> */
>>> + if (TARGET_CRC32 && INTVAL (operands[3]) == 0x1EDC6F41
>>> + && <SWI124:MODE>mode == SImode)
>>> + emit_insn (gen_sse4_2_crc32<SWI1248x:mode> (operands[0], operands[1],
>>> + operands[2]));
>>> + else if (TARGET_PCLMUL && TARGET_64BIT)
>>> + ix86_expand_reversed_crc_using_pclmul (<SWI124: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 00000000000..21edf417f0c
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-1-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
>>> \ No newline at end of file
Please put a newline here, also in other test files.
Uros.
>>> 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 00000000000..39bfd386d9c
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-10-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..1ac9a6bf56d
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-12-pclmul.c
>>> @@ -0,0 +1,9 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { 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 00000000000..c290539fad3
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-13-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..cc62ee471c7
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-14-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..660bff55e1b
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-17-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..e54392b32a9
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-18-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..4db1504cd49
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-21-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { 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 00000000000..d0f27d96069
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-22-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { 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 00000000000..666f3620597
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-23-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { 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 00000000000..398ecaa4aba
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-4-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..b80368e81bc
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-5-pclmul.c
>>> @@ -0,0 +1,9 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
>>> \ No newline at end of file
>>> 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 00000000000..20b851e3596
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-6-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
>>> \ No newline at end of file
>>> 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 00000000000..3e5cc75338e
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-7-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..4b1145553fc
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-8-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..204d6c84d47
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-9-pclmul.c
>>> @@ -0,0 +1,8 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "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 00000000000..ca728120858
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-CCIT-data16-pclmul.c
>>> @@ -0,0 +1,9 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
>>> \ No newline at end of file
>>> 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 00000000000..816e0561d8f
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-CCIT-data8-pclmul.c
>>> @@ -0,0 +1,9 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
>>> \ No newline at end of file
>>> 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 00000000000..817d960b0aa
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-coremark-16bitdata-pclmul.c
>>> @@ -0,0 +1,9 @@
>>> +/* { dg-do run } */
>>> +/* { 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"} } */
>>> +/* { dg-final { scan-rtl-dump "pclmulqdq" "dfinish"} } */
>>> \ No newline at end of file
>>> 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 00000000000..49ab5f31ef0
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-crc32-data16.c
>>> @@ -0,0 +1,53 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-mcrc32 -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 < 8; 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 < 8; 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 00000000000..08d6c193a77
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-crc32-data32.c
>>> @@ -0,0 +1,53 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-mcrc32 -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 00000000000..7a76b27fd28
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/crc-crc32-data8.c
>>> @@ -0,0 +1,53 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-mcrc32 -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"} } */
>>> --
>>> 2.55.0
>>>