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.c279
1 files changed, 262 insertions, 17 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 7b6aca9..3e02d5c 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -2575,6 +2575,10 @@ rs6000_debug_reg_global (void)
if (TARGET_VSX)
fprintf (stderr, DEBUG_FMT_D, "VSX easy 64-bit scalar element",
(int)VECTOR_ELEMENT_SCALAR_64BIT);
+
+ if (TARGET_DIRECT_MOVE_128)
+ fprintf (stderr, DEBUG_FMT_D, "VSX easy 64-bit mfvsrld element",
+ (int)VECTOR_ELEMENT_MFVSRLD_64BIT);
}
@@ -2986,6 +2990,10 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
rs6000_constraints[RS6000_CONSTRAINT_wp] = VSX_REGS; /* TFmode */
}
+ /* Support for new direct moves. */
+ if (TARGET_DIRECT_MOVE_128)
+ rs6000_constraints[RS6000_CONSTRAINT_we] = VSX_REGS;
+
/* Set up the reload helper and direct move functions. */
if (TARGET_VSX || TARGET_ALTIVEC)
{
@@ -3034,7 +3042,7 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
reg_addr[TImode].reload_load = CODE_FOR_reload_ti_di_load;
}
- if (TARGET_DIRECT_MOVE)
+ if (TARGET_DIRECT_MOVE && !TARGET_DIRECT_MOVE_128)
{
reg_addr[TImode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxti;
reg_addr[V1TImode].reload_gpr_vsx = CODE_FOR_reload_gpr_from_vsxv1ti;
@@ -18081,6 +18089,11 @@ rs6000_secondary_reload_simple_move (enum rs6000_reg_type to_type,
|| (to_type == VSX_REG_TYPE && from_type == GPR_REG_TYPE)))
return true;
+ else if (TARGET_DIRECT_MOVE_128 && size == 16
+ && ((to_type == VSX_REG_TYPE && from_type == GPR_REG_TYPE)
+ || (to_type == GPR_REG_TYPE && from_type == VSX_REG_TYPE)))
+ return true;
+
else if (TARGET_MFPGPR && TARGET_POWERPC64 && size == 8
&& ((to_type == GPR_REG_TYPE && from_type == FPR_REG_TYPE)
|| (to_type == FPR_REG_TYPE && from_type == GPR_REG_TYPE)))
@@ -18094,7 +18107,7 @@ rs6000_secondary_reload_simple_move (enum rs6000_reg_type to_type,
return false;
}
-/* Power8 helper function for rs6000_secondary_reload, handle all of the
+/* Direct move helper function for rs6000_secondary_reload, handle all of the
special direct moves that involve allocating an extra register, return the
insn code of the helper function if there is such a function or
CODE_FOR_nothing if not. */
@@ -18116,8 +18129,8 @@ rs6000_secondary_reload_direct_move (enum rs6000_reg_type to_type,
if (size == 16)
{
/* Handle moving 128-bit values from GPRs to VSX point registers on
- power8 when running in 64-bit mode using XXPERMDI to glue the two
- 64-bit values back together. */
+ ISA 2.07 (power8, power9) when running in 64-bit mode using
+ XXPERMDI to glue the two 64-bit values back together. */
if (to_type == VSX_REG_TYPE && from_type == GPR_REG_TYPE)
{
cost = 3; /* 2 mtvsrd's, 1 xxpermdi. */
@@ -18125,7 +18138,7 @@ rs6000_secondary_reload_direct_move (enum rs6000_reg_type to_type,
}
/* Handle moving 128-bit values from VSX point registers to GPRs on
- power8 when running in 64-bit mode using XXPERMDI to get access to the
+ ISA 2.07 when running in 64-bit mode using XXPERMDI to get access to the
bottom 64-bit value. */
else if (to_type == GPR_REG_TYPE && from_type == VSX_REG_TYPE)
{
@@ -18150,11 +18163,32 @@ rs6000_secondary_reload_direct_move (enum rs6000_reg_type to_type,
}
}
- else if (size == 8)
+ if (TARGET_POWERPC64 && size == 16)
+ {
+ /* Handle moving 128-bit values from GPRs to VSX point registers on
+ ISA 2.07 when running in 64-bit mode using XXPERMDI to glue the two
+ 64-bit values back together. */
+ if (to_type == VSX_REG_TYPE && from_type == GPR_REG_TYPE)
+ {
+ cost = 3; /* 2 mtvsrd's, 1 xxpermdi. */
+ icode = reg_addr[mode].reload_vsx_gpr;
+ }
+
+ /* Handle moving 128-bit values from VSX point registers to GPRs on
+ ISA 2.07 when running in 64-bit mode using XXPERMDI to get access to the
+ bottom 64-bit value. */
+ else if (to_type == GPR_REG_TYPE && from_type == VSX_REG_TYPE)
+ {
+ cost = 3; /* 2 mfvsrd's, 1 xxpermdi. */
+ icode = reg_addr[mode].reload_gpr_vsx;
+ }
+ }
+
+ else if (!TARGET_POWERPC64 && size == 8)
{
/* Handle moving 64-bit values from GPRs to floating point registers on
- power8 when running in 32-bit mode using FMRGOW to glue the two 32-bit
- values back together. Altivec register classes must be handled
+ ISA 2.07 when running in 32-bit mode using FMRGOW to glue the two
+ 32-bit values back together. Altivec register classes must be handled
specially since a different instruction is used, and the secondary
reload support requires a single instruction class in the scratch
register constraint. However, right now TFmode is not allowed in
@@ -18181,7 +18215,7 @@ rs6000_secondary_reload_direct_move (enum rs6000_reg_type to_type,
/* Return whether a move between two register classes can be done either
directly (simple move) or via a pattern that uses a single extra temporary
- (using power8's direct move in this case. */
+ (using ISA 2.07's direct move in this case. */
static bool
rs6000_secondary_reload_move (enum rs6000_reg_type to_type,
@@ -19220,6 +19254,11 @@ rs6000_output_move_128bit (rtx operands[])
if (src_gpr_p)
return "#";
+ if (TARGET_DIRECT_MOVE_128 && src_vsx_p)
+ return (WORDS_BIG_ENDIAN
+ ? "mfvsrd %0,%x1\n\tmfvsrld %L0,%x1"
+ : "mfvsrd %L0,%x1\n\tmfvsrld %0,%x1");
+
else if (TARGET_VSX && TARGET_DIRECT_MOVE && src_vsx_p)
return "#";
}
@@ -19229,6 +19268,11 @@ rs6000_output_move_128bit (rtx operands[])
if (src_vsx_p)
return "xxlor %x0,%x1,%x1";
+ else if (TARGET_DIRECT_MOVE_128 && src_gpr_p)
+ return (WORDS_BIG_ENDIAN
+ ? "mtvsrdd %x0,%1,%L1"
+ : "mtvsrdd %x0,%L1,%1");
+
else if (TARGET_DIRECT_MOVE && src_gpr_p)
return "#";
}
@@ -20490,11 +20534,12 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
emit_insn (cmp);
}
- /* IEEE 128-bit support in VSX registers. The comparison functions
- (__cmpokf2 and __cmpukf2) returns 0..15 that is laid out the same way as
- the PowerPC CR register would for a normal floating point comparison from
- the fcmpo and fcmpu instructions. */
- else if (FLOAT128_IEEE_P (mode))
+ /* IEEE 128-bit support in VSX registers. If we do not have IEEE 128-bit
+ hardware, the comparison functions (__cmpokf2 and __cmpukf2) returns 0..15
+ that is laid out the same way as the PowerPC CR register would for a
+ normal floating point comparison from the fcmpo and fcmpu
+ instructions. */
+ else if (!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (mode))
{
rtx and_reg = gen_reg_rtx (SImode);
rtx dest = gen_reg_rtx (SImode);
@@ -20633,7 +20678,7 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
/* Some kinds of FP comparisons need an OR operation;
under flag_finite_math_only we don't bother. */
if (FLOAT_MODE_P (mode)
- && !FLOAT128_IEEE_P (mode)
+ && (!FLOAT128_IEEE_P (mode) || TARGET_FLOAT128_HW)
&& !flag_finite_math_only
&& !(TARGET_HARD_FLOAT && !TARGET_FPRS)
&& (code == LE || code == GE
@@ -20726,6 +20771,56 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
bool do_move = false;
rtx libfunc = NULL_RTX;
rtx dest2;
+ typedef rtx (*rtx_2func_t) (rtx, rtx);
+ rtx_2func_t hw_convert = (rtx_2func_t)0;
+ size_t kf_or_tf;
+
+ struct hw_conv_t {
+ rtx_2func_t from_df;
+ rtx_2func_t from_sf;
+ rtx_2func_t from_si_sign;
+ rtx_2func_t from_si_uns;
+ rtx_2func_t from_di_sign;
+ rtx_2func_t from_di_uns;
+ rtx_2func_t to_df;
+ rtx_2func_t to_sf;
+ rtx_2func_t to_si_sign;
+ rtx_2func_t to_si_uns;
+ rtx_2func_t to_di_sign;
+ rtx_2func_t to_di_uns;
+ } hw_conversions[2] = {
+ /* convertions to/from KFmode */
+ {
+ gen_extenddfkf2_hw, /* KFmode <- DFmode. */
+ gen_extendsfkf2_hw, /* KFmode <- SFmode. */
+ gen_float_kfsi2_hw, /* KFmode <- SImode (signed). */
+ gen_floatuns_kfsi2_hw, /* KFmode <- SImode (unsigned). */
+ gen_float_kfdi2_hw, /* KFmode <- DImode (signed). */
+ gen_floatuns_kfdi2_hw, /* KFmode <- DImode (unsigned). */
+ gen_trunckfdf2_hw, /* DFmode <- KFmode. */
+ gen_trunckfsf2_hw, /* SFmode <- KFmode. */
+ gen_fix_kfsi2_hw, /* SImode <- KFmode (signed). */
+ gen_fixuns_kfsi2_hw, /* SImode <- KFmode (unsigned). */
+ gen_fix_kfdi2_hw, /* DImode <- KFmode (signed). */
+ gen_fixuns_kfdi2_hw, /* DImode <- KFmode (unsigned). */
+ },
+
+ /* convertions to/from TFmode */
+ {
+ gen_extenddftf2_hw, /* TFmode <- DFmode. */
+ gen_extendsftf2_hw, /* TFmode <- SFmode. */
+ gen_float_tfsi2_hw, /* TFmode <- SImode (signed). */
+ gen_floatuns_tfsi2_hw, /* TFmode <- SImode (unsigned). */
+ gen_float_tfdi2_hw, /* TFmode <- DImode (signed). */
+ gen_floatuns_tfdi2_hw, /* TFmode <- DImode (unsigned). */
+ gen_trunctfdf2_hw, /* DFmode <- TFmode. */
+ gen_trunctfsf2_hw, /* SFmode <- TFmode. */
+ gen_fix_tfsi2_hw, /* SImode <- TFmode (signed). */
+ gen_fixuns_tfsi2_hw, /* SImode <- TFmode (unsigned). */
+ gen_fix_tfdi2_hw, /* DImode <- TFmode (signed). */
+ gen_fixuns_tfdi2_hw, /* DImode <- TFmode (unsigned). */
+ },
+ };
if (dest_mode == src_mode)
gcc_unreachable ();
@@ -20745,14 +20840,23 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
/* Convert to IEEE 128-bit floating point. */
if (FLOAT128_IEEE_P (dest_mode))
{
+ if (dest_mode == KFmode)
+ kf_or_tf = 0;
+ else if (dest_mode == TFmode)
+ kf_or_tf = 1;
+ else
+ gcc_unreachable ();
+
switch (src_mode)
{
case DFmode:
cvt = sext_optab;
+ hw_convert = hw_conversions[kf_or_tf].from_df;
break;
case SFmode:
cvt = sext_optab;
+ hw_convert = hw_conversions[kf_or_tf].from_sf;
break;
case KFmode:
@@ -20765,8 +20869,29 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
break;
case SImode:
+ if (unsigned_p)
+ {
+ cvt = ufloat_optab;
+ hw_convert = hw_conversions[kf_or_tf].from_si_uns;
+ }
+ else
+ {
+ cvt = sfloat_optab;
+ hw_convert = hw_conversions[kf_or_tf].from_si_sign;
+ }
+ break;
+
case DImode:
- cvt = (unsigned_p) ? ufloat_optab : sfloat_optab;
+ if (unsigned_p)
+ {
+ cvt = ufloat_optab;
+ hw_convert = hw_conversions[kf_or_tf].from_di_uns;
+ }
+ else
+ {
+ cvt = sfloat_optab;
+ hw_convert = hw_conversions[kf_or_tf].from_di_sign;
+ }
break;
default:
@@ -20777,14 +20902,23 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
/* Convert from IEEE 128-bit floating point. */
else if (FLOAT128_IEEE_P (src_mode))
{
+ if (src_mode == KFmode)
+ kf_or_tf = 0;
+ else if (src_mode == TFmode)
+ kf_or_tf = 1;
+ else
+ gcc_unreachable ();
+
switch (dest_mode)
{
case DFmode:
cvt = trunc_optab;
+ hw_convert = hw_conversions[kf_or_tf].to_df;
break;
case SFmode:
cvt = trunc_optab;
+ hw_convert = hw_conversions[kf_or_tf].to_sf;
break;
case KFmode:
@@ -20797,8 +20931,29 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
break;
case SImode:
+ if (unsigned_p)
+ {
+ cvt = ufix_optab;
+ hw_convert = hw_conversions[kf_or_tf].to_si_uns;
+ }
+ else
+ {
+ cvt = sfix_optab;
+ hw_convert = hw_conversions[kf_or_tf].to_si_sign;
+ }
+ break;
+
case DImode:
- cvt = (unsigned_p) ? ufix_optab : sfix_optab;
+ if (unsigned_p)
+ {
+ cvt = ufix_optab;
+ hw_convert = hw_conversions[kf_or_tf].to_di_uns;
+ }
+ else
+ {
+ cvt = sfix_optab;
+ hw_convert = hw_conversions[kf_or_tf].to_di_sign;
+ }
break;
default:
@@ -20817,6 +20972,10 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
if (do_move)
emit_move_insn (dest, gen_lowpart (dest_mode, src));
+ /* Handle conversion if we have hardware support. */
+ else if (TARGET_FLOAT128_HW && hw_convert)
+ emit_insn ((hw_convert) (dest, src));
+
/* Call an external function to do the conversion. */
else if (cvt != unknown_optab)
{
@@ -20837,6 +20996,92 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
return;
}
+/* Split a conversion from __float128 to an integer type into separate insns.
+ OPERANDS points to the destination, source, and V2DI temporary
+ register. CODE is either FIX or UNSIGNED_FIX. */
+
+void
+convert_float128_to_int (rtx *operands, enum rtx_code code)
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+ rtx tmp = operands[2];
+ rtx cvt;
+ rtvec cvt_vec;
+ rtx cvt_unspec;
+ rtvec move_vec;
+ rtx move_unspec;
+
+ if (GET_CODE (tmp) == SCRATCH)
+ tmp = gen_reg_rtx (V2DImode);
+
+ if (MEM_P (dest))
+ dest = rs6000_address_for_fpconvert (dest);
+
+ /* Generate the actual convert insn of the form:
+ (set (tmp) (unspec:V2DI [(fix:SI (reg:KF))] UNSPEC_IEEE128_CONVERT)). */
+ cvt = gen_rtx_fmt_e (code, GET_MODE (dest), src);
+ cvt_vec = gen_rtvec (1, cvt);
+ cvt_unspec = gen_rtx_UNSPEC (V2DImode, cvt_vec, UNSPEC_IEEE128_CONVERT);
+ emit_insn (gen_rtx_SET (tmp, cvt_unspec));
+
+ /* Generate the move insn of the form:
+ (set (dest:SI) (unspec:SI [(tmp:V2DI))] UNSPEC_IEEE128_MOVE)). */
+ move_vec = gen_rtvec (1, tmp);
+ move_unspec = gen_rtx_UNSPEC (GET_MODE (dest), move_vec, UNSPEC_IEEE128_MOVE);
+ emit_insn (gen_rtx_SET (dest, move_unspec));
+}
+
+/* Split a conversion from an integer type to __float128 into separate insns.
+ OPERANDS points to the destination, source, and V2DI temporary
+ register. CODE is either FLOAT or UNSIGNED_FLOAT. */
+
+void
+convert_int_to_float128 (rtx *operands, enum rtx_code code)
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+ rtx tmp = operands[2];
+ rtx cvt;
+ rtvec cvt_vec;
+ rtx cvt_unspec;
+ rtvec move_vec;
+ rtx move_unspec;
+ rtx unsigned_flag;
+
+ if (GET_CODE (tmp) == SCRATCH)
+ tmp = gen_reg_rtx (V2DImode);
+
+ if (MEM_P (src))
+ src = rs6000_address_for_fpconvert (src);
+
+ /* Generate the move of the integer into the Altivec register of the form:
+ (set (tmp:V2DI) (unspec:V2DI [(src:SI)
+ (const_int 0)] UNSPEC_IEEE128_MOVE)).
+
+ or:
+ (set (tmp:V2DI) (unspec:V2DI [(src:DI)] UNSPEC_IEEE128_MOVE)). */
+
+ if (GET_MODE (src) == SImode)
+ {
+ unsigned_flag = (code == UNSIGNED_FLOAT) ? const1_rtx : const0_rtx;
+ move_vec = gen_rtvec (2, src, unsigned_flag);
+ }
+ else
+ move_vec = gen_rtvec (1, src);
+
+ move_unspec = gen_rtx_UNSPEC (V2DImode, move_vec, UNSPEC_IEEE128_MOVE);
+ emit_insn (gen_rtx_SET (tmp, move_unspec));
+
+ /* Generate the actual convert insn of the form:
+ (set (dest:KF) (float:KF (unspec:DI [(tmp:V2DI)]
+ UNSPEC_IEEE128_CONVERT))). */
+ cvt_vec = gen_rtvec (1, tmp);
+ cvt_unspec = gen_rtx_UNSPEC (DImode, cvt_vec, UNSPEC_IEEE128_CONVERT);
+ cvt = gen_rtx_fmt_e (code, GET_MODE (dest), cvt_unspec);
+ emit_insn (gen_rtx_SET (dest, cvt));
+}
+
/* Emit the RTL for an sISEL pattern. */