From: Michael Meissner Date: Wed, 26 Aug 2015 21:22:23 +0000 (+0000) Subject: rs6000-protos.h (rs6000_expand_float128_convert): Add declaration. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=526303ecaaf13762aaad638ec8fa75fed778e332;p=gcc.git rs6000-protos.h (rs6000_expand_float128_convert): Add declaration. 2015-08-26 Michael Meissner * config/rs6000/rs6000-protos.h (rs6000_expand_float128_convert): Add declaration. * config/rs6000/rs6000.c (rs6000_emit_le_vsx_store): Fix a comment. (rs6000_cannot_change_mode_class): Add support for IEEE 128-bit floating point in VSX registers. (rs6000_output_move_128bit): Always print out the set insn if we can't generate an appropriate 128-bit move. (rs6000_generate_compare): Add support for IEEE 128-bit floating point in VSX registers comparisons. (rs6000_expand_float128_convert): Likewise. * config/rs6000/predicates.md (int_reg_operand_not_pseudo): New predicate for only GPR hard registers. * config/rs6000/rs6000.md (FP): Add IEEE 128-bit floating point modes to iterators. Add new iterators for moving 128-bit values in scalar FPR registers and VSX registers. (FMOVE128): Likewise. (FMOVE128_FPR): Likewise. (FMOVE128_GPR): Likewise. (FMOVE128_VSX): Likewise. (FLOAT128_SFDFTF): New iterators for IEEE 128-bit floating point in VSX registers. (IFKF): Likewise. (IBM128): Likewise. (TFIFKF): Likewise. (RELOAD): Add IEEE 128-bit floating point modes. (signbittf2): Convert TF insns to add support for new IEEE 128-bit floating point in VSX registers modes. (signbit2, IBM128 iterator): Likewise. (mov_64bit_dm, FMOVE128_FPR iterator): Likewise. (mov_32bit, FMOVE128_FPR iterator): Likewise. (negtf2): Likewise. (neg2, TFIFKF iterator): Likewise. (negtf2_internal): Likewise. (abstf2): Likewise. (abs2, TFIFKF iterator): Likewise. (ieee_128bit_negative_zero): New IEEE 128-bit floating point in VSX insn support for negate, absolute value, and negative absolute value. (ieee_128bit_vsx_neg2): Likewise. (ieee_128bit_vsx_neg2_internal): Likewise. (ieee_128bit_vsx_abs2): Likewise. (ieee_128bit_vsx_abs2_internal): Likewise. (ieee_128bit_vsx_nabs2): Likewise. (ieee_128bit_vsx_nabs2_internal): Likewise. (FP128_64): Update pack/unpack 128-bit insns for IEEE 128-bit floating point in VSX registers. (unpack_dm): Likewise. (unpack_nodm): Likewise. (pack): Likewise. (unpackv1ti): Likewise. (unpack, FMOVE128_VSX iterator): Likewise. (packv1ti): Likewise. (pack, FMOVE128_VSX iterator): Likewise. (extenddftf2): Add support for IEEE 128-bit floating point in VSX registers. (extenddftf2_internal): Likewise. (trunctfdf2): Likewise. (trunctfdf2_internal2): Likewise. (fix_trunc_helper): Likewise. (fix_trunctfdi2"): Likewise. (floatditf2): Likewise. (floatunstf2): Likewise. (extend2): Likewise. (trunc2): Likewise. (fix_trunc2): Likewise. (fixuns_trunc2): Likewise. (float2): Likewise. (floatuns2): Likewise. From-SVN: r227230 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c56f8ba11f5..f38da546d0a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,79 @@ +2015-08-26 Michael Meissner + + * config/rs6000/rs6000-protos.h (rs6000_expand_float128_convert): + Add declaration. + + * config/rs6000/rs6000.c (rs6000_emit_le_vsx_store): Fix a + comment. + (rs6000_cannot_change_mode_class): Add support for IEEE 128-bit + floating point in VSX registers. + (rs6000_output_move_128bit): Always print out the set insn if we + can't generate an appropriate 128-bit move. + (rs6000_generate_compare): Add support for IEEE 128-bit floating + point in VSX registers comparisons. + (rs6000_expand_float128_convert): Likewise. + + * config/rs6000/predicates.md (int_reg_operand_not_pseudo): New + predicate for only GPR hard registers. + + * config/rs6000/rs6000.md (FP): Add IEEE 128-bit floating point + modes to iterators. Add new iterators for moving 128-bit values in + scalar FPR registers and VSX registers. + (FMOVE128): Likewise. + (FMOVE128_FPR): Likewise. + (FMOVE128_GPR): Likewise. + (FMOVE128_VSX): Likewise. + (FLOAT128_SFDFTF): New iterators for IEEE 128-bit floating point + in VSX registers. + (IFKF): Likewise. + (IBM128): Likewise. + (TFIFKF): Likewise. + (RELOAD): Add IEEE 128-bit floating point modes. + (signbittf2): Convert TF insns to add support for new IEEE 128-bit + floating point in VSX registers modes. + (signbit2, IBM128 iterator): Likewise. + (mov_64bit_dm, FMOVE128_FPR iterator): Likewise. + (mov_32bit, FMOVE128_FPR iterator): Likewise. + (negtf2): Likewise. + (neg2, TFIFKF iterator): Likewise. + (negtf2_internal): Likewise. + (abstf2): Likewise. + (abs2, TFIFKF iterator): Likewise. + (ieee_128bit_negative_zero): New IEEE 128-bit floating point in + VSX insn support for negate, absolute value, and negative absolute + value. + (ieee_128bit_vsx_neg2): Likewise. + (ieee_128bit_vsx_neg2_internal): Likewise. + (ieee_128bit_vsx_abs2): Likewise. + (ieee_128bit_vsx_abs2_internal): Likewise. + (ieee_128bit_vsx_nabs2): Likewise. + (ieee_128bit_vsx_nabs2_internal): Likewise. + (FP128_64): Update pack/unpack 128-bit insns for IEEE 128-bit + floating point in VSX registers. + (unpack_dm): Likewise. + (unpack_nodm): Likewise. + (pack): Likewise. + (unpackv1ti): Likewise. + (unpack, FMOVE128_VSX iterator): Likewise. + (packv1ti): Likewise. + (pack, FMOVE128_VSX iterator): Likewise. + (extenddftf2): Add support for IEEE 128-bit floating point in VSX + registers. + (extenddftf2_internal): Likewise. + (trunctfdf2): Likewise. + (trunctfdf2_internal2): Likewise. + (fix_trunc_helper): Likewise. + (fix_trunctfdi2"): Likewise. + (floatditf2): Likewise. + (floatunstf2): Likewise. + (extend2): Likewise. + (trunc2): Likewise. + (fix_trunc2): Likewise. + (fixuns_trunc2): Likewise. + (float2): Likewise. + (floatuns2): Likewise. + + 2015-08-26 Renlin Li * config/aarch64/aarch64.md (*aarch64_bfi4): New. diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index ae74796849d..b111df62df8 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -239,6 +239,25 @@ return INT_REGNO_P (REGNO (op)); }) +;; Like int_reg_operand, but don't return true for pseudo registers +(define_predicate "int_reg_operand_not_pseudo" + (match_operand 0 "register_operand") +{ + if ((TARGET_E500_DOUBLE || TARGET_SPE) && invalid_e500_subreg (op, mode)) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (!REG_P (op)) + return 0; + + if (REGNO (op) >= FIRST_PSEUDO_REGISTER) + return 0; + + return INT_REGNO_P (REGNO (op)); +}) + ;; Like int_reg_operand, but only return true for base registers (define_predicate "base_reg_operand" (match_operand 0 "int_reg_operand") diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 7262a151438..7be529fab49 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -54,6 +54,7 @@ extern const char *output_vec_const_move (rtx *); extern const char *rs6000_output_move_128bit (rtx *); extern bool rs6000_move_128bit_ok_p (rtx []); extern bool rs6000_split_128bit_ok_p (rtx []); +extern void rs6000_expand_float128_convert (rtx, rtx, bool); extern void rs6000_expand_vector_init (rtx, rtx); extern void paired_expand_vector_init (rtx, rtx); extern void rs6000_expand_vector_set (rtx, rtx, int); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index b4469564ca9..93fdece9a32 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -8485,7 +8485,7 @@ rs6000_emit_le_vsx_store (rtx dest, rtx source, machine_mode mode) during expand. */ gcc_assert (!reload_in_progress && !lra_in_progress && !reload_completed); - /* Use V2DImode to do swaps of types with 128-bit scalare parts (TImode, + /* Use V2DImode to do swaps of types with 128-bit scalar parts (TImode, V1TImode). */ if (mode == TImode || mode == V1TImode) { @@ -18542,6 +18542,8 @@ rs6000_cannot_change_mode_class (machine_mode from, { unsigned to_nregs = hard_regno_nregs[FIRST_FPR_REGNO][to]; unsigned from_nregs = hard_regno_nregs[FIRST_FPR_REGNO][from]; + bool to_float128_vector_p = FLOAT128_VECTOR_P (to); + bool from_float128_vector_p = FLOAT128_VECTOR_P (from); /* Don't allow 64-bit types to overlap with 128-bit types that take a single register under VSX because the scalar part of the register @@ -18550,7 +18552,10 @@ rs6000_cannot_change_mode_class (machine_mode from, IEEE floating point can't overlap, and neither can small values. */ - if (TARGET_IEEEQUAD && (to == TFmode || from == TFmode)) + if (to_float128_vector_p && from_float128_vector_p) + return false; + + else if (to_float128_vector_p || from_float128_vector_p) return true; /* TDmode in floating-mode registers must always go into a register @@ -18578,6 +18583,8 @@ rs6000_cannot_change_mode_class (machine_mode from, if (TARGET_E500_DOUBLE && ((((to) == DFmode) + ((from) == DFmode)) == 1 || (((to) == TFmode) + ((from) == TFmode)) == 1 + || (((to) == IFmode) + ((from) == IFmode)) == 1 + || (((to) == KFmode) + ((from) == KFmode)) == 1 || (((to) == DDmode) + ((from) == DDmode)) == 1 || (((to) == TDmode) + ((from) == TDmode)) == 1 || (((to) == DImode) + ((from) == DImode)) == 1)) @@ -18774,13 +18781,7 @@ rs6000_output_move_128bit (rtx operands[]) return output_vec_const_move (operands); } - if (TARGET_DEBUG_ADDR) - { - fprintf (stderr, "\n===== Bad 128 bit move:\n"); - debug_rtx (gen_rtx_SET (dest, src)); - } - - gcc_unreachable (); + fatal_insn ("Bad 128-bit move", gen_rtx_SET (dest, src)); } /* Validate a 128-bit move. */ @@ -19824,6 +19825,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) break; case TFmode: + case IFmode: + case KFmode: cmp = (flag_finite_math_only && !flag_trapping_math) ? gen_tsttfeq_gpr (compare_result, op0, op1) : gen_cmptfeq_gpr (compare_result, op0, op1); @@ -19851,6 +19854,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) break; case TFmode: + case IFmode: + case KFmode: cmp = (flag_finite_math_only && !flag_trapping_math) ? gen_tsttfgt_gpr (compare_result, op0, op1) : gen_cmptfgt_gpr (compare_result, op0, op1); @@ -19878,6 +19883,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) break; case TFmode: + case IFmode: + case KFmode: cmp = (flag_finite_math_only && !flag_trapping_math) ? gen_tsttflt_gpr (compare_result, op0, op1) : gen_cmptflt_gpr (compare_result, op0, op1); @@ -19915,6 +19922,8 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) break; case TFmode: + case IFmode: + case KFmode: cmp = (flag_finite_math_only && !flag_trapping_math) ? gen_tsttfeq_gpr (compare_result2, op0, op1) : gen_cmptfeq_gpr (compare_result2, op0, op1); @@ -19937,14 +19946,117 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) emit_insn (cmp); } + + /* IEEE 128-bit support in VSX registers. The comparison function (__cmpkf2) + returns 0..15 that is laid out the same way as the PowerPC CR register + would for a normal floating point comparison. */ + else if (FLOAT128_IEEE_P (mode)) + { + rtx and_reg = gen_reg_rtx (SImode); + rtx dest = gen_reg_rtx (SImode); + rtx libfunc = optab_libfunc (cmp_optab, mode); + HOST_WIDE_INT mask_value = 0; + + /* Values that __cmpkf2 returns. */ +#define PPC_CMP_UNORDERED 0x1 /* isnan (a) || isnan (b). */ +#define PPC_CMP_EQUAL 0x2 /* a == b. */ +#define PPC_CMP_GREATER_THEN 0x4 /* a > b. */ +#define PPC_CMP_LESS_THEN 0x8 /* a < b. */ + + switch (code) + { + case EQ: + mask_value = PPC_CMP_EQUAL; + code = NE; + break; + + case NE: + mask_value = PPC_CMP_EQUAL; + code = EQ; + break; + + case GT: + mask_value = PPC_CMP_GREATER_THEN; + code = NE; + break; + + case GE: + mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL; + code = NE; + break; + + case LT: + mask_value = PPC_CMP_LESS_THEN; + code = NE; + break; + + case LE: + mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL; + code = NE; + break; + + case UNLE: + mask_value = PPC_CMP_GREATER_THEN; + code = EQ; + break; + + case UNLT: + mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL; + code = EQ; + break; + + case UNGE: + mask_value = PPC_CMP_LESS_THEN; + code = EQ; + break; + + case UNGT: + mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL; + code = EQ; + break; + + case UNEQ: + mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED; + code = NE; + + case LTGT: + mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED; + code = EQ; + break; + + case UNORDERED: + mask_value = PPC_CMP_UNORDERED; + code = NE; + break; + + case ORDERED: + mask_value = PPC_CMP_UNORDERED; + code = EQ; + break; + + default: + gcc_unreachable (); + } + + gcc_assert (mask_value != 0); + and_reg = emit_library_call_value (libfunc, and_reg, LCT_CONST, SImode, 2, + op0, mode, op1, mode); + + emit_insn (gen_andsi3 (dest, and_reg, GEN_INT (mask_value))); + compare_result = gen_reg_rtx (CCmode); + comp_mode = CCmode; + + emit_insn (gen_rtx_SET (compare_result, + gen_rtx_COMPARE (comp_mode, dest, const0_rtx))); + } + else { /* Generate XLC-compatible TFmode compare as PARALLEL with extra CLOBBERs to match cmptf_internal2 pattern. */ if (comp_mode == CCFPmode && TARGET_XL_COMPAT - && GET_MODE (op0) == TFmode - && !TARGET_IEEEQUAD - && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128) + && FLOAT128_IBM_P (GET_MODE (op0)) + && TARGET_HARD_FLOAT && TARGET_FPRS) emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (10, gen_rtx_SET (compare_result, @@ -19977,6 +20089,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) && !flag_finite_math_only && !(TARGET_HARD_FLOAT && !TARGET_FPRS) && (code == LE || code == GE @@ -20016,6 +20129,68 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) } +/* Expand floating point conversion to/from __float128 and __ibm128. */ + +void +rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p) +{ + machine_mode dest_mode = GET_MODE (dest); + machine_mode src_mode = GET_MODE (src); + convert_optab cvt = unknown_optab; + rtx libfunc = NULL_RTX; + rtx dest2; + + if (dest_mode == src_mode) + gcc_unreachable (); + + if (FLOAT128_IEEE_P (dest_mode)) + { + if (src_mode == SFmode + || src_mode == DFmode + || FLOAT128_IBM_P (src_mode)) + cvt = sext_optab; + + else if (GET_MODE_CLASS (src_mode) == MODE_INT) + cvt = (unsigned_p) ? ufloat_optab : sfloat_optab; + + else if (FLOAT128_IEEE_P (src_mode)) + emit_move_insn (dest, gen_lowpart (dest_mode, src)); + + else + gcc_unreachable (); + } + + else if (FLOAT128_IEEE_P (src_mode)) + { + if (dest_mode == SFmode + || dest_mode == DFmode + || FLOAT128_IBM_P (dest_mode)) + cvt = trunc_optab; + + else if (GET_MODE_CLASS (dest_mode) == MODE_INT) + cvt = (unsigned_p) ? ufix_optab : sfix_optab; + + else + gcc_unreachable (); + } + + else + gcc_unreachable (); + + gcc_assert (cvt != unknown_optab); + libfunc = convert_optab_libfunc (cvt, dest_mode, src_mode); + gcc_assert (libfunc != NULL_RTX); + + dest2 = emit_library_call_value (libfunc, dest, LCT_CONST, dest_mode, 1, src, + src_mode); + + gcc_assert (dest != NULL_RTX); + if (!rtx_equal_p (dest, dest2)) + emit_move_insn (dest, dest2); + + return; +} + /* Emit the RTL for an sISEL pattern. */ void diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index f7b3b4e3032..48abc266349 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -348,6 +348,8 @@ && TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128") + (IF "TARGET_FLOAT128") + (KF "TARGET_FLOAT128") (DD "TARGET_DFP") (TD "TARGET_DFP")]) @@ -365,9 +367,14 @@ (define_mode_iterator FMOVE32 [SF SD]) (define_mode_iterator FMOVE64 [DF DD]) (define_mode_iterator FMOVE64X [DI DF DD]) -(define_mode_iterator FMOVE128 [(TF "!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128") +(define_mode_iterator FMOVE128 [(TF "TARGET_LONG_DOUBLE_128") + (IF "TARGET_LONG_DOUBLE_128") (TD "TARGET_HARD_FLOAT && TARGET_FPRS")]) +(define_mode_iterator FMOVE128_FPR [(TF "FLOAT128_2REG_P (TFmode)") + (IF "FLOAT128_2REG_P (IFmode)") + (TD "TARGET_HARD_FLOAT && TARGET_FPRS")]) + ; Iterators for 128 bit types for direct move (define_mode_iterator FMOVE128_GPR [(TI "TARGET_VSX_TIMODE") (V16QI "") @@ -376,7 +383,13 @@ (V4SF "") (V2DI "") (V2DF "") - (V1TI "")]) + (V1TI "") + (KF "") + (TF "") + (IF "")]) + +; Iterator for 128-bit VSX types for pack/unpack +(define_mode_iterator FMOVE128_VSX [V1TI KF]) ; Whether a floating point move is ok, don't allow SD without hardware FP (define_mode_attr fmove_ok [(SF "") @@ -432,6 +445,25 @@ ; Iterator for just SF/DF (define_mode_iterator SFDF [SF DF]) +; Iterator for float128 floating conversions +(define_mode_iterator FLOAT128_SFDFTF [ + (SF "TARGET_FLOAT128") + (DF "TARGET_FLOAT128") + (TF "FLOAT128_IBM_P (TFmode)") + (IF "TARGET_FLOAT128")]) + +; Iterator for special 128-bit floating point. This is for non-default +; conversions, so TFmode is not used here. +(define_mode_iterator IFKF [IF KF]) + +; Iterator for 128-bit floating point that uses the IBM double-double format +(define_mode_iterator IBM128 [IF TF]) + +; Iterator for 128-bit floating point +(define_mode_iterator TFIFKF [(KF "TARGET_FLOAT128") + (IF "TARGET_FLOAT128") + (TF "TARGET_LONG_DOUBLE_128")]) + ; SF/DF suffix for traditional floating instructions (define_mode_attr Ftrad [(SF "s") (DF "")]) @@ -596,7 +628,7 @@ ;; Reload iterator for creating the function to allocate a base register to ;; supplement addressing modes. (define_mode_iterator RELOAD [V16QI V8HI V4SI V2DI V4SF V2DF V1TI - SF SD SI DF DD DI TI PTI]) + SF SD SI DF DD DI TI PTI KF IF TF]) ;; Start with fixed-point load and store insns. Here we put only the more @@ -4204,19 +4236,18 @@ ;; This expander is here to avoid FLOAT_WORDS_BIGENDIAN tests in ;; builtins.c and optabs.c that are not correct for IBM long double ;; when little-endian. -(define_expand "signbittf2" +(define_expand "signbit2" [(set (match_dup 2) - (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" ""))) + (float_truncate:DF (match_operand:IBM128 1 "gpc_reg_operand" ""))) (set (match_dup 3) (subreg:DI (match_dup 2) 0)) (set (match_dup 4) (match_dup 5)) (set (match_operand:SI 0 "gpc_reg_operand" "") (match_dup 6))] - "!TARGET_IEEEQUAD + "FLOAT128_IBM_P (mode) && TARGET_HARD_FLOAT - && (TARGET_FPRS || TARGET_E500_DOUBLE) - && TARGET_LONG_DOUBLE_128" + && (TARGET_FPRS || TARGET_E500_DOUBLE)" { operands[2] = gen_reg_rtx (DFmode); operands[3] = gen_reg_rtx (DImode); @@ -6390,9 +6421,10 @@ ;; problematical. Don't allow direct move for this case. (define_insn_and_split "*mov_64bit_dm" - [(set (match_operand:FMOVE128 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r,r,wm") - (match_operand:FMOVE128 1 "input_operand" "d,m,d,j,r,jY,r,wm,r"))] + [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r,r,wm") + (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,j,r,jY,r,wm,r"))] "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_POWERPC64 + && FLOAT128_2REG_P (mode) && (mode != TDmode || WORDS_BIG_ENDIAN) && (gpc_reg_operand (operands[0], mode) || gpc_reg_operand (operands[1], mode))" @@ -6415,9 +6447,12 @@ [(set_attr "length" "8,8,8,8,12,12,8")]) (define_insn_and_split "*mov_32bit" - [(set (match_operand:FMOVE128 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r") - (match_operand:FMOVE128 1 "input_operand" "d,m,d,j,r,jY,r"))] + [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r") + (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,j,r,jY,r"))] "TARGET_HARD_FLOAT && TARGET_FPRS && !TARGET_POWERPC64 + && (FLOAT128_2REG_P (mode) + || int_reg_operand_not_pseudo (operands[0], mode) + || int_reg_operand_not_pseudo (operands[1], mode)) && (gpc_reg_operand (operands[0], mode) || gpc_reg_operand (operands[1], mode))" "#" @@ -6441,12 +6476,12 @@ (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_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128" { - if (TARGET_E500_DOUBLE) + if (TARGET_IEEEQUAD) + rs6000_expand_float128_convert (operands[0], operands[1], false); + else if (TARGET_E500_DOUBLE) emit_insn (gen_spe_extenddftf2 (operands[0], operands[1])); else emit_insn (gen_extenddftf2_fprs (operands[0], operands[1])); @@ -6495,25 +6530,34 @@ (define_expand "extendsftf2" [(set (match_operand:TF 0 "nonimmediate_operand" "") (float_extend:TF (match_operand:SF 1 "gpc_reg_operand" "")))] - "!TARGET_IEEEQUAD - && TARGET_HARD_FLOAT + "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])); - emit_insn (gen_extenddftf2 (operands[0], tmp)); + if (TARGET_IEEEQUAD) + rs6000_expand_float128_convert (operands[0], operands[1], false); + else + { + rtx tmp = gen_reg_rtx (DFmode); + emit_insn (gen_extendsfdf2 (tmp, operands[1])); + emit_insn (gen_extenddftf2 (operands[0], tmp)); + } DONE; }) (define_expand "trunctfdf2" [(set (match_operand:DF 0 "gpc_reg_operand" "") (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))] - "!TARGET_IEEEQUAD - && TARGET_HARD_FLOAT + "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128" - "") +{ + if (TARGET_IEEEQUAD) + { + rs6000_expand_float128_convert (operands[0], operands[1], false); + DONE; + } +}) (define_insn_and_split "trunctfdf2_internal1" [(set (match_operand:DF 0 "gpc_reg_operand" "=d,?d") @@ -6544,12 +6588,13 @@ (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_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128" { - if (TARGET_E500_DOUBLE) + if (TARGET_IEEEQUAD) + rs6000_expand_float128_convert (operands[0], operands[1], false); + else if (TARGET_E500_DOUBLE) emit_insn (gen_spe_trunctfsf2 (operands[0], operands[1])); else emit_insn (gen_trunctfsf2_fprs (operands[0], operands[1])); @@ -6600,10 +6645,12 @@ (define_expand "fix_trunctfsi2" [(set (match_operand:SI 0 "gpc_reg_operand" "") (fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))] - "!TARGET_IEEEQUAD && TARGET_HARD_FLOAT + "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128" { - if (TARGET_E500_DOUBLE) + if (TARGET_IEEEQUAD) + rs6000_expand_float128_convert (operands[0], operands[1], false); + else 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])); @@ -6651,20 +6698,73 @@ DONE; }) -(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_expand "fix_trunctfdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (match_operand:TF 1 "gpc_reg_operand" "")))] + "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], false); + DONE; +}) + +(define_expand "fixuns_trunctf2" + [(set (match_operand:SDI 0 "nonimmediate_operand" "") + (unsigned_fix:SDI (match_operand:TF 1 "gpc_reg_operand" "")))] + "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], true); + DONE; +}) + +(define_expand "floatditf2" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (float:TF (match_operand:DI 1 "gpc_reg_operand" "")))] + "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], false); + DONE; +}) + +(define_expand "floatunstf2" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (unsigned_float:TF (match_operand:SDI 1 "gpc_reg_operand" "")))] + "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], true); + DONE; +}) + +(define_expand "neg2" + [(set (match_operand:TFIFKF 0 "gpc_reg_operand" "") + (neg:TFIFKF (match_operand:TFIFKF 1 "gpc_reg_operand" "")))] + "FLOAT128_IEEE_P (mode) + || (FLOAT128_IBM_P (mode) + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE))" + " +{ + if (FLOAT128_IEEE_P (mode)) + { + if (TARGET_FLOAT128) + emit_insn (gen_ieee_128bit_vsx_neg2 (operands[0], operands[1])); + else + { + rtx libfunc = optab_libfunc (neg_optab, mode); + rtx target = emit_library_call_value (libfunc, operands[0], LCT_CONST, + mode, 1, + operands[1], mode); + + if (target && !rtx_equal_p (target, operands[0])) + emit_move_insn (operands[0], target); + } + DONE; + } +}") (define_insn "negtf2_internal" [(set (match_operand:TF 0 "gpc_reg_operand" "=d") (neg:TF (match_operand:TF 1 "gpc_reg_operand" "d")))] - "!TARGET_IEEEQUAD - && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128" + "TARGET_HARD_FLOAT && TARGET_FPRS && FLOAT128_IBM_P (TFmode)" "* { if (REGNO (operands[0]) == REGNO (operands[1]) + 1) @@ -6675,16 +6775,29 @@ [(set_attr "type" "fp") (set_attr "length" "8")]) -(define_expand "abstf2" - [(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_E500_DOUBLE) - && TARGET_LONG_DOUBLE_128" +(define_expand "abs2" + [(set (match_operand:TFIFKF 0 "gpc_reg_operand" "") + (abs:TFIFKF (match_operand:TFIFKF 1 "gpc_reg_operand" "")))] + "FLOAT128_IEEE_P (mode) + || (FLOAT128_IBM_P (mode) + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE))" " { - rtx label = gen_label_rtx (); + rtx label; + + if (FLOAT128_IEEE_P (mode)) + { + if (TARGET_FLOAT128) + { + emit_insn (gen_ieee_128bit_vsx_abs2 (operands[0], operands[1])); + DONE; + } + else + FAIL; + } + + label = gen_label_rtx (); if (TARGET_E500_DOUBLE) { if (flag_finite_math_only && !flag_trapping_math) @@ -6720,6 +6833,184 @@ operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word); operands[6] = simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word); }") + + +;; Generate IEEE 128-bit -0.0 (0x80000000000000000000000000000000) in a vector +;; register + +(define_expand "ieee_128bit_negative_zero" + [(set (match_operand:V16QI 0 "register_operand" "") (match_dup 1))] + "TARGET_FLOAT128" +{ + rtvec v = rtvec_alloc (16); + int i, high; + + for (i = 0; i < 16; i++) + RTVEC_ELT (v, i) = const0_rtx; + + high = (BYTES_BIG_ENDIAN) ? 0 : 15; + RTVEC_ELT (v, high) = GEN_INT (0x80); + + rs6000_expand_vector_init (operands[0], gen_rtx_PARALLEL (V16QImode, v)); + DONE; +}) + +;; IEEE 128-bit negate + +;; We have 2 insns here for negate and absolute value. The first uses +;; match_scratch so that phases like combine can recognize neg/abs as generic +;; insns, and second insn after the first split pass loads up the bit to +;; twiddle the sign bit. Later GCSE passes can then combine multiple uses of +;; neg/abs to create the constant just once. + +(define_insn_and_split "ieee_128bit_vsx_neg2" + [(set (match_operand:TFIFKF 0 "register_operand" "=wa") + (neg:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa"))) + (clobber (match_scratch:V16QI 2 "=v"))] + "TARGET_FLOAT128 && FLOAT128_IEEE_P (mode)" + "#" + "&& 1" + [(parallel [(set (match_dup 0) + (neg:TFIFKF (match_dup 1))) + (use (match_dup 2))])] +{ + if (GET_CODE (operands[2]) == SCRATCH) + operands[2] = gen_reg_rtx (V16QImode); + + operands[3] = gen_reg_rtx (V16QImode); + emit_insn (gen_ieee_128bit_negative_zero (operands[2])); +} + [(set_attr "length" "8") + (set_attr "type" "vecsimple")]) + +(define_insn "*ieee_128bit_vsx_neg2_internal" + [(set (match_operand:TFIFKF 0 "register_operand" "=wa") + (neg:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa"))) + (use (match_operand:V16QI 2 "register_operand" "=v"))] + "TARGET_FLOAT128" + "xxlxor %x0,%x1,%x2" + [(set_attr "type" "vecsimple")]) + +;; IEEE 128-bit absolute value +(define_insn_and_split "ieee_128bit_vsx_abs2" + [(set (match_operand:TFIFKF 0 "register_operand" "=wa") + (abs:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa"))) + (clobber (match_scratch:V16QI 2 "=v"))] + "TARGET_FLOAT128 && FLOAT128_IEEE_P (mode)" + "#" + "&& 1" + [(parallel [(set (match_dup 0) + (abs:TFIFKF (match_dup 1))) + (use (match_dup 2))])] +{ + if (GET_CODE (operands[2]) == SCRATCH) + operands[2] = gen_reg_rtx (V16QImode); + + operands[3] = gen_reg_rtx (V16QImode); + emit_insn (gen_ieee_128bit_negative_zero (operands[2])); +} + [(set_attr "length" "8") + (set_attr "type" "vecsimple")]) + +(define_insn "*ieee_128bit_vsx_abs2_internal" + [(set (match_operand:TFIFKF 0 "register_operand" "=wa") + (abs:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa"))) + (use (match_operand:V16QI 2 "register_operand" "=v"))] + "TARGET_FLOAT128" + "xxlandc %x0,%x1,%x2" + [(set_attr "type" "vecsimple")]) + +;; IEEE 128-bit negative absolute value +(define_insn_and_split "*ieee_128bit_vsx_nabs2" + [(set (match_operand:TFIFKF 0 "register_operand" "=wa") + (neg:TFIFKF + (abs:TFIFKF + (match_operand:TFIFKF 1 "register_operand" "wa")))) + (clobber (match_scratch:V16QI 2 "=v"))] + "TARGET_FLOAT128 && FLOAT128_IEEE_P (mode)" + "#" + "&& 1" + [(parallel [(set (match_dup 0) + (abs:TFIFKF (match_dup 1))) + (use (match_dup 2))])] +{ + if (GET_CODE (operands[2]) == SCRATCH) + operands[2] = gen_reg_rtx (V16QImode); + + operands[3] = gen_reg_rtx (V16QImode); + emit_insn (gen_ieee_128bit_negative_zero (operands[2])); +} + [(set_attr "length" "8") + (set_attr "type" "vecsimple")]) + +(define_insn "*ieee_128bit_vsx_nabs2_internal" + [(set (match_operand:TFIFKF 0 "register_operand" "=wa") + (neg:TFIFKF + (abs:TFIFKF + (match_operand:TFIFKF 1 "register_operand" "wa")))) + (use (match_operand:V16QI 2 "register_operand" "=v"))] + "TARGET_FLOAT128" + "xxlor %x0,%x1,%x2" + [(set_attr "type" "vecsimple")]) + +;; Float128 conversion functions. These expand to library function calls. + +(define_expand "extend2" + [(set (match_operand:IFKF 0 "nonimmediate_operand" "") + (float_extend:IFKF + (match_operand:FLOAT128_SFDFTF 1 "gpc_reg_operand" "")))] + "TARGET_FLOAT128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], false); + DONE; +}) + +(define_expand "trunc2" + [(set (match_operand:FLOAT128_SFDFTF 0 "nonimmediate_operand" "") + (float_truncate:FLOAT128_SFDFTF + (match_operand:IFKF 1 "gpc_reg_operand" "")))] + "TARGET_FLOAT128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], false); + DONE; +}) + +(define_expand "fix_trunc2" + [(set (match_operand:SDI 0 "nonimmediate_operand" "") + (fix:SDI (match_operand:IFKF 1 "gpc_reg_operand" "")))] + "TARGET_FLOAT128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], false); + DONE; +}) + +(define_expand "fixuns_trunc2" + [(set (match_operand:SDI 0 "nonimmediate_operand" "") + (unsigned_fix:SDI (match_operand:IFKF 1 "gpc_reg_operand" "")))] + "TARGET_FLOAT128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], true); + DONE; +}) + +(define_expand "float2" + [(set (match_operand:IFKF 0 "nonimmediate_operand" "") + (float:KF (match_operand:SDI 1 "gpc_reg_operand" "")))] + "TARGET_FLOAT128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], false); + DONE; +}) + +(define_expand "floatuns2" + [(set (match_operand:IFKF 0 "nonimmediate_operand" "") + (unsigned_float:IFKF (match_operand:SDI 1 "gpc_reg_operand" "")))] + "TARGET_FLOAT128" +{ + rs6000_expand_float128_convert (operands[0], operands[1], true); + DONE; +}) + ;; Reload helper functions used by rs6000_secondary_reload. The patterns all ;; must have 3 arguments, and scratch register constraint must be a single @@ -12122,7 +12413,10 @@ ;; Pack/unpack 128-bit floating point types that take 2 scalar registers ; Type of the 64-bit part when packing/unpacking 128-bit floating point types -(define_mode_attr FP128_64 [(TF "DF") (TD "DI")]) +(define_mode_attr FP128_64 [(TF "DF") + (IF "DF") + (TD "DI") + (KF "DI")]) (define_expand "unpack" [(set (match_operand: 0 "nonimmediate_operand" "") @@ -12130,7 +12424,7 @@ [(match_operand:FMOVE128 1 "register_operand" "") (match_operand:QI 2 "const_0_to_1_operand" "")] UNSPEC_UNPACK_128BIT))] - "" + "FLOAT128_2REG_P (mode)" "") (define_insn_and_split "unpack_dm" @@ -12139,7 +12433,7 @@ [(match_operand:FMOVE128 1 "register_operand" "d,d,r,d,r") (match_operand:QI 2 "const_0_to_1_operand" "i,i,i,i,i")] UNSPEC_UNPACK_128BIT))] - "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" + "TARGET_POWERPC64 && TARGET_DIRECT_MOVE && FLOAT128_2REG_P (mode)" "#" "&& reload_completed" [(set (match_dup 0) (match_dup 3))] @@ -12163,7 +12457,7 @@ [(match_operand:FMOVE128 1 "register_operand" "d,d") (match_operand:QI 2 "const_0_to_1_operand" "i,i")] UNSPEC_UNPACK_128BIT))] - "!TARGET_POWERPC64 || !TARGET_DIRECT_MOVE" + "(!TARGET_POWERPC64 || !TARGET_DIRECT_MOVE) && FLOAT128_2REG_P (mode)" "#" "&& reload_completed" [(set (match_dup 0) (match_dup 3))] @@ -12187,7 +12481,7 @@ [(match_operand: 1 "register_operand" "0,d") (match_operand: 2 "register_operand" "d,d")] UNSPEC_PACK_128BIT))] - "" + "FLOAT128_2REG_P (mode)" "@ fmr %L0,%2 #" @@ -12207,12 +12501,12 @@ [(set_attr "type" "fp,fp") (set_attr "length" "4,8")]) -(define_insn "unpackv1ti" +(define_insn "unpack" [(set (match_operand:DI 0 "register_operand" "=d,d") - (unspec:DI [(match_operand:V1TI 1 "register_operand" "0,wa") + (unspec:DI [(match_operand:FMOVE128_VSX 1 "register_operand" "0,wa") (match_operand:QI 2 "const_0_to_1_operand" "O,i")] UNSPEC_UNPACK_128BIT))] - "TARGET_VSX" + "VECTOR_MEM_ALTIVEC_OR_VSX_P (mode)" { if (REGNO (operands[0]) == REGNO (operands[1]) && INTVAL (operands[2]) == 0) return ASM_COMMENT_START " xxpermdi to same register"; @@ -12220,19 +12514,17 @@ operands[3] = GEN_INT (INTVAL (operands[2]) == 0 ? 0 : 3); return "xxpermdi %x0,%x1,%x1,%3"; } - [(set_attr "type" "vecperm") - (set_attr "length" "4")]) + [(set_attr "type" "vecperm")]) -(define_insn "packv1ti" - [(set (match_operand:V1TI 0 "register_operand" "=wa") - (unspec:V1TI +(define_insn "pack" + [(set (match_operand:FMOVE128_VSX 0 "register_operand" "=wa") + (unspec:FMOVE128_VSX [(match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d")] UNSPEC_PACK_128BIT))] "TARGET_VSX" "xxpermdi %x0,%x1,%x2,0" - [(set_attr "type" "vecperm") - (set_attr "length" "4")]) + [(set_attr "type" "vecperm")])