https://gcc.gnu.org/g:534545f5e693f208fe206be1be7a4df72bf08333
commit 534545f5e693f208fe206be1be7a4df72bf08333 Author: Michael Meissner <[email protected]> Date: Fri Sep 4 22:42:34 2026 -0400 Add -mfloat16-convert; Improve bf to sf/df on power8/power9 2026-09-04 Michael Meissner <[email protected]> gcc/ * config/rs6000/float16.md (extendbf<mode>2): Convert to be a define_expand, and handle conversions on power8/power9 systems. (extendbfsf2_sw): New insn. (extendbfsf2_sw_memory): Likewise. (extendbfdf2_sw): Likewise. (extendbf<mode>2_hw): Rename from extendbf<mode>2. * config/rs6000/rs6000-call.cc (rs6000_promote_function_mode): Only do argument conversions if -mfloat16-convert. (rs6000_promote_function_mode_convert): Likewise. * config/rs6000/rs6000.opt (-mfloat16-convert): New option. Diff: --- gcc/config/rs6000/float16.md | 128 ++++++++++++++++++++++++++++++++++++++- gcc/config/rs6000/rs6000-call.cc | 5 +- gcc/config/rs6000/rs6000.opt | 4 ++ 3 files changed, 133 insertions(+), 4 deletions(-) diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md index 461369b821e6..114d5bf576a5 100644 --- a/gcc/config/rs6000/float16.md +++ b/gcc/config/rs6000/float16.md @@ -232,12 +232,136 @@ "xscvdphp %x0,%x1" [(set_attr "type" "fpsimple")]) -;; Convert BFmode to SFmode/DFmode. + +;; Convert BFmode to either SFmode or DFmode. +(define_expand "extendbf<mode>2" + [(set (match_operand:SFDF 0 "register_operand") + (float_extend:SFDF + (match_operand:BF 1 "register_operand")))] + "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT" +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + + if (TARGET_BFLOAT16_HW) + emit_insn (gen_extendbf<mode>2_hw (op0, op1)); + + else if (<MODE>mode == SFmode) + emit_insn (gen_extendbfsf2_sw (op0, op1)); + + else + emit_insn (gen_extendbfdf2_sw (op0, op1)); + + DONE; +}) + +;; Convert BFmode to SFmode via software. +;; BFmode format is the same as SFmode with the bottom 8 bits zero. On +;; 64-bit systems possibly combine the 8 bit shift to get SFmode and +;; the 32 bit shift to use xcvspdpn. +(define_insn_and_split "extendbfsf2_sw" + [(set (match_operand:SF 0 "gpc_reg_operand" "=wa,?r") + (float_extend:SF + (match_operand:BF 1 "int_reg_operand" "r,r"))) + (match_scratch:DI 2 "=r,X")] + "TARGET_FLOAT16 && !TARGET_BFLOAT16_HW && TARGET_DIRECT_MOVE_64BIT" + "#" + "&& reload_completed" + [(pc)] +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + rtx op2 = operands[2]; + + if (int_reg_operand (op0, SFmode)) + { + rtx op1_di = gen_rtx_REG (DImode, reg_or_subregno (op1)); + + /* Do the convert in GPR using the SFmode memory format. */ + rtx op0_di = gen_rtx_REG (DImode, reg_or_subregno (op0)); + + emit_insn (gen_ashldi3 (op0_di, op1_di, GEN_INT (8))); + } + + else + { + /* Do the shift in the GPR and then convert it to a VSX register. */ + rtx op1_di = gen_rtx_REG (DImode, reg_or_subregno (op1)); + + /* Combine shifting 8 bits left to convert to SFmode, and then + shifting those bits left 32 bits to generate xscvspdpn. */ + emit_insn (gen_ashldi3 (op2, op1_di, GEN_INT (40))); + + /* Convert SFmode memory format to SFmode register format (DFmode). */ + emit_insn (gen_p8_mtvsrd_sf (op0, op2)); + emit_insn (gen_vsx_xscvspdpn_directmove (op0, op0)); + } + + DONE; +} + [(set_attr "type" "fpsimple,shift") + (set_attr "length" "12,*")]) + +(define_insn_and_split "extendbfsf2_sw_memory" + [(set (match_operand:SF 0 "memory_operand" "=m") + (float_extend:SF + (match_operand:BF 1 "int_reg_operand" "r"))) + (match_scratch:DI 2 "=r")] + "TARGET_FLOAT16 && !TARGET_BFLOAT16_HW" + "#" + "&& reload_completed" + [(pc)] +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + rtx op2 = operands[2]; + rtx op1_di = gen_rtx_REG (DImode, reg_or_subregno (op1)); + rtx op2_sf = gen_rtx_REG (SFmode, reg_or_subregno (op2)); + + /* Do the convert in GPR using the SFmode memory format. */ + emit_insn (gen_ashldi3 (op2, op1_di, GEN_INT (8))); + emit_move_insn (op0, op2_sf); + DONE; +} + [(set_attr "type" "store") + (set_attr "length" "8")]) + +;; Convert BFmode to DFmode via software on 64-bit systems. +;; BFmode format is the same as SFmode with the bottom 8 bits zero. +;; First convert to SFmode and then convert that to DFmode. +(define_insn_and_split "extendbfdf2_sw" + [(set (match_operand:DF 0 "vsx_register_operand" "=wa") + (float_extend:DF + (match_operand:BF 1 "int_reg_operand" "r"))) + (match_scratch:DI 2 "=r")] + "TARGET_FLOAT16 && !TARGET_BFLOAT16_HW && TARGET_DIRECT_MOVE_64BIT" + "#" + "&& reload_completed" + [(pc)] +{ + rtx op0_sf = gen_rtx_REG (SFmode, reg_or_subregno (operands[0])); + rtx op1_di = gen_rtx_REG (DImode, reg_or_subregno (operands[1])); + rtx op2_di = operands[2]; + + /* Combine shifting 8 bits left to convert to SFmode, and then + shifting those bits left 32 bits to generate xscvspdpn. */ + emit_insn (gen_ashldi3 (op2_di, op1_di, GEN_INT (40))); + + /* Convert SFmode to DFmode. */ + emit_insn (gen_p8_mtvsrd_sf (op0_sf, op2_di)); + emit_insn (gen_vsx_xscvspdpn_directmove (op0_sf, op0_sf)); + DONE; +} + [(set_attr "type" "fpsimple") + (set_attr "length" "12")]) + +;; Convert BFmode to SFmode/DFmode via hardware. ;; 3 instructions are generated: ;; XXSPLTW -- duplicate BFmode into all even elements ;; XVCVBF16SPN -- convert even BFmode elements to SFmode ;; XSCVSPNDP -- convert memory format of SFmode to DFmode. -(define_insn_and_split "extendbf<mode>2" + +(define_insn_and_split "extendbf<mode>2_hw" [(set (match_operand:SFDF 0 "vsx_register_operand" "=wa") (float_extend:SFDF (match_operand:BF 1 "vsx_register_operand" "v"))) diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc index 9460d4fb49ac..4b6445cdef14 100644 --- a/gcc/config/rs6000/rs6000-call.cc +++ b/gcc/config/rs6000/rs6000-call.cc @@ -723,7 +723,7 @@ rs6000_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, int *punsignedp ATTRIBUTE_UNUSED, const_tree, int for_return) { - if (FP16_SCALAR_MODE_P (mode) && !for_return) + if (FP16_SCALAR_MODE_P (mode) && !for_return && TARGET_FLOAT16_CONVERT) return SFmode; if (GET_MODE_CLASS (mode) == MODE_INT @@ -741,7 +741,8 @@ rs6000_promote_function_mode_convert (machine_mode new_mode, rtx decl_rtl, int unsignedp) { - if (FP16_SCALAR_MODE_P (new_mode) || FP16_SCALAR_MODE_P (old_mode)) + if (TARGET_FLOAT16_CONVERT + && (FP16_SCALAR_MODE_P (new_mode) || FP16_SCALAR_MODE_P (old_mode))) return convert_to_mode (new_mode, decl_rtl, unsignedp); return NULL_RTX; diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt index 28f679ff69c7..b25ef6db84b3 100644 --- a/gcc/config/rs6000/rs6000.opt +++ b/gcc/config/rs6000/rs6000.opt @@ -646,6 +646,10 @@ mfloat16 Target Mask(FLOAT16) Var(rs6000_isa_flags) Enable or disable 16-bit floating point. +mfloat16-convert +Target Undocumented Var(TARGET_FLOAT16_CONVERT) Init(0) Save +Pass and return 16-bit floating point as double. + ; Documented parameters -param=rs6000-vect-unroll-limit=
