https://gcc.gnu.org/g:f245584cd83dedbe8e6c570a2ee971136be9d93e

commit f245584cd83dedbe8e6c570a2ee971136be9d93e
Author: Michael Meissner <[email protected]>
Date:   Tue Sep 15 03:04:09 2026 -0400

    Add -mfloat16-convert-in-gprs.
    
    This patch adds an option to pass and return 16-bit floating values in GPRs
    rather than FPRs.
    
    2026-09-15  Michael Meissner  <[email protected]>
    
    gcc/
    
            * config/rs6000/rs6000-call.cc (USE_FP_FOR_ARG_P): Add support for
            -mfloat16-convert-in-gprs.
            (is_float16_convert_function): Likewise.
            (mark_float16_convert_function): Likewise.
            (init_cumulative_args): Likewise.
            * config/rs6000/rs6000-protos.h (is_float16_convert_function): 
Likewise.
            (mark_float16_convert_function): Likewise.
            * config/rs6000/rs6000.cc (init_float16): Likewise.
            (rs6000_init_libfuncs): Likewise.
            (rs6000_opt_vars): Likewise.
            * config/rs6000/rs6000.h (struct rs6000_args): Likewise.
            * config/rs6000/rs6000.opt (-mfloat16-convert-in-gprs): Likewise.

Diff:
---
 gcc/config/rs6000/rs6000-call.cc  | 50 +++++++++++++++++++---
 gcc/config/rs6000/rs6000-protos.h |  2 +
 gcc/config/rs6000/rs6000.cc       | 87 +++++++++++++++++++++++++++++++++++++++
 gcc/config/rs6000/rs6000.h        |  1 +
 gcc/config/rs6000/rs6000.opt      |  4 ++
 5 files changed, 139 insertions(+), 5 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc
index 790f86218870..c613304036ff 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.  */
@@ -581,6 +583,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.
@@ -590,7 +616,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)
@@ -612,6 +638,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
@@ -653,6 +687,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 6ccd766e5c9b..8df2333d5b3a 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -11837,6 +11837,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)
 {
@@ -11857,6 +11937,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.
@@ -25042,6 +25126,9 @@ static struct rs6000_opt_var const rs6000_opt_vars[] =
   { "speculate-indirect-jumps",
     offsetof (struct gcc_options, x_rs6000_speculate_indirect_jumps),
     offsetof (struct cl_target_option, x_rs6000_speculate_indirect_jumps), },
+  { "float16-convert-in-gprs",
+    offsetof (struct gcc_options, x_TARGET_FLOAT16_CONVERT_IN_GPRS),
+    offsetof (struct cl_target_option, x_TARGET_FLOAT16_CONVERT_IN_GPRS), },
 };
 
 /* Inner function to handle attribute((target("..."))) and #pragma GCC target
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 9eb5ee802c79..1d88e0a46df3 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1515,6 +1515,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 28f679ff69c7..231a5121f9e9 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-in-gprs
+Target Undocumented Var(TARGET_FLOAT16_CONVERT_IN_GPRS) Init(0) 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