aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorUlrich Weigand <uweigand@de.ibm.com>2014-07-24 17:11:02 +0000
committerUlrich Weigand <uweigand@gcc.gnu.org>2014-07-24 17:11:02 +0000
commitff46d64d829740dee098b0181d60db1231d90c09 (patch)
tree23523450e5e7f50219b97dbe687585e7113e9bd7 /gcc
parentc41e1ae6c0ee5face983669fc23e418be1faa1da (diff)
downloadgcc-ff46d64d829740dee098b0181d60db1231d90c09.zip
gcc-ff46d64d829740dee098b0181d60db1231d90c09.tar.gz
gcc-ff46d64d829740dee098b0181d60db1231d90c09.tar.bz2
rs6000.c (rs6000_function_arg): If a float argument does not fit fully into floating-point registers...
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/config/rs6000/rs6000.c61
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.target/powerpc/ppc64-abi-warn-1.c12
4 files changed, 84 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1524ee0..244cf23 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 02fc5d9..0f02862 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d37c6a9..f64ab59 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
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.
2014-07-24 Jiong Wang <jiong.wang@arm.com>
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
index 0000000..c70c14c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc64-abi-warn-1.c
@@ -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" } */
+{
+}
+