https://gcc.gnu.org/g:6c02643adf3a3fdb24b321e4826f214a1964a2a1
commit 6c02643adf3a3fdb24b321e4826f214a1964a2a1 Author: Michael Meissner <[email protected]> Date: Tue Sep 15 00:44:24 2026 -0400 Float16 conversion functions pass 16-bit values in GPRs. 2026-09-14 Michael Meissner <[email protected]> gcc/ * config/rs6000/float16.md (FP16_CVT): New iterator. (extendbf<mode>2): Use TARGET_BFLOAT16_CVT. (extendbf<mode>2_memory): Likewise. (fix_trunc<FP16_HW:mode><GPR:mode>2): Go back to merged insns for BFmode and HFmode. (fixuns_trunc<FP16_HW:mode><GPR:mode>2): Likewise. * config/rs6000/rs6000-call.cc (USE_FP_FOR_ARG_P): If -mfloat16-convert-in-gprs pass/return 16-bit floating point values for conversion functions. (is_float16_convert_function): New helper function. (mark_float16_convert_function): Likewise. (init_cumulative_args): Add support for -mfloat16-convert-in-gprs. If -mdebug=arg, print the function name. * config/rs6000/rs6000-protos.h (is_float16_convert_function): New declaration. (mark_float16_convert_function): Likewise. * config/rs6000/rs6000.cc (init_float16): Mark 16-bit floating point conversion functions. (rs6000_init_libfuncs): Likewise. * config/rs6000/rs6000.h (TARGET_BFLOAT16_CVT): New macro. (struct rs6000_args): Add float16_convert field. * config/rs6000/rs6000.opt (-mfloat16-convert-in-gprs): New option. Diff: --- gcc/config/rs6000/float16.md | 54 +++++++++---------------- gcc/config/rs6000/rs6000-call.cc | 50 ++++++++++++++++++++--- gcc/config/rs6000/rs6000-protos.h | 2 + gcc/config/rs6000/rs6000.cc | 84 +++++++++++++++++++++++++++++++++++++++ gcc/config/rs6000/rs6000.h | 7 ++++ gcc/config/rs6000/rs6000.opt | 4 ++ 6 files changed, 160 insertions(+), 41 deletions(-) diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md index fe6630028884..667a11e5d295 100644 --- a/gcc/config/rs6000/float16.md +++ b/gcc/config/rs6000/float16.md @@ -34,6 +34,12 @@ (define_mode_iterator VFP16_HW [(V8BF "TARGET_BFLOAT16_HW") (V8HF "TARGET_FLOAT16_HW")]) +;; Mode iterator for conversions from 16-bit floating point. +;; Unlike FP16_HW, this specifically allows converting from +;; BFmode even if we don't have the bfloat16 conversion. +(define_mode_iterator FP16_CVT [(BF "TARGET_BFLOAT16_CVT") + (HF "TARGET_FLOAT16_HW")]) + ;; Mode iterator for floating point modes other than SF/DFmode that we ;; convert to/from _Float16 (HFmode) via DFmode. (define_mode_iterator fp16_float_convert [TF KF IF SD DD TD]) @@ -250,7 +256,7 @@ [(set (match_operand:SFDF 0 "vsx_register_operand") (float_extend:SFDF (match_operand:BF 1 "gpc_reg_operand")))] - "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT && TARGET_BFLOAT16_CONVERT" + "TARGET_BFLOAT16_CVT" { if (TARGET_BFLOAT16_HW && TARGET_BFLOAT16_P10_CONVERT) emit_insn (gen_extendbf<mode>2_p10 (operands[0], operands[1])); @@ -303,7 +309,7 @@ (match_operand:BF 1 "int_reg_operand" "r"))) (clobber (match_scratch:V4SF 2 "=wa")) (clobber (match_scratch:DI 3 "=r"))] - "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT && TARGET_BFLOAT16_CONVERT + "TARGET_BFLOAT16_CVT && (!TARGET_BFLOAT16_HW || !TARGET_BFLOAT16_P10_CONVERT)" "#" "&& reload_completed" @@ -705,54 +711,30 @@ DONE; }) -;; Convert 16-bit floating point modes to integers -(define_expand "fix_trunchf<mode>2" +(define_expand "fix_trunc<FP16_HW:mode><GPR:mode>2" [(set (match_operand:GPR 0 "vsx_register_operand") (fix:GPR - (match_operand:HF 1 "vsx_register_operand")))] - "TARGET_FLOAT16_HW" + (match_operand:FP16_HW 1 "vsx_register_operand")))] + "" { rtx df_tmp = gen_reg_rtx (DFmode); - emit_insn (gen_extendhfdf2 (df_tmp, operands[1])); - emit_insn (gen_fix_truncdf<mode>2 (operands[0], df_tmp)); + emit_insn (gen_extend<FP16_HW:mode>df2 (df_tmp, operands[1])); + emit_insn (gen_fix_truncdf<GPR:mode>2 (operands[0], df_tmp)); DONE; }) -(define_expand "fixuns_trunchf<mode>2" +(define_expand "fixuns_trunc<FP16_HW:mode><GPR:mode>2" [(set (match_operand:GPR 0 "vsx_register_operand") (unsigned_fix:GPR - (match_operand:HF 1 "vsx_register_operand")))] - "TARGET_FLOAT16_HW" -{ - rtx df_tmp = gen_reg_rtx (DFmode); - emit_insn (gen_extendhfdf2 (df_tmp, operands[1])); - emit_insn (gen_fixuns_truncdf<mode>2 (operands[0], df_tmp)); - DONE; -}) - -(define_expand "fix_truncbf<mode>2" - [(set (match_operand:GPR 0 "vsx_register_operand") - (fix:GPR - (match_operand:BF 1 "vsx_register_operand")))] - "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT && TARGET_BFLOAT16_CONVERT" + (match_operand:FP16_HW 1 "vsx_register_operand")))] + "" { rtx df_tmp = gen_reg_rtx (DFmode); - emit_insn (gen_extendbfdf2 (df_tmp, operands[1])); - emit_insn (gen_fix_truncdf<mode>2 (operands[0], df_tmp)); + emit_insn (gen_extend<FP16_HW:mode>df2 (df_tmp, operands[1])); + emit_insn (gen_fixuns_truncdf<GPR:mode>2 (operands[0], df_tmp)); DONE; }) -(define_expand "fixuns_truncbf<GPR:mode>2" - [(set (match_operand:GPR 0 "vsx_register_operand") - (unsigned_fix:GPR - (match_operand:BF 1 "vsx_register_operand")))] - "TARGET_FLOAT16 && TARGET_DIRECT_MOVE_64BIT && TARGET_BFLOAT16_CONVERT" -{ - rtx df_tmp = gen_reg_rtx (DFmode); - emit_insn (gen_extendbfdf2 (df_tmp, operands[1])); - emit_insn (gen_fixuns_truncdf<mode>2 (operands[0], df_tmp)); - DONE; -}) ;; Negate 16-bit floating point by XOR with -0.0. diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc index e11a3c10c3af..47dcdd779bb8 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. */ @@ -558,6 +560,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. @@ -567,7 +593,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) @@ -589,6 +615,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 @@ -630,6 +664,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 8efd0e7c9991..e274b5c22706 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -11828,6 +11828,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) { @@ -11848,6 +11928,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. diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 9eb5ee802c79..d91b2a564998 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -355,6 +355,12 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define TARGET_BFLOAT16_HW (TARGET_FLOAT16 && TARGET_POWER10) #define TARGET_FLOAT16_HW (TARGET_FLOAT16 && TARGET_P9_VECTOR) +/* Mode iterator for conversions from 16-bit floating point. Unlike + TARGET_BFLOAT16_HW, this specifically allows converting from BFmode even if + we don't have the bfloat16 conversion. We do this conversion */ +#define TARGET_BFLOAT16_CVT \ + (TARGET_FLOAT16 && TARGET_BFLOAT16_CONVERT && TARGET_P9_VECTOR) + /* Do we have conversion support in hardware for the 16-bit floating point and also enable the 16-bit floating point vector optimizations? */ #define TARGET_BFLOAT16_HW_VECTOR \ @@ -1515,6 +1521,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 4538546f7e89..da13ad4d1a8b 100644 --- a/gcc/config/rs6000/rs6000.opt +++ b/gcc/config/rs6000/rs6000.opt @@ -654,6 +654,10 @@ mbfloat16-p10-convert Target Undocumented Var(TARGET_BFLOAT16_P10_CONVERT) Init(1) Save Generate (do not generate) xvcvbf16spn to do __bf16 to float/double conversions. +mfloat16-convert-in-gprs +Target Undocumented Var(TARGET_FLOAT16_CONVERT_IN_GPRS) Init(1) Save +Pass/return (do not pass/return) 16-it float conversions in GPR registers. + ; Documented parameters -param=rs6000-vect-unroll-limit=
