rs6000.c (rs6000_hard_regno_nregs): Adjust for e500 doubles.
authorAldy Hernandez <aldyh@redhat.com>
Tue, 26 Oct 2004 12:28:59 +0000 (12:28 +0000)
committerAldy Hernandez <aldyh@gcc.gnu.org>
Tue, 26 Oct 2004 12:28:59 +0000 (12:28 +0000)
* config/rs6000/rs6000.c (rs6000_hard_regno_nregs): Adjust for
e500 doubles.
(spe_build_register_parallel): New.
(rs6000_spe_function_arg): Handle e500 doubles.
(function_arg): Same.
(spe_func_has_64bit_regs_p): Same.
(rs6000_function_value): Same.
(rs6000_libcall_value): Same.
(legitimate_lo_sum_address_p): Return false for e500 doubles.

* config/rs6000/rs6000.h (LOCAL_ALIGNMENT): Adjust for e500
doubles.
(DATA_ALIGNMENT): Same.
(CANNOT_CHANGE_MODE_CLASS): Same.

From-SVN: r89582

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

index 64fe9aba3d4b8a3f42dea6e816c53701cbd17ada..bc2a4ecc2be100456206889f1e08bd848816c9c2 100644 (file)
@@ -1,3 +1,20 @@
+2004-10-26  Aldy Hernandez  <aldyh@redhat.com>
+
+       * config/rs6000/rs6000.c (rs6000_hard_regno_nregs): Adjust for
+       e500 doubles.
+       (spe_build_register_parallel): New.
+       (rs6000_spe_function_arg): Handle e500 doubles.
+       (function_arg): Same.
+       (spe_func_has_64bit_regs_p): Same.
+       (rs6000_function_value): Same.
+       (rs6000_libcall_value): Same.
+       (legitimate_lo_sum_address_p): Return false for e500 doubles.
+
+       * config/rs6000/rs6000.h (LOCAL_ALIGNMENT): Adjust for e500
+       doubles.
+       (DATA_ALIGNMENT): Same.
+       (CANNOT_CHANGE_MODE_CLASS): Same.
+
 2004-10-26  Aldy Hernandez  <aldyh@redhat.com>
 
         * expr.c (emit_group_load): Handle floats.
index adf4fec8ffc2e0fb9cb4ffc5a70386708574880e..6909859af299a53f2d567f3a27b0b2f059c87683 100644 (file)
@@ -3281,6 +3281,8 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
     return false;
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
+  if (TARGET_E500_DOUBLE && mode == DFmode)
+    return false;
   x = XEXP (x, 1);
 
   if (TARGET_ELF || TARGET_MACHO)
@@ -3418,8 +3420,7 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && GET_CODE (x) != CONST_INT
           && GET_CODE (x) != CONST_DOUBLE
           && CONSTANT_P (x)
-          && ((TARGET_HARD_FLOAT && TARGET_FPRS)
-              || (mode != DFmode || TARGET_E500_DOUBLE))
+          && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
           && mode != DImode
           && mode != TImode)
     {
@@ -4933,15 +4934,50 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     }
 }
 
-/* Determine where to put a SIMD argument on the SPE.  */
+static rtx
+spe_build_register_parallel (enum machine_mode mode, int gregno)
+{
+  rtx r1, r2;
+  enum machine_mode inner;
+  unsigned int inner_bytes;
+
+  if (mode == DFmode)
+    {
+      inner = SImode;
+      inner_bytes = 4;
+    }
+  else
+    abort ();
+
+  r1 = gen_rtx_REG (inner, gregno);
+  r1 = gen_rtx_EXPR_LIST (SImode, r1, const0_rtx);
+  r2 = gen_rtx_REG (inner, gregno + 1);
+  r2 = gen_rtx_EXPR_LIST (SImode, r2, GEN_INT (inner_bytes));
+  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
+}
 
+/* Determine where to put a SIMD argument on the SPE.  */
 static rtx
 rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                         tree type)
 {
+  int gregno = cum->sysv_gregno;
+
+  /* On E500 v2, double arithmetic is done on the full 64-bit GPR, but
+     are passed and returned in a pair of GPRs for ABI compatability.  */
+  if (TARGET_E500_DOUBLE && mode == DFmode)
+    {
+      /* Doubles go in an odd/even register pair (r5/r6, etc).  */
+      gregno += (1 - gregno) & 1;
+
+      /* We do not split between registers and stack.  */
+      if (gregno + 1 > GP_ARG_MAX_REG)
+       return NULL_RTX;
+
+      return spe_build_register_parallel (mode, gregno);
+    }
   if (cum->stdarg)
     {
-      int gregno = cum->sysv_gregno;
       int n_words = rs6000_arg_size (mode, type);
 
       /* SPE vectors are put in odd registers.  */
@@ -4964,8 +5000,8 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     }
   else
     {
-      if (cum->sysv_gregno <= GP_ARG_MAX_REG)
-       return gen_rtx_REG (mode, cum->sysv_gregno);
+      if (gregno <= GP_ARG_MAX_REG)
+       return gen_rtx_REG (mode, gregno);
       else
        return NULL_RTX;
     }
@@ -5144,7 +5180,9 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
        }
     }
-  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
+  else if (TARGET_SPE_ABI && TARGET_SPE
+          && (SPE_VECTOR_MODE (mode)
+              || (TARGET_E500_DOUBLE && mode == DFmode)))
     return rs6000_spe_function_arg (cum, mode, type);
   else if (abi == ABI_V4)
     {
@@ -12543,9 +12581,15 @@ spe_func_has_64bit_regs_p (void)
          rtx i;
 
          i = PATTERN (insn);
-         if (GET_CODE (i) == SET
-             && SPE_VECTOR_MODE (GET_MODE (SET_SRC (i))))
-           return true;
+         if (GET_CODE (i) == SET)
+           {
+             enum machine_mode mode = GET_MODE (SET_SRC (i));
+
+             if (SPE_VECTOR_MODE (mode))
+               return true;
+             if (TARGET_E500_DOUBLE && mode == DFmode)
+               return true;
+           }
        }
     }
 
@@ -18078,6 +18122,8 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
           && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI
           && ALTIVEC_VECTOR_MODE(mode))
     regno = ALTIVEC_ARG_RETURN;
+  else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT && mode == DFmode)
+    return spe_build_register_parallel (DFmode, GP_ARG_RETURN);
   else
     regno = GP_ARG_RETURN;
 
@@ -18113,6 +18159,8 @@ rs6000_libcall_value (enum machine_mode mode)
     regno = ALTIVEC_ARG_RETURN;
   else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
     return rs6000_complex_function_value (mode);
+  else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT && mode == DFmode)
+    return spe_build_register_parallel (DFmode, GP_ARG_RETURN);
   else
     regno = GP_ARG_RETURN;
 
index 0a209b674cfa48a0f358b5aa2c0c6bdd8db14315..a64d6827538c5ccd60ed0c2f3ec2a11090e5e64b 100644 (file)
@@ -742,6 +742,7 @@ extern const char *rs6000_warn_altivec_long_switch;
    that the object would ordinarily have.  */
 #define LOCAL_ALIGNMENT(TYPE, ALIGN)                           \
   ((TARGET_ALTIVEC && TREE_CODE (TYPE) == VECTOR_TYPE) ? 128 : \
+    (TARGET_E500_DOUBLE && TYPE_MODE (TYPE) == DFmode) ? 64 : \
     (TARGET_SPE && TREE_CODE (TYPE) == VECTOR_TYPE) ? 64 : ALIGN)
 
 /* Alignment of field after `int : 0' in a structure.  */
@@ -774,9 +775,11 @@ extern const char *rs6000_warn_altivec_long_switch;
    : (ALIGN))
 
 /* Make arrays of chars word-aligned for the same reasons.
-   Align vectors to 128 bits.  */
+   Align vectors to 128 bits.  Align SPE vectors and E500 v2 doubles to
+   64 bits.  */
 #define DATA_ALIGNMENT(TYPE, ALIGN)            \
   (TREE_CODE (TYPE) == VECTOR_TYPE ? (TARGET_SPE_ABI ? 64 : 128)       \
+   : (TARGET_E500_DOUBLE && TYPE_MODE (TYPE) == DFmode) ? 64 \
    : TREE_CODE (TYPE) == ARRAY_TYPE            \
    && TYPE_MODE (TREE_TYPE (TYPE)) == QImode   \
    && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
@@ -1433,6 +1436,8 @@ enum reg_class
    ? 0                                                                   \
    : GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)                                  \
    ? reg_classes_intersect_p (FLOAT_REGS, CLASS)                         \
+   : (TARGET_E500_DOUBLE && (((TO) == DFmode) + ((FROM) == DFmode)) == 1) \
+   ? reg_classes_intersect_p (GENERAL_REGS, CLASS)                       \
    : (TARGET_SPE && (SPE_VECTOR_MODE (FROM) + SPE_VECTOR_MODE (TO)) == 1) \
    ? reg_classes_intersect_p (GENERAL_REGS, CLASS)                       \
    : 0)