From e2ff5c1ba465ca4c67eb34bf81d8c13e9056cfd8 Mon Sep 17 00:00:00 2001
From: rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Sun, 14 Nov 2004 06:22:56 +0000
Subject: [PATCH]         * calls.c (precompute_register_parameters): Force all
 PARALLELs         into pseudo registers.         (load_register_parameters):
 Copy PARALLELs into hard registers.         * function.c
 (assign_parm_setup_block): Copy PARALLELS into         pseudo registers.  Do
 emit_group_store in conversion_insns.         * expr.c (emit_group_load_1):
 Rename from emit_group_load, take         tmps as an argument.  Move final
 copy loop ...         (emit_group_load): ... here.  New function.        
 (emit_group_load_into_temps, emit_group_move_into_temps): New.         *
 expr.h: Declare them.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@90613 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog  | 13 +++++++
 gcc/calls.c    | 34 +++++++++++-------
 gcc/expr.c     | 93 +++++++++++++++++++++++++++++++++++++++++++-------
 gcc/expr.h     |  6 ++++
 gcc/function.c | 29 ++++++++++++----
 5 files changed, 143 insertions(+), 32 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index de89cb014687..82ca433c09fe 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2004-11-13  Richard Henderson  <rth@redhat.com>
+
+	* calls.c (precompute_register_parameters): Force all PARALLELs
+	into pseudo registers.
+	(load_register_parameters): Copy PARALLELs into hard registers.
+	* function.c (assign_parm_setup_block): Copy PARALLELS into
+	pseudo registers.  Do emit_group_store in conversion_insns.
+	* expr.c (emit_group_load_1): Rename from emit_group_load, take
+	tmps as an argument.  Move final copy loop ...
+	(emit_group_load): ... here.  New function.
+	(emit_group_load_into_temps, emit_group_move_into_temps): New.
+	* expr.h: Declare them.
+
 2004-11-14  Kazu Hirata  <kazu@cs.umass.edu>
 
 	* tree-cfg.c, tree-if-conv.c, tree-ssa-loop-ivopts.c,
diff --git a/gcc/calls.c b/gcc/calls.c
index cfcf01cf4673..e66181e9f9fc 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -644,7 +644,8 @@ call_expr_flags (tree t)
    Set REG_PARM_SEEN if we encounter a register parameter.  */
 
 static void
-precompute_register_parameters (int num_actuals, struct arg_data *args, int *reg_parm_seen)
+precompute_register_parameters (int num_actuals, struct arg_data *args,
+				int *reg_parm_seen)
 {
   int i;
 
@@ -679,6 +680,17 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, int *reg
 			     TYPE_MODE (TREE_TYPE (args[i].tree_value)),
 			     args[i].value, args[i].unsignedp);
 
+	/* If we're going to have to load the value by parts, pull the
+	   parts into pseudos.  The part extraction process can involve
+	   non-trivial computation.  */
+	if (GET_CODE (args[i].reg) == PARALLEL)
+	  {
+	    tree type = TREE_TYPE (args[i].tree_value);
+	    args[i].value
+	      = emit_group_load_into_temps (args[i].reg, args[i].value,
+					    type, int_size_in_bytes (type));
+	  }
+
 	/* If the value is expensive, and we are inside an appropriately
 	   short loop, put the value into a pseudo and then put the pseudo
 	   into the hard reg.
@@ -687,13 +699,13 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, int *reg
 	   register parameters.  This is to avoid reload conflicts while
 	   loading the parameters registers.  */
 
-	if ((! (REG_P (args[i].value)
-		|| (GET_CODE (args[i].value) == SUBREG
-		    && REG_P (SUBREG_REG (args[i].value)))))
-	    && args[i].mode != BLKmode
-	    && rtx_cost (args[i].value, SET) > COSTS_N_INSNS (1)
-	    && ((SMALL_REGISTER_CLASSES && *reg_parm_seen)
-		|| optimize))
+	else if ((! (REG_P (args[i].value)
+		     || (GET_CODE (args[i].value) == SUBREG
+			 && REG_P (SUBREG_REG (args[i].value)))))
+		 && args[i].mode != BLKmode
+		 && rtx_cost (args[i].value, SET) > COSTS_N_INSNS (1)
+		 && ((SMALL_REGISTER_CLASSES && *reg_parm_seen)
+		     || optimize))
 	  args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);
       }
 }
@@ -1454,11 +1466,7 @@ load_register_parameters (struct arg_data *args, int num_actuals,
 	     locations.  The Irix 6 ABI has examples of this.  */
 
 	  if (GET_CODE (reg) == PARALLEL)
-	    {
-	      tree type = TREE_TYPE (args[i].tree_value);
-	      emit_group_load (reg, args[i].value, type,
-			       int_size_in_bytes (type));
-	    }
+	    emit_group_move (reg, args[i].value);
 
 	  /* If simple case, just do move.  If normal partial, store_one_arg
 	     has already loaded the register for us.  In all other cases,
diff --git a/gcc/expr.c b/gcc/expr.c
index 6037fd12a101..59da4fdbdea5 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -1557,15 +1557,14 @@ gen_group_rtx (rtx orig)
   return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
 }
 
-/* Emit code to move a block ORIG_SRC of type TYPE to a block DST,
-   where DST is non-consecutive registers represented by a PARALLEL.
-   SSIZE represents the total size of block ORIG_SRC in bytes, or -1
-   if not known.  */
+/* A subroutine of emit_group_load.  Arguments as for emit_group_load,
+   except that values are placed in TMPS[i], and must later be moved
+   into corrosponding XEXP (XVECEXP (DST, 0, i), 0) element.  */
 
-void
-emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
+static void
+emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
 {
-  rtx *tmps, src;
+  rtx src;
   int start, i;
   enum machine_mode m = GET_MODE (orig_src);
 
@@ -1585,7 +1584,7 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
       /* ...and back again.  */
       if (imode != BLKmode)
 	src = gen_lowpart (imode, src);
-      emit_group_load (dst, src, type, ssize);
+      emit_group_load_1 (tmps, dst, src, type, ssize);
       return;
     }
 
@@ -1596,8 +1595,6 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
   else
     start = 1;
 
-  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
-
   /* Process the pieces.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
     {
@@ -1709,10 +1706,61 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
 	tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
 				build_int_cst (NULL_TREE, shift), tmps[i], 0);
     }
+}
+
+/* Emit code to move a block SRC of type TYPE to a block DST,
+   where DST is non-consecutive registers represented by a PARALLEL.
+   SSIZE represents the total size of block ORIG_SRC in bytes, or -1
+   if not known.  */
+
+void
+emit_group_load (rtx dst, rtx src, tree type, int ssize)
+{
+  rtx *tmps;
+  int i;
+
+  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
+  emit_group_load_1 (tmps, dst, src, type, ssize);
 
   /* Copy the extracted pieces into the proper (probable) hard regs.  */
-  for (i = start; i < XVECLEN (dst, 0); i++)
-    emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
+  for (i = 0; i < XVECLEN (dst, 0); i++)
+    {
+      rtx d = XEXP (XVECEXP (dst, 0, i), 0);
+      if (d == NULL)
+	continue;
+      emit_move_insn (d, tmps[i]);
+    }
+}
+
+/* Similar, but load SRC into new pseudos in a format that looks like
+   PARALLEL.  This can later be fed to emit_group_move to get things
+   in the right place.  */
+
+rtx
+emit_group_load_into_temps (rtx parallel, rtx src, tree type, int ssize)
+{
+  rtvec vec;
+  int i;
+
+  vec = rtvec_alloc (XVECLEN (parallel, 0));
+  emit_group_load_1 (&RTVEC_ELT (vec, 0), parallel, src, type, ssize);
+
+  /* Convert the vector to look just like the original PARALLEL, except
+     with the computed values.  */
+  for (i = 0; i < XVECLEN (parallel, 0); i++)
+    {
+      rtx e = XVECEXP (parallel, 0, i);
+      rtx d = XEXP (e, 0);
+
+      if (d)
+	{
+	  d = force_reg (GET_MODE (d), RTVEC_ELT (vec, i));
+	  e = alloc_EXPR_LIST (REG_NOTE_KIND (e), d, XEXP (e, 1));
+	}
+      RTVEC_ELT (vec, i) = e;
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (parallel), vec);
 }
 
 /* Emit code to move a block SRC to block DST, where SRC and DST are
@@ -1733,6 +1781,27 @@ emit_group_move (rtx dst, rtx src)
 		    XEXP (XVECEXP (src, 0, i), 0));
 }
 
+/* Move a group of registers represented by a PARALLEL into pseudos.  */
+
+rtx
+emit_group_move_into_temps (rtx src)
+{
+  rtvec vec = rtvec_alloc (XVECLEN (src, 0));
+  int i;
+
+  for (i = 0; i < XVECLEN (src, 0); i++)
+    {
+      rtx e = XVECEXP (src, 0, i);
+      rtx d = XEXP (e, 0);
+
+      if (d)
+	e = alloc_EXPR_LIST (REG_NOTE_KIND (e), copy_to_reg (d), XEXP (e, 1));
+      RTVEC_ELT (vec, i) = e;
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (src), vec);
+}
+
 /* Emit code to move a block SRC to a block ORIG_DST of type TYPE,
    where SRC is non-consecutive registers represented by a PARALLEL.
    SSIZE represents the total size of block ORIG_DST, or -1 if not
diff --git a/gcc/expr.h b/gcc/expr.h
index 21ff1f414018..feac478a5abf 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -387,10 +387,16 @@ extern rtx gen_group_rtx (rtx);
    PARALLEL.  */
 extern void emit_group_load (rtx, rtx, tree, int);
 
+/* Similarly, but load into new temporaries.  */
+extern rtx emit_group_load_into_temps (rtx, rtx, tree, int);
+
 /* Move a non-consecutive group of registers represented by a PARALLEL into
    a non-consecutive group of registers represented by a PARALLEL.  */
 extern void emit_group_move (rtx, rtx);
 
+/* Move a group of registers represented by a PARALLEL into pseudos.  */
+extern rtx emit_group_move_into_temps (rtx);
+
 /* Store a BLKmode value from non-consecutive registers represented by a
    PARALLEL.  */
 extern void emit_group_store (rtx, rtx, tree, int);
diff --git a/gcc/function.c b/gcc/function.c
index 18829019e516..e4e04d2a53d7 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -2536,11 +2536,15 @@ assign_parm_setup_block_p (struct assign_parm_data_one *data)
    present and valid in DATA->STACK_RTL.  */
 
 static void
-assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
+assign_parm_setup_block (struct assign_parm_data_all *all,
+			 tree parm, struct assign_parm_data_one *data)
 {
   rtx entry_parm = data->entry_parm;
   rtx stack_parm = data->stack_parm;
 
+  if (GET_CODE (entry_parm) == PARALLEL)
+    entry_parm = emit_group_move_into_temps (entry_parm);
+
   /* If we've a non-block object that's nevertheless passed in parts,
      reconstitute it in register operations rather than on the stack.  */
   if (GET_CODE (entry_parm) == PARALLEL
@@ -2550,6 +2554,8 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
     {
       rtx parmreg = gen_reg_rtx (data->nominal_mode);
 
+      push_to_sequence (all->conversion_insns);
+
       /* For values returned in multiple registers, handle possible
 	 incompatible calls to emit_group_store.
 
@@ -2572,6 +2578,10 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
       else
 	emit_group_store (parmreg, entry_parm, data->nominal_type,
 			  int_size_in_bytes (data->nominal_type));
+
+      all->conversion_insns = get_insns ();
+      end_sequence ();
+
       SET_DECL_RTL (parm, parmreg);
       return;
     }
@@ -2609,7 +2619,12 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
 
       /* Handle values in multiple non-contiguous locations.  */
       if (GET_CODE (entry_parm) == PARALLEL)
-	emit_group_store (mem, entry_parm, data->passed_type, size);
+	{
+	  push_to_sequence (all->conversion_insns);
+	  emit_group_store (mem, entry_parm, data->passed_type, size);
+	  all->conversion_insns = get_insns ();
+	  end_sequence ();
+	}
 
       else if (size == 0)
 	;
@@ -2648,7 +2663,7 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
 	    {
 	      rtx tem, x;
 	      int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
-	      rtx reg = gen_rtx_REG (word_mode, REGNO (data->entry_parm));
+	      rtx reg = gen_lowpart (word_mode, entry_parm);
 
 	      x = expand_shift (LSHIFT_EXPR, word_mode, reg,
 				build_int_cst (NULL_TREE, by),
@@ -2657,11 +2672,11 @@ assign_parm_setup_block (tree parm, struct assign_parm_data_one *data)
 	      emit_move_insn (tem, x);
 	    }
 	  else
-	    move_block_from_reg (REGNO (data->entry_parm), mem,
+	    move_block_from_reg (REGNO (entry_parm), mem,
 				 size_stored / UNITS_PER_WORD);
 	}
       else
-	move_block_from_reg (REGNO (data->entry_parm), mem,
+	move_block_from_reg (REGNO (entry_parm), mem,
 			     size_stored / UNITS_PER_WORD);
     }
 
@@ -2782,7 +2797,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
 	  emit_move_insn (tempreg, DECL_RTL (parm));
 	  tempreg = convert_to_mode (GET_MODE (parmreg), tempreg, unsigned_p);
 	  emit_move_insn (parmreg, tempreg);
-	  all->conversion_insns = get_insns();
+	  all->conversion_insns = get_insns ();
 	  end_sequence ();
 
 	  did_conversion = true;
@@ -3083,7 +3098,7 @@ assign_parms (tree fndecl)
       assign_parm_adjust_stack_rtl (&data);
 
       if (assign_parm_setup_block_p (&data))
-	assign_parm_setup_block (parm, &data);
+	assign_parm_setup_block (&all, parm, &data);
       else if (data.passed_pointer || use_register_for_decl (parm))
 	assign_parm_setup_reg (&all, parm, &data);
       else
-- 
GitLab