rs6000.c (rs6000_parallel_return): New function.
authorSegher Boessenkool <segher@kernel.crashing.org>
Sat, 17 Jan 2015 20:58:12 +0000 (21:58 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Sat, 17 Jan 2015 20:58:12 +0000 (21:58 +0100)
* config/rs6000/rs6000.c (rs6000_parallel_return): New function.
(rs6000_function_value): Use it.  Handle SCmode and TCmode as well,
for TARGET_32BIT && TARGET_POWERPC64.  Fix another BITS_PER_WORD
snafu.
(rs6000_libcall_value): Use the new function.

From-SVN: r219804

gcc/ChangeLog
gcc/config/rs6000/rs6000.c

index 46515eb43439426e34bca545c35d2865b5ee2f67..fc5fd061099e3b10d64b46d636592499649f7b70 100644 (file)
@@ -1,3 +1,11 @@
+2015-01-17  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       * config/rs6000/rs6000.c (rs6000_parallel_return): New function.
+       (rs6000_function_value): Use it.  Handle SCmode and TCmode as well,
+       for TARGET_32BIT && TARGET_POWERPC64.  Fix another BITS_PER_WORD
+       snafu.
+       (rs6000_libcall_value): Use the new function.
+
 2015-01-17  Sandra Loosemore  <sandra@codesourcery.com>
 
        * doc/invoke.texi ([-ftracer]): Remove duplicate option listing.
index 3926b079523d648f1f90c4aee9c03af528702d49..551181ba7a5c19bfc712e6d0304baca98d2473bc 100644 (file)
@@ -31583,6 +31583,29 @@ rs6000_complex_function_value (machine_mode mode)
   return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
 }
 
+/* Return an rtx describing a return value of MODE as a PARALLEL
+   in N_ELTS registers, each of mode ELT_MODE, starting at REGNO,
+   stride REG_STRIDE.  */
+
+static rtx
+rs6000_parallel_return (machine_mode mode,
+                       int n_elts, machine_mode elt_mode,
+                       unsigned int regno, unsigned int reg_stride)
+{
+  rtx par = gen_rtx_PARALLEL (mode, rtvec_alloc (n_elts));
+
+  int i;
+  for (i = 0; i < n_elts; i++)
+    {
+      rtx r = gen_rtx_REG (elt_mode, regno);
+      rtx off = GEN_INT (i * GET_MODE_SIZE (elt_mode));
+      XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, r, off);
+      regno += reg_stride;
+    }
+
+  return par;
+}
+
 /* Target hook for TARGET_FUNCTION_VALUE.
 
    On the SPE, both FPs and vectors are returned in r3.
@@ -31618,12 +31641,12 @@ rs6000_function_value (const_tree valtype,
       /* Otherwise fall through to standard ABI rules.  */
     }
 
+  mode = TYPE_MODE (valtype);
+
   /* The ELFv2 ABI returns homogeneous VFP aggregates in registers.  */
-  if (rs6000_discover_homogeneous_aggregate (TYPE_MODE (valtype), valtype,
-                                            &elt_mode, &n_elts))
+  if (rs6000_discover_homogeneous_aggregate (mode, valtype, &elt_mode, &n_elts))
     {
-      int first_reg, n_regs, i;
-      rtx par;
+      int first_reg, n_regs;
 
       if (SCALAR_FLOAT_MODE_P (elt_mode))
        {
@@ -31637,53 +31660,25 @@ rs6000_function_value (const_tree valtype,
          n_regs = 1;
        }
 
-      par = gen_rtx_PARALLEL (TYPE_MODE (valtype), rtvec_alloc (n_elts));
-      for (i = 0; i < n_elts; i++)
-       {
-         rtx r = gen_rtx_REG (elt_mode, first_reg + i * n_regs);
-         rtx off = GEN_INT (i * GET_MODE_SIZE (elt_mode));
-         XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, r, off);
-       }
-
-      return par;
+      return rs6000_parallel_return (mode, n_elts, elt_mode, first_reg, n_regs);
     }
 
-  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
-    {
-      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
-      return gen_rtx_PARALLEL (DImode,
-       gen_rtvec (2,
-                  gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (SImode, GP_ARG_RETURN),
-                                     const0_rtx),
-                  gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (SImode,
-                                                  GP_ARG_RETURN + 1),
-                                     GEN_INT (4))));
-    }
-  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DCmode)
-    {
-      return gen_rtx_PARALLEL (DCmode,
-       gen_rtvec (4,
-                  gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (SImode, GP_ARG_RETURN),
-                                     const0_rtx),
-                  gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (SImode,
-                                                  GP_ARG_RETURN + 1),
-                                     GEN_INT (4)),
-                  gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (SImode,
-                                                  GP_ARG_RETURN + 2),
-                                     GEN_INT (8)),
-                  gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (SImode,
-                                                  GP_ARG_RETURN + 3),
-                                     GEN_INT (12))));
-    }
+  /* Some return value types need be split in -mpowerpc64, 32bit ABI.  */
+  if (TARGET_32BIT && TARGET_POWERPC64)
+    switch (mode)
+      {
+      default:
+       break;
+      case DImode:
+      case SCmode:
+      case DCmode:
+      case TCmode:
+       int count = GET_MODE_SIZE (mode) / 4;
+       return rs6000_parallel_return (mode, count, SImode, GP_ARG_RETURN, 1);
+      }
 
-  mode = TYPE_MODE (valtype);
-  if ((INTEGRAL_TYPE_P (valtype) && GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
+  if ((INTEGRAL_TYPE_P (valtype)
+       && GET_MODE_BITSIZE (mode) < (TARGET_32BIT ? 32 : 64))
       || POINTER_TYPE_P (valtype))
     mode = TARGET_32BIT ? SImode : DImode;
 
@@ -31720,19 +31715,9 @@ rs6000_libcall_value (machine_mode mode)
 {
   unsigned int regno;
 
+  /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
   if (TARGET_32BIT && TARGET_POWERPC64 && mode == DImode)
-    {
-      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
-      return gen_rtx_PARALLEL (DImode,
-       gen_rtvec (2,
-                  gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (SImode, GP_ARG_RETURN),
-                                     const0_rtx),
-                  gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (SImode,
-                                                  GP_ARG_RETURN + 1),
-                                     GEN_INT (4))));
-    }
+    return rs6000_parallel_return (mode, 2, SImode, GP_ARG_RETURN, 1);
 
   if (DECIMAL_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
     /* _Decimal128 must use an even/odd register pair.  */