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
