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=

Reply via email to