[2/2] soft-fp: Add new KF routines
Commit Message
From: Michael Meissner <meissner@linux.vnet.ibm.com>
Add cmpukf2, extendkftf2 and trunctfk2 to soft-fp.
This is the minimal set of routines required to be imported in GCC for
IEEE 128-bit floating point support.
2015-10-26 Michael Meissner <meissner@linux.vnet.ibm.com>
Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
* soft-fp/.gitignore: Negate cmpukf2.c, extendkftf2.c and trunctfk2.c.
* soft-fp/Makefile (gcc-kf-routines): New variable with all KF
routines.
* soft-fp/cmpukf2.c: New file
* soft-fp/extendkftf2.c: Likewise
* soft-fp/trunctfk2.c: Likewise
---
soft-fp/.gitignore | 3 ++
soft-fp/Makefile | 2 ++
soft-fp/cmpukf2.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
soft-fp/extendkftf2.c | 59 ++++++++++++++++++++++++++++++++++
soft-fp/trunctfk2.c | 65 ++++++++++++++++++++++++++++++++++++++
5 files changed, 216 insertions(+)
create mode 100644 soft-fp/cmpukf2.c
create mode 100644 soft-fp/extendkftf2.c
create mode 100644 soft-fp/trunctfk2.c
Comments
On Mon, 26 Oct 2015, Tulio Magno Quites Machado Filho wrote:
> From: Michael Meissner <meissner@linux.vnet.ibm.com>
>
> Add cmpukf2, extendkftf2 and trunctfk2 to soft-fp.
> This is the minimal set of routines required to be imported in GCC for
> IEEE 128-bit floating point support.
As noted, these belong directly in libgcc, in an architecture-specific
directory. The soft-fp directory in glibc is for generic,
architecture-independent implementations for the standard
architecture-independent modes. It has some files that in fact aren't
used in glibc, but not anything inherently architecture-specific like
this.
> +CMPtype
> +__cmpukf2 (TFtype a, TFtype b)
> +{
> + FP_DECL_EX;
> + FP_DECL_Q (A);
> + FP_DECL_Q (B);
> + CMPtype r;
> +
> + FP_INIT_EXCEPTIONS;
> + FP_UNPACK_RAW_Q (A, a);
> + FP_UNPACK_RAW_Q (B, b);
> + FP_CMP_Q (r, A, B, 2, 2);
> + if (r == CMP_INVALID)
> + FP_SET_EXCEPTION (FP_EX_INVALID);
No, with current FP_CMP macros you never need to set exceptions
explicitly. If the last argument is 2 exceptions should be raised for all
NaN operands, 1 only for signaling NaNs (so for __cmpukf2 you want 1 as
the last argument, for __cmpokf2 you want 2 there).
> + FP_HANDLE_EXCEPTIONS;
> +
> + return (r < CMP_LOW || r > CMP_HIGH) ? PPC_UNORDERED : ppc_cr_map[r-CMP_LOW];
The r value is -1, 0, 1 or 2 (the fourth argument to FP_CMP_Q). A result
< CMP_LOW is not possible.
> +__ibm128
> +__extendkftf2 (__float128 value)
> +{
> + double high, low;
> +
> + high = (double) value;
> + if (__builtin_isnan (high) || __builtin_isinf (high))
> + low = high;
No, that's incorrect for infinities. See the ibm-ldouble-format file (in
libgcc/config/rs6000/): the low part of an infinity must be 0 or -0, not
another infinity (the low part of a NaN doesn't matter).
> + else
> + {
> + low = (double) (value - (__float128)high);
There are cases where this will produce an invalid IBM long double value,
where the low part is 0.5ulp of the high part and the high part has the
least significant bit of the mantissa set (note that glibc contains code
relying on this aspect of the IBM long double format (see
sysdeps/ieee754/ldbl-128ibm/s_rintl.c: "However, if we have a canonical
long double with the low double 0.5 or -0.5, then the high double must be
even.")).
Thus, you need to renormalize after computing the initial approximations
to the high and low parts. Something like:
high_new = high + low;
low = (high - high_new) + low;
high = high_new;
> + /* Use copysign to propigate the sign bit so that -0.0Q becomes -0.0L. */
> + low = __builtin_copysign (low, high);
And that's completely wrong. The correct low part may be nonzero with
either sign. You need to special-case zeroes, but you can do that by
simply including all of zero, infinity and NaN in the initial case where
the low part is set to 0 (a low part of either +0 or -0 is fine for all
those cases).
Also watch out for spacing in casts throughout this patch; it should be
"(type) value" not "(type)value".
@@ -1 +1,4 @@
*kf*.c
+!cmpukf2.c
+!extendkftf2.c
+!trunctfk2.c
\ No newline at end of file
@@ -41,6 +41,8 @@ gcc-quad-routines := negtf2 addtf3 subtf3 multf3 divtf3 eqtf2 \
gcc-kf-routines-auto := $(subst tf,kf,\
$(filter-out sqrttf2,$(gcc-quad-routines)))
+gcc-kf-routines := cmpukf2 extendtfkf2 trunctfk2 $(gcc-kf-routines-auto)
+
generate-routines: $(addsuffix .c,$(gcc-kf-routines-auto))
clean:
new file mode 100644
@@ -0,0 +1,87 @@
+/* Software IEEE 128-bit floating-point emulation for PowerPC.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Michael Meissner (meissner@linux.vnet.ibm.com)
+ Code is based on the main soft-fp library written by:
+ Richard Henderson (rth@cygnus.com) and
+ Jakub Jelinek (jj@ultra.linux.cz).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file into
+ combinations with other programs, and to distribute those
+ combinations without any restriction coming from the use of this
+ file. (The Lesser General Public License restrictions do apply in
+ other respects; for example, they cover modification of the file,
+ and distribution when not linked into a combine executable.)
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Force the use of the VSX instruction set. */
+#if defined(_ARCH_PPC) && (!defined(__VSX__) || !defined(__FLOAT128__))
+#pragma GCC target ("vsx,float128")
+#endif
+
+#include "soft-fp.h"
+#include "double.h"
+#include "single.h"
+#include "quad-float128.h"
+
+/* PowerPC condition register bits. */
+#define PPC_UNORDERED 0x1 /* isnan (a) || isnan (b). */
+#define PPC_EQUAL 0x2 /* a == b. */
+#define PPC_GREATER_THEN 0x4 /* a > b. */
+#define PPC_LESS_THEN 0x8 /* a < b. */
+
+/* Map FP_CMP_Q output to PowerPC condition register bits. */
+#define CMP_UNORDERED (-2) /* isnan (a) || isnan (b). */
+#define CMP_LESS_THEN (-1) /* a < b. */
+#define CMP_EQUAL 0 /* a == b. */
+#define CMP_GREATER_THEN 1 /* a < b. */
+#define CMP_INVALID 2 /* raise invalid exception. */
+
+#define CMP_LOW CMP_UNORDERED /* comparison low value. */
+#define CMP_HIGH CMP_INVALID /* comparison high value. */
+
+static const unsigned char ppc_cr_map[] = {
+ PPC_UNORDERED, /* -2: unordered. */
+ PPC_LESS_THEN, /* -1: a < b. */
+ PPC_EQUAL, /* 0: a == b. */
+ PPC_GREATER_THEN, /* 1: a > b. */
+ PPC_UNORDERED, /* 2: invalid. */
+};
+
+/* Compare two IEEE 128-bit floating point values and return the status. We
+ return the status as a 4-bit value that can be copied into an appropriate
+ PowerPC conditon code register. */
+
+CMPtype
+__cmpukf2 (TFtype a, TFtype b)
+{
+ FP_DECL_EX;
+ FP_DECL_Q (A);
+ FP_DECL_Q (B);
+ CMPtype r;
+
+ FP_INIT_EXCEPTIONS;
+ FP_UNPACK_RAW_Q (A, a);
+ FP_UNPACK_RAW_Q (B, b);
+ FP_CMP_Q (r, A, B, 2, 2);
+ if (r == CMP_INVALID)
+ FP_SET_EXCEPTION (FP_EX_INVALID);
+ FP_HANDLE_EXCEPTIONS;
+
+ return (r < CMP_LOW || r > CMP_HIGH) ? PPC_UNORDERED : ppc_cr_map[r-CMP_LOW];
+}
new file mode 100644
@@ -0,0 +1,59 @@
+/* Software IEEE 128-bit floating-point emulation for PowerPC.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Michael Meissner (meissner@linux.vnet.ibm.com)
+ Code is based on the main soft-fp library written by:
+ Richard Henderson (rth@cygnus.com) and
+ Jakub Jelinek (jj@ultra.linux.cz).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file into
+ combinations with other programs, and to distribute those
+ combinations without any restriction coming from the use of this
+ file. (The Lesser General Public License restrictions do apply in
+ other respects; for example, they cover modification of the file,
+ and distribution when not linked into a combine executable.)
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Convert IEEE 128-bit floating point to IBM long double. */
+
+/* Force the use of the VSX instruction set. */
+#if defined(_ARCH_PPC) && (!defined(__VSX__) || !defined(__FLOAT128__))
+#pragma GCC target ("vsx,float128")
+#endif
+
+extern __ibm128 __extendkftf2 (__float128);
+
+__ibm128
+__extendkftf2 (__float128 value)
+{
+ double high, low;
+
+ high = (double) value;
+ if (__builtin_isnan (high) || __builtin_isinf (high))
+ low = high;
+
+ else
+ {
+ low = (double) (value - (__float128)high);
+
+ /* Use copysign to propigate the sign bit so that -0.0Q becomes -0.0L. */
+ low = __builtin_copysign (low, high);
+ }
+
+ return __builtin_pack_longdouble (high, low);
+}
new file mode 100644
@@ -0,0 +1,65 @@
+/* Software IEEE 128-bit floating-point emulation for PowerPC.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Michael Meissner (meissner@linux.vnet.ibm.com)
+ Code is based on the main soft-fp library written by:
+ Richard Henderson (rth@cygnus.com) and
+ Jakub Jelinek (jj@ultra.linux.cz).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file into
+ combinations with other programs, and to distribute those
+ combinations without any restriction coming from the use of this
+ file. (The Lesser General Public License restrictions do apply in
+ other respects; for example, they cover modification of the file,
+ and distribution when not linked into a combine executable.)
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Convert IBM long double to IEEE 128-bit floating point. */
+
+/* Force the use of the VSX instruction set. */
+#if defined(_ARCH_PPC) && (!defined(__VSX__) || !defined(__FLOAT128__))
+#pragma GCC target ("vsx,float128")
+#endif
+
+extern __float128 __trunctfkf2 (__ibm128);
+
+#ifdef __LITTLE_ENDIAN__
+#define HIGH_WORD 1
+#define LOW_WORD 0
+#else
+#define HIGH_WORD 0
+#define LOW_WORD 1
+#endif
+
+__float128
+__trunctfkf2 (__ibm128 value)
+{
+ double high = __builtin_unpack_longdouble (value, HIGH_WORD);
+ double low = __builtin_unpack_longdouble (value, LOW_WORD);
+
+ /* Handle the special cases of NAN and inifinity. */
+ if (__builtin_isnan (high) || __builtin_isinf (high))
+ return (__float128) high;
+
+ /* If low is 0.0, there no need to do the add. In addition, avoiding the add
+ produces the correct sign if high is -0.0. */
+ if (low == 0.0)
+ return (__float128) high;
+
+ return ((__float128)high) + ((__float128)low);
+}