rs6000.c (rs6000_psave_function_arg): New function.
authorUlrich Weigand <uweigand@de.ibm.com>
Thu, 14 Nov 2013 18:39:14 +0000 (18:39 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Thu, 14 Nov 2013 18:39:14 +0000 (18:39 +0000)
2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>

* config/rs6000/rs6000.c (rs6000_psave_function_arg): New function.
(rs6000_finish_function_arg): Likewise.
(rs6000_function_arg): Use rs6000_psave_function_arg and
rs6000_finish_function_arg to handle both vector and floating
point arguments that are also passed in GPRs / the stack.

From-SVN: r204806

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

index c51ea9b..bf58d4b 100644 (file)
@@ -1,5 +1,13 @@
 2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
 
+       * config/rs6000/rs6000.c (rs6000_psave_function_arg): New function.
+       (rs6000_finish_function_arg): Likewise.
+       (rs6000_function_arg): Use rs6000_psave_function_arg and
+       rs6000_finish_function_arg to handle both vector and floating
+       point arguments that are also passed in GPRs / the stack.
+
+2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
+
        * config/rs6000/rs6000.c (USE_FP_FOR_ARG_P): Remove TYPE argument.
        (USE_ALTIVEC_FOR_ARG_P): Likewise.
        (rs6000_darwin64_record_arg_advance_recurse): Update uses.
index faeacb0..dd95494 100644 (file)
@@ -9516,6 +9516,83 @@ rs6000_mixed_function_arg (enum machine_mode mode, const_tree type,
   return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
 }
 
+/* We have an argument of MODE and TYPE that goes into FPRs or VRs,
+   but must also be copied into the parameter save area starting at
+   offset ALIGN_WORDS.  Fill in RVEC with the elements corresponding
+   to the GPRs and/or memory.  Return the number of elements used.  */
+
+static int
+rs6000_psave_function_arg (enum machine_mode mode, const_tree type,
+                          int align_words, rtx *rvec)
+{
+  int k = 0;
+
+  if (align_words < GP_ARG_NUM_REG)
+    {
+      int n_words = rs6000_arg_size (mode, type);
+
+      if (align_words + n_words > GP_ARG_NUM_REG
+         || (TARGET_32BIT && TARGET_POWERPC64))
+       {
+         /* If this is partially on the stack, then we only
+            include the portion actually in registers here.  */
+         enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
+         int i = 0;
+
+         if (align_words + n_words > GP_ARG_NUM_REG)
+           {
+             /* Not all of the arg fits in gprs.  Say that it goes in memory
+                too, using a magic NULL_RTX component.  Also see comment in
+                rs6000_mixed_function_arg for why the normal
+                function_arg_partial_nregs scheme doesn't work in this case. */
+             rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
+           }
+
+         do
+           {
+             rtx r = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
+             rtx off = GEN_INT (i++ * GET_MODE_SIZE (rmode));
+             rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
+           }
+         while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
+       }
+      else
+       {
+         /* The whole arg fits in gprs.  */
+         rtx r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+         rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
+       }
+    }
+  else
+    {
+      /* It's entirely in memory.  */
+      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
+    }
+
+  return k;
+}
+
+/* RVEC is a vector of K components of an argument of mode MODE.
+   Construct the final function_arg return value from it.  */
+
+static rtx
+rs6000_finish_function_arg (enum machine_mode mode, rtx *rvec, int k)
+{
+  gcc_assert (k >= 1);
+
+  /* Avoid returning a PARALLEL in the trivial cases.  */
+  if (k == 1)
+    {
+      if (XEXP (rvec[0], 0) == NULL_RTX)
+       return NULL_RTX;
+
+      if (GET_MODE (XEXP (rvec[0], 0)) == mode)
+       return XEXP (rvec[0], 0);
+    }
+
+  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
+}
+
 /* Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
@@ -9585,32 +9662,25 @@ rs6000_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
     }
 
   if (USE_ALTIVEC_FOR_ARG_P (cum, mode, named))
-    if (TARGET_64BIT && ! cum->prototype)
-      {
-       /* Vector parameters get passed in vector register
-          and also in GPRs or memory, in absence of prototype.  */
-       int align_words;
-       rtx slot;
-       align_words = (cum->words + 1) & ~1;
+    {
+      rtx rvec[GP_ARG_NUM_REG + 1];
+      rtx r;
+      int k = 0;
 
-       if (align_words >= GP_ARG_NUM_REG)
-         {
-           slot = NULL_RTX;
-         }
-       else
-         {
-           slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
-         }
-       return gen_rtx_PARALLEL (mode,
-                gen_rtvec (2,
-                           gen_rtx_EXPR_LIST (VOIDmode,
-                                              slot, const0_rtx),
-                           gen_rtx_EXPR_LIST (VOIDmode,
-                                              gen_rtx_REG (mode, cum->vregno),
-                                              const0_rtx)));
-      }
-    else
-      return gen_rtx_REG (mode, cum->vregno);
+      /* Do we also need to pass this argument in the parameter
+        save area?  */
+      if (TARGET_64BIT && ! cum->prototype)
+       {
+         int align_words = (cum->words + 1) & ~1;
+         k = rs6000_psave_function_arg (mode, type, align_words, rvec);
+       }
+
+      /* Describe where this argument goes in the vector registers.  */
+      r = gen_rtx_REG (mode, cum->vregno);
+      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
+
+      return rs6000_finish_function_arg (mode, rvec, k);
+    }
   else if (TARGET_ALTIVEC_ABI
           && (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
               || (type && TREE_CODE (type) == VECTOR_TYPE
@@ -9716,85 +9786,33 @@ rs6000_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
        {
          rtx rvec[GP_ARG_NUM_REG + 1];
          rtx r;
-         int k;
-         bool needs_psave;
+         int k = 0;
          enum machine_mode fmode = mode;
          unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
 
-         if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
-           {
-             /* Currently, we only ever need one reg here because complex
-                doubles are split.  */
-             gcc_assert (cum->fregno == FP_ARG_MAX_REG
-                         && (fmode == TFmode || fmode == TDmode));
-
-             /* Long double or _Decimal128 split over regs and memory.  */
-             fmode = DECIMAL_FLOAT_MODE_P (fmode) ? DDmode : DFmode;
-           }
-
-         /* Do we also need to pass this arg in the parameter save
-            area?  */
-         needs_psave = (type
-                        && (cum->nargs_prototype <= 0
-                            || (DEFAULT_ABI == ABI_AIX
-                                && TARGET_XL_COMPAT
-                                && align_words >= GP_ARG_NUM_REG)));
+         /* Do we also need to pass this argument in the parameter
+            save area?  */
+         if (type && (cum->nargs_prototype <= 0
+                      || (DEFAULT_ABI == ABI_AIX
+                          && TARGET_XL_COMPAT
+                          && align_words >= GP_ARG_NUM_REG)))
+           k = rs6000_psave_function_arg (mode, type, align_words, rvec);
 
-         if (!needs_psave && mode == fmode)
-           return gen_rtx_REG (fmode, cum->fregno);
+         /* Describe where this argument goes in the fprs.  */
 
-         k = 0;
-         if (needs_psave)
+         /* Check if the argument is split over registers and memory.
+            This can only ever happen for long double or _Decimal128;
+            complex types are handled via split_complex_arg.  */
+         if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
            {
-             /* Describe the part that goes in gprs or the stack.
-                This piece must come first, before the fprs.  */
-             if (align_words < GP_ARG_NUM_REG)
-               {
-                 unsigned long n_words = rs6000_arg_size (mode, type);
-
-                 if (align_words + n_words > GP_ARG_NUM_REG
-                     || (TARGET_32BIT && TARGET_POWERPC64))
-                   {
-                     /* If this is partially on the stack, then we only
-                        include the portion actually in registers here.  */
-                     enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
-                     rtx off;
-                     int i = 0;
-                     if (align_words + n_words > GP_ARG_NUM_REG)
-                       /* Not all of the arg fits in gprs.  Say that it
-                          goes in memory too, using a magic NULL_RTX
-                          component.  Also see comment in
-                          rs6000_mixed_function_arg for why the normal
-                          function_arg_partial_nregs scheme doesn't work
-                          in this case. */
-                       rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX,
-                                                      const0_rtx);
-                     do
-                       {
-                         r = gen_rtx_REG (rmode,
-                                          GP_ARG_MIN_REG + align_words);
-                         off = GEN_INT (i++ * GET_MODE_SIZE (rmode));
-                         rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
-                       }
-                     while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
-                   }
-                 else
-                   {
-                     /* The whole arg fits in gprs.  */
-                     r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
-                     rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
-                   }
-               }
-             else
-               /* It's entirely in memory.  */
-               rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
+             gcc_assert (fmode == TFmode || fmode == TDmode);
+             fmode = DECIMAL_FLOAT_MODE_P (fmode) ? DDmode : DFmode;
            }
 
-         /* Describe where this piece goes in the fprs.  */
          r = gen_rtx_REG (fmode, cum->fregno);
          rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
 
-         return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
+         return rs6000_finish_function_arg (mode, rvec, k);
        }
       else if (align_words < GP_ARG_NUM_REG)
        {