diff mbox series

[RFC] PR target/61976 PowerPC & AIX parameter passing

Message ID CAGWvnynqL17zJCOB2ahH0X1F3o=RvbbGnkjEotYu9OuUSPqmLA@mail.gmail.com
State New
Headers show
Series [RFC] PR target/61976 PowerPC & AIX parameter passing | expand

Commit Message

David Edelsohn Nov. 30, 2018, 8:33 p.m. UTC
This patch corrects the manner in which single element structures are
passed.  The implementation always has been wrong and did not match
the AIX ABI. The AIX ABI specifies that aggregates are passed by
values in GPRs, but GCC passes small floating point aggregates in
FPRs. The PPC64 BE ELFv1 Linux ABI was updated in the past to match
the behavior of GCC.

For AIX, the implementation can produce wrong code for the case of a
single precision floating point value (SFmode) argument in 64 bit
mode.

The rs6000 backend parameter passing code chose the location for
arguments based on the MODE of the argument. For small aggregates, GCC
packs the aggregate into a scalar mode and the function arg machinery
is presented with an argument mode of the scalar mode, as opposed to
BLKmode.

On AIX, this meant that a single element floating point aggregate
(float or double) is represented as SFmode or DFmode.  The current
rs6000 function arg machinery passes the arguments in FPRs.  On AIX,
argument are padded upwards in the register, as if the arguments are
strings, not numerical values.  In 64 bit mode, GCC dutifully shifts a
32 bit SFmode value so that it is loaded into the upper 32 bits of the
FPR.  Power FPRs always are 64 bit double precision format, regardless
of the precision, so the value loaded is garbage, in addition to being
passed in the wrong location.  In 32 bit mode (still the default for
AIX), GCC didn't try to shift the value, so it accidentally worked --
self consistently passing the value in an FPR that GCC interpreted as
word mode size.

This patch adds a test for the argument TYPE to override the floating
point argument passing for aggregates only for AIX.

Yes, this will break the ABI for GCC on AIX.  GCC was not following
the AIX ABI. No one really noticed. It only produced wrong code in 64
bit mode. Single element aggregates are rare.  The change sucks, but
it doesn't make sense to have GCC produce code that is incompatible
with the AIX ABI.

I am using AGGREGATE_TYPE_P() to test the type. I believe that macro
captures all GCC cases of interest. Please let me know if this seems
like the wrong choice.  The macro includes ARRAY_TYPE, but arrays
commonly are passed by reference or pointer, not by value, so I don't
believe that this will affect single element vectors, but please
correct me if I'm wrong.  Another option is RECORD_OR_UNION_TYPE_P().

I believe that this change will correct GCC's conformance with the AIX
ABI.  I realize that most people don't know enough or care enough
about AIX and the ABI to determine if the conformance is correct. I am
interested in any feedback about the mechanism (AGGREGATE_TYPE_P) used
to select the behavior.

Bootstrapped on powerpc-ibm-aix7.2.0.0

Thanks, David

* config/rs6000/rs6000.c (rs6000_function_arg): Don't pass aggregates
in FPRs on AIX.
(rs6000_arg_partial_bytes): Same.
diff mbox series

Patch

Index: rs6000.c
===================================================================
--- rs6000.c    (revision 266671)
+++ rs6000.c    (working copy)
@@ -11989,7 +11989,8 @@  rs6000_function_arg (cumulative_args_t cum_v, mach
       if (elt_mode == TDmode && (cum->fregno % 2) == 1)
        cum->fregno++;

-      if (USE_FP_FOR_ARG_P (cum, elt_mode))
+      if (USE_FP_FOR_ARG_P (cum, elt_mode)
+         && !(TARGET_AIX && AGGREGATE_TYPE_P (type)))
        {
          rtx rvec[GP_ARG_NUM_REG + AGGR_ARG_NUM_REG + 1];
          rtx r, off;
@@ -12125,7 +12126,8 @@  rs6000_arg_partial_bytes (cumulative_args_t cum_v,

   align_words = rs6000_parm_start (mode, type, cum->words);

-  if (USE_FP_FOR_ARG_P (cum, elt_mode))
+  if (USE_FP_FOR_ARG_P (cum, elt_mode)
+      && !(TARGET_AIX && AGGREGATE_TYPE_P (type)))
     {
       unsigned long n_fpreg = (GET_MODE_SIZE (elt_mode) + 7) >> 3;