On Tue Oct 6, 2026 at 12:17 AM PDT, Jakub Jelinek wrote:
> Hi!
>
> As the bug report states, we have instructions to implement
> vector _Float16 -> _Float32 and _Float32 -> _Float16 conversions
> not only for AVX512FP16 (in which case we also have direct
> _Float16 <-> _Float64 conversions), but also for F16C and/or
> AVX512F and/or AVX512VL (depending on which exact size,
> F16C or AVX512VL can do vectors of 4 or 8 elements, AVX512F
> can do vectors of 16 elements).
> Unfortunately the RTL for those vector operations is significantly
> different (for non-AVX512FP16 we use UNSPECs and V?HI mode,
> for AVX512FP16 we use float_extend/float_truncate and V?HF mode).
>
> The following patch arranges for the extendvNhfvNsf2 and truncvNsfvNhf2
> expanders to expand code for the F16C/AVX512F/AVX512VL without
> AVX512FP16 cases.
> I've changed 2 mode iterators (added some conditions to them),
> while they are used not just in these 2 expanders, they are
> used only in TARGET_AVX512FP16 && TARGET_AVX512VL resp.
> TARGET_AVX512FP16 guarded insns, so the condition changes shouldn't
> make a difference there (but if you prefer separate iterators just
> for the 4 define_expands, I can certainly add them instead).
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2026-10-06  Jakub Jelinek  <[email protected]>
>
>       PR target/121688
>       * config/i386/sse.md (VF4_128_8_256): Only include
>       V4DF if TARGET_AVX512FP16 && TARGET_AVX512VL.
>       (VF48H_AVX512VL): Only include V8DF if TARGET_AVX512FP16.
>       Include V8SF also if TARGET_F16C && !TARGET_AVX512FP16.
>       (extend<ssePHmodelower><mode>2): Change condition
>       from TARGET_AVX512FP16 to TARGET_F16C || TARGET_AVX512F.
>       Expand !TARGET_AVX512FP16 cases differently.
>       (extendv4hf<mode>2): Change condition from
>       TARGET_AVX512FP16 && TARGET_AVX512VL to
>       TARGET_F16C || TARGET_AVX512VL.  Expand
>       !(TARGET_AVX512FP16 && TARGET_AVX512VL) cases differently.
>       (trunc<mode><ssePHmodelower>2): Change condition
>       from TARGET_AVX512FP16 to TARGET_F16C || TARGET_AVX512F.
>       Expand !TARGET_AVX512FP16 cases differently.
>       (trunc<mode>v4hf2): Change condition from
>       TARGET_AVX512FP16 && TARGET_AVX512VL to
>       TARGET_F16C || TARGET_AVX512VL.  Expand
>       !(TARGET_AVX512FP16 && TARGET_AVX512VL) cases differently.
>       (*vcvtph2ps_load<mask_name>): Rename to ...
>       (vcvtph2ps_load<mask_name>): ... this.
>
>       * gcc.target/i386/pr121688-f16c.c: New test.
>       * gcc.target/i386/pr121688-avx512f.c: New test.
>       * gcc.target/i386/pr121688-avx512fp16.c: New test.
>       * gcc.target/i386/pr121688-avx512vl.c: New test.
>
> --- a/gcc/config/i386/sse.md  2026-09-30 08:56:53.822225116 +0200
> +++ b/gcc/config/i386/sse.md  2026-10-05 18:41:54.537047085 +0200
> @@ -858,7 +858,7 @@ (define_mode_iterator V48_128_256
>  
>  
>  (define_mode_iterator VF4_128_8_256
> -  [V4DF V4SF])
> +  [(V4DF "TARGET_AVX512FP16 && TARGET_AVX512VL") V4SF])
>  
>  (define_mode_attr avx512
>    [(V16QI "avx512vl") (V32QI "avx512vl") (V64QI "avx512bw")
> @@ -1030,7 +1030,8 @@ (define_mode_iterator VI48F_256_512
>     (V8DI "TARGET_AVX512F") (V8DF "TARGET_AVX512F")
>     (V4DI "TARGET_AVX512VL") (V4DF  "TARGET_AVX512VL")])
>  (define_mode_iterator VF48H_AVX512VL
> -  [V8DF V16SF (V8SF "TARGET_AVX512VL")])
> +  [(V8DF "TARGET_AVX512FP16") V16SF
> +   (V8SF "TARGET_AVX512VL || (TARGET_F16C && !TARGET_AVX512FP16)")])
>  
>  (define_mode_iterator VF48_128
>    [V2DF V4SF])
> @@ -8504,7 +8505,26 @@ (define_expand "extend<ssePHmodelower><m
>    [(set (match_operand:VF48H_AVX512VL 0 "register_operand")
>       (float_extend:VF48H_AVX512VL
>         (match_operand:<ssePHmode> 1 "nonimmediate_operand")))]
> -  "TARGET_AVX512FP16")
> +  "TARGET_F16C || TARGET_AVX512F"
With this condidtion extendv16hfv16sf is valid even w/o TARGET_AVX512F.
I suggest to change iterator VF48H_AVX512VL to (or add a new iterator)

 (define_mode_iterator VF48H_F16C
  [(V8DF "TARGET_AVX512FP16") 
   (V16SF "TARGET_AVX512F") 
   (V8SF "TARGET_F16C || TARGET_AVX512VL")])

> +{
> +  if (!TARGET_AVX512FP16)

And change this condition to
     if (!TARGET_AVX512FP16
        || (<MODE>mode == V8SFmode && !TARGET_AVX512VL))

> +    {
> +      rtx tem = force_reg (<ssePHmode>mode, operands[1]);
> +      if (<MODE>mode == V8SFmode)
> +     emit_insn (gen_vcvtph2ps256 (operands[0],
> +                                  lowpart_subreg (V8HImode, tem,
> +                                                  V8HFmode)));
> +      else
> +     emit_insn (gen_avx512f_vcvtph2ps512_mask (operands[0],
> +                                               lowpart_subreg (V16HImode,
> +                                                               tem,
> +                                                               V16HFmode),
> +                                               CONST0_RTX (V16SFmode),
> +                                               force_reg (HImode,
> +                                                          constm1_rtx)));
> +      DONE;
> +    }
> +})
>  
>  (define_insn 
> "avx512fp16_float_extend_ph<mode>2<mask_name><round_saeonly_name>"
>    [(set (match_operand:VF48H_AVX512VL 0 "register_operand" "=v")
> @@ -8520,10 +8540,18 @@ (define_expand "extendv4hf<mode>2"
>    [(set (match_operand:VF4_128_8_256 0 "register_operand")
>       (float_extend:VF4_128_8_256
>         (match_operand:V4HF 1 "nonimmediate_operand")))]
> -  "TARGET_AVX512FP16 && TARGET_AVX512VL"
> +  "TARGET_F16C || TARGET_AVX512VL"
>  {
>    if (!MEM_P (operands[1]))
>      {
> +      if (!(TARGET_AVX512FP16 && TARGET_AVX512VL))
> +     {
> +       rtx tem = force_reg (V4HFmode, operands[1]);
> +       tem = lowpart_subreg (V4HImode, tem, V4HFmode);
> +       tem = lowpart_subreg (V8HImode, force_reg (V4HImode, tem), V4HImode);
> +       emit_insn (gen_vcvtph2ps (operands[0], tem));
> +       DONE;
> +     }
>        operands[1] = lowpart_subreg (V8HFmode,
>                                   force_reg (V4HFmode, operands[1]),
>                                   V4HFmode);
> @@ -8531,6 +8559,12 @@ (define_expand "extendv4hf<mode>2"
>                (operands[0], operands[1]));
>        DONE;
>      }
> +  else if (!(TARGET_AVX512FP16 && TARGET_AVX512VL))
> +    {
> +      rtx mem = adjust_address_nv (operands[1], V4HImode, 0);
> +      emit_insn (gen_vcvtph2ps_load (operands[0], mem));
> +      DONE;
> +    }
>  })
>  
>  (define_insn "avx512fp16_float_extend_ph<mode>2<mask_name>"
> @@ -8598,7 +8632,34 @@ (define_expand "trunc<mode><ssePHmodelow
>    [(set (match_operand:<ssePHmode> 0 "register_operand")
>       (float_truncate:<ssePHmode>
>         (match_operand:VF48H_AVX512VL 1 "nonimmediate_operand")))]
> -  "TARGET_AVX512FP16")
> +  "TARGET_F16C || TARGET_AVX512F"
> +{
> +  if (!TARGET_AVX512FP16)
Ditto here for the condition change.

Others LGTM.

> +    {
> +      rtx tem;
> +      if (<MODE>mode == V8SFmode)
> +     {
> +       tem = gen_reg_rtx (V8HImode);
> +       emit_insn (gen_vcvtps2ph256 (tem, force_reg (<MODE>mode,
> +                                                    operands[1]),
> +                                    GEN_INT (4)));
> +     }
> +      else
> +     {
> +       tem = gen_reg_rtx (V16HImode);
> +       emit_insn (gen_avx512f_vcvtps2ph512_mask (tem,
> +                                                 force_reg (<MODE>mode,
> +                                                            operands[1]),
> +                                                 GEN_INT (4),
> +                                                 CONST0_RTX (V16HImode),
> +                                                 force_reg (HImode,
> +                                                            constm1_rtx)));
> +     }
> +      emit_move_insn (operands[0], lowpart_subreg (<ssePHmode>mode, tem,
> +                                                GET_MODE (tem)));
> +      DONE;
> +    }
> +})
>  
>  (define_insn "avx512fp16_vcvt<castmode>2ph_<mode><mask_name><round_name>"
>    [(set (match_operand:<ssePHmode> 0 "register_operand" "=v")
> @@ -8613,11 +8674,18 @@ (define_insn "avx512fp16_vcvt<castmode>2
>  (define_expand "trunc<mode>v4hf2"
>    [(set (match_operand:V4HF 0 "register_operand")
>       (float_truncate:V4HF (match_operand:VF4_128_8_256 1 "vector_operand")))]
> -  "TARGET_AVX512FP16 && TARGET_AVX512VL"
> +  "TARGET_F16C || TARGET_AVX512VL"
>  {
>    rtx dest = gen_reg_rtx (V8HFmode);
> -
> -  emit_insn (gen_avx512fp16_trunc<mode>v4hf2 (dest, operands[1]));
> +  if (TARGET_AVX512FP16 && TARGET_AVX512VL)
> +    emit_insn (gen_avx512fp16_trunc<mode>v4hf2 (dest, operands[1]));
> +  else
> +    {
> +      rtx tem = gen_reg_rtx (V8HImode);
> +      emit_insn (gen_vcvtps2ph (tem, force_reg (V4SFmode, operands[1]),
> +                             GEN_INT (4)));
> +      emit_move_insn (dest, lowpart_subreg (V8HFmode, tem, V8HImode));
> +    }
>    emit_move_insn (operands[0], lowpart_subreg (V4HFmode, dest, V8HFmode));
>    DONE;
>  })
> @@ -30773,7 +30841,7 @@ (define_insn "vcvtph2ps<mask_name>"
>     (set_attr "prefix" "maybe_evex")
>     (set_attr "mode" "V4SF")])
>  
> -(define_insn "*vcvtph2ps_load<mask_name>"
> +(define_insn "vcvtph2ps_load<mask_name>"
>    [(set (match_operand:V4SF 0 "register_operand" "=v")
>       (unspec:V4SF [(match_operand:V4HI 1 "memory_operand" "m")]
>                    UNSPEC_VCVTPH2PS))]
> --- a/gcc/testsuite/gcc.target/i386/pr121688-f16c.c   2026-10-05 
> 19:00:46.201158140 +0200
> +++ b/gcc/testsuite/gcc.target/i386/pr121688-f16c.c   2026-10-05 
> 19:11:33.490614318 +0200
> @@ -0,0 +1,95 @@
> +/* PR target/121688 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mf16c -mno-avx512f -masm=att" } */
> +/* { dg-final { scan-assembler-times "\tvcvtps2ph\t\\\$4, %xmm\[0-9]\+, 
> %xmm\[0-9]\+" 2 } } */
> +/* { dg-final { scan-assembler-times "\tvcvtps2ph\t\\\$4, %ymm\[0-9]\+, 
> %xmm\[0-9]\+" 2 } } */
> +/* { dg-final { scan-assembler-not "\tvcvtps2ph\t\\\$4, %zmm\[0-9]\+, 
> %ymm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t%xmm\[0-9]\+, %xmm\[0-9]\+" } } 
> */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t%xmm\[0-9]\+, %ymm\[0-9]\+" } } 
> */
> +/* { dg-final { scan-assembler-not "\tvcvtph2ps\t%ymm\[0-9]\+, %zmm\[0-9]\+" 
> } } */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %xmm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %ymm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler-not "\tvcvtph2ps\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %zmm\[0-9]\+" } } */
> +
> +typedef _Float16 v4hf __attribute__((vector_size (8)));
> +typedef _Float16 v8hf __attribute__((vector_size (16)));
> +typedef _Float16 v16hf __attribute__((vector_size (32)));
> +typedef float v4sf __attribute__((vector_size (16)));
> +typedef float v8sf __attribute__((vector_size (32)));
> +typedef float v16sf __attribute__((vector_size (64)));
> +
> +v4sf
> +foo (v4hf x)
> +{
> +  return __builtin_convertvector (x, v4sf);
> +}
> +
> +v4hf
> +bar (v4sf x)
> +{
> +  return __builtin_convertvector (x, v4hf);
> +}
> +
> +v8sf
> +baz (v8hf x)
> +{
> +  return __builtin_convertvector (x, v8sf);
> +}
> +
> +v8hf
> +qux (v8sf x)
> +{
> +  return __builtin_convertvector (x, v8hf);
> +}
> +
> +#ifdef __AVX512VL__
> +v16sf
> +corge (v16hf x)
> +{
> +  return __builtin_convertvector (x, v16sf);
> +}
> +
> +v16hf
> +garply (v16sf x)
> +{
> +  return __builtin_convertvector (x, v16hf);
> +}
> +#endif
> +
> +v4sf
> +foo2 (v4hf *x)
> +{
> +  return __builtin_convertvector (*x, v4sf);
> +}
> +
> +v4hf
> +bar2 (v4sf *x)
> +{
> +  return __builtin_convertvector (*x, v4hf);
> +}
> +
> +v8sf
> +baz2 (v8hf *x)
> +{
> +  return __builtin_convertvector (*x, v8sf);
> +}
> +
> +v8hf
> +qux2 (v8sf *x)
> +{
> +  return __builtin_convertvector (*x, v8hf);
> +}
> +
> +#ifdef __AVX512VL__
> +v16sf
> +corge2 (v16hf *x)
> +{
> +  return __builtin_convertvector (*x, v16sf);
> +}
> +
> +v16hf
> +garply2 (v16sf *x)
> +{
> +  return __builtin_convertvector (*x, v16hf);
> +}
> +#endif
> --- a/gcc/testsuite/gcc.target/i386/pr121688-avx512f.c        2026-10-05 
> 19:01:24.102657862 +0200
> +++ b/gcc/testsuite/gcc.target/i386/pr121688-avx512f.c        2026-10-05 
> 19:11:50.489389944 +0200
> @@ -0,0 +1,33 @@
> +/* PR target/121688 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mno-f16c -mavx512f -mno-avx512vl -mno-avx512fp16 
> -masm=att" } */
> +/* { dg-final { scan-assembler-times "\tvcvtps2ph\t\\\$4, %zmm\[0-9]\+, 
> %ymm\[0-9]\+" 2 } } */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t%ymm\[0-9]\+, %zmm\[0-9]\+" } } 
> */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %zmm\[0-9]\+" } } */
> +
> +typedef _Float16 v16hf __attribute__((vector_size (32)));
> +typedef float v16sf __attribute__((vector_size (64)));
> +
> +v16sf
> +corge (v16hf x)
> +{
> +  return __builtin_convertvector (x, v16sf);
> +}
> +
> +v16hf
> +garply (v16sf x)
> +{
> +  return __builtin_convertvector (x, v16hf);
> +}
> +
> +v16sf
> +corge2 (v16hf *x)
> +{
> +  return __builtin_convertvector (*x, v16sf);
> +}
> +
> +v16hf
> +garply2 (v16sf *x)
> +{
> +  return __builtin_convertvector (*x, v16hf);
> +}
> --- a/gcc/testsuite/gcc.target/i386/pr121688-avx512fp16.c     2026-10-05 
> 19:01:27.064618766 +0200
> +++ b/gcc/testsuite/gcc.target/i386/pr121688-avx512fp16.c     2026-10-05 
> 19:19:21.943410238 +0200
> @@ -0,0 +1,17 @@
> +/* PR target/121688 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mavx512vl -mavx512fp16 -masm=att" } */
> +/* { dg-final { scan-assembler "\tvcvtps2phxx\t%xmm\[0-9]\+, %xmm\[0-9]\+" } 
> } */
> +/* { dg-final { scan-assembler "\tvcvtps2phxy\t%ymm\[0-9]\+, %xmm\[0-9]\+" } 
> } */
> +/* { dg-final { scan-assembler "\tvcvtps2phx\t%zmm\[0-9]\+, %ymm\[0-9]\+" } 
> } */
> +/* { dg-final { scan-assembler "\tvcvtps2phxx\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %xmm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtps2phxy\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %xmm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtps2phx\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %ymm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtph2psx\t%xmm\[0-9]\+, %xmm\[0-9]\+" } 
> } */
> +/* { dg-final { scan-assembler "\tvcvtph2psx\t%xmm\[0-9]\+, %ymm\[0-9]\+" } 
> } */
> +/* { dg-final { scan-assembler "\tvcvtph2psx\t%ymm\[0-9]\+, %zmm\[0-9]\+" } 
> } */
> +/* { dg-final { scan-assembler "\tvcvtph2psx\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %xmm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtph2psx\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %ymm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtph2psx\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %zmm\[0-9]\+" } } */
> +
> +#include "pr121688-f16c.c"
> --- a/gcc/testsuite/gcc.target/i386/pr121688-avx512vl.c       2026-10-05 
> 19:01:30.240576846 +0200
> +++ b/gcc/testsuite/gcc.target/i386/pr121688-avx512vl.c       2026-10-05 
> 19:12:06.885173531 +0200
> @@ -0,0 +1,14 @@
> +/* PR target/121688 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mno-f16c -mavx512vl -mno-avx512fp16 -masm=att" } */
> +/* { dg-final { scan-assembler-times "\tvcvtps2ph\t\\\$4, %xmm\[0-9]\+, 
> %xmm\[0-9]\+" 2 } } */
> +/* { dg-final { scan-assembler-times "\tvcvtps2ph\t\\\$4, %ymm\[0-9]\+, 
> %xmm\[0-9]\+" 2 } } */
> +/* { dg-final { scan-assembler-times "\tvcvtps2ph\t\\\$4, %zmm\[0-9]\+, 
> %ymm\[0-9]\+" 2 } } */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t%xmm\[0-9]\+, %xmm\[0-9]\+" } } 
> */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t%xmm\[0-9]\+, %ymm\[0-9]\+" } } 
> */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t%ymm\[0-9]\+, %zmm\[0-9]\+" } } 
> */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %xmm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %ymm\[0-9]\+" } } */
> +/* { dg-final { scan-assembler "\tvcvtph2ps\t\\\(%\[re]\[a-z0-9]\+\\\), 
> %zmm\[0-9]\+" } } */
> +
> +#include "pr121688-f16c.c"
>
>       Jakub

Reply via email to