On Tue, Oct 13, 2026 at 11:05 AM Hongtao Liu <[email protected]> wrote:

> On Mon Oct 12, 2026 at 10:16 PM PDT, Hongtao Liu wrote:
> > On Mon Oct 12, 2026 at 9:26 AM PDT, Shreesh Adiga wrote:
> >> On Mon, Oct 12, 2026 at 12:45 PM Hongtao Liu <[email protected]>
> wrote:
> >>
> >>> On Sat Oct 10, 2026 at 9:52 AM PDT, Shreesh Adiga 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.
> >>> >
> >>> > 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: Mariam Arutunian <[email protected]>
> >>> > Signed-off-by: Shreesh Adiga <[email protected]>
> >>> > ---
> >>> > Changes in v2:
> >>> >  Replaced movabs + movq of quotient and polynomial with a single
> >>> >  16 byte load and operate on different lanes of it with pclmul
> >>> >  selector argument.
> >>> >  Formatted i386.md changes to remove constraint and comments
> >>> >  after operand as per suggestion.
> >>> >  Added missing newline in the tests.
> >>> >
> >>> >  gcc/config/i386/i386-expand.cc                | 131
> ++++++++++++++++++
> >>> >  gcc/config/i386/i386-protos.h                 |   3 +
> >>> >  gcc/config/i386/i386.md                       |  46 ++++--
> >>> >  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, 483 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..f483a04dfe1 100644
> >>> > --- a/gcc/config/i386/i386-expand.cc
> >>> > +++ b/gcc/config/i386/i386-expand.cc
> >>> > @@ -29917,4 +29917,135 @@ 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 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_mem = validize_mem (force_const_mem (V2DImode,
> >>> constants_v2di));
> >>> > +  rtx constants_reg = gen_reg_rtx (V2DImode);
> >>> > +  emit_move_insn (constants_reg, constants_mem);
> >>> > +
> >>> > +  /* 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 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 (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)
> >>> > +{
> >>> > +  /* 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_mem = validize_mem (force_const_mem (V2DImode,
> >>> constants_v2di));
> >>> > +  rtx constants_reg = gen_reg_rtx (V2DImode);
> >>> > +  emit_move_insn (constants_reg, constants_mem);
> >>> > +
> >>> > +  /* 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 with quotient.  */
> >>> > +  rtx res = gen_reg_rtx (V2DImode);
> >>> > +  emit_insn (gen_vec_concatv2di (res, cd_xor, const0_rtx));
> >>> > +  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 (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..d032c2269f4 100644
> >>> > --- a/gcc/config/i386/i386.md
> >>> > +++ b/gcc/config/i386/i386.md
> >>> > @@ -30504,19 +30504,39 @@ (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"
> >>> > +  [(match_operand:SWI124   0 "register_operand")     ;; return value
> >>> (CRC)
> >>> > +   (match_operand:SWI124   1 "register_operand")     ;; initial CRC
> >>> > +   (match_operand:SWI1248x 2 "register_operand")     ;; data
> >>> > +   (match_operand:SWI124   3 "const_int_operand")]   ;; polynomial
> >>> > +  "TARGET_64BIT && TARGET_PCLMUL
> >>> > +   && <SWI124:MODE>mode >= <SWI1248x:MODE>mode"
> >>> I think pclmul benifts 16/32/64-bit but not 8-bit data?
> >>>
> >>>
> >> It does save on the lookup table though. 32 bit CRC would use 2kB
> storage.
> >> Do you suggest this should be skipped for 8-bit data?
> > Yes.
> >
> >>
> >>
> >>> > +{
> >>> > +   ix86_expand_crc_using_pclmul (<SWI124:MODE>mode,
> <SWI1248x:MODE>mode,
> >>> > +                              operands);
> >>> > +   DONE;
> >>> > +})
> >>> > +
> >>> > +;; Reversed CRC
> >>> > +(define_expand "crc_rev<SWI1248x:mode><SWI124:mode>4"
> >>> > +  [(match_operand:SWI124   0 "register_operand")      ;; return
> value
> >>> (CRC)
> >>> > +   (match_operand:SWI124   1 "register_operand")      ;; initial CRC
> >>> > +   (match_operand:SWI1248x 2 "register_operand")      ;; data
> >>> > +   (match_operand:SWI124   3 "const_int_operand")]    ;; polynomial
> >>> > +  "<SWI124:MODE>mode >= <SWI1248x:MODE>mode"
> >>> Should it be
> >>>  "<SWI124:MODE>mode >= <SWI1248x:MODE>mode
> >>>  && ((TARGET_64BIT && TARGET_PCLMUL)
> >>>  || (TARGET_CRC32 && <SWI124:MODE>mode == SImode))" ?
> >>>
> >>> Without an ISA test, crc_rev is now available on every x86 target.
> >>> I think the purpose of the patch is to extend it with PCLMUL but not
> >>> change other behaviors?
> >>>
> >>>
> >> The else part is generic right? Is it necessary to have all the ISA
> tests
> >> here?
> >> I'm planning to remove the 64 bit check as this seems to also work for
> 32
> >> bit as well.
> > Yes else part is generic, but the existenece of the optab impacts the
> > middle-end optimization decisions(it replaces bit loop with optab when
> it's
> > available,  but the body then emits the table which has bigger codesize
> than
> > bit loop), I think that's why we have TARGET_CRC32 in the original
> crc_rev
> > optab, so I think we probably should also keep TARGET_64BIT check
> instead of
> > falling back to table solution.
> Looks like the patch can generate pclmul solution for ia32 too, so removing
>  TARGET_64BIT won't fall back to table solution, and should be ok.
> >>
> >> Thanks,
> >> Shreesh
> >>
> >>
> >>> > +  {
> >>> > +    /* 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_64BIT && TARGET_PCLMUL)
> >>> > +      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..f423c08cf07
> >>> > --- /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"} } */
> >>> > 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..4b487fefd95
> >>> > --- /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"} } */
> >>> > 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..614423039d4
> >>> > --- /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"} } */
> >>> > 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..1676eb5265b
> >>> > --- /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"} } */
> >>> > 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..241181f89e2
> >>> > --- /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"} } */
> >>> > 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..c64d17e30fd
> >>> > --- /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"} } */
> >>> > 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
> >>>
> >>>
>
>
Thanks for the various suggestions and explanations!
I've incorporated most of the suggestions and submitted v3 follow-up.
This will only cover 16-bit and 32-bit CRCs with 16/32 bit data.
64-bit will be separately taken up once this is merged.

One last thing that I was wondering to change for 32-bit target is
+  /* 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));

I'd like to use movd to move the reg value to XMM but here it seems to be
generating movq which is okay on 64-bit but slightly inefficient on 32-bit.
If someone could provide details on how to achieve this then I'd be happy to
make the changes.

Thanks,
Shreesh

Reply via email to