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