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"
+{
+  if (!TARGET_AVX512FP16)
+    {
+      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)
+    {
+      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