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)
