https://gcc.gnu.org/g:022d58c222229965572e53dc0d24077ff1e94b08

commit 022d58c222229965572e53dc0d24077ff1e94b08
Author: Michael Meissner <[email protected]>
Date:   Thu Sep 24 22:42:19 2026 -0400

    Add ifunc support to extend 16-bit fp to 32/64-bit.
    
    This patch rewrites the __extend{bf,hf}{sf,df}2 functions to have ifunc 
support
    to generate appropriate code for conversions.
    
    Also add _gpr versions to allow doing a conversion with 16-bit fp passed as 
an
    unsigned short.
    
    2026-09-24  Michael Meissner  <[email protected]>
    
            * config/rs6000/extendbf-sfdf2.c: New file.
            * config/rs6000/extendhf-sfdf2.c: Likewise.
            * config/rs6000/t-float16: Use extendbf-sff2 and extendhf-sfhf2 
instead
            of the native soft-fp version.

Diff:
---
 libgcc/config/rs6000/extendbf-sfdf2.c | 222 ++++++++++++++++++++++++++++++++++
 libgcc/config/rs6000/extendhf-sfdf2.c | 180 +++++++++++++++++++++++++++
 libgcc/config/rs6000/t-float16        |  51 +++++---
 3 files changed, 438 insertions(+), 15 deletions(-)

diff --git a/libgcc/config/rs6000/extendbf-sfdf2.c 
b/libgcc/config/rs6000/extendbf-sfdf2.c
new file mode 100644
index 000000000000..6e3801e907f3
--- /dev/null
+++ b/libgcc/config/rs6000/extendbf-sfdf2.c
@@ -0,0 +1,222 @@
+/* Software floating-point emulation.
+   Return an bfloat16 converted to IEEE single
+   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/extendbfsf2.c for the PowerPC.  It
+   provides both __extendbfsf2 and __extendbfdf2, since both types
+   return 64-bit floating point formats.
+
+   We provide power8, power9, and power10 versiosns of the conversion function
+   and we use an ifunc resolver to select the appropriate conversion to
+   use.
+
+   We provide an alternative version of the conversion that takes the value in
+   a GPR passed as an 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 __extend function.  */
+
+#define FP_NO_EXACT_UNDERFLOW
+#include "soft-fp.h"
+#include "brain.h"
+#include "single.h"
+#include "double.h"
+
+union ushort_bf {
+  unsigned short us;
+  BFtype bf;
+};
+
+typedef SFtype bf_fpr_to_sf_function_t (BFtype a);
+typedef SFtype bf_gpr_to_sf_function_t (unsigned short a);
+
+typedef bf_fpr_to_sf_function_t *bf_fpr_to_sf_ptr_function_t;
+typedef bf_gpr_to_sf_function_t *bf_gpr_to_sf_ptr_function_t;
+
+typedef DFtype bf_fpr_to_df_function_t (BFtype a);
+typedef DFtype bf_gpr_to_df_function_t (unsigned short a);
+
+typedef bf_fpr_to_df_function_t *bf_fpr_to_df_ptr_function_t;
+typedef bf_gpr_to_df_function_t *bf_gpr_to_df_ptr_function_t;
+
+static bf_fpr_to_sf_ptr_function_t __extendbfsf2_ifunc (void);
+static bf_gpr_to_sf_ptr_function_t __extendbfsf2_gpr_ifunc (void);
+
+static bf_fpr_to_sf_function_t __extendbfsf2_p8
+  __attribute__ ((__target__("cpu=power8")));
+
+static bf_gpr_to_sf_function_t __extendbfsf2_gpr_p8
+  __attribute__ ((__target__("cpu=power8")));
+
+static bf_fpr_to_sf_function_t __extendbfsf2_p9
+  __attribute__ ((__target__("cpu=power9")));
+
+static bf_gpr_to_sf_function_t __extendbfsf2_gpr_p9
+  __attribute__ ((__target__("cpu=power9")));
+
+static bf_fpr_to_sf_function_t __extendbfsf2_p10
+  __attribute__ ((__target__("cpu=power10")));
+
+static bf_gpr_to_sf_function_t __extendbfsf2_gpr_p10
+  __attribute__ ((__target__("cpu=power10")));
+
+extern bf_fpr_to_sf_function_t __extendbfsf2
+  __attribute__ ((__ifunc__ ("__extendbfsf2_ifunc")));
+
+extern bf_gpr_to_sf_function_t __extendbfsf2_gpr
+  __attribute__ ((__ifunc__ ("__extendbfsf2_gpr_ifunc")));
+
+/* Provide DF version as well, given SFtype & DFtype use the same encoding.  */
+static bf_fpr_to_df_ptr_function_t __extendbfdf2_ifunc (void);
+static bf_gpr_to_df_ptr_function_t __extendbfdf2_gpr_ifunc (void);
+
+extern bf_fpr_to_df_function_t __extendbfdf2
+  __attribute__ ((__ifunc__ ("__extendbfdf2_ifunc")));
+
+extern bf_gpr_to_sf_function_t __extendbfdf2_gpr
+  __attribute__ ((__ifunc__ ("__extendbfdf2_gpr_ifunc")));
+
+/* Power8 implementation, BFtype passed in FPR register, no hardware
+   support.  */
+static SFtype
+__extendbfsf2_p8 (BFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_B (A);
+  FP_DECL_S (R);
+  SFtype r;
+
+  FP_INIT_EXCEPTIONS;
+  FP_UNPACK_RAW_B (A, a);
+  FP_EXTEND (S, B, 1, 1, R, A);
+  FP_PACK_RAW_S (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
+
+/* Power8 implementation, BFtype passed in GPR register, no hardware
+   support.  */
+static SFtype
+__extendbfsf2_gpr_p8 (unsigned short us)
+{
+  union ushort_bf u;
+  BFtype a;
+
+  u.us = us;
+  a = u.bf;
+
+  FP_DECL_EX;
+  FP_DECL_B (A);
+  FP_DECL_S (R);
+  SFtype r;
+
+  FP_INIT_EXCEPTIONS;
+  FP_UNPACK_RAW_B (A, a);
+  FP_EXTEND (S, B, 1, 1, R, A);
+  FP_PACK_RAW_S (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
+
+/* Power9 implementation, BFtype passed in FPR register, use shift and
+   XSCVSPDPN.  */
+static SFtype
+__extendbfsf2_p9 (BFtype a)
+{
+  return (SFtype) a;
+}
+
+/* Power9 implementation, BFtype passed in GPR register, use shift and
+   XSCVSPDPN.  */
+static SFtype
+__extendbfsf2_gpr_p9 (unsigned short a)
+{
+  union ushort_bf u;
+  u.us = a;
+  return (SFtype) u.bf;
+}
+
+/* Power10 implementtion, BFtype passed in FPR register, use XXSPLTW,
+   XVCVBF16SPN, and XSCVSPDPN.  */
+static SFtype
+__extendbfsf2_p10 (BFtype a)
+{
+  return (SFtype) a;
+}
+
+/* Power10 implementtion, BFtype passed in GPR register, use XXSPLTW,
+   XVCVBF16SPN, and XSCVSPDPN.  */
+static SFtype
+__extendbfsf2_gpr_p10 (unsigned short a)
+{
+  union ushort_bf u;
+  u.us = a;
+  return (SFtype) u.bf;
+}
+
+/* Determine if we are on power8, power9, or power10.  */
+static bf_fpr_to_sf_ptr_function_t
+__extendbfsf2_ifunc (void)
+{
+  return (__builtin_cpu_supports ("arch_3_1")
+         ? __extendbfsf2_p10
+         : (__builtin_cpu_supports ("arch_3_00")
+            ? __extendbfsf2_p9
+            : __extendbfsf2_p8));
+}
+
+static bf_gpr_to_sf_ptr_function_t
+__extendbfsf2_gpr_ifunc (void)
+{
+  return (__builtin_cpu_supports ("arch_3_1")
+         ? __extendbfsf2_gpr_p10
+         : (__builtin_cpu_supports ("arch_3_00")
+            ? __extendbfsf2_gpr_p9
+            : __extendbfsf2_gpr_p8));
+}
+
+/* DFtype functions.  */
+static bf_fpr_to_df_ptr_function_t
+__extendbfdf2_ifunc (void)
+{
+  return (bf_fpr_to_df_ptr_function_t) (__builtin_cpu_supports ("arch_3_1")
+                                       ? __extendbfsf2_p10
+                                       : (__builtin_cpu_supports ("arch_3_00")
+                                          ? __extendbfsf2_p9
+                                          : __extendbfsf2_p8));
+}
+
+static bf_gpr_to_df_ptr_function_t
+__extendbfdf2_gpr_ifunc (void)
+{
+  return (bf_gpr_to_df_ptr_function_t) (__builtin_cpu_supports ("arch_3_1")
+                                       ? __extendbfsf2_gpr_p10
+                                       : (__builtin_cpu_supports ("arch_3_00")
+                                          ? __extendbfsf2_gpr_p9
+                                          : __extendbfsf2_gpr_p8));
+}
diff --git a/libgcc/config/rs6000/extendhf-sfdf2.c 
b/libgcc/config/rs6000/extendhf-sfdf2.c
new file mode 100644
index 000000000000..4ae1629545ec
--- /dev/null
+++ b/libgcc/config/rs6000/extendhf-sfdf2.c
@@ -0,0 +1,180 @@
+/* Software floating-point emulation.
+   Return an IEEE half converted to IEEE single
+   Copyright (C) 2021-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/extendhfsf2.c for the PowerPC.  It
+   provides both __extendhfsf2 and __extendhfdf2, since both types
+   return 64-bit floating point formats.
+
+   We provide power8, and power9 versiosns of the conversion function and we
+   use an ifunc resolver to select the appropriate conversion to use.
+
+   We provide an alternative version of the conversion that takes the value in
+   a GPR passed as an 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 __extend function.  */
+
+#define FP_NO_EXACT_UNDERFLOW
+#include "soft-fp.h"
+#include "half.h"
+#include "single.h"
+#include "double.h"
+
+union ushort_hf {
+  unsigned short us;
+  HFtype hf;
+};
+
+typedef SFtype hf_fpr_to_sf_function_t (HFtype a);
+typedef SFtype hf_gpr_to_sf_function_t (unsigned short a);
+
+typedef hf_fpr_to_sf_function_t *hf_fpr_to_sf_ptr_function_t;
+typedef hf_gpr_to_sf_function_t *hf_gpr_to_sf_ptr_function_t;
+
+typedef DFtype hf_fpr_to_df_function_t (HFtype a);
+typedef DFtype hf_gpr_to_df_function_t (unsigned short a);
+
+typedef hf_fpr_to_df_function_t *hf_fpr_to_df_ptr_function_t;
+typedef hf_gpr_to_df_function_t *hf_gpr_to_df_ptr_function_t;
+
+static hf_fpr_to_sf_ptr_function_t __extendhfsf2_ifunc (void);
+static hf_gpr_to_sf_ptr_function_t __extendhfsf2_gpr_ifunc (void);
+
+static hf_fpr_to_df_ptr_function_t __extendhfdf2_ifunc (void);
+static hf_gpr_to_df_ptr_function_t __extendhfdf2_gpr_ifunc (void);
+
+static hf_fpr_to_sf_function_t __extendhfsf2_p8
+  __attribute__ ((__target__("cpu=power8")));
+
+static hf_gpr_to_sf_function_t __extendhfsf2_gpr_p8
+  __attribute__ ((__target__("cpu=power8")));
+
+static hf_fpr_to_sf_function_t __extendhfsf2_p9
+  __attribute__ ((__target__("cpu=power9")));
+
+static hf_gpr_to_sf_function_t __extendhfsf2_gpr_p9
+  __attribute__ ((__target__("cpu=power9")));
+
+extern hf_fpr_to_sf_function_t __extendhfsf2
+  __attribute__ ((__ifunc__ ("__extendhfsf2_ifunc")));
+
+extern hf_gpr_to_sf_function_t __extendhfsf2_gpr
+  __attribute__ ((__ifunc__ ("__extendhfsf2_gpr_ifunc")));
+
+/* Power8 implementation, HFtype passed in FPR register, no hardware
+   support.  */
+static SFtype
+__extendhfsf2_p8 (HFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_H (A);
+  FP_DECL_S (R);
+  SFtype r;
+
+  FP_INIT_EXCEPTIONS;
+  FP_UNPACK_RAW_H (A, a);
+  FP_EXTEND (S, H, 1, 1, R, A);
+  FP_PACK_RAW_S (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
+
+/* Power8 implementation, HFtype passed in GPR register, no hardware
+   support.  */
+static SFtype
+__extendhfsf2_gpr_p8 (unsigned short us)
+{
+  union ushort_hf u;
+  HFtype a;
+
+  u.us = us;
+  a = u.hf;
+
+  FP_DECL_EX;
+  FP_DECL_H (A);
+  FP_DECL_S (R);
+  SFtype r;
+
+  FP_INIT_EXCEPTIONS;
+  FP_UNPACK_RAW_H (A, a);
+  FP_EXTEND (S, H, 1, 1, R, A);
+  FP_PACK_RAW_S (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
+
+/* Power9 implementation, HFtype passed in FPR register, use XVCVHPSP.  */
+static SFtype
+__extendhfsf2_p9 (HFtype a)
+{
+  return (SFtype) a;
+}
+
+/* Power9 implementation, HFtype passed in GPR register, use XVCVHPSP.  */
+static SFtype
+__extendhfsf2_gpr_p9 (unsigned short a)
+{
+  union ushort_hf u;
+  u.us = a;
+  return (SFtype) u.hf;
+}
+
+/* Determine if we are on power8 or power9.  */
+static hf_fpr_to_sf_ptr_function_t
+__extendhfsf2_ifunc (void)
+{
+  return (__builtin_cpu_supports ("arch_3_00")
+         ? __extendhfsf2_p9
+         : __extendhfsf2_p8);
+}
+
+static hf_gpr_to_sf_ptr_function_t
+__extendhfsf2_gpr_ifunc (void)
+{
+  return (__builtin_cpu_supports ("arch_3_00")
+         ? __extendhfsf2_gpr_p9
+         : __extendhfsf2_gpr_p8);
+}
+
+/* DFtype functions.  */
+static hf_fpr_to_df_ptr_function_t
+__extendhfdf2_ifunc (void)
+{
+  return (hf_fpr_to_df_ptr_function_t) (__builtin_cpu_supports ("arch_3_00")
+                                       ? __extendhfsf2_p9
+                                       : __extendhfsf2_p8);
+}
+
+static hf_gpr_to_df_ptr_function_t
+__extendhfdf2_gpr_ifunc (void)
+{
+  return (hf_gpr_to_df_ptr_function_t) (__builtin_cpu_supports ("arch_3_00")
+                                       ? __extendhfsf2_gpr_p9
+                                       : __extendhfsf2_gpr_p8);
+}
diff --git a/libgcc/config/rs6000/t-float16 b/libgcc/config/rs6000/t-float16
index f77df910b3ff..d03c824cc561 100644
--- a/libgcc/config/rs6000/t-float16
+++ b/libgcc/config/rs6000/t-float16
@@ -1,30 +1,51 @@
-# _Float16 library support
-
-fp16_funcs     = eqhf2 extendhfdf2 extendhfsf2 \
-                 fixhfsi  fixhfdi fixhfti fixunshfsi fixunshfdi fixunshfti \
-                 floatsihf floatdihf floattihf floatunsihf floatundihf 
floatuntihf \
+# _Float16 library support, source files in soft-ftp
+fp16_funcs_1   = eqhf2 \
+                 fixhfsi  fixhfdi fixhfti \
+                 fixunshfsi fixunshfdi fixunshfti \
+                 floatsihf floatdihf floattihf \
+                 floatunsihf floatundihf floatuntihf \
                  truncdfhf2 truncsfhf2
 
-fp16_src       = $(addprefix $(srcdir)/soft-fp/,$(addsuffix .c,$(fp16_funcs)))
-fp16_obj       = $(addsuffix $(objext),$(fp16_funcs))
+fp16_src_1     = $(addprefix $(srcdir)/soft-fp/,$(addsuffix 
.c,$(fp16_funcs_1)))
+fp16_obj_1     = $(addsuffix $(objext),$(fp16_funcs_1))
+
+# _Float16 library support, source files in config/rs6000
+fp16_funcs_2   = extendhf-sfdf2
+fp16_src_2     = $(addprefix $(srcdir)/config/rs6000/,$(addsuffix 
.c,$(fp16_funcs_2)))
+fp16_obj_2     = $(addsuffix $(objext),$(fp16_funcs_2))
+
+# _Float16 combined library support
+fp16_funcs     = $(fp16_funcs_1) $(fp16_funcs_2)
+fp16_src       = $(fp16_src_1) $(fp16_src_2)
+fp16_obj       = $(fp16_obj_1) $(fp16_obj_2)
 
 FP16_CFLAGS    = -mfloat16 -Wno-psabi \
-                 -I$(srcdir)/soft-fp -I$(srcdir)/config/rs6000
+                 -I$(srcdir)/soft-fp \
+                 -I$(srcdir)/config/rs6000
 
 $(fp16_obj)    : INTERNAL_CFLAGS += $(FP16_CFLAGS)
 
-# __bfloat16 library support
-
-bfp16_funcs    = extendbfsf2 floatdibf floatsibf floatundibf floatunsibf \
+# __bf16 library support, source files in soft-ftp
+bfp16_funcs_1  = floatsibf floatdibf floattibf \
+                 floatunsibf floatundibf floatuntibf \
                  truncdfbf2 truncsfbf2
 
-bfp16_src      = $(addprefix $(srcdir)/soft-fp/,$(addsuffix .c,$(bfp16_funcs)))
-bfp16_obj      = $(addsuffix $(objext),$(bfp16_funcs))
+bfp16_src_1    = $(addprefix $(srcdir)/soft-fp/,$(addsuffix 
.c,$(bfp16_funcs_1)))
+bfp16_obj_1    = $(addsuffix $(objext),$(bfp16_funcs_1))
 
-$(bfp16_obj)   : INTERNAL_CFLAGS += $(FP16_CFLAGS)
+# __bf16 library support, source files in config/rs6000
+bfp16_funcs_2  = extendbf-sfdf2
+bfp16_src_2    = $(addprefix $(srcdir)/config/rs6000/,$(addsuffix 
.c,$(bfp16_funcs_2)))
+bfp16_obj_2    = $(addsuffix $(objext),$(bfp16_funcs_2))
+
+# __bf16 combined library support
+bfp16_funcs    = $(bfp16_funcs_1) $(bfp16_funcs_2)
+bfp16_src      = $(bfp16_src_1) $(bfp16_src_2)
+bfp16_obj      = $(bfp16_obj_1) $(bfp16_obj_2)
 
-# Conversion between __bfloat16 and _Float16
+$(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_obj   = $(addsuffix $(objext),$(both_fp16_funcs))

Reply via email to