]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
rs6000.c (rs6000_function_arg): If a float argument does not fit fully into floating...
authorUlrich Weigand <uweigand@de.ibm.com>
Thu, 24 Jul 2014 17:11:02 +0000 (17:11 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Thu, 24 Jul 2014 17:11:02 +0000 (17:11 +0000)
gcc/

* config/rs6000/rs6000.c (rs6000_function_arg): If a float argument
does not fit fully into floating-point registers, and there is still
space in the register parameter area, use GPRs to pass those parts
of the argument.  Issue -Wpsabi note if any parameter is now treated
differently than before.
(rs6000_arg_partial_bytes): Update.

gcc/testsuite/

* gcc.target/powerpc/ppc64-abi-warn-1.c: New test.

From-SVN: r213015

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/ppc64-abi-warn-1.c [new file with mode: 0644]

index 1524ee03dee76c192a26e523a584bcfa8a2ef767..244cf230c41be099c5cee5ad1f75705db437be75 100644 (file)
@@ -1,3 +1,12 @@
+2014-07-24  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
+
+       * config/rs6000/rs6000.c (rs6000_function_arg): If a float argument
+       does not fit fully into floating-point registers, and there is still
+       space in the register parameter area, use GPRs to pass those parts
+       of the argument.  Issue -Wpsabi note if any parameter is now treated
+       differently than before.
+       (rs6000_arg_partial_bytes): Update.
+
 2014-07-24  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/alpha/elf.h: Define TARGET_UNWIND_TABLES_DEFAULT.
index 02fc5d90492167e776a5a9ef4de26f9a07eae0bc..0f028623871faa1bbceb6fc3ee21495b1811e929 100644 (file)
@@ -10229,6 +10229,7 @@ rs6000_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
          rtx r, off;
          int i, k = 0;
          unsigned long n_fpreg = (GET_MODE_SIZE (elt_mode) + 7) >> 3;
+         int fpr_words;
 
          /* Do we also need to pass this argument in the parameter
             save area?  */
@@ -10257,6 +10258,47 @@ rs6000_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
              rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
            }
 
+         /* If there were not enough FPRs to hold the argument, the rest
+            usually goes into memory.  However, if the current position
+            is still within the register parameter area, a portion may
+            actually have to go into GPRs.
+
+            Note that it may happen that the portion of the argument
+            passed in the first "half" of the first GPR was already
+            passed in the last FPR as well.
+
+            For unnamed arguments, we already set up GPRs to cover the
+            whole argument in rs6000_psave_function_arg, so there is
+            nothing further to do at this point.  */
+         fpr_words = (i * GET_MODE_SIZE (elt_mode)) / (TARGET_32BIT ? 4 : 8);
+         if (i < n_elts && align_words + fpr_words < GP_ARG_NUM_REG
+             && cum->nargs_prototype > 0)
+            {
+             static bool warned;
+
+             enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
+             int n_words = rs6000_arg_size (mode, type);
+
+             align_words += fpr_words;
+             n_words -= fpr_words;
+
+             do
+               {
+                 r = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
+                 off = GEN_INT (fpr_words++ * GET_MODE_SIZE (rmode));
+                 rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
+               }
+             while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
+
+             if (!warned && warn_psabi)
+               {
+                 warned = true;
+                 inform (input_location,
+                         "the ABI of passing homogeneous float aggregates"
+                         " has changed in GCC 4.10");
+               }
+           }
+
          return rs6000_finish_function_arg (mode, rvec, k);
        }
       else if (align_words < GP_ARG_NUM_REG)
@@ -10332,8 +10374,23 @@ rs6000_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode,
       /* Otherwise, we pass in FPRs only.  Check for partial copies.  */
       passed_in_gprs = false;
       if (cum->fregno + n_elts * n_fpreg > FP_ARG_MAX_REG + 1)
-       ret = ((FP_ARG_MAX_REG + 1 - cum->fregno)
-              * MIN (8, GET_MODE_SIZE (elt_mode)));
+       {
+         /* Compute number of bytes / words passed in FPRs.  If there
+            is still space available in the register parameter area
+            *after* that amount, a part of the argument will be passed
+            in GPRs.  In that case, the total amount passed in any
+            registers is equal to the amount that would have been passed
+            in GPRs if everything were passed there, so we fall back to
+            the GPR code below to compute the appropriate value.  */
+         int fpr = ((FP_ARG_MAX_REG + 1 - cum->fregno)
+                    * MIN (8, GET_MODE_SIZE (elt_mode)));
+         int fpr_words = fpr / (TARGET_32BIT ? 4 : 8);
+
+         if (align_words + fpr_words < GP_ARG_NUM_REG)
+           passed_in_gprs = true;
+         else
+           ret = fpr;
+       }
     }
 
   if (passed_in_gprs
index d37c6a94737dab1b8fac324b797472cf6423ef6b..f64ab591c9864f78ccf2cfcc3d4c3d6d7936c893 100644 (file)
@@ -1,3 +1,7 @@
+2014-07-24  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
+
+       * gcc.target/powerpc/ppc64-abi-warn-1.c: New test.
+
 2014-07-24  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
 
        * g++.dg/compat/struct-layout-1.exp: Load g++-dg.exp.
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc64-abi-warn-1.c b/gcc/testsuite/gcc.target/powerpc/ppc64-abi-warn-1.c
new file mode 100644 (file)
index 0000000..c70c14c
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile { target { powerpc*-*-linux* && lp64 } } } */
+/* { dg-options "-mabi=elfv2" } */
+
+struct f8
+  {
+    float x[8];
+  };
+
+void test (struct f8 a, struct f8 b) /* { dg-message "note: the ABI of passing homogeneous float aggregates has changed" } */
+{
+}
+