https://gcc.gnu.org/g:3b68e561e5e01951e0e1c4075b77055f6403c673
commit 3b68e561e5e01951e0e1c4075b77055f6403c673 Author: Michael Meissner <[email protected]> Date: Thu Oct 29 21:59:22 2026 -0400 Add conversions between 16-bit floating point and other scalar modes. This patch adds conversions between 16-bit floating point and other scalar modes, by converting the first mode to double, and then converting that double to the second mode. This patch also adds support for converting between 128-bit integers and 16-bit floating point using the IEEE 128-bit floating on power10 systems. 2026-10-29 Michael Meissner <[email protected]> gcc/ * config/rs6000/float16.md (FP16_FLOAT_CONVERT): New mode iterator. (floatti<mode>2): New insn to convert between 128-bit integers and 16-bit floating point. (floatunsti<mode>2): Likewise. (fix_trunc<mode>ti2): Likewise. (fixuns_trunc<mode>ti2): Likewise. (extend<FP16_HW:mode><FP16_FLOAT_CONVERT:mode>2): New insns to convert between the 2 16-bit floating point modes and other floating point scalars other than SFmode/DFmode by converting first to DFmode. (trunc<FP16_FLOAT_CONVERT:mode><FP16_HW:mode>2): Likewise. (fix_trunc<FP16_HW:mode><GPR:mode>): New insns to convert beween the 2 16-bit floating point modes and signed/unsigned integers. (fixuns_trunc<FP16_HW:mode><GPR:mode>2): Likewise. (float<GPR:mode><FP16_HW:mode>2): Likewise. (floatuns<GPR:mode><FP16_HW:mode>2): Likewise. Diff: --- gcc/config/rs6000/float16.md | 205 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md index 62f5403ee42e..3206b0bbc7c9 100644 --- a/gcc/config/rs6000/float16.md +++ b/gcc/config/rs6000/float16.md @@ -34,6 +34,10 @@ (define_mode_iterator VFP16_HW [(V8BF "TARGET_BFLOAT16_HW") (V8HF "TARGET_FLOAT16_HW")]) +;; Mode iterator for floating point modes other than SF/DFmode that we +;; convert to/from _Float16 (HFmode) via DFmode. +(define_mode_iterator FP16_FLOAT_CONVERT [TF KF IF SD DD TD]) + ;; Mode attribute giving the instruction to convert the even ;; V8HFmode or V8BFmode elements to V4SFmode (define_mode_attr cvt_fp16_to_v4sf [(BF "xvcvbf16spn") @@ -355,6 +359,127 @@ "xscvdpspn %x0,%x1" [(set_attr "type" "fp")]) + +;; Convert 128-bit integers to 16-bit floating point if IEEE 128-bit +;; floating point is available by first using a conversion to IEEE +;; 128-bit, then converting that to double, and finally converting it +;; to 16-bit floating point. + +(define_expand "floatti<mode>2" + [(use (match_operand:FP16 0 "vsx_register_operand")) + (use (match_operand:TI 1 "altivec_register_operand"))] + "TARGET_POWER10 && TARGET_FLOAT128_HW && can_create_pseudo_p ()" +{ + rtx tmp_df = gen_reg_rtx (DFmode); + + if (FLOAT128_IEEE_P (TFmode)) + { + rtx tmp_tf = gen_reg_rtx (TFmode); + emit_insn (gen_floattitf2 (tmp_tf, operands[1])); + emit_insn (gen_trunctfdf2 (tmp_df, tmp_tf)); + } + + else if (FLOAT128_IEEE_P (KFmode)) + { + rtx tmp_kf = gen_reg_rtx (KFmode); + emit_insn (gen_floattikf2 (tmp_kf, operands[1])); + emit_insn (gen_trunckfdf2 (tmp_df, tmp_kf)); + } + + else + gcc_unreachable (); + + emit_insn (gen_truncdf<mode>2 (operands[0], tmp_df)); + DONE; +}) + +(define_expand "floatunsti<mode>2" + [(use (match_operand:FP16 0 "vsx_register_operand")) + (use (match_operand:TI 1 "altivec_register_operand"))] + "TARGET_POWER10 && TARGET_FLOAT128_HW && can_create_pseudo_p ()" +{ + rtx tmp_df = gen_reg_rtx (DFmode); + + if (FLOAT128_IEEE_P (TFmode)) + { + rtx tmp_tf = gen_reg_rtx (TFmode); + emit_insn (gen_floatunstitf2 (tmp_tf, operands[1])); + emit_insn (gen_trunctfdf2 (tmp_df, tmp_tf)); + } + + else if (FLOAT128_IEEE_P (KFmode)) + { + rtx tmp_kf = gen_reg_rtx (KFmode); + emit_insn (gen_floatunstikf2 (tmp_kf, operands[1])); + emit_insn (gen_trunckfdf2 (tmp_df, tmp_kf)); + } + + else + gcc_unreachable (); + + emit_insn (gen_truncdf<mode>2 (operands[0], tmp_df)); + DONE; +}) + +;; Convert 16-bit floating point to 128-bit integers if IEEE 128-bit +;; floating point is available by first using a conversion to double, +;; then to IEEE 128-bit, and finally to 128-bit integers. + +(define_expand "fix_trunc<mode>ti2" + [(use (match_operand:TI 0 "altivec_register_operand")) + (use (match_operand:FP16 1 "vsx_register_operand"))] + "TARGET_POWER10 && TARGET_FLOAT128_HW && can_create_pseudo_p ()" +{ + rtx tmp_df = gen_reg_rtx (DFmode); + + emit_insn (gen_extend<mode>df2 (tmp_df, operands[1])); + if (FLOAT128_IEEE_P (TFmode)) + { + rtx tmp_tf = gen_reg_rtx (TFmode); + emit_insn (gen_extenddftf2 (tmp_tf, tmp_df)); + emit_insn (gen_fix_trunctfti2 (operands[0], tmp_tf)); + } + + else if (FLOAT128_IEEE_P (KFmode)) + { + rtx tmp_kf = gen_reg_rtx (KFmode); + emit_insn (gen_extenddfkf2 (tmp_kf, tmp_df)); + emit_insn (gen_fix_trunckfti2 (operands[0], tmp_kf)); + } + + else + gcc_unreachable (); + + DONE; +}) + +(define_expand "fixuns_trunc<mode>ti2" + [(use (match_operand:TI 0 "altivec_register_operand")) + (use (match_operand:FP16 1 "vsx_register_operand"))] + "TARGET_POWER10 && TARGET_FLOAT128_HW && can_create_pseudo_p ()" +{ + rtx tmp_df = gen_reg_rtx (DFmode); + + emit_insn (gen_extend<mode>df2 (tmp_df, operands[1])); + if (FLOAT128_IEEE_P (TFmode)) + { + rtx tmp_tf = gen_reg_rtx (TFmode); + emit_insn (gen_extenddftf2 (tmp_tf, tmp_df)); + emit_insn (gen_fixuns_trunctfti2 (operands[0], tmp_tf)); + } + + else if (FLOAT128_IEEE_P (KFmode)) + { + rtx tmp_kf = gen_reg_rtx (KFmode); + emit_insn (gen_extenddfkf2 (tmp_kf, tmp_df)); + emit_insn (gen_fixuns_trunckfti2 (operands[0], tmp_kf)); + } + + else + gcc_unreachable (); + + DONE; +}) ;; Convert the even elements of a vector 16-bit floating point to ;; V4SFmode. Deal with little endian vs. big endian element ordering @@ -582,3 +707,83 @@ } [(set_attr "length" "12") (set_attr "type" "vecfloat")]) + +;; Convert between HFmode/BFmode and 128-bit binary floating point and +;; decimal floating point types. We use convert_move since some of the +;; types might not have valid RTX expanders. We use DFmode as the +;; intermediate conversion destination. + +(define_expand "extend<FP16_HW:mode><FP16_FLOAT_CONVERT:mode>2" + [(use (match_operand:FP16_FLOAT_CONVERT 0 "vsx_register_operand")) + (use (match_operand:FP16_HW 1 "vsx_register_operand"))] + "can_create_pseudo_p ()" +{ + rtx df_tmp = gen_reg_rtx (DFmode); + + convert_move (df_tmp, operands[1], 0); + convert_move (operands[0], df_tmp, 0); + DONE; +}) + +(define_expand "trunc<FP16_FLOAT_CONVERT:mode><FP16_HW:mode>2" + [(use (match_operand:FP16_HW 0 "vsx_register_operand")) + (use (match_operand:FP16_FLOAT_CONVERT 1 "vsx_register_operand"))] + "can_create_pseudo_p ()" +{ + rtx df_tmp = gen_reg_rtx (DFmode); + + convert_move (df_tmp, operands[1], 0); + convert_move (operands[0], df_tmp, 0); + DONE; +}) + +;; Convert 16-bit floating point to integers +(define_expand "fix_trunc<FP16:mode><GPR:mode>2" + [(use (match_operand:GPR 0 "vsx_register_operand")) + (use (match_operand:FP16 1 "vsx_register_operand"))] + "can_create_pseudo_p ()" +{ + rtx df_tmp = gen_reg_rtx (DFmode); + + convert_move (df_tmp, operands[1], 0); + emit_insn (gen_fix_truncdf<GPR:mode>2 (operands[0], df_tmp)); + + DONE; +}) + +(define_expand "fixuns_trunc<FP16:mode><GPR:mode>2" + [(use (match_operand:GPR 0 "vsx_register_operand")) + (use (match_operand:FP16 1 "vsx_register_operand"))] + "can_create_pseudo_p ()" +{ + rtx df_tmp = gen_reg_rtx (DFmode); + + convert_move (df_tmp, operands[1], 0); + emit_insn (gen_fixuns_truncdf<GPR:mode>2 (operands[0], df_tmp)); + + DONE; +}) + +;; Convert integers to 16-bit floating point +(define_expand "float<GPR:mode><FP16:mode>2" + [(use (match_operand:FP16 0 "vsx_register_operand")) + (use (match_operand:GPR 1 "vsx_register_operand"))] + "can_create_pseudo_p ()" +{ + rtx df_tmp = gen_reg_rtx (DFmode); + + emit_insn (gen_float<GPR:mode>df2 (df_tmp, operands[1])); + convert_move (operands[0], df_tmp, 0); + DONE; +}) + +(define_expand "floatuns<GPR:mode><FP16:mode>2" + [(use (match_operand:FP16 0 "vsx_register_operand")) + (use (match_operand:GPR 1 "vsx_register_operand"))] + "can_create_pseudo_p ()" +{ + rtx df_tmp = gen_reg_rtx (DFmode); + emit_insn (gen_floatuns<GPR:mode>df2 (df_tmp, operands[1])); + convert_move (operands[0], df_tmp, 0); + DONE; +})
