https://gcc.gnu.org/g:95155bf22107dbb043d22078b10e97f5b0bf20cf
commit 95155bf22107dbb043d22078b10e97f5b0bf20cf Author: Michael Meissner <[email protected]> Date: Fri Sep 25 01:50:09 2026 -0400 Add ifunc support to truncate 32/64-bit to 16-bit fp. This patch rewrites the __trunc{sf,df}{bf,hf}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-25 Michael Meissner <[email protected]> * config/rs6000/extendbf-sfdf2.c: Update to make the df versions use the same code as the sf versions. * config/rs6000/extendhf-sfdf2.c: Likewise. * config/rs6000/truncsfdf-bf2.c: New file. * config/rs6000/truncsfdf-hf2.c: Likewise. * config/rs6000/t-float16: Use truncsfdf-bf2 and truncsfdf-hf2 instead of the native soft-fp version. Diff: --- libgcc/config/rs6000/extendbf-sfdf2.c | 49 ++-------- libgcc/config/rs6000/extendhf-sfdf2.c | 36 ++------ libgcc/config/rs6000/t-float16 | 11 ++- libgcc/config/rs6000/truncsfdf-bf2.c | 165 ++++++++++++++++++++++++++++++++++ libgcc/config/rs6000/truncsfdf-hf2.c | 160 +++++++++++++++++++++++++++++++++ 5 files changed, 347 insertions(+), 74 deletions(-) diff --git a/libgcc/config/rs6000/extendbf-sfdf2.c b/libgcc/config/rs6000/extendbf-sfdf2.c index 6e3801e907f3..ec0d8f176a96 100644 --- a/libgcc/config/rs6000/extendbf-sfdf2.c +++ b/libgcc/config/rs6000/extendbf-sfdf2.c @@ -24,11 +24,9 @@ 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/>. */ + <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. + This is a clone of soft-fp/extendbfsf2.c for the PowerPC. We provide power8, power9, and power10 versiosns of the conversion function and we use an ifunc resolver to select the appropriate conversion to @@ -56,12 +54,6 @@ 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); @@ -89,16 +81,6 @@ extern bf_fpr_to_sf_function_t __extendbfsf2 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 @@ -200,23 +182,10 @@ __extendbfsf2_gpr_ifunc (void) : __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)); -} +/* On the PowerPC DFtype scalars use the same encoding as SFtype, so use the + same function for both. */ +__asm__ ("\t.globl __extendbfdf2\n" + "__extendbfdf2 = __extendbfsf2\n" + "\n" + "\t.globl __extendbfdf2_gpr\n" + "__extendbfdf2_gpr = __extendbfsf2_gpr"); diff --git a/libgcc/config/rs6000/extendhf-sfdf2.c b/libgcc/config/rs6000/extendhf-sfdf2.c index 4ae1629545ec..b99b1f1d4f97 100644 --- a/libgcc/config/rs6000/extendhf-sfdf2.c +++ b/libgcc/config/rs6000/extendhf-sfdf2.c @@ -26,9 +26,7 @@ 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. +/* This is a clone of soft-fp/extendhfsf2.c for the PowerPC. We provide power8, and power9 versiosns of the conversion function and we use an ifunc resolver to select the appropriate conversion to use. @@ -55,18 +53,9 @@ 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"))); @@ -162,19 +151,10 @@ __extendhfsf2_gpr_ifunc (void) : __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); -} +/* On the PowerPC DFtype scalars use the same encoding as SFtype, so use the + same function for both. */ +__asm__ ("\t.globl __extendhfdf2\n" + "__extendhfdf2 = __extendhfsf2\n" + "\n" + "\t.globl __extendhfdf2_gpr\n" + "__extendhfdf2_gpr = __extendhfsf2_gpr"); diff --git a/libgcc/config/rs6000/t-float16 b/libgcc/config/rs6000/t-float16 index d03c824cc561..d42047b02d98 100644 --- a/libgcc/config/rs6000/t-float16 +++ b/libgcc/config/rs6000/t-float16 @@ -3,14 +3,14 @@ fp16_funcs_1 = eqhf2 \ fixhfsi fixhfdi fixhfti \ fixunshfsi fixunshfdi fixunshfti \ floatsihf floatdihf floattihf \ - floatunsihf floatundihf floatuntihf \ - truncdfhf2 truncsfhf2 + floatunsihf floatundihf floatuntihf + 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_funcs_2 = extendhf-sfdf2 truncsfdf-hf2 fp16_src_2 = $(addprefix $(srcdir)/config/rs6000/,$(addsuffix .c,$(fp16_funcs_2))) fp16_obj_2 = $(addsuffix $(objext),$(fp16_funcs_2)) @@ -27,14 +27,13 @@ $(fp16_obj) : INTERNAL_CFLAGS += $(FP16_CFLAGS) # __bf16 library support, source files in soft-ftp bfp16_funcs_1 = floatsibf floatdibf floattibf \ - floatunsibf floatundibf floatuntibf \ - truncdfbf2 truncsfbf2 + floatunsibf floatundibf floatuntibf bfp16_src_1 = $(addprefix $(srcdir)/soft-fp/,$(addsuffix .c,$(bfp16_funcs_1))) bfp16_obj_1 = $(addsuffix $(objext),$(bfp16_funcs_1)) # __bf16 library support, source files in config/rs6000 -bfp16_funcs_2 = extendbf-sfdf2 +bfp16_funcs_2 = extendbf-sfdf2 truncsfdf-bf2 bfp16_src_2 = $(addprefix $(srcdir)/config/rs6000/,$(addsuffix .c,$(bfp16_funcs_2))) bfp16_obj_2 = $(addsuffix $(objext),$(bfp16_funcs_2)) diff --git a/libgcc/config/rs6000/truncsfdf-bf2.c b/libgcc/config/rs6000/truncsfdf-bf2.c new file mode 100644 index 000000000000..ccb9dc8742a8 --- /dev/null +++ b/libgcc/config/rs6000/truncsfdf-bf2.c @@ -0,0 +1,165 @@ +/* Software floating-point emulation. + Truncate IEEE single into IEEE half. + 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/truncdfbf2.c for the PowerPC. + + We provide power8, 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 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 "single.h" +#include "double.h" + +/* Union to convert between BFtype and unsigned short. */ +union ushort_bf { + unsigned short us; + BFtype bf; +}; + +/* Function and pointer to function prototypes. */ +typedef BFtype sf_to_bf_fpr_function_t (SFtype a); +typedef unsigned short sf_to_bf_gpr_function_t (SFtype a); + +typedef sf_to_bf_fpr_function_t *sf_to_bf_fpr_ptr_function_t; +typedef sf_to_bf_gpr_function_t *sf_to_bf_gpr_ptr_function_t; + +static sf_to_bf_fpr_ptr_function_t __truncsfbf2_ifunc (void); +static sf_to_bf_gpr_ptr_function_t __truncsfbf2_gpr_ifunc (void); + +static sf_to_bf_fpr_function_t __truncsfbf2_p8 + __attribute__ ((__target__ ("cpu=power8"))); + +static sf_to_bf_gpr_function_t __truncsfbf2_gpr_p8 + __attribute__ ((__target__ ("cpu=power8"))); + +static sf_to_bf_fpr_function_t __truncsfbf2_p10 + __attribute__ ((__target__ ("cpu=power10"))); + +static sf_to_bf_gpr_function_t __truncsfbf2_gpr_p10 + __attribute__ ((__target__ ("cpu=power10"))); + +extern sf_to_bf_fpr_function_t __truncsfbf2 + __attribute__ ((__ifunc__ ("__truncsfbf2_ifunc"))); + +extern sf_to_bf_gpr_function_t __truncsfbf2_gpr + __attribute__ ((__ifunc__ ("__truncsfbf2_gpr_ifunc"))); + +/* Power8, return BFtype in a FPR register, no hardware support. */ +static BFtype +__truncsfbf2_p8 (SFtype a) +{ + FP_DECL_EX; + FP_DECL_S (A); + FP_DECL_B (R); + BFtype r; + + FP_INIT_ROUNDMODE; + FP_UNPACK_SEMIRAW_D (A, a); +#if _FP_W_TYPE_SIZE < _FP_FRACBITS_D + FP_TRUNC (B, D, 1, 2, R, A); +#else + FP_TRUNC (B, D, 1, 1, R, A); +#endif + FP_PACK_SEMIRAW_B (r, R); + FP_HANDLE_EXCEPTIONS; + + return r; +} + +/* Power8, return BFtype in a GPR register, no hardware support. */ +static unsigned short +__truncsfbf2_gpr_p8 (SFtype a) +{ + union ushort_bf u; + + FP_DECL_EX; + FP_DECL_S (A); + FP_DECL_B (R); + BFtype r; + + FP_INIT_ROUNDMODE; + FP_UNPACK_SEMIRAW_D (A, a); +#if _FP_W_TYPE_SIZE < _FP_FRACBITS_D + FP_TRUNC (B, D, 1, 2, R, A); +#else + FP_TRUNC (B, D, 1, 1, R, A); +#endif + FP_PACK_SEMIRAW_B (r, R); + FP_HANDLE_EXCEPTIONS; + + u.bf = r; + return u.us; +} + +/* Power10, return BFtype in a FPR register, use XVCVSPBF16. */ +static BFtype +__truncsfbf2_p10 (SFtype a) +{ + return (BFtype) a; +} + +/* Power9, return BFtype in a GPR register, use XVCVSPBF16. */ +static unsigned short +__truncsfbf2_gpr_p10 (SFtype a) +{ + union ushort_bf u; + u.bf = a; + return u.us; +} + +/* Resolve ifunc declarations for SFtype to BFtype. */ +static sf_to_bf_fpr_ptr_function_t +__truncsfbf2_ifunc (void) +{ + return (__builtin_cpu_supports ("arch_3_1") + ? __truncsfbf2_p10 + : __truncsfbf2_p8); +} + +static sf_to_bf_gpr_ptr_function_t +__truncsfbf2_gpr_ifunc (void) +{ + return (__builtin_cpu_supports ("arch_3_1") + ? __truncsfbf2_gpr_p10 + : __truncsfbf2_gpr_p8); +} + +/* On the PowerPC DFtype scalars use the same encoding as SFtype, so use the + same function for both. */ +__asm__ ("\n" + "\t.globl __truncdfbf2\n" + "__truncdfbf2 = __truncsfbf2\n" + "\n" + "\t.globl __truncdfbf2_gpr\n" + "__truncdfbf2_gpr = __truncsfbf2_gpr\n"); diff --git a/libgcc/config/rs6000/truncsfdf-hf2.c b/libgcc/config/rs6000/truncsfdf-hf2.c new file mode 100644 index 000000000000..4ee28daa74d9 --- /dev/null +++ b/libgcc/config/rs6000/truncsfdf-hf2.c @@ -0,0 +1,160 @@ +/* Software floating-point emulation. + Truncate IEEE single into IEEE half. + 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/truncsfhf2.c for the PowerPC. + + 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 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 "single.h" +#include "double.h" + +/* Union to convert between HFtype and unsigned short. */ +union ushort_hf { + unsigned short us; + HFtype hf; +}; + +/* Function and pointer to function prototypes. */ +typedef HFtype sf_to_hf_fpr_function_t (SFtype a); +typedef unsigned short sf_to_hf_gpr_function_t (SFtype a); + +typedef sf_to_hf_fpr_function_t *sf_to_hf_fpr_ptr_function_t; +typedef sf_to_hf_gpr_function_t *sf_to_hf_gpr_ptr_function_t; + +static sf_to_hf_fpr_ptr_function_t __truncsfhf2_ifunc (void); +static sf_to_hf_gpr_ptr_function_t __truncsfhf2_gpr_ifunc (void); + +static sf_to_hf_fpr_function_t __truncsfhf2_p8 + __attribute__ ((__target__ ("cpu=power8"))); + +static sf_to_hf_gpr_function_t __truncsfhf2_gpr_p8 + __attribute__ ((__target__ ("cpu=power8"))); + +static sf_to_hf_fpr_function_t __truncsfhf2_p9 + __attribute__ ((__target__ ("cpu=power9"))); + +static sf_to_hf_gpr_function_t __truncsfhf2_gpr_p9 + __attribute__ ((__target__ ("cpu=power9"))); + +extern sf_to_hf_fpr_function_t __truncsfhf2 + __attribute__ ((__ifunc__ ("__truncsfhf2_ifunc"))); + +extern sf_to_hf_gpr_function_t __truncsfhf2_gpr + __attribute__ ((__ifunc__ ("__truncsfhf2_gpr_ifunc"))); + +extern HFtype __truncdfhf2 (DFtype a); +extern unsigned short __truncdfhf2_gpr (DFtype a); + +/* Power8, return HFtype in a FPR register, no hardware support. */ +static HFtype +__truncsfhf2_p8 (SFtype a) +{ + FP_DECL_EX; + FP_DECL_S (A); + FP_DECL_H (R); + HFtype r; + + FP_INIT_ROUNDMODE; + FP_UNPACK_SEMIRAW_S (A, a); + FP_TRUNC (H, S, 1, 1, R, A); + FP_PACK_SEMIRAW_H (r, R); + FP_HANDLE_EXCEPTIONS; + + return r; +} + +/* Power8, return HFtype in a GPR register, no hardware support. */ +static unsigned short +__truncsfhf2_gpr_p8 (SFtype a) +{ + union ushort_hf u; + + FP_DECL_EX; + FP_DECL_S (A); + FP_DECL_H (R); + HFtype r; + + FP_INIT_ROUNDMODE; + FP_UNPACK_SEMIRAW_S (A, a); + FP_TRUNC (H, S, 1, 1, R, A); + FP_PACK_SEMIRAW_H (r, R); + FP_HANDLE_EXCEPTIONS; + + u.hf = r; + return u.us; +} + +/* Power9, return HFtype in a FPR register, use XSCVSPDPN. */ +static HFtype +__truncsfhf2_p9 (SFtype a) +{ + return (HFtype) a; +} + +/* Power9, return HFtype in a GPR register, use XSCVSPDPN. */ +static unsigned short +__truncsfhf2_gpr_p9 (SFtype a) +{ + union ushort_hf u; + u.hf = a; + return u.us; +} + +/* Resolve ifunc declarations for SFtype to HFtype. */ +static sf_to_hf_fpr_ptr_function_t +__truncsfhf2_ifunc (void) +{ + return (__builtin_cpu_supports ("arch_3_00") + ? __truncsfhf2_p9 + : __truncsfhf2_p8); +} + +static sf_to_hf_gpr_ptr_function_t +__truncsfhf2_gpr_ifunc (void) +{ + return (__builtin_cpu_supports ("arch_3_00") + ? __truncsfhf2_gpr_p9 + : __truncsfhf2_gpr_p8); +} + +/* On the PowerPC DFtype scalars use the same encoding as SFtype, so use the + same function for both. */ +__asm__ ("\n" + "\t.globl __truncdfhf2\n" + "__truncdfhf2 = __truncsfhf2\n" + "\n" + "\t.globl __truncdfhf2_gpr\n" + "__truncdfhf2_gpr = __truncsfhf2_gpr\n");
