OSDN Git Service

gcc:
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Jan 2007 19:38:33 +0000 (19:38 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Jan 2007 19:38:33 +0000 (19:38 +0000)
* config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define
_SOFT_DOUBLE if doubles use software floating-point.
* config/rs6000/libgcc-ppc-glibc.ver: Export additional long
double functions if _SOFT_DOUBLE, not _SOFT_FLOAT.
* config/rs6000/darwin-ldouble.c: Also compile functions for
hard-float without FPRs.  Use fmsub function for all __NO_FPRS__
cases.  Compile extra functions if _SOFT_DOUBLE, not _SOFT_FLOAT.
* config/rs6000/linuxspe.h (SUBSUBTARGET_OVERRIDE_OPTIONS): Remove
commented-out long double override.
(CPP_LONGDOUBLE_DEFAULT_SPEC): Likewise.
* config/rs6000/eabispe.h: Likewise.
* config/rs6000/rs6000.c (rs6000_override_options): Don't override
long double for non-SPE.
(rs6000_handle_option): Likewise.
(invalid_e500_subreg): Disallow more subregs involding DImode,
DFmode, TImode or TFmode.
(rs6000_legitimate_offset_address_p): Check TFmode offsets for
E500 double.
(legitimate_lo_sum_address_p): Also check for TFmode for E500
double.
(rs6000_legitimize_address): Also handle TFmode for E500 double.
(rs6000_legitimize_reload_address): Also handle TFmode for E500
double.
(rs6000_legitimate_address): Also check for TFmode for E500
double.
(rs6000_emit_move): Use DFmode subregs of TFmode for E500 double.
(spe_build_register_parallel): Handle TFmode and TCmode.
(rs6000_spe_function_arg): Handle TFmode and TCmode for E500
double.
(function_arg): Handle TFmode and TCmode for E500 double.
(rs6000_init_libfuncs): Initialize extra libfuncs for soft double
in general.
(print_operand): Handle TFmode and TImode for %y.
(rs6000_generate_compare): Handle TFmode comparisons for E500
double.
(spe_func_has_64bit_regs_p): Check for TFmode for E500 double.
(rs6000_function_value): Handle TFmode and TCmode for E500 double.
(rs6000_libcall_value): Handle TFmode and TCmode for E500 double.
* config/rs6000/rs6000.h (CANNOT_CHANGE_MODE_CLASS): Check for
TFmode for E500 double.
* config/rs6000/rs6000.md (FP): Allow TF for E500 double.
(floatsidf2): Enable for E500 double.
(movtf_softfloat): Use rs6000_nonimmediate_operand.
(extenddftf2): Change to extenddftf2_fprs.
(extenddftf2): Call gen_spe_extenddftf2 or gen_extenddftf2_fprs
depending on TARGET_E500_DOUBLE.
(extendsftf2): Enable for E500 double.
(trunctfdf2): Enable for E500 double.
(trunctfsf2): Change to trunctfsf2_fprs.
(trunctfsf2): Call gen_spe_trunctfsf2 or gen_trunctfsf2_fprs
depending on TARGET_E500_DOUBLE.
(floatsitf2): Enable for E500 double.
(fix_trunctfsi2): Change to fix_trunctfsi2_fprs.
(fix_trunctfsi2): Call gen_spe_fix_trunctfsi2 or
gen_fix_trunctfsi2_fprs depending on TARGET_E500_DOUBLE.
(negtf2): Change to negtf2_internal.
(negtf2): New expander.
(abstf2): Enable for E500 double.  Call gen_spe_abstf2_tst,
gen_spe_abstf2_cmp or gen_abstf2_internal depending on
TARGET_E500_DOUBLE and flag_unsafe_math_optimizations.
(movdi_internal32): Use rs6000_nonimmediate_operand.
(unnamed splitter): Likewise.
* config/rs6000/spe.md (CMPTFEQ_GPR, TSTTFEQ_GPR, CMPTFGT_GPR,
TSTTFGT_GPR, CMPTFLT_GPR, TSTTFLT_GPR): New unspecs.
(SPE64TF, DITI): New mode macros.
(frob_df_di): Change to frob_<SPE64:mode>_<DITI:mode>; allow more
modes.
(frob_tf_ti): New.
(frob_<mode>_di_2): New.
(frob_tf_di_8_2): New.
(frob_di_df): Change to frob_di_<mode>; allow more modes.
(frob_ti_tf): New.
(frob_di_df_2): Change to frob_<DITI:mode>_<SPE64:mode>_2; allow
more modes.
(frob_ti_<mode>_8_2): New.
(frob_ti_tf_2): New.
(mov_si<mode>_e500_subreg0, mov_si<mode>_e500_subreg0_2,
mov_si<mode>_e500_subreg4, mov_si<mode>_e500_subreg4_2): Allow
TFmode.
(mov_sitf_e500_subreg8, mov_sitf_e500_subreg8_2,
mov_sitf_e500_subreg12, mov_sitf_e500_subreg12_2): New.
(spe_trunctfdf2_internal1, spe_trunctfsf2, spe_extenddftf2,
spe_fix_trunctfsi2, spe_fix_trunctfsi2_internal,
spe_negtf2_internal, spe_abstf2_cmp, spe_abstf2_tst): New.
(cmptfeq_gpr, tsttfeq_gpr, cmptfgt_gpr, tsttfgt_gpr, cmptflt_gpr,
tsttflt_gp): New.

libgcc:
* config/rs6000/t-ldbl128: Always use -mlong-double-128.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@121085 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/ChangeLog
gcc/config/rs6000/darwin-ldouble.c
gcc/config/rs6000/eabispe.h
gcc/config/rs6000/libgcc-ppc-glibc.ver
gcc/config/rs6000/linuxspe.h
gcc/config/rs6000/rs6000-c.c
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md
gcc/config/rs6000/spe.md
libgcc/ChangeLog
libgcc/config/rs6000/t-ldbl128

index f050d94..abd821f 100644 (file)
@@ -1,3 +1,92 @@
+2007-01-23  Joseph Myers  <joseph@codesourcery.com>
+
+       * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define
+       _SOFT_DOUBLE if doubles use software floating-point.
+       * config/rs6000/libgcc-ppc-glibc.ver: Export additional long
+       double functions if _SOFT_DOUBLE, not _SOFT_FLOAT.
+       * config/rs6000/darwin-ldouble.c: Also compile functions for
+       hard-float without FPRs.  Use fmsub function for all __NO_FPRS__
+       cases.  Compile extra functions if _SOFT_DOUBLE, not _SOFT_FLOAT.
+       * config/rs6000/linuxspe.h (SUBSUBTARGET_OVERRIDE_OPTIONS): Remove
+       commented-out long double override.
+       (CPP_LONGDOUBLE_DEFAULT_SPEC): Likewise.
+       * config/rs6000/eabispe.h: Likewise.
+       * config/rs6000/rs6000.c (rs6000_override_options): Don't override
+       long double for non-SPE.
+       (rs6000_handle_option): Likewise.
+       (invalid_e500_subreg): Disallow more subregs involding DImode,
+       DFmode, TImode or TFmode.
+       (rs6000_legitimate_offset_address_p): Check TFmode offsets for
+       E500 double.
+       (legitimate_lo_sum_address_p): Also check for TFmode for E500
+       double.
+       (rs6000_legitimize_address): Also handle TFmode for E500 double.
+       (rs6000_legitimize_reload_address): Also handle TFmode for E500
+       double.
+       (rs6000_legitimate_address): Also check for TFmode for E500
+       double.
+       (rs6000_emit_move): Use DFmode subregs of TFmode for E500 double.
+       (spe_build_register_parallel): Handle TFmode and TCmode.
+       (rs6000_spe_function_arg): Handle TFmode and TCmode for E500
+       double.
+       (function_arg): Handle TFmode and TCmode for E500 double.
+       (rs6000_init_libfuncs): Initialize extra libfuncs for soft double
+       in general.
+       (print_operand): Handle TFmode and TImode for %y.
+       (rs6000_generate_compare): Handle TFmode comparisons for E500
+       double.
+       (spe_func_has_64bit_regs_p): Check for TFmode for E500 double.
+       (rs6000_function_value): Handle TFmode and TCmode for E500 double.
+       (rs6000_libcall_value): Handle TFmode and TCmode for E500 double.
+       * config/rs6000/rs6000.h (CANNOT_CHANGE_MODE_CLASS): Check for
+       TFmode for E500 double.
+       * config/rs6000/rs6000.md (FP): Allow TF for E500 double.
+       (floatsidf2): Enable for E500 double.
+       (movtf_softfloat): Use rs6000_nonimmediate_operand.
+       (extenddftf2): Change to extenddftf2_fprs.
+       (extenddftf2): Call gen_spe_extenddftf2 or gen_extenddftf2_fprs
+       depending on TARGET_E500_DOUBLE.
+       (extendsftf2): Enable for E500 double.
+       (trunctfdf2): Enable for E500 double.
+       (trunctfsf2): Change to trunctfsf2_fprs.
+       (trunctfsf2): Call gen_spe_trunctfsf2 or gen_trunctfsf2_fprs
+       depending on TARGET_E500_DOUBLE.
+       (floatsitf2): Enable for E500 double.
+       (fix_trunctfsi2): Change to fix_trunctfsi2_fprs.
+       (fix_trunctfsi2): Call gen_spe_fix_trunctfsi2 or
+       gen_fix_trunctfsi2_fprs depending on TARGET_E500_DOUBLE.
+       (negtf2): Change to negtf2_internal.
+       (negtf2): New expander.
+       (abstf2): Enable for E500 double.  Call gen_spe_abstf2_tst,
+       gen_spe_abstf2_cmp or gen_abstf2_internal depending on
+       TARGET_E500_DOUBLE and flag_unsafe_math_optimizations.
+       (movdi_internal32): Use rs6000_nonimmediate_operand.
+       (unnamed splitter): Likewise.
+       * config/rs6000/spe.md (CMPTFEQ_GPR, TSTTFEQ_GPR, CMPTFGT_GPR,
+       TSTTFGT_GPR, CMPTFLT_GPR, TSTTFLT_GPR): New unspecs.
+       (SPE64TF, DITI): New mode macros.
+       (frob_df_di): Change to frob_<SPE64:mode>_<DITI:mode>; allow more
+       modes.
+       (frob_tf_ti): New.
+       (frob_<mode>_di_2): New.
+       (frob_tf_di_8_2): New.
+       (frob_di_df): Change to frob_di_<mode>; allow more modes.
+       (frob_ti_tf): New.
+       (frob_di_df_2): Change to frob_<DITI:mode>_<SPE64:mode>_2; allow
+       more modes.
+       (frob_ti_<mode>_8_2): New.
+       (frob_ti_tf_2): New.
+       (mov_si<mode>_e500_subreg0, mov_si<mode>_e500_subreg0_2,
+       mov_si<mode>_e500_subreg4, mov_si<mode>_e500_subreg4_2): Allow
+       TFmode.
+       (mov_sitf_e500_subreg8, mov_sitf_e500_subreg8_2,
+       mov_sitf_e500_subreg12, mov_sitf_e500_subreg12_2): New.
+       (spe_trunctfdf2_internal1, spe_trunctfsf2, spe_extenddftf2,
+       spe_fix_trunctfsi2, spe_fix_trunctfsi2_internal,
+       spe_negtf2_internal, spe_abstf2_cmp, spe_abstf2_tst): New.
+       (cmptfeq_gpr, tsttfeq_gpr, cmptfgt_gpr, tsttfgt_gpr, cmptflt_gpr,
+       tsttflt_gp): New.
+
 2007-01-23  Ian Lance Taylor  <iant@google.com>
 
        * Makefile.in (OBJS-common): Reformat, alphabetize, but put
index eaffb34..7405448 100644 (file)
@@ -1,5 +1,5 @@
 /* 128-bit long double support routines for Darwin.
-   Copyright (C) 1993, 2003, 2004, 2005, 2006
+   Copyright (C) 1993, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -49,8 +49,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 
    This code currently assumes big-endian.  */
 
-#if ((!defined (__NO_FPRS__) || defined (_SOFT_FLOAT)) \
-     && !defined (__LITTLE_ENDIAN__) \
+#if (!defined (__LITTLE_ENDIAN__) \
      && (defined (__MACH__) || defined (__powerpc__) || defined (_AIX)))
 
 #define fabs(x) __builtin_fabs(x)
@@ -145,7 +144,7 @@ __gcc_qsub (double a, double b, double c, double d)
   return __gcc_qadd (a, b, -c, -d);
 }
 
-#ifdef _SOFT_FLOAT
+#ifdef __NO_FPRS__
 static double fmsub (double, double, double);
 #endif
 
@@ -164,7 +163,7 @@ __gcc_qmul (double a, double b, double c, double d)
   /* Sum terms of two highest orders. */
   
   /* Use fused multiply-add to get low part of a * c.  */
-#ifndef _SOFT_FLOAT
+#ifndef __NO_FPRS__
   asm ("fmsub %0,%1,%2,%3" : "=f"(tau) : "f"(a), "f"(c), "f"(t));
 #else
   tau = fmsub (a, c, t);
@@ -201,7 +200,7 @@ __gcc_qdiv (double a, double b, double c, double d)
                           numerically necessary.  */
   
   /* Use fused multiply-add to get low part of c * t.   */
-#ifndef _SOFT_FLOAT
+#ifndef __NO_FPRS__
   asm ("fmsub %0,%1,%2,%3" : "=f"(sigma) : "f"(c), "f"(t), "f"(s));
 #else
   sigma = fmsub (c, t, s);
@@ -219,7 +218,7 @@ __gcc_qdiv (double a, double b, double c, double d)
   return z.ldval;
 }
 
-#if defined (_SOFT_FLOAT) && defined (__LONG_DOUBLE_128__)
+#if defined (_SOFT_DOUBLE) && defined (__LONG_DOUBLE_128__)
 
 long double __gcc_qneg (double, double);
 int __gcc_qeq (double, double, double, double);
@@ -362,6 +361,10 @@ __gcc_utoq (unsigned int a)
   return __gcc_dtoq ((double) a);
 }
 
+#endif
+
+#ifdef __NO_FPRS__
+
 #include "config/soft-fp/soft-fp.h"
 #include "config/soft-fp/double.h"
 #include "config/soft-fp/quad.h"
index 2a0b923..40669dd 100644 (file)
@@ -1,6 +1,7 @@
 /* Core target definitions for GNU compiler
    for PowerPC embedded targeted systems with SPE support.
-   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Aldy Hernandez (aldyh@redhat.com).
 
    This file is part of GCC.
@@ -35,9 +36,6 @@
     rs6000_spe_abi = 1; \
   if (!rs6000_explicit_options.float_gprs) \
     rs6000_float_gprs = 1; \
-  /* See note below.  */ \
-  /*if (!rs6000_explicit_options.long_double)*/ \
-  /*  rs6000_long_double_type_size = 128;*/ \
   if (!rs6000_explicit_options.spe) \
     rs6000_spe = 1; \
   if (!rs6000_explicit_options.isel) \
@@ -52,8 +50,7 @@
    specifications, until I properly fix the emulation.
 
    Enable these later.
-#undef CPP_LONGDOUBLE_DEFAULT_SPEC
-#define CPP_LONGDOUBLE_DEFAULT_SPEC "-D__LONG_DOUBLE_128__=1"
+#define RS6000_DEFAULT_LONG_DOUBLE_SIZE (TARGET_SPE ? 128 : 64)
 */
 
 #undef  ASM_DEFAULT_SPEC
index d8ffd2a..d065c13 100644 (file)
@@ -31,7 +31,7 @@ GCC_4.2.0 {
   __gcc_qmul
   __gcc_qdiv
 
-%ifdef _SOFT_FLOAT
+%ifdef _SOFT_DOUBLE
   __gcc_qneg
   __gcc_qeq
   __gcc_qne
index 9b98616..8dc2dc9 100644 (file)
@@ -35,9 +35,6 @@
     rs6000_spe_abi = 1; \
   if (!rs6000_explicit_options.float_gprs) \
     rs6000_float_gprs = 1; \
-  /* See note below.  */ \
-  /*if (!rs6000_explicit_options.long_double)*/ \
-  /*  rs6000_long_double_type_size = 128;*/ \
   if (!rs6000_explicit_options.spe) \
     rs6000_spe = 1; \
   if (!rs6000_explicit_options.isel) \
   if (target_flags & MASK_64BIT) \
     error ("-m64 not supported in this configuration")
 
-/* The e500 ABI says that either long doubles are 128 bits, or if
-   implemented in any other size, the compiler/linker should error out.
-   We have no emulation libraries for 128 bit long doubles, and I hate
-   the dozens of failures on the regression suite.  So I'm breaking ABI
-   specifications, until I properly fix the emulation.
-
-   Enable these later.
-#undef CPP_LONGDOUBLE_DEFAULT_SPEC
-#define CPP_LONGDOUBLE_DEFAULT_SPEC "-D__LONG_DOUBLE_128__=1"
-*/
-
 #undef  ASM_DEFAULT_SPEC
 #define        ASM_DEFAULT_SPEC "-mppc -mspe -me500"
index d8f1075..55c9b7c 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for the C front end on the POWER and PowerPC architectures.
-   Copyright (C) 2002, 2003, 2004, 2005
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
    Contributed by Zack Weinberg <zack@codesourcery.com>
@@ -124,6 +124,8 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfile)
     builtin_define ("__SPE__");
   if (TARGET_SOFT_FLOAT)
     builtin_define ("_SOFT_FLOAT");
+  if (!(TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)))
+    builtin_define ("_SOFT_DOUBLE");
   /* Used by lwarx/stwcx. errata work-around.  */
   if (rs6000_cpu == PROCESSOR_PPC405)
     builtin_define ("__PPC405__");
index 532d10c..f72fde3 100644 (file)
@@ -1464,8 +1464,6 @@ rs6000_override_options (const char *default_cpu)
        rs6000_float_gprs = 0;
       if (!rs6000_explicit_options.isel)
        rs6000_isel = 0;
-      if (!rs6000_explicit_options.long_double)
-       rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
     }
 
   /* Detect invalid option combinations with E500.  */
@@ -1892,9 +1890,6 @@ rs6000_handle_option (size_t code, const char *arg, int value)
     case OPT_mspe_:
       rs6000_explicit_options.spe = true;
       rs6000_parse_yes_no_option ("spe", arg, &(rs6000_spe));
-      /* No SPE means 64-bit long doubles, even if an E500.  */
-      if (!rs6000_spe)
-       rs6000_long_double_type_size = 64;
       break;
 
     case OPT_mdebug_:
@@ -2718,18 +2713,22 @@ invalid_e500_subreg (rtx op, enum machine_mode mode)
 {
   if (TARGET_E500_DOUBLE)
     {
-      /* Reject (subreg:SI (reg:DF)).  */
+      /* Reject (subreg:SI (reg:DF)); likewise with subreg:DI or
+        subreg:TI and reg:TF.  */
       if (GET_CODE (op) == SUBREG
-         && mode == SImode
+         && (mode == SImode || mode == DImode || mode == TImode)
          && REG_P (SUBREG_REG (op))
-         && GET_MODE (SUBREG_REG (op)) == DFmode)
+         && (GET_MODE (SUBREG_REG (op)) == DFmode
+             || GET_MODE (SUBREG_REG (op)) == TFmode))
        return true;
 
-      /* Reject (subreg:DF (reg:DI)).  */
+      /* Reject (subreg:DF (reg:DI)); likewise with subreg:TF and
+        reg:TI.  */
       if (GET_CODE (op) == SUBREG
-         && mode == DFmode
+         && (mode == DFmode || mode == TFmode)
          && REG_P (SUBREG_REG (op))
-         && GET_MODE (SUBREG_REG (op)) == DImode)
+         && (GET_MODE (SUBREG_REG (op)) == DImode
+             || GET_MODE (SUBREG_REG (op)) == TImode))
        return true;
     }
 
@@ -2989,6 +2988,10 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
       break;
 
     case TFmode:
+      if (TARGET_E500_DOUBLE)
+       return (SPE_CONST_OFFSET_OK (offset)
+               && SPE_CONST_OFFSET_OK (offset + 8));
+
     case TImode:
       if (mode == TFmode || !TARGET_POWERPC64)
        extra = 12;
@@ -3067,7 +3070,8 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
   /* Restrict addressing for DI because of our SUBREG hackery.  */
-  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
+  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                            || mode == DImode))
     return false;
   x = XEXP (x, 1);
 
@@ -3165,7 +3169,7 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       return reg;
     }
   else if (SPE_VECTOR_MODE (mode)
-          || (TARGET_E500_DOUBLE && (mode == DFmode
+          || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
                                      || mode == DImode)))
     {
       if (mode == DImode)
@@ -3570,7 +3574,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
       && GET_CODE (XEXP (x, 1)) == CONST_INT
       && !SPE_VECTOR_MODE (mode)
-      && !(TARGET_E500_DOUBLE && (mode == DFmode
+      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
                                  || mode == DImode))
       && !ALTIVEC_VECTOR_MODE (mode))
     {
@@ -3707,7 +3711,8 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && !SPE_VECTOR_MODE (mode)
       && mode != TFmode
       /* Restrict addressing for DI because of our SUBREG hackery.  */
-      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
+      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                                 || mode == DImode))
       && TARGET_UPDATE
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
     return 1;
@@ -4222,14 +4227,15 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
     {
       /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
         know how to get a DFmode SUBREG of a TFmode.  */
-      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0),
-                       simplify_gen_subreg (DImode, operands[1], mode, 0),
-                       DImode);
-      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode,
-                                            GET_MODE_SIZE (DImode)),
-                       simplify_gen_subreg (DImode, operands[1], mode,
-                                            GET_MODE_SIZE (DImode)),
-                       DImode);
+      enum machine_mode imode = (TARGET_E500_DOUBLE ? DFmode : DImode);
+      rs6000_emit_move (simplify_gen_subreg (imode, operands[0], mode, 0),
+                       simplify_gen_subreg (imode, operands[1], mode, 0),
+                       imode);
+      rs6000_emit_move (simplify_gen_subreg (imode, operands[0], mode,
+                                            GET_MODE_SIZE (imode)),
+                       simplify_gen_subreg (imode, operands[1], mode,
+                                            GET_MODE_SIZE (imode)),
+                       imode);
       return;
     }
 
@@ -5019,7 +5025,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 static rtx
 spe_build_register_parallel (enum machine_mode mode, int gregno)
 {
-  rtx r1, r3;
+  rtx r1, r3, r5, r7;
 
   switch (mode)
     {
@@ -5029,12 +5035,24 @@ spe_build_register_parallel (enum machine_mode mode, int gregno)
       return gen_rtx_PARALLEL (mode, gen_rtvec (1, r1));
 
     case DCmode:
+    case TFmode:
       r1 = gen_rtx_REG (DImode, gregno);
       r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
       r3 = gen_rtx_REG (DImode, gregno + 2);
       r3 = gen_rtx_EXPR_LIST (VOIDmode, r3, GEN_INT (8));
       return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r3));
 
+    case TCmode:
+      r1 = gen_rtx_REG (DImode, gregno);
+      r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
+      r3 = gen_rtx_REG (DImode, gregno + 2);
+      r3 = gen_rtx_EXPR_LIST (VOIDmode, r3, GEN_INT (8));
+      r5 = gen_rtx_REG (DImode, gregno + 4);
+      r5 = gen_rtx_EXPR_LIST (VOIDmode, r5, GEN_INT (16));
+      r7 = gen_rtx_REG (DImode, gregno + 6);
+      r7 = gen_rtx_EXPR_LIST (VOIDmode, r7, GEN_INT (24));
+      return gen_rtx_PARALLEL (mode, gen_rtvec (4, r1, r3, r5, r7));
+
     default:
       gcc_unreachable ();
     }
@@ -5049,7 +5067,8 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
   /* 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 compatibility.  */
-  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DCmode))
+  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DCmode
+                            || mode == TFmode || mode == TCmode))
     {
       int n_words = rs6000_arg_size (mode, type);
 
@@ -5467,7 +5486,9 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   else if (TARGET_SPE_ABI && TARGET_SPE
           && (SPE_VECTOR_MODE (mode)
               || (TARGET_E500_DOUBLE && (mode == DFmode
-                                         || mode == DCmode))))
+                                         || mode == DCmode
+                                         || mode == TFmode
+                                         || mode == TCmode))))
     return rs6000_spe_function_arg (cum, mode, type);
 
   else if (abi == ABI_V4)
@@ -9420,7 +9441,7 @@ rs6000_init_libfuncs (void)
        set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
        set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
 
-       if (TARGET_SOFT_FLOAT)
+       if (!(TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)))
          {
            set_optab_libfunc (neg_optab, TFmode, "__gcc_qneg");
            set_optab_libfunc (eq_optab, TFmode, "__gcc_qeq");
@@ -11034,7 +11055,9 @@ print_operand (FILE *file, rtx x, int code)
 
        /* Ugly hack because %y is overloaded.  */
        if ((TARGET_SPE || TARGET_E500_DOUBLE)
-           && GET_MODE_SIZE (GET_MODE (x)) == 8)
+           && (GET_MODE_SIZE (GET_MODE (x)) == 8
+               || GET_MODE (x) == TFmode
+               || GET_MODE (x) == TImode))
          {
            /* Handle [reg].  */
            if (GET_CODE (tmp) == REG)
@@ -11366,6 +11389,14 @@ rs6000_generate_compare (enum rtx_code code)
                                   rs6000_compare_op1);
              break;
 
+           case TFmode:
+             cmp = flag_unsafe_math_optimizations
+               ? gen_tsttfeq_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1)
+               : gen_cmptfeq_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1);
+             break;
+
            default:
              gcc_unreachable ();
            }
@@ -11390,6 +11421,14 @@ rs6000_generate_compare (enum rtx_code code)
                                   rs6000_compare_op1);
              break;
 
+           case TFmode:
+             cmp = flag_unsafe_math_optimizations
+               ? gen_tsttfgt_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1)
+               : gen_cmptfgt_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1);
+             break;
+
            default:
              gcc_unreachable ();
            }
@@ -11414,6 +11453,14 @@ rs6000_generate_compare (enum rtx_code code)
                                   rs6000_compare_op1);
              break;
 
+           case TFmode:
+             cmp = flag_unsafe_math_optimizations
+               ? gen_tsttflt_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1)
+               : gen_cmptflt_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1);
+             break;
+
            default:
              gcc_unreachable ();
            }
@@ -11457,6 +11504,14 @@ rs6000_generate_compare (enum rtx_code code)
                                   rs6000_compare_op1);
              break;
 
+           case TFmode:
+             cmp = flag_unsafe_math_optimizations
+               ? gen_tsttfeq_gpr (compare_result2, rs6000_compare_op0,
+                                  rs6000_compare_op1)
+               : gen_cmptfeq_gpr (compare_result2, rs6000_compare_op0,
+                                  rs6000_compare_op1);
+             break;
+
            default:
              gcc_unreachable ();
            }
@@ -13504,7 +13559,7 @@ spe_func_has_64bit_regs_p (void)
 
              if (SPE_VECTOR_MODE (mode))
                return true;
-             if (TARGET_E500_DOUBLE && mode == DFmode)
+             if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode))
                return true;
            }
        }
@@ -20274,7 +20329,8 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
           && ALTIVEC_VECTOR_MODE (mode))
     regno = ALTIVEC_ARG_RETURN;
   else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
-          && (mode == DFmode || mode == DCmode))
+          && (mode == DFmode || mode == DCmode
+              || mode == TFmode || mode == TCmode))
     return spe_build_register_parallel (mode, GP_ARG_RETURN);
   else
     regno = GP_ARG_RETURN;
@@ -20314,7 +20370,8 @@ rs6000_libcall_value (enum machine_mode mode)
   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 || mode == DCmode))
+          && (mode == DFmode || mode == DCmode
+              || mode == TFmode || mode == TCmode))
     return spe_build_register_parallel (mode, GP_ARG_RETURN);
   else
     regno = GP_ARG_RETURN;
index 17a2298..decaf8f 100644 (file)
@@ -1160,6 +1160,7 @@ enum reg_class
       && reg_classes_intersect_p (FLOAT_REGS, CLASS))                  \
    : (((TARGET_E500_DOUBLE                                             \
        && ((((TO) == DFmode) + ((FROM) == DFmode)) == 1                \
+           || (((TO) == TFmode) + ((FROM) == TFmode)) == 1             \
            || (((TO) == DImode) + ((FROM) == DImode)) == 1))           \
        || (TARGET_SPE                                                  \
           && (SPE_VECTOR_MODE (FROM) + SPE_VECTOR_MODE (TO)) == 1))    \
index 14b73c2..ce774b1 100644 (file)
 (define_mode_macro FP [(SF "TARGET_HARD_FLOAT")
   (DF "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)")
   (TF "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128")])
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128")])
 
 ; Various instructions that come in SI and DI forms.
 ; A generic w/d attribute, for things like cmpw/cmpd.
              (clobber (match_dup 4))
              (clobber (match_dup 5))
              (clobber (match_dup 6))])]
-  "TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
   "
 {
   if (TARGET_E500_DOUBLE)
   [(set_attr "length" "8,8,8,20,20,16")])
 
 (define_insn_and_split "*movtf_softfloat"
-  [(set (match_operand:TF 0 "nonimmediate_operand" "=r,Y,r")
+  [(set (match_operand:TF 0 "rs6000_nonimmediate_operand" "=r,Y,r")
        (match_operand:TF 1 "input_operand"         "YGHF,r,r"))]
   "!TARGET_IEEEQUAD
    && (TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_LONG_DOUBLE_128
   [(set_attr "length" "20,20,16")])
 
 (define_expand "extenddftf2"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (float_extend:TF (match_operand:DF 1 "input_operand" "")))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+{
+  if (TARGET_E500_DOUBLE)
+    emit_insn (gen_spe_extenddftf2 (operands[0], operands[1]));
+  else
+    emit_insn (gen_extenddftf2_fprs (operands[0], operands[1]));
+  DONE;
+})
+
+(define_expand "extenddftf2_fprs"
   [(parallel [(set (match_operand:TF 0 "nonimmediate_operand" "")
                   (float_extend:TF (match_operand:DF 1 "input_operand" "")))
              (use (match_dup 2))])]
   [(set (match_operand:TF 0 "nonimmediate_operand" "")
        (float_extend:TF (match_operand:SF 1 "gpc_reg_operand" "")))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
 {
   rtx tmp = gen_reg_rtx (DFmode);
   emit_insn (gen_extendsfdf2 (tmp, operands[1]));
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
   "")
 
 (define_insn_and_split "trunctfdf2_internal1"
   "fadd %0,%1,%L1"
   [(set_attr "type" "fp")])
 
-(define_insn_and_split "trunctfsf2"
+(define_expand "trunctfsf2"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "")
+       (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "")))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+{
+  if (TARGET_E500_DOUBLE)
+    emit_insn (gen_spe_trunctfsf2 (operands[0], operands[1]));
+  else
+    emit_insn (gen_trunctfsf2_fprs (operands[0], operands[1]));
+  DONE;
+})
+
+(define_insn_and_split "trunctfsf2_fprs"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "f")))
    (clobber (match_scratch:DF 2 "=f"))]
   [(set (match_operand:TF 0 "gpc_reg_operand" "")
         (float:TF (match_operand:SI 1 "gpc_reg_operand" "")))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
 {
   rtx tmp = gen_reg_rtx (DFmode);
   expand_float (tmp, operands[1], false);
    (set_attr "length" "20")])
 
 (define_expand "fix_trunctfsi2"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+       (fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))]
+  "!TARGET_IEEEQUAD
+   && (TARGET_POWER2 || TARGET_POWERPC)
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+{
+  if (TARGET_E500_DOUBLE)
+    emit_insn (gen_spe_fix_trunctfsi2 (operands[0], operands[1]));
+  else
+    emit_insn (gen_fix_trunctfsi2_fprs (operands[0], operands[1]));
+  DONE;
+})
+
+(define_expand "fix_trunctfsi2_fprs"
   [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
                   (fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))
              (clobber (match_dup 2))
   DONE;
 })
 
-(define_insn "negtf2"
+(define_expand "negtf2"
+  [(set (match_operand:TF 0 "gpc_reg_operand" "")
+       (neg:TF (match_operand:TF 1 "gpc_reg_operand" "")))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+  "")
+
+(define_insn "negtf2_internal"
   [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
        (neg:TF (match_operand:TF 1 "gpc_reg_operand" "f")))]
   "!TARGET_IEEEQUAD
    (set_attr "length" "8")])
 
 (define_expand "abstf2"
-  [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
-       (abs:TF (match_operand:TF 1 "gpc_reg_operand" "f")))]
+  [(set (match_operand:TF 0 "gpc_reg_operand" "")
+       (abs:TF (match_operand:TF 1 "gpc_reg_operand" "")))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
   "
 {
   rtx label = gen_label_rtx ();
-  emit_insn (gen_abstf2_internal (operands[0], operands[1], label));
+  if (TARGET_E500_DOUBLE)
+    {
+      if (flag_unsafe_math_optimizations)
+       emit_insn (gen_spe_abstf2_tst (operands[0], operands[1], label));
+      else
+       emit_insn (gen_spe_abstf2_cmp (operands[0], operands[1], label));
+    }
+  else
+    emit_insn (gen_abstf2_internal (operands[0], operands[1], label));
   emit_label (label);
   DONE;
 }")
 ; List r->r after r->"o<>", otherwise reload will try to reload a
 ; non-offsettable address by using r->r which won't make progress.
 (define_insn "*movdi_internal32"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=o<>,r,r,*f,*f,m,r")
+  [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=o<>,r,r,*f,*f,m,r")
        (match_operand:DI 1 "input_operand" "r,r,m,f,m,f,IJKnGHF"))]
   "! TARGET_POWERPC64
    && (gpc_reg_operand (operands[0], DImode)
 }")
 
 (define_split
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+  [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "")
         (match_operand:DI 1 "input_operand" ""))]
   "reload_completed && !TARGET_POWERPC64
    && gpr_or_gpr_p (operands[0], operands[1])"
index 7d05e08..d39bcad 100644 (file)
@@ -1,5 +1,6 @@
 ;; e500 SPE description
-;; Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+;; Free Software Foundation, Inc.
 ;; Contributed by Aldy Hernandez (aldy@quesejoda.com)
 
 ;; This file is part of GCC.
    (TSTDFGT_GPR                1009)
    (CMPDFLT_GPR                1010)
    (TSTDFLT_GPR                1011)
-   (E500_CR_IOR_COMPARE 1012)
+   (CMPTFEQ_GPR                1012)
+   (TSTTFEQ_GPR                1013)
+   (CMPTFGT_GPR                1014)
+   (TSTTFGT_GPR                1015)
+   (CMPTFLT_GPR                1016)
+   (TSTTFLT_GPR                1017)
+   (E500_CR_IOR_COMPARE 1018)
    ])
 
 ;; Modes using a 64-bit register.
 (define_mode_macro SPE64 [DF V4HI V2SF V1DI V2SI])
 
+;; Likewise, but allow TFmode (two registers) as well.
+(define_mode_macro SPE64TF [DF V4HI V2SF V1DI V2SI TF])
+
+;; DImode and TImode.
+(define_mode_macro DITI [DI TI])
+
 (define_insn "*negsf2_gpr"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=r")
         (neg:SF (match_operand:SF 1 "gpc_reg_operand" "r")))]
 ;; Double-precision floating point instructions.
 
 ;; FIXME: Add o=r option.
-(define_insn "*frob_df_di"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r")
-        (subreg:DF (match_operand:DI 1 "input_operand" "r,m") 0))]
+(define_insn "*frob_<SPE64:mode>_<DITI:mode>"
+  [(set (match_operand:SPE64 0 "nonimmediate_operand" "=r,r")
+        (subreg:SPE64 (match_operand:DITI 1 "input_operand" "r,m") 0))]
+  "(TARGET_E500_DOUBLE && <SPE64:MODE>mode == DFmode)
+   || (TARGET_SPE && <SPE64:MODE>mode != DFmode)"
+  "@
+   evmergelo %0,%1,%L1
+   evldd%X1 %0,%y1")
+
+(define_insn "*frob_tf_ti"
+  [(set (match_operand:TF 0 "gpc_reg_operand" "=r")
+        (subreg:TF (match_operand:TI 1 "gpc_reg_operand" "r") 0))]
   "TARGET_E500_DOUBLE"
+  "evmergelo %0,%1,%L1\;evmergelo %L0,%Y1,%Z1")
+
+(define_insn "*frob_<mode>_di_2"
+  [(set (subreg:DI (match_operand:SPE64TF 0 "nonimmediate_operand" "+&r,r") 0)
+        (match_operand:DI 1 "input_operand" "r,m"))]
+  "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+   || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
   "@
    evmergelo %0,%1,%L1
    evldd%X1 %0,%y1")
 
-(define_insn "*frob_di_df"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r")
-        (subreg:DI (match_operand:DF 1 "input_operand" "r") 0))]
+(define_insn "*frob_tf_di_8_2"
+  [(set (subreg:DI (match_operand:TF 0 "nonimmediate_operand" "+&r,r") 8)
+        (match_operand:DI 1 "input_operand" "r,m"))]
   "TARGET_E500_DOUBLE"
+  "@
+   evmergelo %L0,%1,%L1
+   evldd%X1 %L0,%y1")
+
+(define_insn "*frob_di_<mode>"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r")
+        (subreg:DI (match_operand:SPE64TF 1 "input_operand" "r") 0))]
+  "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+   || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
   "evmergehi %0,%1,%1\;mr %L0,%1"
   [(set_attr "length" "8")])
 
-(define_insn "*frob_di_df_2"
-  [(set (subreg:DF (match_operand:DI 0 "register_operand" "=&r,r") 0)
-       (match_operand:DF 1 "input_operand" "r,m"))]
+(define_insn "*frob_ti_tf"
+  [(set (match_operand:TI 0 "nonimmediate_operand" "=&r")
+        (subreg:TI (match_operand:TF 1 "input_operand" "r") 0))]
   "TARGET_E500_DOUBLE"
+  "evmergehi %0,%1,%1\;mr %L0,%1\;evmergehi %Y0,%L1,%L1\;mr %Z0,%L1")
+
+(define_insn "*frob_<DITI:mode>_<SPE64:mode>_2"
+  [(set (subreg:SPE64 (match_operand:DITI 0 "register_operand" "+&r,r") 0)
+       (match_operand:SPE64 1 "input_operand" "r,m"))]
+  "(TARGET_E500_DOUBLE && <SPE64:MODE>mode == DFmode)
+   || (TARGET_SPE && <SPE64:MODE>mode != DFmode)"
   "*
 {
   switch (which_alternative)
 }"
   [(set_attr "length" "8,8")])
 
+; As the above, but TImode at offset 8.
+(define_insn "*frob_ti_<mode>_8_2"
+  [(set (subreg:SPE64 (match_operand:TI 0 "register_operand" "+&r,r") 8)
+       (match_operand:SPE64 1 "input_operand" "r,m"))]
+  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode)
+   || (TARGET_SPE && <MODE>mode != DFmode)"
+  "*
+{
+  switch (which_alternative)
+    {
+    default: 
+      gcc_unreachable ();
+    case 0:
+      return \"evmergehi %Y0,%1,%1\;mr %Z0,%1\";
+    case 1:
+      if (!offsettable_nonstrict_memref_p (operands[1]))
+       return \"evldd%X1 %Z0,%y1\;evmergehi %Y0,%Z0,%Z0\";
+      if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+                            operands[1], 0))
+       return \"{l|lwz} %Z0,%L1\;{l|lwz} %Y0,%1\";
+      else
+        return \"{l%U1%X1|lwz%U1%X1} %Y0,%1\;{l|lwz} %Z0,%L1\";
+    }
+}"
+  [(set_attr "length" "8,8")])
+
+(define_insn "*frob_ti_tf_2"
+  [(set (subreg:TF (match_operand:TI 0 "gpc_reg_operand" "=&r") 0)
+       (match_operand:TF 1 "gpc_reg_operand" "r"))]
+  "TARGET_E500_DOUBLE"
+  "evmergehi %0,%1,%1\;mr %L0,%1\;evmergehi %Y0,%L1,%L1\;mr %Z0,%L1")
+
 (define_insn "*mov_si<mode>_e500_subreg0"
-  [(set (subreg:SI (match_operand:SPE64 0 "register_operand" "+r,&r") 0)
+  [(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r,&r") 0)
        (match_operand:SI 1 "input_operand" "r,m"))]
-  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode) || (TARGET_SPE && <MODE>mode != DFmode)"
+  "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+   || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
   "@
    evmergelo %0,%1,%0
    evmergelohi %0,%0,%0\;{l%U1%X1|lwz%U1%X1} %0,%1\;evmergelohi %0,%0,%0")
 ;; the offset.
 (define_insn "*mov_si<mode>_e500_subreg0_2"
   [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
-       (subreg:SI (match_operand:SPE64 1 "register_operand" "+r,&r") 0))]
-  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode) || (TARGET_SPE && <MODE>mode != DFmode)"
+       (subreg:SI (match_operand:SPE64TF 1 "register_operand" "+r,&r") 0))]
+  "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+   || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
   "@
    evmergehi %0,%0,%1
    evmergelohi %1,%1,%1\;{st%U0%X0|stw%U0%X0} %1,%0")
 
 (define_insn "*mov_si<mode>_e500_subreg4"
-  [(set (subreg:SI (match_operand:SPE64 0 "register_operand" "+r,r") 4)
+  [(set (subreg:SI (match_operand:SPE64TF 0 "register_operand" "+r,r") 4)
        (match_operand:SI 1 "input_operand" "r,m"))]
-  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode) || (TARGET_SPE && <MODE>mode != DFmode)"
+  "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+   || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
   "@
    mr %0,%1
    {l%U1%X1|lwz%U1%X1} %0,%1")
 
 (define_insn "*mov_si<mode>_e500_subreg4_2"
   [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
-       (subreg:SI (match_operand:SPE64 1 "register_operand" "r,r") 4))]
-  "(TARGET_E500_DOUBLE && <MODE>mode == DFmode) || (TARGET_SPE && <MODE>mode != DFmode)"
+       (subreg:SI (match_operand:SPE64TF 1 "register_operand" "r,r") 4))]
+  "(TARGET_E500_DOUBLE && (<MODE>mode == DFmode || <MODE>mode == TFmode))
+   || (TARGET_SPE && <MODE>mode != DFmode && <MODE>mode != TFmode)"
   "@
    mr %0,%1
    {st%U0%X0|stw%U0%X0} %1,%0")
 
+(define_insn "*mov_sitf_e500_subreg8"
+  [(set (subreg:SI (match_operand:TF 0 "register_operand" "+r,&r") 8)
+       (match_operand:SI 1 "input_operand" "r,m"))]
+  "TARGET_E500_DOUBLE"
+  "@
+   evmergelo %L0,%1,%L0
+   evmergelohi %L0,%L0,%L0\;{l%U1%X1|lwz%U1%X1} %L0,%1\;evmergelohi %L0,%L0,%L0")
+
+(define_insn "*mov_sitf_e500_subreg8_2"
+  [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
+       (subreg:SI (match_operand:TF 1 "register_operand" "+r,&r") 8))]
+  "TARGET_E500_DOUBLE"
+  "@
+   evmergehi %0,%0,%L1
+   evmergelohi %L1,%L1,%L1\;{st%U0%X0|stw%U0%X0} %L1,%0")
+
+(define_insn "*mov_sitf_e500_subreg12"
+  [(set (subreg:SI (match_operand:TF 0 "register_operand" "+r,r") 12)
+       (match_operand:SI 1 "input_operand" "r,m"))]
+  "TARGET_E500_DOUBLE"
+  "@
+   mr %L0,%1
+   {l%U1%X1|lwz%U1%X1} %L0,%1")
+
+(define_insn "*mov_sitf_e500_subreg12_2"
+  [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "+r,m")
+       (subreg:SI (match_operand:TF 1 "register_operand" "r,r") 12))]
+  "TARGET_E500_DOUBLE"
+  "@
+   mr %0,%L1
+   {st%U0%X0|stw%U0%X0} %L1,%0")
+
 ;; FIXME: Allow r=CONST0.
 (define_insn "*movdf_e500_double"
   [(set (match_operand:DF 0 "rs6000_nonimmediate_operand" "=r,r,m")
   "TARGET_HARD_FLOAT && TARGET_E500_DOUBLE"
   "efddiv %0,%1,%2")
 
+;; Double-precision floating point instructions for IBM long double.
+
+(define_insn_and_split "spe_trunctfdf2_internal1"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=r,?r")
+       (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "0,r")))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
+  "@
+   #
+   evor %0,%1,%1"
+  "&& reload_completed && REGNO (operands[0]) == REGNO (operands[1])"
+  [(const_int 0)]
+{
+  emit_note (NOTE_INSN_DELETED);
+  DONE;
+})
+
+(define_insn_and_split "spe_trunctfsf2"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=r")
+       (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "r")))
+   (clobber (match_scratch:DF 2 "=r"))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2)
+       (float_truncate:DF (match_dup 1)))
+   (set (match_dup 0)
+       (float_truncate:SF (match_dup 2)))]
+  "")
+
+(define_insn "spe_extenddftf2"
+  [(set (match_operand:TF 0 "rs6000_nonimmediate_operand" "=r,?r,r,o")
+       (float_extend:TF (match_operand:DF 1 "input_operand" "0,r,m,r")))
+   (clobber (match_scratch:DF 2 "=X,X,X,&r"))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
+  "@
+   evxor %L0,%L0,%L0
+   evor %0,%1,%1\;evxor %L0,%L0,%L0
+   evldd%X1 %0,%y1\;evxor %L0,%L0,%L0
+   evstdd%X0 %1,%y0\;evxor %2,%2,%2\;evstdd %2,%Y0")
+
+(define_expand "spe_fix_trunctfsi2"
+  [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+                  (fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))
+             (clobber (match_dup 2))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
+{
+  operands[2] = gen_reg_rtx (DFmode);
+  operands[3] = gen_reg_rtx (SImode);
+  operands[4] = gen_reg_rtx (SImode);
+})
+
+; Like fix_trunc_helper, add with rounding towards 0.
+(define_insn "spe_fix_trunctfsi2_internal"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+        (fix:SI (match_operand:TF 1 "gpc_reg_operand" "r")))
+   (clobber (match_operand:DF 2 "gpc_reg_operand" "=r"))
+   (clobber (match_operand:SI 3 "gpc_reg_operand" "=&r"))
+   (clobber (match_operand:SI 4 "gpc_reg_operand" "=&r"))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
+  "mfspefscr %3\;rlwinm %4,%3,0,0,29\;ori %4,%4,1\;efdadd %2,%1,%L1\;mtspefscr %3\;efdctsiz %0, %2")
+
+(define_insn "spe_negtf2_internal"
+  [(set (match_operand:TF 0 "gpc_reg_operand" "=r")
+       (neg:TF (match_operand:TF 1 "gpc_reg_operand" "r")))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
+  "*
+{
+  if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
+    return \"efdneg %L0,%L1\;efdneg %0,%1\";
+  else
+    return \"efdneg %0,%1\;efdneg %L0,%L1\";
+}")
+
+(define_expand "spe_abstf2_cmp"
+  [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
+       (match_operand:TF 1 "gpc_reg_operand" "f"))
+   (set (match_dup 3) (match_dup 5))
+   (set (match_dup 5) (abs:DF (match_dup 5)))
+   (set (match_dup 4) (unspec:CCFP [(compare:CCFP (match_dup 3)
+                                                  (match_dup 5))] CMPDFEQ_GPR))
+   (set (pc) (if_then_else (eq (match_dup 4) (const_int 0))
+                          (label_ref (match_operand 2 "" ""))
+                          (pc)))
+   (set (match_dup 6) (neg:DF (match_dup 6)))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
+  "
+{
+  const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode);
+  const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
+  operands[3] = gen_reg_rtx (DFmode);
+  operands[4] = gen_reg_rtx (CCFPmode);
+  operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word);
+  operands[6] = simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word);
+}")
+
+(define_expand "spe_abstf2_tst"
+  [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
+       (match_operand:TF 1 "gpc_reg_operand" "f"))
+   (set (match_dup 3) (match_dup 5))
+   (set (match_dup 5) (abs:DF (match_dup 5)))
+   (set (match_dup 4) (unspec:CCFP [(compare:CCFP (match_dup 3)
+                                                  (match_dup 5))] TSTDFEQ_GPR))
+   (set (pc) (if_then_else (eq (match_dup 4) (const_int 0))
+                          (label_ref (match_operand 2 "" ""))
+                          (pc)))
+   (set (match_dup 6) (neg:DF (match_dup 6)))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
+  "
+{
+  const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode);
+  const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
+  operands[3] = gen_reg_rtx (DFmode);
+  operands[4] = gen_reg_rtx (CCFPmode);
+  operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word);
+  operands[6] = simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word);
+}")
+
 ;; Vector move instructions.
 
 (define_expand "movv2si"
   "efdtstlt %0,%1,%2"
   [(set_attr "type" "veccmpsimple")])
 
+;; Same thing, but for IBM long double.
+
+(define_insn "cmptfeq_gpr"
+  [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
+       (unspec:CCFP
+        [(compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "r")
+                       (match_operand:TF 2 "gpc_reg_operand" "r"))]
+        CMPTFEQ_GPR))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128
+   && !flag_unsafe_math_optimizations"
+  "efdcmpeq %0,%1,%2\;bng %0,$+8\;efdcmpeq %0,%L1,%L2"
+  [(set_attr "type" "veccmp")])
+
+(define_insn "tsttfeq_gpr"
+  [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
+       (unspec:CCFP
+        [(compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "r")
+                       (match_operand:TF 2 "gpc_reg_operand" "r"))]
+        TSTTFEQ_GPR))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128
+   && flag_unsafe_math_optimizations"
+  "efdtsteq %0,%1,%2\;bng %0,$+8\;efdtsteq %0,%L1,%L2"
+  [(set_attr "type" "veccmpsimple")])
+
+(define_insn "cmptfgt_gpr"
+  [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
+       (unspec:CCFP
+        [(compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "r")
+                       (match_operand:TF 2 "gpc_reg_operand" "r"))]
+        CMPTFGT_GPR))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128
+   && !flag_unsafe_math_optimizations"
+  "efdcmpgt %0,%1,%2\;bgt %0,$+16\;efdcmpeq %0,%1,%2\;bng %0,$+8\;efdcmpgt %0,%L1,%L2"
+  [(set_attr "type" "veccmp")])
+
+(define_insn "tsttfgt_gpr"
+  [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
+       (unspec:CCFP
+        [(compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "r")
+                       (match_operand:TF 2 "gpc_reg_operand" "r"))]
+        TSTTFGT_GPR))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128
+   && flag_unsafe_math_optimizations"
+  "efdtstgt %0,%1,%2\;bgt %0,$+16\;efdtsteq %0,%1,%2\;bng %0,$+8\;efdtstgt %0,%L1,%L2"
+  [(set_attr "type" "veccmpsimple")])
+
+(define_insn "cmptflt_gpr"
+  [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
+       (unspec:CCFP
+        [(compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "r")
+                       (match_operand:TF 2 "gpc_reg_operand" "r"))]
+        CMPTFLT_GPR))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128
+   && !flag_unsafe_math_optimizations"
+  "efdcmplt %0,%1,%2\;bgt %0,$+16\;efdcmpeq %0,%1,%2\;bng %0,$+8\;efdcmplt %0,%L1,%L2"
+  [(set_attr "type" "veccmp")])
+
+(define_insn "tsttflt_gpr"
+  [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
+       (unspec:CCFP
+        [(compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "r")
+                       (match_operand:TF 2 "gpc_reg_operand" "r"))]
+        TSTTFLT_GPR))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128
+   && flag_unsafe_math_optimizations"
+  "efdtstlt %0,%1,%2\;bgt %0,$+16\;efdtsteq %0,%1,%2\;bng %0,$+8\;efdtstlt %0,%L1,%L2"
+  [(set_attr "type" "veccmpsimple")])
+
 ;; Like cceq_ior_compare, but compare the GT bits.
 (define_insn "e500_cr_ior_compare"
   [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
index 2ab5eeb..21d32f0 100644 (file)
@@ -1,3 +1,7 @@
+2007-01-23  Joseph Myers  <joseph@codesourcery.com>
+
+       * config/rs6000/t-ldbl128: Always use -mlong-double-128.
+
 2007-01-21  Andrew Pinski  <pinskia@gmail.com>
 
        PR target/30519
index 96e242b..bdd62f3 100644 (file)
@@ -1,7 +1,3 @@
 SHLIB_MAPFILES += $(gcc_srcdir)/config/rs6000/libgcc-ppc-glibc.ver
 
-# Use -mlong-double-128 only when not compiling nof libgcc.
-predefined-macros := $(shell true | $(CC) $(CFLAGS) -x c -dD -E -)
-ifeq ($(findstring _SOFT_FLOAT,$(predefined-macros)),)
 HOST_LIBGCC2_CFLAGS += -mlong-double-128
-endif