> -----Original Message-----
> From: Sarvesh Chandra <[email protected]>
> Sent: Thursday, October 29, 2026 8:52 PM
> To: Liu, Hongtao <[email protected]>
> Cc: [email protected]; [email protected];
> [email protected]
> Subject: [PATCH v2] i386: Add AVX512BMM bitreverse lowering
> 
> Use vbitrevb for scalar bitreverse when AVX512BMM and AVX512VL are
> available, while retaining GFNI as the fallback without AVX512VL.
> 
> Bootstrapped and regression tested on x86_64-pc-linux-gnu.
> 
> The vector bitreverse optab has also been added; vectorizer support will be
> addressed separately.
Please open a Bugzilla for it.

Ok for the patch.
> 
> 
> gcc/
>       * config/i386/i386-expand.cc (ix86_expand_bitreverse): Use vbitrevb
> only
>       when AVX512BMM and AVX512VL are available; retain GFNI
> otherwise.
>       * config/i386/i386.md (bitreverse<mode>2): Require AVX512VL for
> BMM.
> 
> gcc/testsuite/
>         * gcc.target/i386/avx512bmm-bitreverse-1.c: Test BMM scalar lowering.
>         * gcc.target/i386/gfni-bitreverse-scalar.c: Test the GFNI-only path.
> 
> Co-authored-by: Venkataramanan Kumar
> <[email protected]>
> Signed-off-by: Sarvesh Chandra <[email protected]>
> ---
> 
> > > It bypasses avx256_optimal/prefer-vector-width=256 and
> > > unconditionally generates ZMM even with -mavx512bmm + -mprefer-
> vector-width=256.
> 
> Changed now for simplicity. However, even BMM with ZMMs is more optimal
> code than the GFNI counterpart.
> 
> > > It appears that even with the vector optab added, the loop is still
> > > not being vectorized.
> 
> Yes, we must do so. Venkat was planning to take this up.
> 
>  gcc/config/i386/i386-expand.cc                | 32 ++++++++++++--------
>  gcc/config/i386/i386-protos.h                 |  2 +-
>  gcc/config/i386/i386.md                       |  4 +--
>  gcc/config/i386/sse.md                        | 10 ++++++
>  .../gcc.target/i386/avx512bmm-bitreverse-1.c  | 28
> ++++++++++++++++  .../gcc.target/i386/gfni-bitreverse-scalar.c  | 30
> +++++++++++++++++
>  6 files changed, 90 insertions(+), 16 deletions(-)  create mode 100644
> gcc/testsuite/gcc.target/i386/avx512bmm-bitreverse-1.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/gfni-bitreverse-scalar.c
> 
> diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
> index 7cc210f8e68..7418cb4f1d2 100644
> --- a/gcc/config/i386/i386-expand.cc
> +++ b/gcc/config/i386/i386-expand.cc
> @@ -28151,10 +28151,10 @@ ix86_expand_vector_bf2sf_with_vec_perm
> (rtx dest, rtx src)
>    emit_move_insn (dest, lowpart_subreg (GET_MODE (dest), target,
> vperm_mode));  }
> 
> -/* Implement bitreverse<mode>2 using gf2p8affineqb.  */
> +/* Implement bitreverse<mode>2 using vbitrevb or gf2p8affineqb.  */
> 
>  void
> -ix86_expand_gfni_bitreverse (rtx dest, rtx src)
> +ix86_expand_bitreverse (rtx dest, rtx src)
>  {
>    machine_mode mode = GET_MODE (dest);
>    rtx temp;
> @@ -28201,18 +28201,24 @@ ix86_expand_gfni_bitreverse (rtx dest, rtx src)
>      }
>    src = temp;
>    temp = gen_reg_rtx (V16QImode);
> -  rtx src2 = gen_rtx_CONST_VECTOR (V16QImode,
> -                                gen_rtvec (16, GEN_INT (1), GEN_INT (2),
> -                                           GEN_INT (4), GEN_INT (8),
> -                                           GEN_INT (16), GEN_INT (32),
> -                                           GEN_INT (64), GEN_INT (-128),
> -                                           GEN_INT (1), GEN_INT (2),
> -                                           GEN_INT (4), GEN_INT (8),
> -                                           GEN_INT (16), GEN_INT (32),
> -                                           GEN_INT (64), GEN_INT (-128)));
> -  src2 = validize_mem (force_const_mem (V16QImode, src2));
>    src = lowpart_subreg (V16QImode, src, GET_MODE (src));
> -  emit_insn (gen_vgf2p8affineqb_v16qi (temp, src, src2, const0_rtx));
> +  if (TARGET_AVX512BMM && TARGET_AVX512VL)
> +    emit_insn (gen_avx512bmm_vbitrevb_v16qi (temp, src));
> +  else if (TARGET_GFNI)
> +    {
> +      rtx src2 = gen_rtx_CONST_VECTOR (V16QImode,
> +                                    gen_rtvec (16, GEN_INT (1), GEN_INT (2),
> +                                               GEN_INT (4), GEN_INT (8),
> +                                               GEN_INT (16), GEN_INT
> (32),
> +                                               GEN_INT (64), GEN_INT (-
> 128),
> +                                               GEN_INT (1), GEN_INT (2),
> +                                               GEN_INT (4), GEN_INT (8),
> +                                               GEN_INT (16), GEN_INT
> (32),
> +                                               GEN_INT (64),
> +                                               GEN_INT (-128)));
> +      src2 = validize_mem (force_const_mem (V16QImode, src2));
> +      emit_insn (gen_vgf2p8affineqb_v16qi (temp, src, src2, const0_rtx));
> +    }
>    if (mode == QImode)
>      {
>        rtx temp1 = gen_reg_rtx (SImode); diff --git a/gcc/config/i386/i386-
> protos.h b/gcc/config/i386/i386-protos.h index
> 106a79dd41e..99814eb5bc1 100644
> --- a/gcc/config/i386/i386-protos.h
> +++ b/gcc/config/i386/i386-protos.h
> @@ -263,7 +263,7 @@ extern rtx ix86_expand_ternlog (machine_mode
> mode, rtx op0, rtx op1, rtx op2,
>                               int idx, rtx target);
>  extern void ix86_expand_vector_sf2bf_with_vec_perm (rtx, rtx);  extern void
> ix86_expand_vector_bf2sf_with_vec_perm (rtx, rtx); -extern void
> ix86_expand_gfni_bitreverse (rtx, rtx);
> +extern void ix86_expand_bitreverse (rtx, rtx);
> 
> 
>  #ifdef TREE_CODE
> diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index
> 063e14cb2c1..59d02551f2d 100644
> --- a/gcc/config/i386/i386.md
> +++ b/gcc/config/i386/i386.md
> @@ -22967,9 +22967,9 @@
>  (define_expand "bitreverse<mode>2"
>    [(set (match_operand:SWIDWI 0 "register_operand")
>       (bitreverse:SWIDWI (match_operand:SWIDWI 1
> "nonimmediate_operand")))]
> -  "TARGET_GFNI && TARGET_SSE2"
> +  "(TARGET_GFNI || (TARGET_AVX512BMM && TARGET_AVX512VL)) &&
> TARGET_SSE2"
>  {
> -  ix86_expand_gfni_bitreverse (operands[0], operands[1]);
> +  ix86_expand_bitreverse (operands[0], operands[1]);
>    DONE;
>  })
> 
> diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index
> de092f4b9ae..6cb2a8ba36c 100644
> --- a/gcc/config/i386/sse.md
> +++ b/gcc/config/i386/sse.md
> @@ -33668,3 +33668,13 @@
>    "vbitrevb\t{%1, %0|%0, %1}"
>    [(set_attr "prefix" "evex")
>     (set_attr "mode" "<sseinsnmode>")])
> +
> +(define_expand "bitreverse<mode>2"
> +  [(set (match_operand:VI1_AVX512VL 0 "register_operand")
> +     (bitreverse:VI1_AVX512VL
> +       (match_operand:VI1_AVX512VL 1 "nonimmediate_operand")))]
> +  "TARGET_AVX512BMM"
> +{
> +  emit_insn (gen_avx512bmm_vbitrevb_<mode> (operands[0],
> operands[1]));
> +  DONE;
> +})
> diff --git a/gcc/testsuite/gcc.target/i386/avx512bmm-bitreverse-1.c
> b/gcc/testsuite/gcc.target/i386/avx512bmm-bitreverse-1.c
> new file mode 100644
> index 00000000000..a2dd451e533
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/avx512bmm-bitreverse-1.c
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mavx512bmm -mavx512vl -mno-gfni -O2" } */
> +/* { dg-final { scan-assembler-times "vbitrevb" 4 } } */
> +/* { dg-final { scan-assembler-not "gf2p8affineqb" } } */
> +
> +unsigned char
> +br8 (unsigned char x)
> +{
> +  return __builtin_bitreverse8 (x);
> +}
> +
> +unsigned short
> +br16 (unsigned short x)
> +{
> +  return __builtin_bitreverse16 (x);
> +}
> +
> +unsigned int
> +br32 (unsigned int x)
> +{
> +  return __builtin_bitreverse32 (x);
> +}
> +
> +unsigned long long
> +br64 (unsigned long long x)
> +{
> +  return __builtin_bitreverse64 (x);
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/gfni-bitreverse-scalar.c
> b/gcc/testsuite/gcc.target/i386/gfni-bitreverse-scalar.c
> new file mode 100644
> index 00000000000..94c032f27b7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/gfni-bitreverse-scalar.c
> @@ -0,0 +1,30 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mgfni -mno-avx512bmm -O2" } */
> +/* { dg-final { scan-assembler-times "gf2p8affineqb" 4 } } */
> +/* { dg-final { scan-assembler-not "vbitrevb" } } */
> +/* { dg-final { scan-assembler-not "vgf2p8affineqb" } } */
> +
> +/* GFNI-only scalar bitreverse must retain the existing legacy GFNI
> +path.  */ unsigned char
> +br8 (unsigned char x)
> +{
> +  return __builtin_bitreverse8 (x);
> +}
> +
> +unsigned short
> +br16 (unsigned short x)
> +{
> +  return __builtin_bitreverse16 (x);
> +}
> +
> +unsigned int
> +br32 (unsigned int x)
> +{
> +  return __builtin_bitreverse32 (x);
> +}
> +
> +unsigned long long
> +br64 (unsigned long long x)
> +{
> +  return __builtin_bitreverse64 (x);
> +}
> --
> 2.34.1

Reply via email to