aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2006-12-06 17:30:34 +0000
committerJoseph Myers <joseph@codesourcery.com>2006-12-06 17:30:34 +0000
commit96f43d5a0f2f7f4cfba76d8f80bf784d6e966c23 (patch)
treeb1c0579bd87ef53e070c2d288fceeb6602eb0c7b
parentf279fd6f682ef1bdc82b2f2a7bf5e9b45fb0cdec (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.csl106
-rw-r--r--gcc/caller-save.c22
-rw-r--r--gcc/config/rs6000/darwin-ldouble.c15
-rw-r--r--gcc/config/rs6000/eabispe.h6
-rw-r--r--gcc/config/rs6000/libgcc-ppc-glibc.ver2
-rw-r--r--gcc/config/rs6000/linuxspe.h14
-rw-r--r--gcc/config/rs6000/rs6000-c.c2
-rw-r--r--gcc/config/rs6000/rs6000.c119
-rw-r--r--gcc/config/rs6000/rs6000.h1
-rw-r--r--gcc/config/rs6000/rs6000.md105
-rw-r--r--gcc/config/rs6000/spe.md349
-rw-r--r--gcc/doc/tm.texi2
-rw-r--r--gcc/flow.c3
-rw-r--r--gcc/postreload.c8
-rw-r--r--gcc/reload.c8
-rw-r--r--gcc/resource.c20
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/rtlanal.c215
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;