expr.c (gen_group_rtx, [...]): New functions.
authorJohn David Anglin <dave@hiauly1.hia.nrc.ca>
Wed, 27 Nov 2002 02:29:12 +0000 (02:29 +0000)
committerJohn David Anglin <danglin@gcc.gnu.org>
Wed, 27 Nov 2002 02:29:12 +0000 (02:29 +0000)
* expr.c (gen_group_rtx, emit_group_move): New functions.
* expr.h (gen_group_rtx, emit_group_move): Prototype.
* function.c (expand_function_start): Use gen_group_rtx to create a
PARALLEL rtx to hold the return value when the real return rtx is a
PARALLEL.
(expand_function_end): Use emit_group_move to move the return value
from a PARALLEL to the real return registers.
* rtl.h (REG_FUNCTION_VALUE_P): Allow function values to be returned
in PARALLELs.

From-SVN: r59554

gcc/ChangeLog
gcc/expr.c
gcc/expr.h
gcc/function.c
gcc/rtl.h

index a198c85896e9db94cbfb7b653e8fdef26c247d8d..a6572299b2f401faf0ef32c703e815eb0f81bbbb 100644 (file)
@@ -1,3 +1,15 @@
+2002-11-26  John David Anglin  <dave@hiauly1.hia.nrc.ca>
+
+       * expr.c (gen_group_rtx, emit_group_move): New functions.
+       * expr.h (gen_group_rtx, emit_group_move): Prototype.
+       * function.c (expand_function_start): Use gen_group_rtx to create a
+       PARALLEL rtx to hold the return value when the real return rtx is a
+       PARALLEL.
+       (expand_function_end): Use emit_group_move to move the return value
+       from a PARALLEL to the real return registers.
+       * rtl.h (REG_FUNCTION_VALUE_P): Allow function values to be returned
+       in PARALLELs.
+
 2002-11-26  Jason Thorpe  <thorpej@wasabisystems.com>
 
        * config/t-libc-ok: Fix typo.
index 8dd9a8678b5b39e018b044f8eba75a3a2a0b9d42..8851343299ae2c3b445d692f405482e825ad1e2b 100644 (file)
@@ -2203,6 +2203,42 @@ move_block_from_reg (regno, x, nregs, size)
     }
 }
 
+/* Generate a PARALLEL rtx for a new non-consecutive group of registers from
+   ORIG, where ORIG is a non-consecutive group of registers represented by
+   a PARALLEL.  The clone is identical to the original except in that the
+   original set of registers is replaced by a new set of pseudo registers.
+   The new set has the same modes as the original set.  */
+
+rtx
+gen_group_rtx (orig)
+     rtx orig;
+{
+  int i, length;
+  rtx *tmps;
+
+  if (GET_CODE (orig) != PARALLEL)
+    abort ();
+
+  length = XVECLEN (orig, 0);
+  tmps = (rtx *) alloca (sizeof (rtx) * length);
+
+  /* Skip a NULL entry in first slot.  */
+  i = XEXP (XVECEXP (orig, 0, 0), 0) ? 0 : 1;
+
+  if (i)
+    tmps[0] = 0;
+
+  for (; i < length; i++)
+    {
+      enum machine_mode mode = GET_MODE (XEXP (XVECEXP (orig, 0, i), 0));
+      rtx offset = XEXP (XVECEXP (orig, 0, i), 1);
+
+      tmps[i] = gen_rtx_EXPR_LIST (VOIDmode, gen_reg_rtx (mode), offset);
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
+}
+
 /* Emit code to move a block SRC to a block DST, where DST is non-consecutive
    registers represented by a PARALLEL.  SSIZE represents the total size of
    block SRC in bytes, or -1 if not known.  */
@@ -2324,6 +2360,26 @@ emit_group_load (dst, orig_src, ssize)
     emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
 }
 
+/* Emit code to move a block SRC to block DST, where SRC and DST are
+   non-consecutive groups of registers, each represented by a PARALLEL.  */
+
+void
+emit_group_move (dst, src)
+     rtx dst, src;
+{
+  int i;
+
+  if (GET_CODE (src) != PARALLEL
+      || GET_CODE (dst) != PARALLEL
+      || XVECLEN (src, 0) != XVECLEN (dst, 0))
+    abort ();
+
+  /* Skip first entry if NULL.  */
+  for (i = XEXP (XVECEXP (src, 0, 0), 0) ? 0 : 1; i < XVECLEN (src, 0); i++)
+    emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0),
+                   XEXP (XVECEXP (src, 0, i), 0));
+}
+
 /* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
    registers represented by a PARALLEL.  SSIZE represents the total size of
    block DST, or -1 if not known.  */
index e8b2c1760646592c9740dcfa80301690fd55b7f5..6e8d19e994b84702c7d7c3a6aac3cea95b6e2c03 100644 (file)
@@ -412,10 +412,17 @@ extern void move_block_to_reg PARAMS ((int, rtx, int, enum machine_mode));
    The number of registers to be filled is NREGS.  */
 extern void move_block_from_reg PARAMS ((int, rtx, int, int));
 
+/* Generate a non-consecutive group of registers represented by a PARALLEL.  */
+extern rtx gen_group_rtx PARAMS ((rtx));
+
 /* Load a BLKmode value into non-consecutive registers represented by a
    PARALLEL.  */
 extern void emit_group_load PARAMS ((rtx, rtx, 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 PARAMS ((rtx, rtx));
+
 /* Store a BLKmode value from non-consecutive registers represented by a
    PARALLEL.  */
 extern void emit_group_store PARAMS ((rtx, rtx, int));
index 0c066ed03588974b5be2fe32f8a84cd4a48be143..6e6d6d7fbf941a41e2b53f71f834c0d415bcde23 100644 (file)
@@ -6559,18 +6559,17 @@ expand_function_start (subr, parms_have_cleanups)
                               subr, 1);
 
       /* Structures that are returned in registers are not aggregate_value_p,
-        so we may see a PARALLEL.  Don't play pseudo games with this.  */
-      if (! REG_P (hard_reg))
-       SET_DECL_RTL (DECL_RESULT (subr), hard_reg);
+        so we may see a PARALLEL or a REG.  */
+      if (REG_P (hard_reg))
+       SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+      else if (GET_CODE (hard_reg) == PARALLEL)
+       SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
       else
-       {
-         /* Create the pseudo.  */
-         SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (GET_MODE (hard_reg)));
+       abort ();
 
-         /* Needed because we may need to move this to memory
-            in case it's a named return value whose address is taken.  */
-         DECL_REGISTER (DECL_RESULT (subr)) = 1;
-       }
+      /* Set DECL_REGISTER flag so that expand_function_end will copy the
+        result to the real return register(s).  */
+      DECL_REGISTER (DECL_RESULT (subr)) = 1;
     }
 
   /* Initialize rtx for parameters and local variables.
@@ -6998,8 +6997,16 @@ expand_function_end (filename, line, end_bindings)
              convert_move (real_decl_rtl, decl_rtl, unsignedp);
            }
          else if (GET_CODE (real_decl_rtl) == PARALLEL)
-           emit_group_load (real_decl_rtl, decl_rtl,
-                            int_size_in_bytes (TREE_TYPE (decl_result)));
+           {
+             /* If expand_function_start has created a PARALLEL for decl_rtl,
+                move the result to the real return registers.  Otherwise, do
+                a group load from decl_rtl for a named return.  */
+             if (GET_CODE (decl_rtl) == PARALLEL)
+               emit_group_move (real_decl_rtl, decl_rtl);
+             else
+               emit_group_load (real_decl_rtl, decl_rtl,
+                                int_size_in_bytes (TREE_TYPE (decl_result)));
+           }
          else
            emit_move_insn (real_decl_rtl, decl_rtl);
        }
index 1d71ec90ce41d1400fe893224656082e66e654a7..5f727b08d9c70c3c69447270b31ca42cc7ca06a2 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -185,7 +185,7 @@ struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"),
      has used it as the function.  */
   unsigned int used : 1;
   /* Nonzero if this rtx came from procedure integration.
-     1 in a REG means this reg refers to the return value
+     1 in a REG or PARALLEL means this rtx refers to the return value
      of the current function.
      1 in a SYMBOL_REF if the symbol is weak.  */
   unsigned integrated : 1;
@@ -988,9 +988,10 @@ enum label_kind
 #define REGNO(RTX) XCUINT (RTX, 0, REG)
 #define ORIGINAL_REGNO(RTX) X0UINT (RTX, 1)
 
-/* 1 if RTX is a reg that is the current function's return value.  */
+/* 1 if RTX is a reg or parallel that is the current function's return
+   value.  */
 #define REG_FUNCTION_VALUE_P(RTX)                                      \
-  (RTL_FLAG_CHECK1("REG_FUNCTION_VALUE_P", (RTX), REG)->integrated)
+  (RTL_FLAG_CHECK2("REG_FUNCTION_VALUE_P", (RTX), REG, PARALLEL)->integrated)
 
 /* 1 if RTX is a reg that corresponds to a variable declared by the user.  */
 #define REG_USERVAR_P(RTX)                                             \