Evidently I attached the wrong file for patch #6. 2015-08-13 Michael Meissner <meiss...@linux.vnet.ibm.com>
* 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/rs6000.md (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. (floatuns<mode>tf2): Likewise. (extend<FLOAT128_SFDFTF:mode><IFKF:mode>2): Likewise. (trunc<IFKF:mode><FLOAT128_SFDFTF:mode>2): Likewise. (fix_trunc<IFKF:mode><SDI:mode>2): Likewise. (fixuns_trunc<IFKF:mode><SDI:mode>2): Likewise. (float<SDI:mode><IFKF:mode>2): Likewise. (floatuns<SDI:mode><IFKF:mode>2): Likewise. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc/config/rs6000/rs6000-protos.h (revision 226838) +++ gcc/config/rs6000/rs6000-protos.h (working copy) @@ -54,6 +54,7 @@ extern const char *output_vec_const_move 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); Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 226838) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -8462,7 +8462,7 @@ rs6000_emit_le_vsx_store (rtx dest, rtx 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) { @@ -18519,6 +18519,8 @@ rs6000_cannot_change_mode_class (machine { 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 @@ -18527,7 +18529,10 @@ rs6000_cannot_change_mode_class (machine 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 @@ -18555,6 +18560,8 @@ rs6000_cannot_change_mode_class (machine 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)) @@ -18751,13 +18758,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. */ @@ -19801,6 +19802,8 @@ rs6000_generate_compare (rtx cmp, machin 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); @@ -19828,6 +19831,8 @@ rs6000_generate_compare (rtx cmp, machin 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); @@ -19855,6 +19860,8 @@ rs6000_generate_compare (rtx cmp, machin 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); @@ -19892,6 +19899,8 @@ rs6000_generate_compare (rtx cmp, machin 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); @@ -19914,14 +19923,117 @@ rs6000_generate_compare (rtx cmp, machin 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, @@ -19954,6 +20066,7 @@ rs6000_generate_compare (rtx cmp, machin /* 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 @@ -19993,6 +20106,68 @@ rs6000_generate_compare (rtx cmp, machin } +/* 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 Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 226871) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -6488,12 +6488,12 @@ (define_insn_and_split "*mov<mode>_softf (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])); @@ -6542,25 +6542,34 @@ (define_insn_and_split "*extenddftf2_int (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") @@ -6591,12 +6600,13 @@ (define_insn "trunctfdf2_internal2" (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])); @@ -6647,10 +6657,12 @@ (define_insn "fix_trunc_helper" (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])); @@ -6698,6 +6710,42 @@ (define_insn_and_split "*fix_trunctfsi2_ DONE; }) +(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_trunctf<mode>2" + [(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 "floatuns<mode>tf2" + [(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 "neg<mode>2" [(set (match_operand:TFIFKF 0 "gpc_reg_operand" "") (neg:TFIFKF (match_operand:TFIFKF 1 "gpc_reg_operand" "")))] @@ -6920,6 +6968,64 @@ (define_insn "*ieee_128bit_vsx_nabs<mode [(set_attr "length" "4") (set_attr "type" "vecsimple")]) +;; Float128 conversion functions. These expand to library function calls. + +(define_expand "extend<FLOAT128_SFDFTF:mode><IFKF:mode>2" + [(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 "trunc<IFKF:mode><FLOAT128_SFDFTF:mode>2" + [(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_trunc<IFKF:mode><SDI:mode>2" + [(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_trunc<IFKF:mode><SDI:mode>2" + [(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 "float<SDI:mode><IFKF:mode>2" + [(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 "floatuns<SDI:mode><IFKF:mode>2" + [(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