https://gcc.gnu.org/g:dfba6b52f5cd44d7bb444085a2b95c9809137c4d

commit r17-5104-gdfba6b52f5cd44d7bb444085a2b95c9809137c4d
Author: Jakub Jelinek <[email protected]>
Date:   Tue Oct 13 08:53:19 2026 +0200

    i386: Enable extendvNhfvNsf2 and truncvNsfvNhf2 for N 4, 8, 16 even for 
F16C or AVX512VL [PR121688]
    
    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).
    
    2026-10-13  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.
    
    Reviewed-by: Hongtao Liu <[email protected]>

Diff:
---
 gcc/config/i386/sse.md                             | 88 ++++++++++++++++++--
 gcc/testsuite/gcc.target/i386/pr121688-avx512f.c   | 33 ++++++++
 .../gcc.target/i386/pr121688-avx512fp16.c          | 17 ++++
 gcc/testsuite/gcc.target/i386/pr121688-avx512vl.c  | 14 ++++
 gcc/testsuite/gcc.target/i386/pr121688-f16c.c      | 95 ++++++++++++++++++++++
 5 files changed, 238 insertions(+), 9 deletions(-)

diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index c1e8b2562958..3a8ecfa3e395 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -858,7 +858,7 @@
 
 
 (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 @@
    (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 "TARGET_AVX512F")
+   (V8SF "TARGET_AVX512VL || (TARGET_F16C && !TARGET_AVX512FP16)")])
 
 (define_mode_iterator VF48_128
   [V2DF V4SF])
@@ -8504,7 +8505,27 @@
   [(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
+      || (<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 +8541,18 @@
   [(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 +8560,12 @@
                 (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 +8633,35 @@
   [(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
+      || (<MODE>mode == V8SFmode && !TARGET_AVX512VL))
+    {
+      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 +8676,18 @@
 (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;
 })
@@ -30784,7 +30854,7 @@
    (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))]
diff --git a/gcc/testsuite/gcc.target/i386/pr121688-avx512f.c 
b/gcc/testsuite/gcc.target/i386/pr121688-avx512f.c
new file mode 100644
index 000000000000..0962136f781e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr121688-avx512f.c
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr121688-avx512fp16.c 
b/gcc/testsuite/gcc.target/i386/pr121688-avx512fp16.c
new file mode 100644
index 000000000000..57bbd23f1032
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr121688-avx512fp16.c
@@ -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"
diff --git a/gcc/testsuite/gcc.target/i386/pr121688-avx512vl.c 
b/gcc/testsuite/gcc.target/i386/pr121688-avx512vl.c
new file mode 100644
index 000000000000..9183f99d2767
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr121688-avx512vl.c
@@ -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"
diff --git a/gcc/testsuite/gcc.target/i386/pr121688-f16c.c 
b/gcc/testsuite/gcc.target/i386/pr121688-f16c.c
new file mode 100644
index 000000000000..760676671ecb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr121688-f16c.c
@@ -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

Reply via email to