diff options
author | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-01-23 19:38:33 +0000 |
---|---|---|
committer | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-01-23 19:38:33 +0000 |
commit | 3da0fdbcca15cc0fe05cc9aca5b067a8c544e36c (patch) | |
tree | 77969358c67c7847cfce02257d673e18e43d6378 /gcc | |
parent | fabdc1d15e571f29ef8a47a134ab04b0cabcd321 (diff) | |
download | gcc-3da0fdbcca15cc0fe05cc9aca5b067a8c544e36c.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@121085 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 89 | ||||
-rw-r--r-- | gcc/config/rs6000/darwin-ldouble.c | 17 | ||||
-rw-r--r-- | gcc/config/rs6000/eabispe.h | 9 | ||||
-rw-r--r-- | gcc/config/rs6000/libgcc-ppc-glibc.ver | 2 | ||||
-rw-r--r-- | gcc/config/rs6000/linuxspe.h | 14 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-c.c | 4 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 119 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 1 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 101 | ||||
-rw-r--r-- | gcc/config/rs6000/spe.md | 352 |
10 files changed, 615 insertions, 93 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f050d943814..abd821fa2ae 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 eaffb34cd18..7405448706a 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 2a0b92368c0..40669dd94b8 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 d8ffd2ad282..d065c13bca4 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 9b986164677..8dc2dc90e12 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 d8f107505eb..55c9b7c66b2 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 532d10c7314..f72fde34ffc 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 17a22983ffd..decaf8fae8f 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 14b73c213a8..ce774b187b2 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 7d05e0882d5..d39bcad84d9 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") |