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=
