+2018-05-21 Michael Meissner <meissner@linux.ibm.com>
+
+ PR target/85657
+ * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Do not
+ define __ibm128 as long double.
+ * config/rs6000/rs6000.c (rs6000_init_builtins): Always create
+ __ibm128 as a distinct type.
+ (init_float128_ieee): Fix up conversions between IFmode and IEEE
+ 128-bit types to use the correct functions.
+ (rs6000_expand_float128_convert): Use explicit FLOAT_EXTEND to
+ convert between 128-bit floating point types that have different
+ modes but the same representation, instead of using gen_lowpart to
+ makean alias.
+ * config/rs6000/rs6000.md (IFKF): New iterator for IFmode and
+ KFmode.
+ (IFKF_reg): New attributes to give the register constraints for
+ IFmode and KFmode.
+ (extend<mode>tf2_internal): New insns to mark an explicit
+ conversion between 128-bit floating point types that have a
+ different mode but share the same representation.
+
2018-05-21 Richard Sandiford <richard.sandiford@linaro.org>
PR tree-optimization/85814
builtin_define ("__RSQRTEF__");
if (TARGET_FLOAT128_TYPE)
builtin_define ("__FLOAT128_TYPE__");
- if (TARGET_LONG_DOUBLE_128 && FLOAT128_IBM_P (TFmode))
- builtin_define ("__ibm128=long double");
#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
builtin_define ("__BUILTIN_CPU_SUPPORTS__");
#endif
floating point, we need make sure the type is non-zero or else self-test
fails during bootstrap.
- We don't register a built-in type for __ibm128 if the type is the same as
- long double. Instead we add a #define for __ibm128 in
- rs6000_cpu_cpp_builtins to long double.
+ Always create __ibm128 as a separate type, even if the current long double
+ format is IBM extended double.
For IEEE 128-bit floating point, always create the type __ieee128. If the
user used -mfloat128, rs6000-c.c will create a define from __float128 to
__ieee128. */
- if (TARGET_LONG_DOUBLE_128 && FLOAT128_IEEE_P (TFmode))
+ if (TARGET_FLOAT128_TYPE)
{
ibm128_float_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (ibm128_float_type_node) = 128;
SET_TYPE_MODE (ibm128_float_type_node, IFmode);
layout_type (ibm128_float_type_node);
-
lang_hooks.types.register_builtin_type (ibm128_float_type_node,
"__ibm128");
- }
- else
- ibm128_float_type_node = long_double_type_node;
- if (TARGET_FLOAT128_TYPE)
- {
ieee128_float_type_node = float128_type_node;
lang_hooks.types.register_builtin_type (ieee128_float_type_node,
"__ieee128");
}
else
- ieee128_float_type_node = long_double_type_node;
+ ieee128_float_type_node = ibm128_float_type_node = long_double_type_node;
/* Initialize the modes for builtin_function_type, mapping a machine mode to
tree type node. */
set_conv_libfunc (trunc_optab, SFmode, mode, "__trunckfsf2");
set_conv_libfunc (trunc_optab, DFmode, mode, "__trunckfdf2");
- set_conv_libfunc (sext_optab, mode, IFmode, "__extendtfkf2");
+ set_conv_libfunc (sext_optab, mode, IFmode, "__trunctfkf2");
if (mode != TFmode && FLOAT128_IBM_P (TFmode))
- set_conv_libfunc (sext_optab, mode, TFmode, "__extendtfkf2");
+ set_conv_libfunc (sext_optab, mode, TFmode, "__trunctfkf2");
- set_conv_libfunc (trunc_optab, IFmode, mode, "__trunckftf2");
+ set_conv_libfunc (trunc_optab, IFmode, mode, "__extendkftf2");
if (mode != TFmode && FLOAT128_IBM_P (TFmode))
- set_conv_libfunc (trunc_optab, TFmode, mode, "__trunckftf2");
+ set_conv_libfunc (trunc_optab, TFmode, mode, "__extendkftf2");
set_conv_libfunc (sext_optab, mode, SDmode, "__dpd_extendsdkf2");
set_conv_libfunc (sext_optab, mode, DDmode, "__dpd_extendddkf2");
else
gcc_unreachable ();
- /* Handle conversion between TFmode/KFmode. */
+ /* Handle conversion between TFmode/KFmode/IFmode. */
if (do_move)
- emit_move_insn (dest, gen_lowpart (dest_mode, src));
+ emit_insn (gen_rtx_SET (dest, gen_rtx_FLOAT_EXTEND (dest_mode, src)));
/* Handle conversion if we have hardware support. */
else if (TARGET_FLOAT128_HW && hw_convert)
if (type == ieee128_float_type_node)
return "U10__float128";
- if (TARGET_LONG_DOUBLE_128)
- {
- if (type == long_double_type_node)
- return (TARGET_IEEEQUAD) ? "U10__float128" : "g";
+ if (type == ibm128_float_type_node)
+ return "u8__ibm128";
- if (type == ibm128_float_type_node)
- return "g";
- }
+ if (TARGET_LONG_DOUBLE_128 && type == long_double_type_node)
+ return (TARGET_IEEEQUAD) ? "U10__float128" : "g";
}
/* Mangle IBM extended float long double as `g' (__float128) on
; Iterator for 128-bit VSX types for pack/unpack
(define_mode_iterator FMOVE128_VSX [V1TI KF])
+; Iterators for converting to/from TFmode
+(define_mode_iterator IFKF [IF KF])
+
+; Constraints for moving IF/KFmode.
+(define_mode_attr IFKF_reg [(IF "d") (KF "wa")])
+
; Whether a floating point move is ok, don't allow SD without hardware FP
(define_mode_attr fmove_ok [(SF "")
(DF "")
DONE;
})
+(define_insn_and_split "*extend<mode>tf2_internal"
+ [(set (match_operand:TF 0 "gpc_reg_operand" "=<IFKF_reg>")
+ (float_extend:TF
+ (match_operand:IFKF 1 "gpc_reg_operand" "<IFKF_reg>")))]
+ "TARGET_FLOAT128_TYPE
+ && FLOAT128_IBM_P (TFmode) == FLOAT128_IBM_P (<MODE>mode)"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0) (match_dup 2))]
+{
+ operands[2] = gen_rtx_REG (TFmode, REGNO (operands[1]));
+})
+
+(define_insn_and_split "*extendtf<mode>2_internal"
+ [(set (match_operand:IFKF 0 "gpc_reg_operand" "=<IFKF_reg>")
+ (float_extend:IFKF
+ (match_operand:TF 1 "gpc_reg_operand" "<IFKF_reg>")))]
+ "TARGET_FLOAT128_TYPE
+ && FLOAT128_IBM_P (TFmode) == FLOAT128_IBM_P (<MODE>mode)"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0) (match_dup 2))]
+{
+ operands[2] = gen_rtx_REG (<MODE>mode, REGNO (operands[1]));
+})
+
\f
;; Reload helper functions used by rs6000_secondary_reload. The patterns all
;; must have 3 arguments, and scratch register constraint must be a single
+2018-05-21 Michael Meissner <meissner@linux.ibm.com>
+
+ PR target/85657
+ * gcc.target/powerpc/pr85657-1.c: New test for converting between
+ __float128, __ibm128, and long double.
+ * gcc.target/powerpc/pr85657-2.c: Likewise.
+ * gcc.target/powerpc/pr85657-3.c: Likewise.
+ * g++.dg/pr85667.C: New test to make sure __ibm128 is
+ implementated as a separate type internally, and is not just an
+ alias for long double.
+
2018-05-21 Richard Sandiford <richard.sandiford@linaro.org>
PR tree-optimization/85814
--- /dev/null
+// { dg-do compile { target { powerpc*-*-linux* } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -O2 -mabi=ibmlongdouble -Wno-psabi" }
+
+// PR 85657
+// Check that __ibm128 and long double are represented as different types, even
+// if long double is currently using the same representation as __ibm128.
+
+template <class __T> inline bool
+iszero (__T __val)
+{
+ return __val == 0;
+}
+
+int
+use_template (void)
+{
+ long double ld = 0.0;
+ __ibm128 ibm = 0.0;
+
+#ifdef _ARCH_PWR7
+ __asm__ (" # %x0, %x1" : "+d" (ld), "+d" (ibm));
+#endif
+
+ return iszero (ld) + iszero (ibm);
+}
+
+class foo {
+public:
+ foo () {}
+ ~foo () {}
+ inline bool iszero (long double ld) { return ld == 0.0; }
+ inline bool iszero (__ibm128 i128) { return i128 == 0.0; }
+} st;
+
+int
+use_class (void)
+{
+ long double ld = 0.0;
+ __ibm128 ibm = 0.0;
+
+#ifdef _ARCH_PWR7
+ __asm__ (" # %x0, %x1" : "+d" (ld), "+d" (ibm));
+#endif
+
+ return st.iszero (ld) + st.iszero (ibm);
+}
--- /dev/null
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2 -mabi=ibmlongdouble -Wno-psabi" } */
+
+// PR 85657 -- make sure conversions work between each of the 128-bit floating
+// point types.
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+ return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+ return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+ return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+ return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+ return (long double)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+ return (long double)a;
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+volatile __float128 f128 = 1.2Q;
+volatile __ibm128 i128 = (__ibm128)3.4L;
+volatile long double ld = 5.6L;
+
+int
+main (void)
+{
+ printf ("f128 (1.2) = %g (ld), %g (ibm128)\n",
+ (double) float128_to_ldouble (f128),
+ (double) float128_to_ibm128 (f128));
+
+ printf ("i128 (3.4) = %g (ld), %g (float128)\n",
+ (double) ibm128_to_ldouble (i128),
+ (double) ibm128_to_float128 (i128));
+
+ printf ("long double (5.6) = %g (ibm128), %g (float128)\n",
+ (double) ldouble_to_ibm128 (ld),
+ (double) ldouble_to_float128 (ld));
+
+ return 0;
+}
+#endif
--- /dev/null
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2 -mabi=ieeelongdouble -Wno-psabi" } */
+
+// PR 85657 -- make sure conversions work between each of the 128-bit floating
+// point types.
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+ return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+ return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+ return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+ return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+ return (long double)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+ return (long double)a;
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+volatile __float128 f128 = 1.2Q;
+volatile __ibm128 i128 = (__ibm128)3.4L;
+volatile long double ld = 5.6L;
+
+int
+main (void)
+{
+ printf ("f128 (1.2) = %g (ld), %g (ibm128)\n",
+ (double) float128_to_ldouble (f128),
+ (double) float128_to_ibm128 (f128));
+
+ printf ("i128 (3.4) = %g (ld), %g (float128)\n",
+ (double) ibm128_to_ldouble (i128),
+ (double) ibm128_to_float128 (i128));
+
+ printf ("long double (5.6) = %g (ibm128), %g (float128)\n",
+ (double) ldouble_to_ibm128 (ld),
+ (double) ldouble_to_float128 (ld));
+
+ return 0;
+}
+#endif
--- /dev/null
+/* { dg-do run { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-require-effective-target vsx_hw } */
+/* { dg-options "-mvsx -O2" } */
+
+/* PR 85657 -- make __ibm128 a full type. */
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+ return (__float128)a + 1.0q;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+ return (__float128)a + 1.0q;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+ return (__ibm128)a + (__ibm128)1.0;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+ return (__ibm128)a + (__ibm128)1.0;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+ return (long double)a + 1.0L;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+ return (long double)a + 1.0L;
+}
+
+volatile __float128 f128 = 1.25Q;
+volatile __ibm128 i128 = (__ibm128)3.5L;
+volatile long double ld = 4.75L;
+
+volatile double f128_p1 = 2.25;
+volatile double i128_p1 = 4.5;
+volatile double ld_p1 = 5.75;
+
+extern void abort (void);
+
+int
+main (void)
+{
+ if (((double) float128_to_ldouble (f128)) != f128_p1)
+ abort ();
+
+ if (((double) float128_to_ibm128 (f128)) != f128_p1)
+ abort ();
+
+ if (((double) ibm128_to_ldouble (i128)) != i128_p1)
+ abort ();
+
+ if (((double) ibm128_to_float128 (i128)) != i128_p1)
+ abort ();
+
+ if (((double) ldouble_to_ibm128 (ld)) != ld_p1)
+ abort ();
+
+ if (((double) ldouble_to_float128 (ld)) != ld_p1)
+ abort ();
+
+ return 0;
+}