diff mbox series

[1/3] Use sub mode to move block for struct parameter

Message ID 20221129134507.185951-1-guojiufu@linux.ibm.com
State New
Headers show
Series [1/3] Use sub mode to move block for struct parameter | expand

Commit Message

Jiufu Guo Nov. 29, 2022, 1:45 p.m. UTC
Hi,

This patch checks an assignment to see if the "from" is about parameter,
and if the parameter may passing through registers, then use the register
mode to move sub-blocks for the assignment.

Bootstraped and regtested on ppc{,le} and x86_64.
Is this ok for trunk?

BR,
Jeff (Jiufu)

gcc/ChangeLog:

	* expr.cc (move_sub_blocks): New function.
	(expand_assignment): Call move_sub_blocks for assigning from parameter.

---
 gcc/expr.cc | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

Comments

Jiufu Guo Dec. 5, 2022, 6:30 a.m. UTC | #1
Hi,

Jiufu Guo <guojiufu@linux.ibm.com> writes:

> Hi,
>
> This patch checks an assignment to see if the "from" is about parameter,
> and if the parameter may passing through registers, then use the register
> mode to move sub-blocks for the assignment.
>
> Bootstraped and regtested on ppc{,le} and x86_64.
> Is this ok for trunk?
>
> BR,
> Jeff (Jiufu)
>
> gcc/ChangeLog:
>
> 	* expr.cc (move_sub_blocks): New function.
> 	(expand_assignment): Call move_sub_blocks for assigning from parameter.
>
> ---
>  gcc/expr.cc | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 70 insertions(+)
>
> diff --git a/gcc/expr.cc b/gcc/expr.cc
> index d9407432ea5..201fee6fd9a 100644
> --- a/gcc/expr.cc
> +++ b/gcc/expr.cc
> @@ -5559,6 +5559,57 @@ mem_ref_refers_to_non_mem_p (tree ref)
>    return non_mem_decl_p (base);
>  }
>  
> +/* Sub routine of expand_assignment, invoked when assigning from a
> +   parameter or assigning to a return val on struct type which may
> +   be passed through registers.  The mode of register is used to
> +   move the content for the assignment.
> +
> +   This routine generates code for expression FROM which is BLKmode,
> +   and move the generated content to TO_RTX by su-blocks in SUB_MODE.  */
> +
> +static void
> +move_sub_blocks (rtx to_rtx, tree from, machine_mode sub_mode, bool nontemporal)
> +{
> +  HOST_WIDE_INT size, sub_size;
> +  int len;
> +
> +  gcc_assert (MEM_P (to_rtx));
> +
> +  size = MEM_SIZE (to_rtx).to_constant ();
> +  sub_size = GET_MODE_SIZE (sub_mode).to_constant ();
> +  len = size / sub_size;
> +
> +  /* As there are limit registers for passing parameters or return
> +     value according target ABI.  It would be not profitable to move
> +     through sub-modes, if the size does not follow registers.  */
> +  int heurisitic_num = 8;
> +  if (!size || (size % sub_size) != 0 || len < 2 || len > heurisitic_num)
> +    {
I think that when each parameter is initialized and handled during
setup, we already figured out how it is passed by registers or stack (or
mixed).  And we could use this 'accurate' information and not need the
arbitray number here.

BR,
Jeff (Jiufu)
> +      push_temp_slots ();
> +      rtx result = store_expr (from, to_rtx, 0, nontemporal, false);
> +      preserve_temp_slots (result);
> +      pop_temp_slots ();
> +      return;
> +    }
> +
> +  push_temp_slots ();
> +
> +  rtx from_rtx;
> +  from_rtx = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL);
> +  for (int i = 0; i < len; i++)
> +    {
> +      rtx temp = gen_reg_rtx (sub_mode);
> +      rtx src = adjust_address (from_rtx, sub_mode, sub_size * i);
> +      rtx dest = adjust_address (to_rtx, sub_mode, sub_size * i);
> +      emit_move_insn (temp, src);
> +      emit_move_insn (dest, temp);
> +    }
> +
> +  preserve_temp_slots (to_rtx);
> +  pop_temp_slots ();
> +  return;
> +}
> +
>  /* Expand an assignment that stores the value of FROM into TO.  If NONTEMPORAL
>     is true, try generating a nontemporal store.  */
>  
> @@ -6045,6 +6096,25 @@ expand_assignment (tree to, tree from, bool nontemporal)
>        return;
>      }
>  
> +  /* If it is assigning from a struct param which may be passed via registers,
> +     It would be better to use the register's mode to move sub-blocks for the
> +     assignment.  */
> +  if (TREE_CODE (from) == PARM_DECL && mode == BLKmode
> +      && DECL_INCOMING_RTL (from)
> +      && (GET_CODE (DECL_INCOMING_RTL (from)) == PARALLEL
> +	  || REG_P (DECL_INCOMING_RTL (from))))
> +    {
> +      rtx parm = DECL_INCOMING_RTL (from);
> +      machine_mode sub_mode;
> +      if (REG_P (parm))
> +	sub_mode = word_mode;
> +      else
> +	sub_mode = GET_MODE (XEXP (XVECEXP (parm, 0, 0), 0));
> +
> +      move_sub_blocks (to_rtx, from, sub_mode, nontemporal);
> +      return;
> +    }
> +
>    /* Compute FROM and store the value in the rtx we got.  */
>  
>    push_temp_slots ();
diff mbox series

Patch

diff --git a/gcc/expr.cc b/gcc/expr.cc
index d9407432ea5..201fee6fd9a 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -5559,6 +5559,57 @@  mem_ref_refers_to_non_mem_p (tree ref)
   return non_mem_decl_p (base);
 }
 
+/* Sub routine of expand_assignment, invoked when assigning from a
+   parameter or assigning to a return val on struct type which may
+   be passed through registers.  The mode of register is used to
+   move the content for the assignment.
+
+   This routine generates code for expression FROM which is BLKmode,
+   and move the generated content to TO_RTX by su-blocks in SUB_MODE.  */
+
+static void
+move_sub_blocks (rtx to_rtx, tree from, machine_mode sub_mode, bool nontemporal)
+{
+  HOST_WIDE_INT size, sub_size;
+  int len;
+
+  gcc_assert (MEM_P (to_rtx));
+
+  size = MEM_SIZE (to_rtx).to_constant ();
+  sub_size = GET_MODE_SIZE (sub_mode).to_constant ();
+  len = size / sub_size;
+
+  /* As there are limit registers for passing parameters or return
+     value according target ABI.  It would be not profitable to move
+     through sub-modes, if the size does not follow registers.  */
+  int heurisitic_num = 8;
+  if (!size || (size % sub_size) != 0 || len < 2 || len > heurisitic_num)
+    {
+      push_temp_slots ();
+      rtx result = store_expr (from, to_rtx, 0, nontemporal, false);
+      preserve_temp_slots (result);
+      pop_temp_slots ();
+      return;
+    }
+
+  push_temp_slots ();
+
+  rtx from_rtx;
+  from_rtx = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL);
+  for (int i = 0; i < len; i++)
+    {
+      rtx temp = gen_reg_rtx (sub_mode);
+      rtx src = adjust_address (from_rtx, sub_mode, sub_size * i);
+      rtx dest = adjust_address (to_rtx, sub_mode, sub_size * i);
+      emit_move_insn (temp, src);
+      emit_move_insn (dest, temp);
+    }
+
+  preserve_temp_slots (to_rtx);
+  pop_temp_slots ();
+  return;
+}
+
 /* Expand an assignment that stores the value of FROM into TO.  If NONTEMPORAL
    is true, try generating a nontemporal store.  */
 
@@ -6045,6 +6096,25 @@  expand_assignment (tree to, tree from, bool nontemporal)
       return;
     }
 
+  /* If it is assigning from a struct param which may be passed via registers,
+     It would be better to use the register's mode to move sub-blocks for the
+     assignment.  */
+  if (TREE_CODE (from) == PARM_DECL && mode == BLKmode
+      && DECL_INCOMING_RTL (from)
+      && (GET_CODE (DECL_INCOMING_RTL (from)) == PARALLEL
+	  || REG_P (DECL_INCOMING_RTL (from))))
+    {
+      rtx parm = DECL_INCOMING_RTL (from);
+      machine_mode sub_mode;
+      if (REG_P (parm))
+	sub_mode = word_mode;
+      else
+	sub_mode = GET_MODE (XEXP (XVECEXP (parm, 0, 0), 0));
+
+      move_sub_blocks (to_rtx, from, sub_mode, nontemporal);
+      return;
+    }
+
   /* Compute FROM and store the value in the rtx we got.  */
 
   push_temp_slots ();