diff mbox

[rs6000,v2] Fix ELFv2 homogeneous float aggregate ABI bug

Message ID 201407141852.s6EIqmOw008657@d06av02.portsmouth.uk.ibm.com
State New
Headers show

Commit Message

Ulrich Weigand July 14, 2014, 6:52 p.m. UTC
Hello,

this patch updates the prior version:
https://gcc.gnu.org/ml/gcc-patches/2014-07/msg00632.html
to add a -Wpsabi note as discussed.

(We may need to change the "GCC 4.10" string if the next release turns out
to get a different name ...)

In a testsuite run, this note triggers only in those two ABI compat suite
test cases mentioned in the previous patch email (only on ELFv2, of course).

Tested on powerpc64le-linux.

OK for mainline?

Bye,
Ulrich


gcc/testsuite/ChangLog:

	* 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/ChangLog:

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

Comments

David Edelsohn July 18, 2014, 4:27 p.m. UTC | #1
On Mon, Jul 14, 2014 at 2:52 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> Hello,
>
> this patch updates the prior version:
> https://gcc.gnu.org/ml/gcc-patches/2014-07/msg00632.html
> to add a -Wpsabi note as discussed.
>
> (We may need to change the "GCC 4.10" string if the next release turns out
> to get a different name ...)
>
> In a testsuite run, this note triggers only in those two ABI compat suite
> test cases mentioned in the previous patch email (only on ELFv2, of course).
>
> Tested on powerpc64le-linux.
>
> OK for mainline?
>
> Bye,
> Ulrich
>
>
> gcc/testsuite/ChangLog:
>
>         * 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/ChangLog:
>
>         * gcc.target/powerpc/ppc64-abi-warn-2.c: New test.

This patch is okay.

Thanks, David
diff mbox

Patch

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 212147)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -10227,6 +10227,7 @@ 
 	  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?  */
@@ -10255,6 +10256,47 @@ 
 	      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)
@@ -10330,8 +10372,23 @@ 
       /* 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: gcc/testsuite/gcc.target/powerpc/ppc64-abi-warn-1.c
===================================================================
--- /dev/null
+++ gcc/testsuite/gcc.target/powerpc/ppc64-abi-warn-1.c	(revision 0)
@@ -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" } */
+{
+}
+