From ec21a884b30c42083cb79da52db5257acb12fc5d Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Tue, 29 Dec 2015 17:15:14 +0000 Subject: [PATCH] rs6000.c (init_float128_ieee): Remove IEEE 128-bit comparison functions in cmp_optab and ucmp_optab. 2015-12-29 Michael Meissner * config/rs6000/rs6000.c (init_float128_ieee): Remove IEEE 128-bit comparison functions in cmp_optab and ucmp_optab. (rs6000_generate_compare): Rewrite IEEE 128-bit floating point software emulation comparisons to only use __eqkf2, __gekf2, __lekf2, and __unordkf2 functions. (rs6000_invalid_binary_op): Add support for -mfloat128-convert. * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define __FLOAT128_HARDWARE__ if hardware IEEE 128-bit support is available. * config/rs6000/rs6000.opt (-mfloat128-convert): Add debug switch to allow IBM extended double and IEEE 128-bit floating point to be converted with default conversions. * config/rs6000/rs6000.md (extendkftf2): Add converters between KFmode and TFmode if -mabi=ieeelongdouble. (trunctfkf2): Likewise. (ieee128_mfvsrd): Split 64-bit integer conversions into 32-bit and 64-bit insns. (ieee128_mfvsrd_64bit): Likewise. (ieee128_mfvsrd_32bit): Likewise. (ieee128_mtvsrd): Likewise. (ieee128_mtvsrd_64bit): Likewise. (ieee128_mtvsrd_32bit): Likewise. * doc/extend.texi (Floating Types): Document that complex __float128 does not work currently. * doc/invoke.texi (RS/6000 and PowerPC Options): Document that -mfloat128 is only supported on PowerPC 64-bit Linux systems. From-SVN: r231996 --- gcc/ChangeLog | 34 +++++++++ gcc/config/rs6000/rs6000-c.c | 2 + gcc/config/rs6000/rs6000.c | 142 +++++++++++++++-------------------- gcc/config/rs6000/rs6000.md | 61 ++++++++++++++- gcc/config/rs6000/rs6000.opt | 4 + gcc/doc/extend.texi | 20 +++-- gcc/doc/invoke.texi | 3 +- 7 files changed, 168 insertions(+), 98 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5f7e0009d84..1643888b2c8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +2015-12-29 Michael Meissner + + * config/rs6000/rs6000.c (init_float128_ieee): Remove IEEE 128-bit + comparison functions in cmp_optab and ucmp_optab. + (rs6000_generate_compare): Rewrite IEEE 128-bit floating point + software emulation comparisons to only use __eqkf2, __gekf2, + __lekf2, and __unordkf2 functions. + (rs6000_invalid_binary_op): Add support for -mfloat128-convert. + + * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define + __FLOAT128_HARDWARE__ if hardware IEEE 128-bit support is + available. + + * config/rs6000/rs6000.opt (-mfloat128-convert): Add debug switch + to allow IBM extended double and IEEE 128-bit floating point to be + converted with default conversions. + + * config/rs6000/rs6000.md (extendkftf2): Add converters between + KFmode and TFmode if -mabi=ieeelongdouble. + (trunctfkf2): Likewise. + (ieee128_mfvsrd): Split 64-bit integer conversions into 32-bit and + 64-bit insns. + (ieee128_mfvsrd_64bit): Likewise. + (ieee128_mfvsrd_32bit): Likewise. + (ieee128_mtvsrd): Likewise. + (ieee128_mtvsrd_64bit): Likewise. + (ieee128_mtvsrd_32bit): Likewise. + + * doc/extend.texi (Floating Types): Document that complex + __float128 does not work currently. + + * doc/invoke.texi (RS/6000 and PowerPC Options): Document that + -mfloat128 is only supported on PowerPC 64-bit Linux systems. + 2015-12-28 Bill Schmidt * config/rs6000/rs6000.c (rs6000_emit_le_vsx_move): Verify that diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c index a1b4fd4d17e..85b4b3cfcb0 100644 --- a/gcc/config/rs6000/rs6000-c.c +++ b/gcc/config/rs6000/rs6000-c.c @@ -412,6 +412,8 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfile) builtin_define ("__RSQRTEF__"); if (TARGET_FLOAT128) builtin_define ("__FLOAT128__"); + if (TARGET_FLOAT128_HW) + builtin_define ("__FLOAT128_HARDWARE__"); if (TARGET_EXTRA_BUILTINS && cpp_get_options (pfile)->lang != CLK_ASM) { diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index a97e47a72ba..a71d0b63544 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -16501,8 +16501,6 @@ init_float128_ieee (machine_mode mode) set_optab_libfunc (lt_optab, mode, "__ltkf2"); set_optab_libfunc (le_optab, mode, "__lekf2"); set_optab_libfunc (unord_optab, mode, "__unordkf2"); - set_optab_libfunc (cmp_optab, mode, "__cmpokf2"); /* fcmpo */ - set_optab_libfunc (ucmp_optab, mode, "__cmpukf2"); /* fcmpu */ set_conv_libfunc (sext_optab, mode, SFmode, "__extendsfkf2"); set_conv_libfunc (sext_optab, mode, DFmode, "__extenddfkf2"); @@ -20297,7 +20295,9 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) rtx op0 = XEXP (cmp, 0); rtx op1 = XEXP (cmp, 1); - if (FLOAT_MODE_P (mode)) + if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode)) + comp_mode = CCmode; + else if (FLOAT_MODE_P (mode)) comp_mode = CCFPmode; else if (code == GTU || code == LTU || code == GEU || code == LEU) @@ -20503,106 +20503,77 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) emit_insn (cmp); } - /* 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)) + /* IEEE 128-bit support in VSX registers when we do not have hardware + support. */ + else if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode)) { - rtx and_reg = gen_reg_rtx (SImode); + rtx libfunc = NULL_RTX; + bool uneq_or_ltgt = false; rtx dest = gen_reg_rtx (SImode); - rtx libfunc = optab_libfunc (ucmp_optab, mode); - HOST_WIDE_INT mask_value = 0; - - /* Values that __cmpokf2/__cmpukf2 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; + libfunc = optab_libfunc (eq_optab, mode); 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; + libfunc = optab_libfunc (ge_optab, mode); 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; + libfunc = optab_libfunc (le_optab, mode); break; - case UNLT: - mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL; - code = EQ; + case UNORDERED: + case ORDERED: + libfunc = optab_libfunc (unord_optab, mode); + code = (code == UNORDERED) ? NE : EQ; break; case UNGE: - mask_value = PPC_CMP_LESS_THEN; - code = EQ; + case UNGT: + libfunc = optab_libfunc (le_optab, mode); + code = (code == UNGE) ? GE : GT; break; - case UNGT: - mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL; - code = EQ; + case UNLE: + case UNLT: + libfunc = optab_libfunc (ge_optab, mode); + code = (code == UNLE) ? LE : LT; 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; + libfunc = optab_libfunc (le_optab, mode); + uneq_or_ltgt = true; + code = (code = UNEQ) ? NE : 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); + gcc_assert (libfunc); + dest = emit_library_call_value (libfunc, NULL_RTX, 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; + /* If this is UNEQ or LTGT, we call __lekf2, which returns -1 for less + than, 0 for equal, +1 for greater, and +2 for nan. We add 1, to give + a value of 0..3, and then do and AND immediate of 1 to isolate whether + it is 0/Nan (i.e. bottom bit is 0), or less than/greater than + (i.e. bottom bit is 1). */ + if (uneq_or_ltgt) + { + rtx add_result = gen_reg_rtx (SImode); + rtx and_result = gen_reg_rtx (SImode); + emit_insn (gen_addsi3 (add_result, dest, GEN_INT (1))); + emit_insn (gen_andsi3 (and_result, add_result, GEN_INT (1))); + dest = and_result; + } emit_insn (gen_rtx_SET (compare_result, gen_rtx_COMPARE (comp_mode, dest, const0_rtx))); @@ -20706,24 +20677,29 @@ rs6000_invalid_binary_op (int op ATTRIBUTE_UNUSED, mode2 = GET_MODE_INNER (mode2); /* Don't allow IEEE 754R 128-bit binary floating point and IBM extended - double to intermix. */ + double to intermix unless -mfloat128-convert. */ if (mode1 == mode2) return NULL; - if ((mode1 == KFmode && mode2 == IFmode) - || (mode1 == IFmode && mode2 == KFmode)) - return N_("__float128 and __ibm128 cannot be used in the same expression"); + if (!TARGET_FLOAT128_CVT) + { + if ((mode1 == KFmode && mode2 == IFmode) + || (mode1 == IFmode && mode2 == KFmode)) + return N_("__float128 and __ibm128 cannot be used in the same " + "expression"); - if (TARGET_IEEEQUAD - && ((mode1 == IFmode && mode2 == TFmode) - || (mode1 == TFmode && mode2 == IFmode))) - return N_("__ibm128 and long double cannot be used in the same expression"); + if (TARGET_IEEEQUAD + && ((mode1 == IFmode && mode2 == TFmode) + || (mode1 == TFmode && mode2 == IFmode))) + return N_("__ibm128 and long double cannot be used in the same " + "expression"); - if (!TARGET_IEEEQUAD - && ((mode1 == KFmode && mode2 == TFmode) - || (mode1 == TFmode && mode2 == KFmode))) - return N_("__float128 and long double cannot be used in the same " - "expression"); + if (!TARGET_IEEEQUAD + && ((mode1 == KFmode && mode2 == TFmode) + || (mode1 == TFmode && mode2 == KFmode))) + return N_("__float128 and long double cannot be used in the same " + "expression"); + } return NULL; } diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 35685a92e1a..0b035ca8f91 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -13352,6 +13352,40 @@ "xscvdpqp %0,%1" [(set_attr "type" "vecfloat")]) +;; Conversion between KFmode and TFmode if TFmode is ieee 128-bit floating +;; point is a simple copy. +(define_insn_and_split "extendkftf2" + [(set (match_operand:TF 0 "vsx_register_operand" "=wa,?wa") + (float_extend:TF (match_operand:KF 1 "vsx_register_operand" "0,wa")))] + "TARGET_FLOAT128 && TARGET_IEEEQUAD" + "@ + # + xxlor %x0,%x1,%x1" + "&& reload_completed && REGNO (operands[0]) == REGNO (operands[1])" + [(const_int 0)] +{ + emit_note (NOTE_INSN_DELETED); + DONE; +} + [(set_attr "type" "*,vecsimple") + (set_attr "length" "0,4")]) + +(define_insn_and_split "trunctfkf2" + [(set (match_operand:KF 0 "vsx_register_operand" "=wa,?wa") + (float_extend:KF (match_operand:TF 1 "vsx_register_operand" "0,wa")))] + "TARGET_FLOAT128 && TARGET_IEEEQUAD" + "@ + # + xxlor %x0,%x1,%x1" + "&& reload_completed && REGNO (operands[0]) == REGNO (operands[1])" + [(const_int 0)] +{ + emit_note (NOTE_INSN_DELETED); + DONE; +} + [(set_attr "type" "*,vecsimple") + (set_attr "length" "0,4")]) + (define_insn "truncdf2_hw" [(set (match_operand:DF 0 "altivec_register_operand" "=v") (float_truncate:DF @@ -13476,7 +13510,7 @@ "xscvdqp %0,%1" [(set_attr "type" "vecfloat")]) -(define_insn "*ieee128_mfvsrd" +(define_insn "*ieee128_mfvsrd_64bit" [(set (match_operand:DI 0 "reg_or_indexed_operand" "=wr,Z,wi") (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v,v")] UNSPEC_IEEE128_MOVE))] @@ -13487,6 +13521,17 @@ xxlor %x0,%x1,%x1" [(set_attr "type" "mftgpr,vecsimple,fpstore")]) + +(define_insn "*ieee128_mfvsrd_32bit" + [(set (match_operand:DI 0 "reg_or_indexed_operand" "=Z,wi") + (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")] + UNSPEC_IEEE128_MOVE))] + "TARGET_FLOAT128_HW && !TARGET_POWERPC64" + "@ + stxsdx %x1,%y0 + xxlor %x0,%x1,%x1" + [(set_attr "type" "vecsimple,fpstore")]) + (define_insn "*ieee128_mfvsrwz" [(set (match_operand:SI 0 "reg_or_indexed_operand" "=r,Z") (unspec:SI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")] @@ -13512,17 +13557,27 @@ [(set_attr "type" "mffgpr,fpload,mffgpr,fpload")]) -(define_insn "*ieee128_mtvsrd" +(define_insn "*ieee128_mtvsrd_64bit" [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v") (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "wr,Z,wi")] UNSPEC_IEEE128_MOVE))] - "TARGET_FLOAT128_HW" + "TARGET_FLOAT128_HW && TARGET_POWERPC64" "@ mtvsrd %x0,%1 lxsdx %x0,%y1 xxlor %x0,%x1,%x1" [(set_attr "type" "mffgpr,fpload,vecsimple")]) +(define_insn "*ieee128_mtvsrd_32bit" + [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v") + (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "Z,wi")] + UNSPEC_IEEE128_MOVE))] + "TARGET_FLOAT128_HW && !TARGET_POWERPC64" + "@ + lxsdx %x0,%y1 + xxlor %x0,%x1,%x1" + [(set_attr "type" "fpload,vecsimple")]) + ;; IEEE 128-bit instructions with round to odd semantics (define_insn "*truncdf2_odd" [(set (match_operand:DF 0 "vsx_register_operand" "=v") diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt index 61e3c8a323e..8064f23a39c 100644 --- a/gcc/config/rs6000/rs6000.opt +++ b/gcc/config/rs6000/rs6000.opt @@ -632,3 +632,7 @@ Enable/disable IEEE 128-bit floating point via the __float128 keyword. mfloat128-hardware Target Report Mask(FLOAT128_HW) Var(rs6000_isa_flags) Enable/disable using IEEE 128-bit floating point instructions. + +mfloat128-convert +Target Undocumented Mask(FLOAT128_CVT) Var(rs6000_isa_flags) +Enable/disable default conversions between __float128 & long double. diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4578925854d..65b6a96f1d6 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -954,22 +954,20 @@ typedef _Complex float __attribute__((mode(TC))) _Complex128; typedef _Complex float __attribute__((mode(XC))) _Complex80; @end smallexample -On PowerPC Linux, Freebsd and Darwin systems, the default for -@code{long double} is to use the IBM extended floating point format -that uses a pair of @code{double} values to extend the precision. -This means that the mode @code{TCmode} was already used by the -traditional IBM long double format, and you would need to use the mode -@code{KCmode}: +On PowerPC 64-bit Linux systems there are currently problems in using +the complex @code{__float128} type. When these problems are fixed, +you would use: @smallexample typedef _Complex float __attribute__((mode(KC))) _Complex128; @end smallexample -Not all targets support additional floating-point types. @code{__float80} -and @code{__float128} types are supported on x86 and IA-64 targets. -The @code{__float128} type is supported on hppa HP-UX. -The @code{__float128} type is supported on PowerPC systems by default -if the vector scalar instruction set (VSX) is enabled. +Not all targets support additional floating-point types. +@code{__float80} and @code{__float128} types are supported on x86 and +IA-64 targets. The @code{__float128} type is supported on hppa HP-UX. +The @code{__float128} type is supported on PowerPC 64-bit Linux +systems by default if the vector scalar instruction set (VSX) is +enabled. On the PowerPC, @code{__ibm128} provides access to the IBM extended double format, and it is intended to be used by the library functions diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 4e2cf8f7beb..b85f9b5942d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -19690,7 +19690,8 @@ hardware instructions. The VSX instruction set (@option{-mvsx}, @option{-mcpu=power7}, or @option{-mcpu=power8}) must be enabled to use the @option{-mfloat128} -option. +option. The @code{-mfloat128} option only works on PowerPC 64-bit +Linux systems. @item -mfloat128-hardware @itemx -mno-float128-hardware -- 2.30.2