[RS6000] complex long double ABI_V4 fix
authorAlan Modra <amodra@gmail.com>
Wed, 11 May 2016 02:09:38 +0000 (11:39 +0930)
committerAlan Modra <amodra@gcc.gnu.org>
Wed, 11 May 2016 02:09:38 +0000 (11:39 +0930)
Revision 235794 regressed compat/scalar-by-value-6 for powerpc-linux
-m32 due to accidentally changing the ABI.  By another historical
accident, complex long double is stupidly passed in gprs for -m32.

* config/rs6000/rs6000.c (is_complex_IBM_long_double,
abi_v4_pass_in_fpr): New functions.
(rs6000_function_arg_boundary): Exclude complex IBM long double
from 64-bit alignment when ABI_V4.
(rs6000_function_arg, rs6000_function_arg_advance_1,
rs6000_gimplify_va_arg): Use abi_v4_pass_in_fpr.

From-SVN: r236111

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

index e95fcad02a60c9f026308ec3a109c8ae71f13206..84d5ddcba2c8a4ee2549309e373e567f2a4c83ef 100644 (file)
@@ -1,3 +1,12 @@
+2016-05-11  Alan Modra  <amodra@gmail.com>
+
+       * config/rs6000/rs6000.c (is_complex_IBM_long_double,
+       abi_v4_pass_in_fpr): New functions.
+       (rs6000_function_arg_boundary): Exclude complex IBM long double
+       from 64-bit alignment when ABI_V4.
+       (rs6000_function_arg, rs6000_function_arg_advance_1,
+       rs6000_gimplify_va_arg): Use abi_v4_pass_in_fpr.
+
 2016-05-10  Segher Boessenkool  <segher@kernel.crashing.org>
 
        PR rtl-optimization/71028
index 007bf5758d8d2caf193e284edcc270161b306e8b..0f70bb91126c17d8ee50e60860c539c30c9cb823 100644 (file)
@@ -10089,6 +10089,35 @@ rs6000_must_pass_in_stack (machine_mode mode, const_tree type)
     return must_pass_in_stack_var_size_or_pad (mode, type);
 }
 
+static inline bool
+is_complex_IBM_long_double (machine_mode mode)
+{
+  return mode == ICmode || (!TARGET_IEEEQUAD && mode == TCmode);
+}
+
+/* Whether ABI_V4 passes MODE args to a function in floating point
+   registers.  */
+
+static bool
+abi_v4_pass_in_fpr (machine_mode mode)
+{
+  if (!TARGET_FPRS || !TARGET_HARD_FLOAT)
+    return false;
+  if (TARGET_SINGLE_FLOAT && mode == SFmode)
+    return true;
+  if (TARGET_DOUBLE_FLOAT && mode == DFmode)
+    return true;
+  /* ABI_V4 passes complex IBM long double in 8 gprs.
+     Stupid, but we can't change the ABI now.  */
+  if (is_complex_IBM_long_double (mode))
+    return false;
+  if (FLOAT128_2REG_P (mode))
+    return true;
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    return true;
+  return false;
+}
+
 /* If defined, a C expression which determines whether, and in which
    direction, to pad out an argument with extra space.  The value
    should be of type `enum direction': either `upward' to pad above
@@ -10173,6 +10202,7 @@ rs6000_function_arg_boundary (machine_mode mode, const_tree type)
       && (GET_MODE_SIZE (mode) == 8
          || (TARGET_HARD_FLOAT
              && TARGET_FPRS
+             && !is_complex_IBM_long_double (mode)
              && FLOAT128_2REG_P (mode))))
     return 64;
   else if (FLOAT128_VECTOR_P (mode))
@@ -10552,11 +10582,7 @@ rs6000_function_arg_advance_1 (CUMULATIVE_ARGS *cum, machine_mode mode,
     }
   else if (DEFAULT_ABI == ABI_V4)
     {
-      if (TARGET_HARD_FLOAT && TARGET_FPRS
-         && ((TARGET_SINGLE_FLOAT && mode == SFmode)
-             || (TARGET_DOUBLE_FLOAT && mode == DFmode)
-             || FLOAT128_2REG_P (mode)
-             || DECIMAL_FLOAT_MODE_P (mode)))
+      if (abi_v4_pass_in_fpr (mode))
        {
          /* _Decimal128 must use an even/odd register pair.  This assumes
             that the register number is odd when fregno is odd.  */
@@ -11213,11 +11239,7 @@ rs6000_function_arg (cumulative_args_t cum_v, machine_mode mode,
 
   else if (abi == ABI_V4)
     {
-      if (TARGET_HARD_FLOAT && TARGET_FPRS
-         && ((TARGET_SINGLE_FLOAT && mode == SFmode)
-             || (TARGET_DOUBLE_FLOAT && mode == DFmode)
-             || FLOAT128_2REG_P (mode)
-             || DECIMAL_FLOAT_MODE_P (mode)))
+      if (abi_v4_pass_in_fpr (mode))
        {
          /* _Decimal128 must use an even/odd register pair.  This assumes
             that the register number is odd when fregno is odd.  */
@@ -12138,19 +12160,15 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   rsize = (size + 3) / 4;
   align = 1;
 
-  if (TARGET_HARD_FLOAT && TARGET_FPRS
-      && ((TARGET_SINGLE_FLOAT && TYPE_MODE (type) == SFmode)
-          || (TARGET_DOUBLE_FLOAT 
-              && (TYPE_MODE (type) == DFmode 
-                 || FLOAT128_2REG_P (TYPE_MODE (type))
-                 || DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))))))
+  machine_mode mode = TYPE_MODE (type);
+  if (abi_v4_pass_in_fpr (mode))
     {
       /* FP args go in FP registers, if present.  */
       reg = fpr;
       n_reg = (size + 7) / 8;
       sav_ofs = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4) * 4;
       sav_scale = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4);
-      if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode)
+      if (mode != SFmode && mode != SDmode)
        align = 8;
     }
   else
@@ -12170,7 +12188,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   addr = create_tmp_var (ptr_type_node, "addr");
 
   /*  AltiVec vectors never go in registers when -mabi=altivec.  */
-  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
+  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     align = 16;
   else
     {
@@ -12191,7 +12209,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
        }
       /* _Decimal128 is passed in even/odd fpr pairs; the stored
         reg number is 0 for f1, so we want to make it odd.  */
-      else if (reg == fpr && TYPE_MODE (type) == TDmode)
+      else if (reg == fpr && mode == TDmode)
        {
          t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), unshare_expr (reg),
                      build_int_cst (TREE_TYPE (reg), 1));
@@ -12218,7 +12236,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
         FP register for 32-bit binaries.  */
       if (TARGET_32BIT
          && TARGET_HARD_FLOAT && TARGET_FPRS
-         && TYPE_MODE (type) == SDmode)
+         && mode == SDmode)
        t = fold_build_pointer_plus_hwi (t, size);
 
       gimplify_assign (addr, t, pre_p);