aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/rs6000/rs6000.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r--gcc/config/rs6000/rs6000.c119
1 files changed, 88 insertions, 31 deletions
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;