diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 279 |
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. */ |