https://gcc.gnu.org/g:51e7b464b1d61138f2aad4e0984b99e044f4dab0

commit 51e7b464b1d61138f2aad4e0984b99e044f4dab0
Author: Michael Meissner <[email protected]>
Date:   Thu Sep 3 21:30:14 2026 -0400

    Pass/return HFmode and BFmode as SFmode.
    
    2026-09-03  Michael Meissner  <[email protected]>
    
    gcc/
    
            * config/rs6000/rs6000-call.cc (rs6000_promote_function_mode): Pass 
and
            return BFmode and HFmode as SFmode.
            * config/rs6000/rs6000-internal.h
            (rs6000_promote_function_mode_convert): New declaration.
            * config/rs6000/rs6000.cc (TARGET_PROMOTE_FUNCTION_MODE_CONVERT):
            Override default.
            (rs6000_function_value): Return BFmode/HFmode as SFmode.
            * doc/tm.texi: Regenerate.
            * doc/tm.texi.in: (TARGET_PROMOTE_FUNCTION_MODE_CONVERT): New hook.
            * expr.cc (expand_expr_real_1): Add support for doing a conversion 
if
            the argument is passed as a different mode instead of doing a 
SUBREG.
            * target.def (promote_function_mode_convert): Add a new target hook 
to
            possibly do a real conversion if a function argument is passed ass a
            different mode.
            * targhooks.cc (default_promot_function_mode_convert): Likewise.
            * targhooks.h (default_promot_function_mode_convert): Likewise.

Diff:
---
 gcc/config/rs6000/rs6000-call.cc    | 18 ++++++++++++++++++
 gcc/config/rs6000/rs6000-internal.h |  3 +++
 gcc/config/rs6000/rs6000.cc         |  6 ++++++
 gcc/doc/tm.texi                     |  9 +++++++++
 gcc/doc/tm.texi.in                  |  2 ++
 gcc/expr.cc                         | 15 ++++++++++++---
 gcc/target.def                      | 11 +++++++++++
 gcc/targhooks.cc                    |  8 ++++++++
 gcc/targhooks.h                     |  2 ++
 9 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc
index 1abb7843f10a..2c7d864f495b 100644
--- a/gcc/config/rs6000/rs6000-call.cc
+++ b/gcc/config/rs6000/rs6000-call.cc
@@ -723,6 +723,9 @@ rs6000_promote_function_mode (const_tree type 
ATTRIBUTE_UNUSED,
                              int *punsignedp ATTRIBUTE_UNUSED,
                              const_tree, int for_return ATTRIBUTE_UNUSED)
 {
+  if (FP16_SCALAR_MODE_P (mode))
+    return SFmode;
+
   if (GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_SIZE (mode) < (TARGET_32BIT ? 4 : 8))
     mode = TARGET_32BIT ? SImode : DImode;
@@ -730,6 +733,21 @@ rs6000_promote_function_mode (const_tree type 
ATTRIBUTE_UNUSED,
   return mode;
 }
 
+/* Convert 16-bit floating arguments and return values to SFmode.  */
+
+rtx
+rs6000_promote_function_mode_convert (machine_mode new_mode,
+                                     machine_mode old_mode,
+                                     rtx decl_rtl)
+{
+  if (new_mode != old_mode
+      && (FP16_SCALAR_MODE_P (new_mode)
+         || FP16_SCALAR_MODE_P (old_mode)))
+    return convert_to_mode (new_mode, decl_rtl, 0);
+
+  return NULL_RTX;
+}
+
 /* Return true if TYPE must be passed on the stack and not in registers.  */
 
 bool
diff --git a/gcc/config/rs6000/rs6000-internal.h 
b/gcc/config/rs6000/rs6000-internal.h
index bb1e85cf9be5..7e5b40b73db6 100644
--- a/gcc/config/rs6000/rs6000-internal.h
+++ b/gcc/config/rs6000/rs6000-internal.h
@@ -149,6 +149,9 @@ extern machine_mode rs6000_promote_function_mode 
(const_tree type ATTRIBUTE_UNUS
                                                  machine_mode mode,
                                                  int *punsignedp 
ATTRIBUTE_UNUSED,
                                                  const_tree, int);
+extern rtx rs6000_promote_function_mode_convert (machine_mode new_mode,
+                                                machine_mode old_mode,
+                                                rtx decl_rtl);
 extern bool rs6000_return_in_memory (const_tree type,
                                     const_tree fntype ATTRIBUTE_UNUSED);
 extern bool rs6000_return_in_msb (const_tree valtype);
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 8efd0e7c9991..9ee451d8912e 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -1513,6 +1513,9 @@ static const scoped_attribute_specs *const 
rs6000_attribute_table[] =
 #undef TARGET_PROMOTE_FUNCTION_MODE
 #define TARGET_PROMOTE_FUNCTION_MODE rs6000_promote_function_mode
 
+#undef TARGET_PROMOTE_FUNCTION_MODE_CONVERT
+#define TARGET_PROMOTE_FUNCTION_MODE_CONVERT 
rs6000_promote_function_mode_convert
+
 #undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE
 #define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE 
rs6000_override_options_after_change
 
@@ -24423,6 +24426,9 @@ rs6000_function_value (const_tree valtype,
   else
     regno = GP_ARG_RETURN;
 
+  if (FP16_SCALAR_MODE_P (mode))
+    mode = SFmode;
+
   return gen_rtx_REG (mode, regno);
 }
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index a319634ea4db..68721b73d2ce 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1110,6 +1110,15 @@ also define the hook to 
@code{default_promote_function_mode_always_promote}
 if you would like to apply the same rules given by @code{PROMOTE_MODE}.
 @end deftypefn
 
+@deftypefn {Target Hook} rtx TARGET_PROMOTE_FUNCTION_MODE_CONVERT 
(machine_mode @var{new_mode}, machine_mode @var{old_mode}, rtx @var{decl_rtl})
+If @code{PROMOTE_FUNCTION_MODE} returns mode (@code{@var{NEW_MODE}}) which
+is a different mode for the function argument or return value
+(@code{@var{OLD_MODE}}) for @var{DECL_RTL}, either return @code{NULL_RTX} to
+use @code{SUBREG} to pass the value untranslated, or return a conversion rtl.
+
+The default is to not do a conversion.
+@end deftypefn
+
 @defmac PARM_BOUNDARY
 Normal alignment required for function parameters on the stack, in
 bits.  All stack parameters receive at least this much alignment
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index dbc090360da3..86b216850df6 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -987,6 +987,8 @@ applied.
 
 @hook TARGET_PROMOTE_FUNCTION_MODE
 
+@hook TARGET_PROMOTE_FUNCTION_MODE_CONVERT
+
 @defmac PARM_BOUNDARY
 Normal alignment required for function parameters on the stack, in
 bits.  All stack parameters receive at least this much alignment
diff --git a/gcc/expr.cc b/gcc/expr.cc
index 3d99be8472f8..ab0d6af870de 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -11852,9 +11852,11 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode 
tmode,
       /* If the mode of DECL_RTL does not match that of the decl,
         there are two cases: we are dealing with a BLKmode value
         that is returned in a register, or we are dealing with
-        a promoted value.  In the latter case, return a SUBREG
-        of the wanted mode, but mark it so that we know that it
-        was already extended.  */
+        a promoted value.
+
+        In the latter case, either do a regular conversion or return a SUBREG
+        of the wanted mode, but mark it so that we know that it was already
+        extended.  */
       if (REG_P (decl_rtl)
          && dmode != BLKmode
          && GET_MODE (decl_rtl) != dmode)
@@ -11875,6 +11877,13 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode 
tmode,
            pmode = promote_ssa_mode (ssa_name, &unsignedp);
          gcc_assert (GET_MODE (decl_rtl) == pmode);
 
+         /* Convert the value if the target wants it converted.  */
+         rtx cvt = targetm.calls.promote_function_mode_convert (pmode, mode,
+                                                                decl_rtl);
+
+         if (cvt)
+           return EXTEND_BITINT (cvt);
+
          /* Some ABIs require scalar floating point modes to be passed
             in a wider scalar integer mode.  We need to explicitly
             truncate to an integer mode of the correct precision before
diff --git a/gcc/target.def b/gcc/target.def
index 66c20a9c9d2a..884862096154 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4930,6 +4930,17 @@ if you would like to apply the same rules given by 
@code{PROMOTE_MODE}.",
                     const_tree funtype, int for_return),
  default_promote_function_mode)
 
+DEFHOOK
+(promote_function_mode_convert,
+ "If @code{PROMOTE_FUNCTION_MODE} returns mode (@code{@var{NEW_MODE}}) which\n\
+is a different mode for the function argument or return value\n\
+(@code{@var{OLD_MODE}}) for @var{DECL_RTL}, either return @code{NULL_RTX} to\n\
+use @code{SUBREG} to pass the value untranslated, or return a conversion 
rtl.\n\
+\n\
+The default is to not do a conversion.",
+ rtx, (machine_mode new_mode, machine_mode old_mode, rtx decl_rtl),
+ default_promote_function_mode_convert)
+
 DEFHOOK
 (promote_prototypes,
  "This target hook returns @code{true} if an argument declared in a\n\
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 388f696c8aa1..9ec801e79df9 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -152,6 +152,14 @@ default_promote_function_mode (const_tree type 
ATTRIBUTE_UNUSED,
   return mode;
 }
 
+rtx
+default_promot_function_mode_convert (machine_mode new_mode ATTRIBUTE_UNUSED,
+                                     machine_mode old_mode ATTRIBUTE_UNUSED,
+                                     rtx decl_rtx ATTRIBUTE_UNUSED)
+{
+  return NULL_RTX;
+}
+
 machine_mode
 default_promote_function_mode_always_promote (const_tree type,
                                              machine_mode mode,
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 86de6ef8a699..204f7f7e0be8 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -31,6 +31,8 @@ extern bool default_const_not_ok_for_debug_p (rtx);
 extern int default_unspec_may_trap_p (const_rtx, unsigned);
 extern machine_mode default_promote_function_mode (const_tree, machine_mode,
                                                        int *, const_tree, int);
+extern rtx default_promote_function_mode_convert (machine_mode, machine_mode,
+                                                 rtx);
 extern machine_mode default_promote_function_mode_always_promote
                        (const_tree, machine_mode, int *, const_tree, int);
 extern machine_mode default_promote_function_mode_sign_extend

Reply via email to