public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-1462] middle-end: Support ABIs that pass FP values as wider integers.
@ 2022-07-04 15:47 Roger Sayle
  0 siblings, 0 replies; only message in thread
From: Roger Sayle @ 2022-07-04 15:47 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:ac4c8f53b0f735be17aa020796602de2299da1c5

commit r13-1462-gac4c8f53b0f735be17aa020796602de2299da1c5
Author: Roger Sayle <roger@nextmovesoftware.com>
Date:   Mon Jul 4 16:45:47 2022 +0100

    middle-end: Support ABIs that pass FP values as wider integers.
    
    Sorry for the long delay getting back to this, but after deeper
    investigation, it turns out that Jeff Law's tingling spider senses
    that the original patch wasn't updating everywhere that was required
    were spot on.  Although my nvptx testing showed no problems with -O2,
    compiling the same tests with -O0 found several additional assertion
    ICEs (exactly where he'd predicted they'd be).
    
    Here's a revised patch that updates five locations (up from the
    previous two).  Finding any remaining locations (if any) might be
    easier once folks are able to test things on their targets.  This
    also implements Jeff's suggestion to factor the common code into
    helper routines.
    
    2022-07-04  Roger Sayle  <roger@nextmovesoftware.com>
    
    gcc/ChangeLog
            PR target/104489
            * calls.cc (precompute_register_parameters): Allow promotion
            of floating point values to be passed in wider integer modes
            by calling new convert_float_to_wider_int.
            (expand_call): Allow floating point results to be returned in
            wider integer modes by calling new convert wider_int_to_float.
            * cfgexpand.cc (expand_value_return): Allow backends to promote
            a scalar floating point return value to a wider integer mode
            by calling new convert_float_to_wider_int.
            * expr.cc (convert_float_to_wider_int): New function.
            (convert_wider_int_to_float): Likewise.
            (expand_expr_real_1) <expand_decl_rtl>: Allow backends to promote
            scalar FP PARM_DECLs to wider integer modes, by calling new
            convert_wider_int_to_float.
            * expr.h (convert_modes): Name arguments for improved documentation.
            (convert_float_to_wider_int): Prototype new function here.
            (convert_wider_int_to_float): Likewise.
            * function.cc (assign_parm_setup_stack): Allow floating point
            values to be passed on the stack as wider integer modes by
            calling new convert_wider_int_to_float.

Diff:
---
 gcc/calls.cc     | 38 +++++++++++++++++++++++++++-----------
 gcc/cfgexpand.cc | 13 ++++++++++++-
 gcc/expr.cc      | 35 +++++++++++++++++++++++++++++++++++
 gcc/expr.h       | 11 ++++++++++-
 gcc/function.cc  | 11 +++++++++++
 5 files changed, 95 insertions(+), 13 deletions(-)

diff --git a/gcc/calls.cc b/gcc/calls.cc
index f4e1299505e..7f3cf5fd047 100644
--- a/gcc/calls.cc
+++ b/gcc/calls.cc
@@ -992,11 +992,21 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
 	/* If we are to promote the function arg to a wider mode,
 	   do it now.  */
 
-	if (args[i].mode != TYPE_MODE (TREE_TYPE (args[i].tree_value)))
-	  args[i].value
-	    = convert_modes (args[i].mode,
-			     TYPE_MODE (TREE_TYPE (args[i].tree_value)),
-			     args[i].value, args[i].unsignedp);
+	machine_mode old_mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
+
+	/* Some ABIs require scalar floating point modes to be returned
+	   in a wider scalar integer mode.  We need to explicitly
+	   reinterpret to an integer mode of the correct precision
+	   before extending to the desired result.  */
+	if (SCALAR_INT_MODE_P (args[i].mode)
+	    && SCALAR_FLOAT_MODE_P (old_mode)
+	    && known_gt (GET_MODE_SIZE (args[i].mode),
+			 GET_MODE_SIZE (old_mode)))
+	  args[i].value = convert_float_to_wider_int (args[i].mode, old_mode,
+						      args[i].value);
+	else if (args[i].mode != old_mode)
+	  args[i].value = convert_modes (args[i].mode, old_mode,
+					 args[i].value, args[i].unsignedp);
 
 	/* If the value is a non-legitimate constant, force it into a
 	   pseudo now.  TLS symbols sometimes need a call to resolve.  */
@@ -3825,18 +3835,24 @@ expand_call (tree exp, rtx target, int ignore)
 	{
 	  tree type = rettype;
 	  int unsignedp = TYPE_UNSIGNED (type);
+	  machine_mode ret_mode = TYPE_MODE (type);
 	  machine_mode pmode;
 
 	  /* Ensure we promote as expected, and get the new unsignedness.  */
-	  pmode = promote_function_mode (type, TYPE_MODE (type), &unsignedp,
+	  pmode = promote_function_mode (type, ret_mode, &unsignedp,
 					 funtype, 1);
 	  gcc_assert (GET_MODE (target) == pmode);
 
-	  poly_uint64 offset = subreg_lowpart_offset (TYPE_MODE (type),
-						      GET_MODE (target));
-	  target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
-	  SUBREG_PROMOTED_VAR_P (target) = 1;
-	  SUBREG_PROMOTED_SET (target, unsignedp);
+	  if (SCALAR_INT_MODE_P (pmode)
+	      && SCALAR_FLOAT_MODE_P (ret_mode)
+	      && known_gt (GET_MODE_SIZE (pmode), GET_MODE_SIZE (ret_mode)))
+	    target = convert_wider_int_to_float (ret_mode, pmode, target);
+	  else
+	    {
+	      target = gen_lowpart_SUBREG (ret_mode, target);
+	      SUBREG_PROMOTED_VAR_P (target) = 1;
+	      SUBREG_PROMOTED_SET (target, unsignedp);
+	    }
 	}
 
       /* If size of args is variable or this was a constructor call for a stack
diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index 1d7f6b260d0..dd29ffffc03 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -3720,7 +3720,18 @@ expand_value_return (rtx val)
         mode = promote_function_mode (type, old_mode, &unsignedp, funtype, 1);
 
       if (mode != old_mode)
-	val = convert_modes (mode, old_mode, val, unsignedp);
+	{
+	  /* Some ABIs require scalar floating point modes to be returned
+	     in a wider scalar integer mode.  We need to explicitly
+	     reinterpret to an integer mode of the correct precision
+	     before extending to the desired result.  */
+	  if (SCALAR_INT_MODE_P (mode)
+	      && SCALAR_FLOAT_MODE_P (old_mode)
+	      && known_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (old_mode)))
+	    val = convert_float_to_wider_int (mode, old_mode, val);
+	  else
+	    val = convert_modes (mode, old_mode, val, unsignedp);
+	}
 
       if (GET_CODE (return_reg) == PARALLEL)
 	emit_group_load (return_reg, val, type, int_size_in_bytes (type));
diff --git a/gcc/expr.cc b/gcc/expr.cc
index 53af027a4d0..62297379ec9 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -776,6 +776,32 @@ convert_modes (machine_mode mode, machine_mode oldmode, rtx x, int unsignedp)
   convert_move (temp, x, unsignedp);
   return temp;
 }
+
+/* Variant of convert_modes for ABI parameter passing/return.
+   Return an rtx for a value that would result from converting X from
+   a floating point mode FMODE to wider integer mode MODE.  */
+
+rtx
+convert_float_to_wider_int (machine_mode mode, machine_mode fmode, rtx x)
+{
+  gcc_assert (SCALAR_INT_MODE_P (mode) && SCALAR_FLOAT_MODE_P (fmode));
+  scalar_int_mode tmp_mode = int_mode_for_mode (fmode).require ();
+  rtx tmp = force_reg (tmp_mode, gen_lowpart (tmp_mode, x));
+  return convert_modes (mode, tmp_mode, tmp, 1);
+}
+
+/* Variant of convert_modes for ABI parameter passing/return.
+   Return an rtx for a value that would result from converting X from
+   an integer mode IMODE to a narrower floating point mode MODE.  */
+ 
+rtx
+convert_wider_int_to_float (machine_mode mode, machine_mode imode, rtx x)
+{
+  gcc_assert (SCALAR_FLOAT_MODE_P (mode) && SCALAR_INT_MODE_P (imode));
+  scalar_int_mode tmp_mode = int_mode_for_mode (mode).require ();
+  rtx tmp = force_reg (tmp_mode, gen_lowpart (tmp_mode, x));
+  return gen_lowpart_SUBREG (mode, tmp);
+}
 \f
 /* Return the largest alignment we can use for doing a move (or store)
    of MAX_PIECES.  ALIGN is the largest alignment we could use.  */
@@ -10771,6 +10797,15 @@ 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);
 
+	  /* 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
+	     using a SUBREG to reinterpret as a floating point value.  */
+	  if (SCALAR_FLOAT_MODE_P (mode)
+	      && SCALAR_INT_MODE_P (pmode)
+	      && known_lt (GET_MODE_SIZE (mode), GET_MODE_SIZE (pmode)))
+	    return convert_wider_int_to_float (mode, pmode, decl_rtl);
+
 	  temp = gen_lowpart_SUBREG (mode, decl_rtl);
 	  SUBREG_PROMOTED_VAR_P (temp) = 1;
 	  SUBREG_PROMOTED_SET (temp, unsignedp);
diff --git a/gcc/expr.h b/gcc/expr.h
index 03511832405..b00c068f2fa 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -69,7 +69,16 @@ extern void convert_move (rtx, rtx, int);
 extern rtx convert_to_mode (machine_mode, rtx, int);
 
 /* Convert an rtx to MODE from OLDMODE and return the result.  */
-extern rtx convert_modes (machine_mode, machine_mode, rtx, int);
+extern rtx convert_modes (machine_mode mode, machine_mode oldmode,
+			  rtx x, int unsignedp);
+
+/* Variant of convert_modes for ABI parameter passing/return.  */
+extern rtx convert_float_to_wider_int (machine_mode mode, machine_mode fmode,
+				       rtx x);
+
+/* Variant of convert_modes for ABI parameter passing/return.  */
+extern rtx convert_wider_int_to_float (machine_mode mode, machine_mode imode,
+				       rtx x);
 
 /* Expand a call to memcpy or memmove or memcmp, and return the result.  */
 extern rtx emit_block_op_via_libcall (enum built_in_function, rtx, rtx, rtx,
diff --git a/gcc/function.cc b/gcc/function.cc
index 0c3e4fffb05..31256b57197 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -3472,6 +3472,17 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
 
       emit_move_insn (tempreg, validize_mem (copy_rtx (data->entry_parm)));
 
+      /* 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
+	 using a SUBREG to reinterpret as a floating point value.  */
+      if (SCALAR_FLOAT_MODE_P (data->nominal_mode)
+	  && SCALAR_INT_MODE_P (data->arg.mode)
+	  && known_lt (GET_MODE_SIZE (data->nominal_mode),
+		       GET_MODE_SIZE (data->arg.mode)))
+	tempreg = convert_wider_int_to_float (data->nominal_mode,
+					      data->arg.mode, tempreg);
+
       push_to_sequence2 (all->first_conversion_insn, all->last_conversion_insn);
       to_conversion = true;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-07-04 15:47 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-04 15:47 [gcc r13-1462] middle-end: Support ABIs that pass FP values as wider integers Roger Sayle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).