diff options
author | Joseph Myers <joseph@codesourcery.com> | 2006-12-06 17:30:34 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2006-12-06 17:30:34 +0000 |
commit | 96f43d5a0f2f7f4cfba76d8f80bf784d6e966c23 (patch) | |
tree | b1c0579bd87ef53e070c2d288fceeb6602eb0c7b | |
parent | f279fd6f682ef1bdc82b2f2a7bf5e9b45fb0cdec (diff) |
gcc/
* rtlanal.c (struct subreg_info, subreg_get_info, subreg_nregs):
New.
(subreg_regno_offset, subreg_offset_representable_p): Change to
wrappers about subreg_get_info.
(refers_to_regno_p, reg_overlap_mentioned_p): Use subreg_nregs.
* rtl.h (subreg_nregs): Declare.
* tm.texi (HARD_REGNO_NREGS_HAS_PADDING): Update to refer to
subreg_get_info.
* caller-save.c (mark_set_regs, add_stored_regs): Use
subreg_nregs.
* flow.c (mark_set_1): Use subreg_nregs.
* postreload.c (move2add_note_store): Use subreg_nregs.
* reload.c (decompose, refers_to_regno_for_reload_p,
reg_overlap_mentioned_for_reload_p): Use subreg_nregs.
* resource.c (update_live_status, mark_referenced_resources,
mark_set_resources): Use subreg_nregs.
* 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.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/csl/sourcerygxx-4_1@119585 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | ChangeLog.csl | 106 | ||||
-rw-r--r-- | gcc/caller-save.c | 22 | ||||
-rw-r--r-- | gcc/config/rs6000/darwin-ldouble.c | 15 | ||||
-rw-r--r-- | gcc/config/rs6000/eabispe.h | 6 | ||||
-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 | 2 | ||||
-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 | 105 | ||||
-rw-r--r-- | gcc/config/rs6000/spe.md | 349 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 2 | ||||
-rw-r--r-- | gcc/flow.c | 3 | ||||
-rw-r--r-- | gcc/postreload.c | 8 | ||||
-rw-r--r-- | gcc/reload.c | 8 | ||||
-rw-r--r-- | gcc/resource.c | 20 | ||||
-rw-r--r-- | gcc/rtl.h | 1 | ||||
-rw-r--r-- | gcc/rtlanal.c | 215 |
18 files changed, 809 insertions, 189 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl index 8a16fc0dc8f..36c766311e7 100644 --- a/ChangeLog.csl +++ b/ChangeLog.csl @@ -1,3 +1,109 @@ +2006-12-06 Joseph Myers <joseph@codesourcery.com> + + gcc/ + * rtlanal.c (struct subreg_info, subreg_get_info, subreg_nregs): + New. + (subreg_regno_offset, subreg_offset_representable_p): Change to + wrappers about subreg_get_info. + (refers_to_regno_p, reg_overlap_mentioned_p): Use subreg_nregs. + * rtl.h (subreg_nregs): Declare. + * tm.texi (HARD_REGNO_NREGS_HAS_PADDING): Update to refer to + subreg_get_info. + * caller-save.c (mark_set_regs, add_stored_regs): Use + subreg_nregs. + * flow.c (mark_set_1): Use subreg_nregs. + * postreload.c (move2add_note_store): Use subreg_nregs. + * reload.c (decompose, refers_to_regno_for_reload_p, + reg_overlap_mentioned_for_reload_p): Use subreg_nregs. + * resource.c (update_live_status, mark_referenced_resources, + mark_set_resources): Use subreg_nregs. + * 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. + 2006-12-01 Joseph Myers <joseph@codesourcery.com> David Edelsohn <edelsohn@gnu.org> diff --git a/gcc/caller-save.c b/gcc/caller-save.c index ea85044cfec..86579c8d398 100644 --- a/gcc/caller-save.c +++ b/gcc/caller-save.c @@ -507,15 +507,17 @@ mark_set_regs (rtx reg, rtx setter ATTRIBUTE_UNUSED, void *data) if (!REG_P (inner) || REGNO (inner) >= FIRST_PSEUDO_REGISTER) return; regno = subreg_regno (reg); + endregno = regno + subreg_nregs (reg); } else if (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER) - regno = REGNO (reg); + { + regno = REGNO (reg); + endregno = regno + hard_regno_nregs[regno][mode]; + } else return; - endregno = regno + hard_regno_nregs[regno][mode]; - for (i = regno; i < endregno; i++) SET_HARD_REG_BIT (*this_insn_sets, i); } @@ -541,13 +543,17 @@ add_stored_regs (rtx reg, rtx setter, void *data) SUBREG_BYTE (reg), GET_MODE (reg)); reg = SUBREG_REG (reg); + regno = REGNO (reg) + offset; + endregno = regno + subreg_nregs (reg); } + else + { + if (!REG_P (reg) || REGNO (reg) >= FIRST_PSEUDO_REGISTER) + return; - if (!REG_P (reg) || REGNO (reg) >= FIRST_PSEUDO_REGISTER) - return; - - regno = REGNO (reg) + offset; - endregno = regno + hard_regno_nregs[regno][mode]; + regno = REGNO (reg) + offset; + endregno = regno + hard_regno_nregs[regno][mode]; + } for (i = regno; i < endregno; i++) SET_REGNO_REG_SET ((regset) data, i); diff --git a/gcc/config/rs6000/darwin-ldouble.c b/gcc/config/rs6000/darwin-ldouble.c index a61703f1589..5871cec4190 100644 --- a/gcc/config/rs6000/darwin-ldouble.c +++ b/gcc/config/rs6000/darwin-ldouble.c @@ -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; } -#ifdef _SOFT_FLOAT +#ifdef _SOFT_DOUBLE 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..34cfab6dc92 100644 --- a/gcc/config/rs6000/eabispe.h +++ b/gcc/config/rs6000/eabispe.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) \ @@ -52,8 +49,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 fd7d20ebd68..6672d278920 100644 --- a/gcc/config/rs6000/linuxspe.h +++ b/gcc/config/rs6000/linuxspe.h @@ -51,9 +51,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) \ @@ -61,16 +58,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 259fc53c980..13bc8275088 100644 --- a/gcc/config/rs6000/rs6000-c.c +++ b/gcc/config/rs6000/rs6000-c.c @@ -122,6 +122,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 e474b7b5650..5249188b60f 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1356,8 +1356,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; } rs6000_always_hint = (rs6000_cpu != PROCESSOR_POWER4 @@ -1709,9 +1707,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_: @@ -2536,18 +2531,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; } @@ -2767,6 +2766,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; @@ -2845,7 +2848,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); @@ -2943,7 +2947,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) @@ -3349,7 +3353,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)) { @@ -3486,7 +3490,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; @@ -3959,14 +3964,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; } @@ -4751,7 +4757,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) { @@ -4761,12 +4767,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 (); } @@ -4781,7 +4799,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); @@ -5200,7 +5219,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) @@ -9153,7 +9174,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"); @@ -10765,7 +10786,9 @@ print_operand (FILE *file, rtx x, int code) tmp = XEXP (x, 0); /* Ugly hack because %y is overloaded. */ - if (TARGET_E500 && GET_MODE_SIZE (GET_MODE (x)) == 8) + if (TARGET_E500 && (GET_MODE_SIZE (GET_MODE (x)) == 8 + || GET_MODE (x) == TFmode + || GET_MODE (x) == TImode)) { /* Handle [reg]. */ if (GET_CODE (tmp) == REG) @@ -11098,6 +11121,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 (); } @@ -11122,6 +11153,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 (); } @@ -11146,6 +11185,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 (); } @@ -11189,6 +11236,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 (); } @@ -13144,7 +13199,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; } } @@ -19024,7 +19079,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; @@ -19062,7 +19118,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 1d6c4c1bd9e..66dc94467b3 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1227,6 +1227,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 c4ac7b3b0ca..c4996591cdf 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -153,7 +153,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. @@ -5119,7 +5121,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) @@ -7811,7 +7813,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 @@ -7824,6 +7826,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))])] @@ -7858,7 +7875,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])); @@ -7870,7 +7889,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" @@ -7897,7 +7918,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"))] @@ -7912,10 +7948,12 @@ "") (define_expand "floatsitf2" - [(set (match_operand:TF 0 "gpc_reg_operand" "=f") - (float:TF (match_operand:SI 1 "gpc_reg_operand" "r")))] + [(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); @@ -7936,6 +7974,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)) @@ -7977,7 +8031,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 @@ -7993,14 +8056,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; }") @@ -8033,7 +8106,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) @@ -8070,7 +8143,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..81b965b98de 100644 --- a/gcc/config/rs6000/spe.md +++ b/gcc/config/rs6000/spe.md @@ -29,12 +29,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 +2210,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 +2288,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 +2333,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 +2466,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 +3042,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/gcc/doc/tm.texi b/gcc/doc/tm.texi index 4baac440ab8..6adddabc345 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1972,7 +1972,7 @@ registers but takes up 128 bits in memory, then this would be nonzero. This macros only needs to be defined if there are cases where -@code{subreg_regno_offset} and @code{subreg_offset_representable_p} +@code{subreg_get_info} would otherwise wrongly determine that a @code{subreg} can be represented by an offset to the register number, when in fact such a @code{subreg} would contain some of the padding not stored in diff --git a/gcc/flow.c b/gcc/flow.c index 295a3dac026..2745f3fd44e 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -2733,8 +2733,7 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c regno_first += subreg_regno_offset (regno_first, inner_mode, SUBREG_BYTE (reg), outer_mode); - regno_last = (regno_first - + hard_regno_nregs[regno_first][outer_mode] - 1); + regno_last = (regno_first + subreg_nregs (reg) - 1); /* Since we've just adjusted the register number ranges, make sure REG matches. Otherwise some_was_live will be clear diff --git a/gcc/postreload.c b/gcc/postreload.c index f2c15676895..badec483858 100644 --- a/gcc/postreload.c +++ b/gcc/postreload.c @@ -1433,6 +1433,7 @@ static void move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED) { unsigned int regno = 0; + unsigned int nregs = 0; unsigned int i; enum machine_mode mode = GET_MODE (dst); @@ -1442,6 +1443,7 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED) GET_MODE (SUBREG_REG (dst)), SUBREG_BYTE (dst), GET_MODE (dst)); + nregs = subreg_nregs (dst); dst = SUBREG_REG (dst); } @@ -1459,9 +1461,11 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED) return; regno += REGNO (dst); + if (!nregs) + nregs = hard_regno_nregs[regno][mode]; if (SCALAR_INT_MODE_P (GET_MODE (dst)) - && hard_regno_nregs[regno][mode] == 1 && GET_CODE (set) == SET + && nregs == 1 && GET_CODE (set) == SET && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART) { @@ -1561,7 +1565,7 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED) } else { - unsigned int endregno = regno + hard_regno_nregs[regno][mode]; + unsigned int endregno = regno + nregs; for (i = regno; i < endregno; i++) /* Reset the information about this register. */ diff --git a/gcc/reload.c b/gcc/reload.c index 74a9f28825a..54899058184 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -2424,7 +2424,7 @@ decompose (rtx x) return decompose (SUBREG_REG (x)); else /* A hard reg. */ - val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)]; + val.end = val.start + subreg_nregs (x); break; case SCRATCH: @@ -6317,7 +6317,7 @@ refers_to_regno_for_reload_p (unsigned int regno, unsigned int endregno, unsigned int inner_regno = subreg_regno (x); unsigned int inner_endregno = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER - ? hard_regno_nregs[inner_regno][GET_MODE (x)] : 1); + ? subreg_nregs (x) : 1); return endregno > inner_regno && regno < inner_endregno; } @@ -6413,6 +6413,10 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in) GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x), GET_MODE (x)); + endregno = regno + (regno < FIRST_PSEUDO_REGISTER + ? subreg_nregs (x) : 1); + + return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0); } else if (REG_P (x)) { diff --git a/gcc/resource.c b/gcc/resource.c index a248989fd67..e7b5e47db29 100644 --- a/gcc/resource.c +++ b/gcc/resource.c @@ -100,11 +100,17 @@ update_live_status (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED) return; if (GET_CODE (dest) == SUBREG) - first_regno = subreg_regno (dest); - else - first_regno = REGNO (dest); + { + first_regno = subreg_regno (dest); + last_regno = first_regno + subreg_nregs (dest); - last_regno = first_regno + hard_regno_nregs[first_regno][GET_MODE (dest)]; + } + else + { + first_regno = REGNO (dest); + last_regno + = first_regno + hard_regno_nregs[first_regno][GET_MODE (dest)]; + } if (GET_CODE (x) == CLOBBER) for (i = first_regno; i < last_regno; i++) @@ -230,8 +236,7 @@ mark_referenced_resources (rtx x, struct resources *res, else { unsigned int regno = subreg_regno (x); - unsigned int last_regno - = regno + hard_regno_nregs[regno][GET_MODE (x)]; + unsigned int last_regno = regno + subreg_nregs (x); gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER); for (r = regno; r < last_regno; r++) @@ -764,8 +769,7 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, else { unsigned int regno = subreg_regno (x); - unsigned int last_regno - = regno + hard_regno_nregs[regno][GET_MODE (x)]; + unsigned int last_regno = regno + subreg_nregs (x); gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER); for (r = regno; r < last_regno; r++) diff --git a/gcc/rtl.h b/gcc/rtl.h index d7344c5e886..62ce9e47958 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -976,6 +976,7 @@ extern unsigned int subreg_regno_offset (unsigned int, enum machine_mode, extern bool subreg_offset_representable_p (unsigned int, enum machine_mode, unsigned int, enum machine_mode); extern unsigned int subreg_regno (rtx); +extern unsigned int subreg_nregs (rtx); extern unsigned HOST_WIDE_INT nonzero_bits (rtx, enum machine_mode); extern unsigned int num_sign_bit_copies (rtx, enum machine_mode); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 93d07614a51..e223dcf28fc 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -38,6 +38,18 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "function.h" #include "tree.h" +/* Information about a subreg of a hard register. */ +struct subreg_info +{ + /* Offset of first hard register involved in the subreg. */ + int offset; + /* Number of hard registers involved in the subreg. */ + int nregs; + /* Whether this subreg can be represented as a hard reg with the new + mode. */ + bool representable_p; +}; + /* Forward declarations */ static int global_reg_mentioned_p_1 (rtx *, void *); static void set_of_1 (rtx, rtx, void *); @@ -46,6 +58,9 @@ static bool covers_regno_no_parallel_p (rtx, unsigned int); static int rtx_referenced_p_1 (rtx *, void *); static int computed_jump_p_1 (rtx); static void parms_set (rtx, rtx, void *); +static void subreg_get_info (unsigned int, enum machine_mode, + unsigned int, enum machine_mode, + struct subreg_info *); static unsigned HOST_WIDE_INT cached_nonzero_bits (rtx, enum machine_mode, rtx, enum machine_mode, @@ -1285,7 +1300,7 @@ refers_to_regno_p (unsigned int regno, unsigned int endregno, rtx x, unsigned int inner_regno = subreg_regno (x); unsigned int inner_endregno = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER - ? hard_regno_nregs[inner_regno][GET_MODE (x)] : 1); + ? subreg_nregs (x) : 1); return endregno > inner_regno && regno < inner_endregno; } @@ -1375,13 +1390,15 @@ reg_overlap_mentioned_p (rtx x, rtx in) regno = REGNO (SUBREG_REG (x)); if (regno < FIRST_PSEUDO_REGISTER) regno = subreg_regno (x); + endregno = regno + (regno < FIRST_PSEUDO_REGISTER + ? subreg_nregs (x) : 1); goto do_reg; case REG: regno = REGNO (x); - do_reg: endregno = regno + (regno < FIRST_PSEUDO_REGISTER ? hard_regno_nregs[regno][GET_MODE (x)] : 1); + do_reg: return refers_to_regno_p (regno, endregno, in, (rtx*) 0); case MEM: @@ -3177,69 +3194,27 @@ subreg_lsb (rtx x) SUBREG_BYTE (x)); } -/* This function returns the regno offset of a subreg expression. - xregno - A regno of an inner hard subreg_reg (or what will become one). - xmode - The mode of xregno. - offset - The byte offset. - ymode - The mode of a top level SUBREG (or what may become one). - RETURN - The regno offset which would be used. */ -unsigned int -subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, - unsigned int offset, enum machine_mode ymode) -{ - int nregs_xmode, nregs_ymode; - int mode_multiple, nregs_multiple; - int y_offset; - - gcc_assert (xregno < FIRST_PSEUDO_REGISTER); - - /* Adjust nregs_xmode to allow for 'holes'. */ - if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) - nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode); - else - nregs_xmode = hard_regno_nregs[xregno][xmode]; - - nregs_ymode = hard_regno_nregs[xregno][ymode]; - - /* If this is a big endian paradoxical subreg, which uses more actual - hard registers than the original register, we must return a negative - offset so that we find the proper highpart of the register. */ - if (offset == 0 - && nregs_ymode > nregs_xmode - && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD - ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)) - return nregs_xmode - nregs_ymode; - - if (offset == 0 || nregs_xmode == nregs_ymode) - return 0; - - /* Size of ymode must not be greater than the size of xmode. */ - mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode); - gcc_assert (mode_multiple != 0); - - y_offset = offset / GET_MODE_SIZE (ymode); - nregs_multiple = nregs_xmode / nregs_ymode; - return (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode; -} - -/* This function returns true when the offset is representable via - subreg_offset in the given regno. +/* Fill in information about a subreg of a hard register. xregno - A regno of an inner hard subreg_reg (or what will become one). xmode - The mode of xregno. offset - The byte offset. ymode - The mode of a top level SUBREG (or what may become one). - RETURN - Whether the offset is representable. */ -bool -subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, - unsigned int offset, enum machine_mode ymode) + info - Pointer to structure to fill in. */ +static void +subreg_get_info (unsigned int xregno, enum machine_mode xmode, + unsigned int offset, enum machine_mode ymode, + struct subreg_info *info) { int nregs_xmode, nregs_ymode; int mode_multiple, nregs_multiple; - int y_offset; + int offset_adj, y_offset, y_offset_adj; int regsize_xmode, regsize_ymode; + bool rknown; gcc_assert (xregno < FIRST_PSEUDO_REGISTER); + rknown = false; + /* If there are holes in a non-scalar mode in registers, we expect that it is made up of its units concatenated together. */ if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) @@ -3272,7 +3247,10 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, && (offset / GET_MODE_SIZE (xmode_unit) != ((offset + GET_MODE_SIZE (ymode) - 1) / GET_MODE_SIZE (xmode_unit)))) - return false; + { + info->representable_p = false; + rknown = true; + } } else nregs_xmode = hard_regno_nregs[xregno][xmode]; @@ -3280,24 +3258,57 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, nregs_ymode = hard_regno_nregs[xregno][ymode]; /* Paradoxical subregs are otherwise valid. */ - if (offset == 0 - && nregs_ymode > nregs_xmode - && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD - ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)) - return true; + if (!rknown + && offset == 0 + && GET_MODE_SIZE (ymode) > GET_MODE_SIZE (xmode)) + { + info->representable_p = true; + /* If this is a big endian paradoxical subreg, which uses more + actual hard registers than the original register, we must + return a negative offset so that we find the proper highpart + of the register. */ + if (GET_MODE_SIZE (ymode) > UNITS_PER_WORD + ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN) + info->offset = nregs_xmode - nregs_ymode; + else + info->offset = 0; + info->nregs = nregs_ymode; + return; + } /* If registers store different numbers of bits in the different modes, we cannot generally form this subreg. */ - regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode; - regsize_ymode = GET_MODE_SIZE (ymode) / nregs_ymode; - if (regsize_xmode > regsize_ymode && nregs_ymode > 1) - return false; - if (regsize_ymode > regsize_xmode && nregs_xmode > 1) - return false; + if (!HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode) + && !HARD_REGNO_NREGS_HAS_PADDING (xregno, ymode)) + { + regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode; + gcc_assert (regsize_xmode * nregs_xmode == GET_MODE_SIZE (xmode)); + regsize_ymode = GET_MODE_SIZE (ymode) / nregs_ymode; + gcc_assert (regsize_ymode * nregs_ymode == GET_MODE_SIZE (ymode)); + if (!rknown && regsize_xmode > regsize_ymode && nregs_ymode > 1) + { + info->representable_p = false; + info->nregs + = (GET_MODE_SIZE (ymode) + regsize_xmode - 1) / regsize_xmode; + info->offset = offset / regsize_xmode; + return; + } + if (!rknown && regsize_ymode > regsize_xmode && nregs_xmode > 1) + { + info->representable_p = false; + info->nregs + = (GET_MODE_SIZE (ymode) + regsize_xmode - 1) / regsize_xmode; + info->offset = offset / regsize_xmode; + return; + } + } /* Lowpart subregs are otherwise valid. */ - if (offset == subreg_lowpart_offset (ymode, xmode)) - return true; + if (!rknown && offset == subreg_lowpart_offset (ymode, xmode)) + { + info->representable_p = true; + rknown = true; + } /* This should always pass, otherwise we don't know how to verify the constraint. These conditions may be relaxed but @@ -3308,22 +3319,61 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, /* The XMODE value can be seen as a vector of NREGS_XMODE values. The subreg must represent a lowpart of given field. Compute what field it is. */ - offset -= subreg_lowpart_offset (ymode, - mode_for_size (GET_MODE_BITSIZE (xmode) - / nregs_xmode, - MODE_INT, 0)); + offset_adj = offset; + offset_adj -= subreg_lowpart_offset (ymode, + mode_for_size (GET_MODE_BITSIZE (xmode) + / nregs_xmode, + MODE_INT, 0)); /* Size of ymode must not be greater than the size of xmode. */ mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode); gcc_assert (mode_multiple != 0); y_offset = offset / GET_MODE_SIZE (ymode); - nregs_multiple = nregs_xmode / nregs_ymode; + y_offset_adj = offset_adj / GET_MODE_SIZE (ymode); + nregs_multiple = nregs_xmode / nregs_ymode; - gcc_assert ((offset % GET_MODE_SIZE (ymode)) == 0); + gcc_assert ((offset_adj % GET_MODE_SIZE (ymode)) == 0); gcc_assert ((mode_multiple % nregs_multiple) == 0); - return (!(y_offset % (mode_multiple / nregs_multiple))); + if (!rknown) + { + info->representable_p = (!(y_offset_adj % (mode_multiple / nregs_multiple))); + rknown = true; + } + info->offset = (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode; + info->nregs = nregs_ymode; +} + +/* This function returns the regno offset of a subreg expression. + xregno - A regno of an inner hard subreg_reg (or what will become one). + xmode - The mode of xregno. + offset - The byte offset. + ymode - The mode of a top level SUBREG (or what may become one). + RETURN - The regno offset which would be used. */ +unsigned int +subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, + unsigned int offset, enum machine_mode ymode) +{ + struct subreg_info info; + subreg_get_info (xregno, xmode, offset, ymode, &info); + return info.offset; +} + +/* This function returns true when the offset is representable via + subreg_offset in the given regno. + xregno - A regno of an inner hard subreg_reg (or what will become one). + xmode - The mode of xregno. + offset - The byte offset. + ymode - The mode of a top level SUBREG (or what may become one). + RETURN - Whether the offset is representable. */ +bool +subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, + unsigned int offset, enum machine_mode ymode) +{ + struct subreg_info info; + subreg_get_info (xregno, xmode, offset, ymode, &info); + return info.representable_p; } /* Return the final regno that a subreg expression refers to. */ @@ -3341,6 +3391,21 @@ subreg_regno (rtx x) return ret; } + +/* Return the number of registers that a subreg expression refers + to. */ +unsigned int +subreg_nregs (rtx x) +{ + struct subreg_info info; + rtx subreg = SUBREG_REG (x); + int regno = REGNO (subreg); + + subreg_get_info (regno, GET_MODE (subreg), SUBREG_BYTE (x), GET_MODE (x), + &info); + return info.nregs; +} + struct parms_set_data { int nregs; |