re PR target/85657 (Make __ibm128 a separate type, even if long double uses the IBM double-double format)

[gcc]
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.

[gcc/testsuite]
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.

From-SVN: r260489
This commit is contained in:
Michael Meissner 2018-05-21 22:21:40 +00:00 committed by Michael Meissner
parent 9c8c733858
commit 75705fa9fd
9 changed files with 355 additions and 26 deletions

View File

@ -1,3 +1,24 @@
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

View File

@ -608,8 +608,6 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfile)
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

View File

@ -16347,35 +16347,28 @@ rs6000_init_builtins (void)
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. */
@ -17865,13 +17858,13 @@ init_float128_ieee (machine_mode mode)
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");
@ -21700,9 +21693,9 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
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)
@ -32128,14 +32121,11 @@ rs6000_mangle_type (const_tree type)
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

View File

@ -422,6 +422,12 @@
; 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 "")
@ -8188,6 +8194,32 @@
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]));
})
;; Reload helper functions used by rs6000_secondary_reload. The patterns all
;; must have 3 arguments, and scratch register constraint must be a single

View File

@ -1,3 +1,14 @@
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

View File

@ -0,0 +1,47 @@
// { 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);
}

View File

@ -0,0 +1,74 @@
/* { 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

View File

@ -0,0 +1,74 @@
/* { 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

View File

@ -0,0 +1,82 @@
/* { 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;
}