https://gcc.gnu.org/g:6c02643adf3a3fdb24b321e4826f214a1964a2a1

commit 6c02643adf3a3fdb24b321e4826f214a1964a2a1
Author: Michael Meissner <[email protected]>
Date:   Tue Sep 15 00:44:24 2026 -0400

    Float16 conversion functions pass 16-bit values in GPRs.
    
    2026-09-14  Michael Meissner  <[email protected]>
    
    gcc/
    
            * config/rs6000/float16.md (FP16_CVT): New iterator.
            (extendbf<mode>2): Use TARGET_BFLOAT16_CVT.
            (extendbf<mode>2_memory): Likewise.
            (fix_trunc<FP16_HW:mode><GPR:mode>2): Go back to merged insns for 
BFmode
            and HFmode.
            (fixuns_trunc<FP16_HW:mode><GPR:mode>2): Likewise.
            * config/rs6000/rs6000-call.cc (USE_FP_FOR_ARG_P): If
            -mfloat16-convert-in-gprs pass/return 16-bit floating point values 
for
            conversion functions.
            (is_float16_convert_function): New helper function.
            (mark_float16_convert_function): Likewise.
            (init_cumulative_args): Add support for -mfloat16-convert-in-gprs.  
If
            -mdebug=arg, print the function name.
            * config/rs6000/rs6000-protos.h (is_float16_convert_function): New
            declaration.
            (mark_float16_convert_function): Likewise.
            * config/rs6000/rs6000.cc (init_float16): Mark 16-bit floating point
            conversion functions.
            (rs6000_init_libfuncs): Likewise.
            * config/rs6000/rs6000.h (TARGET_BFLOAT16_CVT): New macro.
            (struct rs6000_args): Add float16_convert field.
            * config/rs6000/rs6000.opt (-mfloat16-convert-in-gprs): New option.

Diff:
---
 gcc/config/rs6000/float16.md      | 54 +++++++++----------------
 gcc/config/rs6000/rs6000-call.cc  | 50 ++++++++++++++++++++---
 gcc/config/rs6000/rs6000-protos.h |  2 +
 gcc/config/rs6000/rs6000.cc       | 84 +++++++++++++++++++++++++++++++++++++++
 gcc/config/rs6000/rs6000.h        |  7 ++++
 gcc/config/rs6000/rs6000.opt      |  4 ++
 6 files changed, 160 insertions(+), 41 deletions(-)

diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md
index fe6630028884..667a11e5d295 100644
--- a/gcc/config/rs6000/float16.md
+++ b/gcc/config/rs6000/float16.md
@@ -34,6 +34,12 @@
 (define_mode_iterator VFP16_HW [(V8BF "TARGET_BFLOAT16_HW")
                                (V8HF "TARGET_FLOAT16_HW")])
 
+;; Mode iterator for conversions from 16-bit floating point.
+;; Unlike FP16_HW, this specifically allows converting from
+;; BFmode even if we don't have the bfloat16 conversion.
+(define_mode_iterator FP16_CVT [(BF "TARGET_BFLOAT16_CVT")
+                               (HF "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])
@@ -250,7 +256,7 @@
   [(set (match_operand:SFDF 0 "vsx_register_operand")
        (float_extend:SFDF
         (match_operand:BF 1 "gpc_reg_operand")))]
-  "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT && TARGET_BFLOAT16_CONVERT"
+  "TARGET_BFLOAT16_CVT"
 {
   if (TARGET_BFLOAT16_HW && TARGET_BFLOAT16_P10_CONVERT)
     emit_insn (gen_extendbf<mode>2_p10 (operands[0], operands[1]));
@@ -303,7 +309,7 @@
         (match_operand:BF 1 "int_reg_operand" "r")))
    (clobber (match_scratch:V4SF 2 "=wa"))
    (clobber (match_scratch:DI 3 "=r"))]
-  "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT && TARGET_BFLOAT16_CONVERT
+  "TARGET_BFLOAT16_CVT
    && (!TARGET_BFLOAT16_HW || !TARGET_BFLOAT16_P10_CONVERT)"
   "#"
   "&& reload_completed"
@@ -705,54 +711,30 @@
   DONE;
 })
 
-;; Convert 16-bit floating point modes to integers
-(define_expand "fix_trunchf<mode>2"
+(define_expand "fix_trunc<FP16_HW:mode><GPR:mode>2"
   [(set (match_operand:GPR 0 "vsx_register_operand")
        (fix:GPR
-        (match_operand:HF 1 "vsx_register_operand")))]
-  "TARGET_FLOAT16_HW"
+        (match_operand:FP16_HW 1 "vsx_register_operand")))]
+  ""
 {
   rtx df_tmp = gen_reg_rtx (DFmode);
-  emit_insn (gen_extendhfdf2 (df_tmp, operands[1]));
-  emit_insn (gen_fix_truncdf<mode>2 (operands[0], df_tmp));
+  emit_insn (gen_extend<FP16_HW:mode>df2 (df_tmp, operands[1]));
+  emit_insn (gen_fix_truncdf<GPR:mode>2 (operands[0], df_tmp));
   DONE;
 })
 
-(define_expand "fixuns_trunchf<mode>2"
+(define_expand "fixuns_trunc<FP16_HW:mode><GPR:mode>2"
   [(set (match_operand:GPR 0 "vsx_register_operand")
        (unsigned_fix:GPR
-        (match_operand:HF 1 "vsx_register_operand")))]
-  "TARGET_FLOAT16_HW"
-{
-  rtx df_tmp = gen_reg_rtx (DFmode);
-  emit_insn (gen_extendhfdf2 (df_tmp, operands[1]));
-  emit_insn (gen_fixuns_truncdf<mode>2 (operands[0], df_tmp));
-  DONE;
-})
-
-(define_expand "fix_truncbf<mode>2"
-  [(set (match_operand:GPR 0 "vsx_register_operand")
-       (fix:GPR
-        (match_operand:BF 1 "vsx_register_operand")))]
-  "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT && TARGET_BFLOAT16_CONVERT"
+        (match_operand:FP16_HW 1 "vsx_register_operand")))]
+  ""
 {
   rtx df_tmp = gen_reg_rtx (DFmode);
-  emit_insn (gen_extendbfdf2 (df_tmp, operands[1]));
-  emit_insn (gen_fix_truncdf<mode>2 (operands[0], df_tmp));
+  emit_insn (gen_extend<FP16_HW:mode>df2 (df_tmp, operands[1]));
+  emit_insn (gen_fixuns_truncdf<GPR:mode>2 (operands[0], df_tmp));
   DONE;
 })
 
-(define_expand "fixuns_truncbf<GPR:mode>2"
-  [(set (match_operand:GPR 0 "vsx_register_operand")
-       (unsigned_fix:GPR
-        (match_operand:BF 1 "vsx_register_operand")))]
-  "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT && TARGET_BFLOAT16_CONVERT"
-{
-  rtx df_tmp = gen_reg_rtx (DFmode);
-  emit_insn (gen_extendbfdf2 (df_tmp, operands[1]));
-  emit_insn (gen_fixuns_truncdf<mode>2 (operands[0], df_tmp));
-  DONE;
-})
 
 ;; Negate 16-bit floating point by XOR with -0.0.
 
diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc
index e11a3c10c3af..47dcdd779bb8 100644
--- a/gcc/config/rs6000/rs6000-call.cc
+++ b/gcc/config/rs6000/rs6000-call.cc
@@ -81,10 +81,12 @@
 #define TARGET_NO_PROTOTYPE 0
 #endif
 
-/* Nonzero if we can use a floating-point register to pass this arg.  */
-#define USE_FP_FOR_ARG_P(CUM,MODE)             \
-  (SCALAR_FLOAT_MODE_NOT_VECTOR_P (MODE)               \
-   && (CUM)->fregno <= FP_ARG_MAX_REG          \
+/* Nonzero if we can use a floating-point register to pass this arg.  16-bit
+   floating point arguments to library functions are passed as ints.  */
+#define USE_FP_FOR_ARG_P(CUM,MODE)                                     \
+  (SCALAR_FLOAT_MODE_NOT_VECTOR_P (MODE)                               \
+   && !(CUM)->float16_convert                                          \
+   && (CUM)->fregno <= FP_ARG_MAX_REG                                  \
    && TARGET_HARD_FLOAT)
 
 /* Nonzero if we can use an AltiVec register to pass this arg.  */
@@ -558,6 +560,30 @@ call_ABI_of_interest (tree fndecl)
 }
 #endif
 
+/* For 16-bit floating point, mark the identifier of the conversion functions
+   so they pass the HFmode and BFmode in an integer register rather than a
+   floating point register.  Thus if HFmode/BFmode are converted to DFmode for
+   passing and returning values, we can do the conversion on machines that
+   don't have the conversions.  */
+
+bool
+is_float16_convert_function (const char *name)
+{
+  if (!name)
+    return false;
+
+  tree id = get_identifier (name);
+  return id->base.default_def_flag;
+}
+
+void
+mark_float16_convert_function (char *name)
+{
+  tree id = get_identifier (name);
+  id->base.default_def_flag = 1;
+  fprintf (stderr, "=== %s ===\n", name);
+}
+
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
    For a library call, FNTYPE is 0 and RETURN_MODE the return value mode.
@@ -567,7 +593,7 @@ call_ABI_of_interest (tree fndecl)
 
 void
 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
-                     rtx libname ATTRIBUTE_UNUSED, int incoming,
+                     rtx libname, int incoming,
                      int libcall, int n_named_args,
                      tree fndecl,
                      machine_mode return_mode ATTRIBUTE_UNUSED)
@@ -589,6 +615,14 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
   if (incoming || cum->prototype)
     cum->nargs_prototype = n_named_args;
 
+  if (TARGET_FLOAT16 && TARGET_FLOAT16_CONVERT_IN_GPRS && libname
+      && SYMBOL_REF_P (libname))
+    {
+      const char *name = XSTR (libname, 0);
+      if (name)
+       cum->float16_convert = is_float16_convert_function (name);
+    }
+
   /* Check for a longcall attribute.  */
   if ((!fntype && rs6000_default_long_calls)
       || (fntype
@@ -630,6 +664,12 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
       if (cum->call_cookie & CALL_LONG)
        fprintf (stderr, " longcall,");
 
+      if (cum->float16_convert)
+       fprintf (stderr, " fp16-cvt,");
+
+      if (libname)
+       fprintf (stderr, " name=%s,", XSTR (libname, 0));
+
       fprintf (stderr, " proto = %d, nargs = %d\n",
               cum->prototype, cum->nargs_prototype);
     }
diff --git a/gcc/config/rs6000/rs6000-protos.h 
b/gcc/config/rs6000/rs6000-protos.h
index 3691b522f42c..59cad4cc2165 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -297,6 +297,8 @@ extern void rs6000_xcoff_asm_output_aligned_decl_common 
(FILE *, tree,
                                                         unsigned int);
 extern void rs6000_elf_declare_function_name (FILE *, const char *, tree);
 extern bool rs6000_elf_in_small_data_p (const_tree);
+extern bool is_float16_convert_function (const char *);
+extern void mark_float16_convert_function (char *);
 
 #endif /* TREE_CODE */
 
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 8efd0e7c9991..e274b5c22706 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -11828,6 +11828,86 @@ init_float128_ieee (machine_mode mode)
     }
 }
 
+/* For 16-bit floating point, mark the identifier of the conversion functions
+   so they pass/register the HFmode and BFmode in a GPR register rather than a
+   floating point register.  Thus if HFmode/BFmode are converted to DFmode for
+   passing and returning values, we can do the conversion on machines that
+   don't have the conversions.  */
+
+static void
+init_float16 (void)
+{
+  char fname[80];
+
+  /* Map mode to a string.  */
+  struct mode_string  {
+    const enum machine_mode mode;
+    const char *const name;
+  };
+
+  const static struct mode_string fp16_modes[] = {
+    { E_BFmode, "bf" },
+    { E_HFmode, "hf" },
+  };
+
+  const static struct mode_string fp_modes[] = {
+    { E_SFmode, "sf" },
+    { E_DFmode, "df" },
+  };
+
+  const static struct mode_string int_modes[] = {
+    { E_SImode, "si" },
+    { E_DImode, "di" },
+  };
+
+  for (size_t i = 0; i < ARRAY_SIZE (fp16_modes); i++)
+    {
+      enum machine_mode fp16_mode = fp16_modes[i].mode;
+      const char *fp16_name = fp16_modes[i].name;
+
+      /* Conversions between {SFmode,DFmode} <=> {BFmode,HFmode}.  */
+      for (size_t j = 0; j < ARRAY_SIZE (fp_modes); j++)
+       {
+         enum machine_mode fp_mode = fp_modes[j].mode;
+         const char *fp_name = fp_modes[j].name;
+
+         sprintf (fname, "__extend%s%s2_gpr", fp16_name, fp_name);
+         set_conv_libfunc (sext_optab, fp_mode, fp16_mode, fname);
+         mark_float16_convert_function (fname);
+
+         sprintf (fname, "__trunc%s%s2_gpr", fp_name, fp16_name);
+         set_conv_libfunc (trunc_optab, fp16_mode, fp_mode, fname);
+         mark_float16_convert_function (fname);
+       }
+
+      /* Conversions between {SImode,DImode} <=> {BFmode,HFmode}.  */
+      for (size_t j = 0; j < ARRAY_SIZE (int_modes); j++)
+       {
+         enum machine_mode int_mode = int_modes[j].mode;
+         const char *int_name = int_modes[j].name;
+
+         if (int_mode == SImode || TARGET_POWERPC64)
+           {
+             sprintf (fname, "__float%s%s2_gpr", int_name, fp16_name);
+             set_conv_libfunc (sfloat_optab, fp16_mode, int_mode, fname);
+             mark_float16_convert_function (fname);
+
+             sprintf (fname, "__floatuns%s%s2_gpr", int_name, fp16_name);
+             set_conv_libfunc (ufloat_optab, fp16_mode, int_mode, fname);
+             mark_float16_convert_function (fname);
+
+             sprintf (fname, "__fix_trunc%s%s2_gpr", fp16_name, int_name);
+             set_conv_libfunc (sfix_optab, int_mode, fp16_mode, fname);
+             mark_float16_convert_function (fname);
+
+             sprintf (fname, "__fixuns_trunc%s%s2_gpr", fp16_name, int_name);
+             set_conv_libfunc (ufix_optab, int_mode, fp16_mode, fname);
+             mark_float16_convert_function (fname);
+           }
+       }
+    }
+}
+
 static void
 rs6000_init_libfuncs (void)
 {
@@ -11848,6 +11928,10 @@ rs6000_init_libfuncs (void)
       else
        init_float128_ieee (TFmode);
     }
+
+  /* 16-bit float support functions.  */
+  if (TARGET_FLOAT16 && TARGET_FLOAT16_CONVERT_IN_GPRS)
+    init_float16 ();
 }
 
 /* Emit a potentially record-form instruction, setting DST from SRC.
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 9eb5ee802c79..d91b2a564998 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -355,6 +355,12 @@ extern const char *host_detect_local_cpu (int argc, const 
char **argv);
 #define TARGET_BFLOAT16_HW     (TARGET_FLOAT16 && TARGET_POWER10)
 #define TARGET_FLOAT16_HW      (TARGET_FLOAT16 && TARGET_P9_VECTOR)
 
+/* Mode iterator for conversions from 16-bit floating point.  Unlike
+   TARGET_BFLOAT16_HW, this specifically allows converting from BFmode even if
+   we don't have the bfloat16 conversion.  We do this conversion  */
+#define TARGET_BFLOAT16_CVT                                            \
+  (TARGET_FLOAT16 && TARGET_BFLOAT16_CONVERT && TARGET_P9_VECTOR)
+
 /* Do we have conversion support in hardware for the 16-bit floating point and
    also enable the 16-bit floating point vector optimizations?  */
 #define TARGET_BFLOAT16_HW_VECTOR                                      \
@@ -1515,6 +1521,7 @@ typedef struct rs6000_args
   int named;                   /* false for varargs params */
   int escapes;                 /* if function visible outside tu */
   int libcall;                 /* If this is a compiler generated call.  */
+  int float16_convert;         /* 16-bit float conversion function.  */
 } CUMULATIVE_ARGS;
 
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt
index 4538546f7e89..da13ad4d1a8b 100644
--- a/gcc/config/rs6000/rs6000.opt
+++ b/gcc/config/rs6000/rs6000.opt
@@ -654,6 +654,10 @@ mbfloat16-p10-convert
 Target Undocumented Var(TARGET_BFLOAT16_P10_CONVERT) Init(1) Save
 Generate (do not generate) xvcvbf16spn to do __bf16 to float/double 
conversions.
 
+mfloat16-convert-in-gprs
+Target Undocumented Var(TARGET_FLOAT16_CONVERT_IN_GPRS) Init(1) Save
+Pass/return (do not pass/return) 16-it float conversions in GPR registers.
+
 ; Documented parameters
 
 -param=rs6000-vect-unroll-limit=

Reply via email to