https://gcc.gnu.org/g:12495dbddc79a516127edc2d98011a637f63f291

commit 12495dbddc79a516127edc2d98011a637f63f291
Author: Michael Meissner <[email protected]>
Date:   Sat Sep 26 03:36:03 2026 -0400

    Rewrite -mfloat16-gpr-convert support.
    
    2026-09-26  Michael Meissner  <[email protected]>
    
    gcc/
    
            * config/rs6000/rs6000-call.cc (FP16_USE_GPR): New macro.
            (USE_FP_FOR_ARG_P); Pass/return 16-bit floating values to compiler
            generated library functions in gprs if -mfloat16-gpr-convert.
            (is_float16_convert_function): Delete.
            (mark_float16_convert_function): Likewise.
            (init_cumulative_args): Don't set up the float16_convert field.  If
            -mdebug=arg, print whether this is a library call.
            * config/rs6000/rs6000-protos.h (is_float16_convert_function): 
Delete.
            (mark_float16_convert_function): Likewise.
            * config/rs6000/rs6000.cc (init_float16) Remove
            mark_float16_convert_function call.  Set up __truncbfhf2_gpr and
            __trunchfbf2_gpr.
            * config/rs6000/rs6000h (CUMULATIVE_ARGS): Delete float16_convert 
field.
    
    libgcc/
    
            * config/rs6000/pc-truncbfhf2.c: New file.
            * config/rs6000/pc-trunchfbf2.c: Likewise.
            * config/rs6000/spf-machine.h (__truncbfhf2_gpr): Add declaration.
            (__trunchfbf2_gpr): Likewise.
            * config/rs6000/t-float16 (both_fp16_*): Switch to using
            ppc-truncbfhf2.c and ppc-trunchfbf2.c.

Diff:
---
 gcc/config/rs6000/rs6000-call.cc      |  46 +++---------
 gcc/config/rs6000/rs6000-protos.h     |   2 -
 gcc/config/rs6000/rs6000.cc           |  19 +++--
 gcc/config/rs6000/rs6000.h            |   1 -
 libgcc/config/rs6000/ppc-truncbfhf2.c | 130 ++++++++++++++++++++++++++++++++++
 libgcc/config/rs6000/ppc-trunchfbf2.c |  96 +++++++++++++++++++++++++
 libgcc/config/rs6000/sfp-machine.h    |  16 +++--
 libgcc/config/rs6000/t-float16        |   4 +-
 8 files changed, 260 insertions(+), 54 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc
index 4d64996e6d15..e970f63f2f08 100644
--- a/gcc/config/rs6000/rs6000-call.cc
+++ b/gcc/config/rs6000/rs6000-call.cc
@@ -81,11 +81,16 @@
 #define TARGET_NO_PROTOTYPE 0
 #endif
 
+/* Whether we pass 16-bit floating point values in GPRs for library
+   calls.  */
+#define FP16_USE_GPR(MODE, LIBCALL)                                    \
+  (FP16_SCALAR_MODE_P (MODE) && TARGET_FLOAT16_GPR_CONVERT && LIBCALL)
+
 /* 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                                          \
+   && !FP16_USE_GPR (MODE, (CUM)->libcall)                             \
    && (CUM)->fregno <= FP_ARG_MAX_REG                                  \
    && TARGET_HARD_FLOAT)
 
@@ -583,31 +588,6 @@ 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;
-  if (TARGET_DEBUG_ARG)
-    fprintf (stderr, "Pass _Float16/__bf16 via GPRs: %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.
@@ -639,14 +619,6 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
   if (incoming || cum->prototype)
     cum->nargs_prototype = n_named_args;
 
-  if (TARGET_FLOAT16 && TARGET_FLOAT16_GPR_CONVERT && 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
@@ -688,12 +660,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));
 
+      if (libcall)
+       fprintf (stderr, " libcall,");
+
       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 59cad4cc2165..3691b522f42c 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -297,8 +297,6 @@ 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 cd2cce4ad99d..c1f75d4ac3aa 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -11883,11 +11883,9 @@ init_float16 (void)
 
          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}.  */
@@ -11900,19 +11898,28 @@ init_float16 (void)
            {
              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);
+           }
+       }
+
+      /* Conversions between the two 16-bit floating point formats.  */
+      for (size_t j = 0; j < ARRAY_SIZE (fp16_modes); j++)
+       {
+         enum machine_mode fp16_mode2 = fp16_modes[j].mode;
+         const char *fp16_name2 = fp16_modes[j].name;
+
+         if (fp16_mode != fp16_mode2)
+           {
+             sprintf (fname, "__trunc%s%s2_gpr", fp16_name, fp16_name2);
+             set_conv_libfunc (trunc_optab, fp16_mode2, fp16_mode, fname);
            }
        }
     }
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 1d88e0a46df3..9eb5ee802c79 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1515,7 +1515,6 @@ 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/libgcc/config/rs6000/ppc-truncbfhf2.c 
b/libgcc/config/rs6000/ppc-truncbfhf2.c
new file mode 100644
index 000000000000..ff660ad52e7d
--- /dev/null
+++ b/libgcc/config/rs6000/ppc-truncbfhf2.c
@@ -0,0 +1,130 @@
+/* Software floating-point emulation.
+   Truncate bfloat16 into IEEE half.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.
+
+   This is a clone of soft-fp/truncbfhf2.c for the PowerPC.
+
+   We provide an alternative version of the conversion that retunrs the HFtype
+   value as unsigned short.  This is to allow the calling sequence where
+   arguments are converted to the 32/64-bit scalar format.  If we don't have
+   the hardware support, we can't use the standard __trunc function.  */
+
+#include "soft-fp.h"
+#include "half.h"
+#include "brain.h"
+#include "single.h"
+
+/* BFtype and HFtype are unordered, neither is a superset or subset
+   of each other.  Convert BFtype to SFtype (lossless) and then
+   truncate to HFtype.  */
+
+/* BFtype passed in FPR, HFtype returned in FPR.  */
+HFtype
+__truncbfhf2 (BFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_H (A);
+  FP_DECL_S (B);
+  FP_DECL_B (R);
+  SFtype b;
+  HFtype r;
+
+  FP_INIT_ROUNDMODE;
+  /* Optimize BFtype to SFtype conversion to simple left shift
+     by 16 if possible, we don't need to raise exceptions on sNaN
+     here as the SFtype to HFtype truncation should do that too.  */
+  if (sizeof (BFtype) == 2
+      && sizeof (unsigned short) == 2
+      && sizeof (SFtype) == 4
+      && sizeof (unsigned int) == 4)
+    {
+      union { BFtype a; unsigned short b; } u1;
+      union { SFtype a; unsigned int b; } u2;
+      u1.a = a;
+      u2.b = (u1.b << 8) << 8;
+      b = u2.a;
+    }
+  else
+    {
+      FP_UNPACK_RAW_B (A, a);
+      FP_EXTEND (S, B, 1, 1, B, A);
+      FP_PACK_RAW_S (b, B);
+    }
+  FP_UNPACK_SEMIRAW_S (B, b);
+  FP_TRUNC (H, S, 1, 1, R, B);
+  FP_PACK_SEMIRAW_H (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
+
+/* BFtype passed in GPR, HFtype returned in GPR.  */
+unsigned short
+__truncbfhf2_gpr (unsigned short us)
+{
+  FP_DECL_EX;
+  FP_DECL_H (A);
+  FP_DECL_S (B);
+  FP_DECL_B (R);
+  SFtype b;
+  HFtype r;
+  BFtype a;
+  union ushort_bf ubf;
+  union ushort_hf uhf;
+
+  ubf.us = us;
+  a = ubf.bf;
+
+  FP_INIT_ROUNDMODE;
+  /* Optimize BFtype to SFtype conversion to simple left shift
+     by 16 if possible, we don't need to raise exceptions on sNaN
+     here as the SFtype to HFtype truncation should do that too.  */
+  if (sizeof (BFtype) == 2
+      && sizeof (unsigned short) == 2
+      && sizeof (SFtype) == 4
+      && sizeof (unsigned int) == 4)
+    {
+      union { BFtype a; unsigned short b; } u1;
+      union { SFtype a; unsigned int b; } u2;
+      u1.a = a;
+      u2.b = (u1.b << 8) << 8;
+      b = u2.a;
+    }
+  else
+    {
+      FP_UNPACK_RAW_B (A, a);
+      FP_EXTEND (S, B, 1, 1, B, A);
+      FP_PACK_RAW_S (b, B);
+    }
+  FP_UNPACK_SEMIRAW_S (B, b);
+  FP_TRUNC (H, S, 1, 1, R, B);
+  FP_PACK_SEMIRAW_H (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  uhf.hf = r;
+  return uhf.us;
+}
diff --git a/libgcc/config/rs6000/ppc-trunchfbf2.c 
b/libgcc/config/rs6000/ppc-trunchfbf2.c
new file mode 100644
index 000000000000..747a90c996ef
--- /dev/null
+++ b/libgcc/config/rs6000/ppc-trunchfbf2.c
@@ -0,0 +1,96 @@
+/* Software floating-point emulation.
+   Truncate IEEE half into bfloat16.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.
+
+   This is a clone of soft-fp/trunchfbf2.c for the PowerPC.
+
+   We provide an alternative version of the conversion that retunrs the HFtype
+   value as unsigned short.  This is to allow the calling sequence where
+   arguments are converted to the 32/64-bit scalar format.  If we don't have
+   the hardware support, we can't use the standard __trunc function  */
+
+#include "soft-fp.h"
+#include "brain.h"
+#include "half.h"
+#include "single.h"
+
+/* BFtype and HFtype are unordered, neither is a superset or subset
+   of each other.  Convert HFtype to SFtype (lossless) and then
+   truncate to BFtype.  */
+
+/* HFtype passed in FPR, BFtype returned in FPR.  */
+BFtype
+__trunchfbf2 (HFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_H (A);
+  FP_DECL_S (B);
+  FP_DECL_B (R);
+  SFtype b;
+  BFtype r;
+
+  FP_INIT_ROUNDMODE;
+  FP_UNPACK_RAW_H (A, a);
+  FP_EXTEND (S, H, 1, 1, B, A);
+  FP_PACK_RAW_S (b, B);
+  FP_UNPACK_SEMIRAW_S (B, b);
+  FP_TRUNC (B, S, 1, 1, R, B);
+  FP_PACK_SEMIRAW_B (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
+
+/* HFtype passed in GPR, BFtype returned in GPR.  */
+unsigned short
+__trunchfbf2_gpr (unsigned short us)
+{
+  FP_DECL_EX;
+  FP_DECL_H (A);
+  FP_DECL_S (B);
+  FP_DECL_B (R);
+  SFtype b;
+  BFtype r;
+  HFtype a;
+  union ushort_bf ubf;
+  union ushort_hf uhf;
+
+  uhf.us = us;
+  a = uhf.hf;
+
+  FP_INIT_ROUNDMODE;
+  FP_UNPACK_RAW_H (A, a);
+  FP_EXTEND (S, H, 1, 1, B, A);
+  FP_PACK_RAW_S (b, B);
+  FP_UNPACK_SEMIRAW_S (B, b);
+  FP_TRUNC (B, S, 1, 1, R, B);
+  FP_PACK_SEMIRAW_B (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  ubf.bf = r;
+  return ubf.us;
+}
diff --git a/libgcc/config/rs6000/sfp-machine.h 
b/libgcc/config/rs6000/sfp-machine.h
index 8fe69e539243..b37bf0903a87 100644
--- a/libgcc/config/rs6000/sfp-machine.h
+++ b/libgcc/config/rs6000/sfp-machine.h
@@ -188,14 +188,18 @@ typedef unsigned int UTItype2 __attribute__ ((mode (TI)));
 extern RET NAME (FP16);                                                        
\
 extern RET NAME ## _gpr (UHItype2)
 
-#define PASS_FP16_2(NAME, RET, FP16)                                   \
-extern RET NAME (FP16, FP16);                                          \
+#define PASS_FP16_2(NAME, RET, FP16_1, FP16_2)                         \
+extern RET NAME (FP16_1, FP16_2);                                      \
 extern RET NAME ## _gpr (UHItype2, UHItype2)
 
 #define RETURN_FP16(NAME, FP16, ARG)                                   \
 extern FP16 NAME (ARG);                                                        
\
 extern UHItype2 NAME ## _gpr (ARG)
 
+#define CONVERT_FP16(NAME, FP16_RET, FP16_ARG)                         \
+extern FP16_RET NAME (FP16_ARG);                                       \
+extern UHItype2 NAME ## _gpr (UHItype2)
+
 #ifdef __FLOAT16__
 typedef float HFtype2 __attribute__ ((mode (HF)));
 
@@ -205,7 +209,7 @@ union ushort_hf {
   HFtype2 hf;
 };
 
-PASS_FP16_2 (__eqhf2, CMPtype, HFtype2);
+PASS_FP16_2 (__eqhf2, CMPtype, HFtype2, HFtype2);
 
 PASS_FP16 (__extendhfsf2, SFtype2, HFtype2);
 PASS_FP16 (__extendhfdf2, DFtype2, HFtype2);
@@ -239,7 +243,7 @@ union ushort_bf {
   BFtype2 bf;
 };
 
-PASS_FP16_2 (__eqbf2, CMPtype, BFtype2);
+PASS_FP16_2 (__eqbf2, CMPtype, BFtype2, BFtype2);
 
 PASS_FP16 (__extendbfsf2, SFtype2, BFtype2);
 PASS_FP16 (__extendbfdf2, DFtype2, BFtype2);
@@ -265,6 +269,6 @@ RETURN_FP16 (__truncdfbf2, BFtype2, DFtype2);
 #endif
 
 #if defined(__FLOAT16__) && defined(__BFLOAT16__)
-extern HFtype2 __truncbfhf2 (BFtype2);
-extern BFtype2 __trunchfbf2 (HFtype2);
+CONVERT_FP16 (__truncbfhf2, HFtype2, BFtype2);
+CONVERT_FP16 (__trunchfbf2, BFtype2, HFtype2);
 #endif
diff --git a/libgcc/config/rs6000/t-float16 b/libgcc/config/rs6000/t-float16
index e04072c0fa80..8bb913e12c17 100644
--- a/libgcc/config/rs6000/t-float16
+++ b/libgcc/config/rs6000/t-float16
@@ -50,8 +50,8 @@ bfp16_obj     = $(bfp16_obj_1) $(bfp16_obj_2)
 $(bfp16_obj)   : INTERNAL_CFLAGS += $(FP16_CFLAGS)
 
 # Conversion between __bf16 and _Float16
-both_fp16_funcs         = truncbfhf2 trunchfbf2
-both_fp16_src   = $(addprefix $(srcdir)/soft-fp/,$(addsuffix 
.c,$(both_fp16_funcs)))
+both_fp16_funcs         = ppc-truncbfhf2 ppc-trunchfbf2
+both_fp16_src   = $(addprefix $(srcdir)/config/rs6000/,$(addsuffix 
.c,$(both_fp16_funcs)))
 both_fp16_obj   = $(addsuffix $(objext),$(both_fp16_funcs))
 
 $(both_fp16_obj) : INTERNAL_CFLAGS += $(FP16_CFLAGS)

Reply via email to