aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2007-01-23 19:38:33 +0000
committerJoseph Myers <jsm28@gcc.gnu.org>2007-01-23 19:38:33 +0000
commit17caeff2620c89d89ba6b473790b1f82327f6d93 (patch)
tree77969358c67c7847cfce02257d673e18e43d6378
parentdc5696215db3d21f19addc6faa866790e962a7cd (diff)
downloadgcc-17caeff2620c89d89ba6b473790b1f82327f6d93.zip
gcc-17caeff2620c89d89ba6b473790b1f82327f6d93.tar.gz
gcc-17caeff2620c89d89ba6b473790b1f82327f6d93.tar.bz2
rs6000-c.c (rs6000_cpu_cpp_builtins): Define _SOFT_DOUBLE if doubles use software floating-point.
gcc: * 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. From-SVN: r121085
-rw-r--r--gcc/ChangeLog89
-rw-r--r--gcc/config/rs6000/darwin-ldouble.c17
-rw-r--r--gcc/config/rs6000/eabispe.h9
-rw-r--r--gcc/config/rs6000/libgcc-ppc-glibc.ver2
-rw-r--r--gcc/config/rs6000/linuxspe.h14
-rw-r--r--gcc/config/rs6000/rs6000-c.c4
-rw-r--r--gcc/config/rs6000/rs6000.c119
-rw-r--r--gcc/config/rs6000/rs6000.h1
-rw-r--r--gcc/config/rs6000/rs6000.md101
-rw-r--r--gcc/config/rs6000/spe.md352
-rw-r--r--libgcc/ChangeLog4
-rw-r--r--libgcc/config/rs6000/t-ldbl1284
12 files changed, 619 insertions, 97 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f050d94..abd821f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/rs6000/darwin-ldouble.c b/gcc/config/rs6000/darwin-ldouble.c
index eaffb34..7405448 100644
--- a/gcc/config/rs6000/darwin-ldouble.c
+++ b/gcc/config/rs6000/darwin-ldouble.c
@@ -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"
diff --git a/gcc/config/rs6000/eabispe.h b/gcc/config/rs6000/eabispe.h
index 2a0b923..40669dd 100644
--- a/gcc/config/rs6000/eabispe.h
+++ b/gcc/config/rs6000/eabispe.h
@@ -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
diff --git a/gcc/config/rs6000/libgcc-ppc-glibc.ver b/gcc/config/rs6000/libgcc-ppc-glibc.ver
index d8ffd2a..d065c13 100644
--- a/gcc/config/rs6000/libgcc-ppc-glibc.ver
+++ b/gcc/config/rs6000/libgcc-ppc-glibc.ver
@@ -31,7 +31,7 @@ GCC_4.2.0 {
__gcc_qmul
__gcc_qdiv
-%ifdef _SOFT_FLOAT
+%ifdef _SOFT_DOUBLE
__gcc_qneg
__gcc_qeq
__gcc_qne
diff --git a/gcc/config/rs6000/linuxspe.h b/gcc/config/rs6000/linuxspe.h
index 9b98616..8dc2dc9 100644
--- a/gcc/config/rs6000/linuxspe.h
+++ b/gcc/config/rs6000/linuxspe.h
@@ -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) \
@@ -45,16 +42,5 @@
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"
diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c
index d8f1075..55c9b7c 100644
--- a/gcc/config/rs6000/rs6000-c.c
+++ b/gcc/config/rs6000/rs6000-c.c
@@ -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__");
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 532d10c..f72fde3 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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;
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 17a2298..decaf8f 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -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)) \
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 14b73c2..ce774b1 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -176,7 +176,9 @@
(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.
@@ -5730,7 +5732,7 @@
(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)
@@ -8538,7 +8540,7 @@
[(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
@@ -8551,6 +8553,21 @@
[(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))])]
@@ -8586,7 +8603,9 @@
[(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]));
@@ -8598,7 +8617,9 @@
[(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"
@@ -8625,7 +8646,22 @@
"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"))]
@@ -8643,7 +8679,9 @@
[(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);
@@ -8664,6 +8702,22 @@
(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))
@@ -8705,7 +8759,16 @@
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
@@ -8721,14 +8784,24 @@
(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;
}")
@@ -8761,7 +8834,7 @@
; 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)
@@ -8798,7 +8871,7 @@
}")
(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])"
diff --git a/gcc/config/rs6000/spe.md b/gcc/config/rs6000/spe.md
index 7d05e08..d39bcad 100644
--- a/gcc/config/rs6000/spe.md
+++ b/gcc/config/rs6000/spe.md
@@ -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.
@@ -29,12 +30,24 @@
(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")))]
@@ -2198,25 +2211,57 @@
;; 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)
@@ -2244,10 +2289,43 @@
}"
[(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")
@@ -2256,28 +2334,63 @@
;; 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")
@@ -2354,6 +2467,133 @@
"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"
@@ -2803,6 +3043,80 @@
"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")
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 2ab5eeb..21d32f0 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -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
diff --git a/libgcc/config/rs6000/t-ldbl128 b/libgcc/config/rs6000/t-ldbl128
index 96e242b..bdd62f3 100644
--- a/libgcc/config/rs6000/t-ldbl128
+++ b/libgcc/config/rs6000/t-ldbl128
@@ -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