diff mbox

[MIPS] Use soft-fp for libgcc floating-point routines

Message ID 87vbwx8p27.fsf@talisman.default
State New
Headers show

Commit Message

Richard Sandiford Feb. 2, 2014, 4:19 p.m. UTC
This patch (finally!) moves MIPS over to the soft-fp routines.  The main
advantage is that we now handle 128-bit long-double exceptions properly
on hard-float targets.

This also removes the last use of TPBIT in libgcc.  It might be worth
removing support for that at some point -- including the associated
libgcc2.c routines -- but probably not at this stage of 4.9.

Tested on mips64-linux-gnu and mipsisa64-sde-elf.  It fixes the
c11-atomic-exec-5.c failures for n32 and n64.  I also checked that
the exported libgcc.so symbols were unchanged for all 3 GNU/Linux ABIs,
just to be sure.  I also did some spot checking of FCSR values after
long-double operations, as well as checking that SIGFPE was raised
for long-double operations when the associated enable bit was set.
Applied.

Thanks,
Richard


libgcc/
	* configure.ac: Check __mips64 when setting host_address.
	* configure: Regenerate.
	* config.host (mips*-*-*): Add t-softfp-sfdf, mips/t-softfp-tf,
	mips/t-mips64 and t-softfp.
	(mips*-*-linux*): Don't add mips/t-tpbit.
	* config/mips/t-mips (LIB2_SIDITI_CONV_FUNCS, FPBIT, FPBIT_CFLAGS)
	(DPBIT, DPBIT_CFLAGS): Delete.
	* config/mips/sfp-machine.h: New file.
	* config/mips/t-mips64: Likewise.
	* config/mips/t-softfp-tf: Likewise.
	* config/mips/t-tpbit: Delete.

Comments

Joseph Myers Feb. 2, 2014, 7:08 p.m. UTC | #1
On Sun, 2 Feb 2014, Richard Sandiford wrote:

> This patch (finally!) moves MIPS over to the soft-fp routines.  The main
> advantage is that we now handle 128-bit long-double exceptions properly
> on hard-float targets.

Thanks for doing this.  At some point I intend to add soft-fp support for 
after-rounding tininess detection, so this can then get underflow 
exceptions exactly right (per IEEE 754, all binary floating-point 
operations need to detect tininess in the same way, and MIPS is an 
after-rounding architecture, and soft-fp only does before-rounding at 
present - this is also wrong for x86 __float128, as x86 is also 
after-rounding).  I'll also update glibc (ports/sysdeps/mips/math-tests.h) 
to know that exceptions and rounding modes for long double are supported 
for MIPS with GCC >= 4.9 (once I've done the after-rounding support, 
otherwise some fma tests will fail).

I note that you're not using t-softfp-excl.  Logically, it's best to use 
the libgcc2.c functions in the cases where hardware floating point is 
involved (when they are providing conversions to/from DImode/TImode, and 
to/from unsigned, based on conversions to/from a narrower type or to/from 
signed, and the floating-point type involved is a hardware type), because 
that will be more efficient than a fully software implementation.  But 
when building for a soft-float multilib, and in any case when TFmode is 
involved, it's best to use the soft-fp functions rather than the libgcc2.c 
versions.  Thus:

* For soft-float, what you have seems optimal.

* For hard-float o32, using t-softfp-excl would be best.

* For hard-float n32 and n64, what's optimal would be a hybrid the 
makefile code doesn't yet support, so would need custom handling in MIPS 
fragments; see above, and the t-softfp comment "This list is taken from 
mklibgcc.in and doesn't presently allow for 64-bit targets where si should 
become di and di should become ti.".  How much this matters (and indeed 
how much it matters for hard-float o32) depends on which of the 
conversions involving SFmode / DFmode do actually end up using a libgcc 
function (for which the libgcc2.c version would be better than the soft-fp 
version).

Obviously any change to this would best be tested including comparisons of 
the libgcc_s.so exported symbols before and after the patch, like you did 
for the present patch.
Joseph Myers Feb. 3, 2014, 12:28 a.m. UTC | #2
On Sun, 2 Feb 2014, Joseph S. Myers wrote:

> On Sun, 2 Feb 2014, Richard Sandiford wrote:
> 
> > This patch (finally!) moves MIPS over to the soft-fp routines.  The main
> > advantage is that we now handle 128-bit long-double exceptions properly
> > on hard-float targets.
> 
> Thanks for doing this.  At some point I intend to add soft-fp support for 
> after-rounding tininess detection, so this can then get underflow 

Now submitted: 
<https://sourceware.org/ml/libc-alpha/2014-02/msg00068.html>.
diff mbox

Patch

Index: libgcc/configure.ac
===================================================================
--- libgcc/configure.ac	2014-02-02 08:29:06.963467177 +0000
+++ libgcc/configure.ac	2014-02-02 08:37:35.158153333 +0000
@@ -279,9 +279,11 @@  AC_CACHE_CHECK([whether assembler suppor
   [libgcc_cv_cfi=yes],
   [libgcc_cv_cfi=no])])
 
-# Check 32bit or 64bit
+# Check 32bit or 64bit.  In the case of MIPS, this really determines the
+# word size rather than the address size.
 cat > conftest.c <<EOF
-#if defined(__x86_64__) || (!defined(__i386__) && defined(__LP64__))
+#if defined(__x86_64__) || (!defined(__i386__) && defined(__LP64__)) \
+    || defined(__mips64)
 host_address=64
 #else
 host_address=32
Index: libgcc/config.host
===================================================================
--- libgcc/config.host	2014-02-02 08:29:06.963467177 +0000
+++ libgcc/config.host	2014-02-02 08:37:35.130153075 +0000
@@ -140,8 +140,16 @@  microblaze*-*-*)
 	cpu_type=microblaze
 	;;
 mips*-*-*)
+	# All MIPS targets provide a full set of FP routines.
 	cpu_type=mips
-	tmake_file=mips/t-mips
+	tmake_file="mips/t-mips t-softfp-sfdf"
+	if test "${ac_cv_sizeof_long_double}" = 16; then
+		tmake_file="${tmake_file} mips/t-softfp-tf"
+	fi
+	if test "${host_address}" = 64; then
+		tmake_file="${tmake_file} mips/t-mips64"
+	fi
+	tmake_file="${tmake_file} t-softfp"
 	;;
 nds32*-*)
 	cpu_type=nds32
@@ -776,9 +784,6 @@  mips*-*-linux*)				# Linux MIPS, either
 	    ;;
 	esac
 	md_unwind_header=mips/linux-unwind.h
-	if test "${ac_cv_sizeof_long_double}" = 16; then
-		tmake_file="${tmake_file} mips/t-tpbit"
-	fi
 	;;
 mips*-sde-elf*)
 	tmake_file="$tmake_file mips/t-crtstuff mips/t-mips16"
Index: libgcc/config/mips/t-mips
===================================================================
--- libgcc/config/mips/t-mips	2014-02-02 08:29:06.963467177 +0000
+++ libgcc/config/mips/t-mips	2014-02-02 08:37:35.138153148 +0000
@@ -1,8 +1,1 @@ 
-LIB2_SIDITI_CONV_FUNCS = yes
-
-FPBIT = true
-FPBIT_CFLAGS = -DQUIET_NAN_NEGATED
-DPBIT = true
-DPBIT_CFLAGS = -DQUIET_NAN_NEGATED
-
 LIB2ADD_ST += $(srcdir)/config/mips/lib2funcs.c
Index: libgcc/config/mips/sfp-machine.h
===================================================================
--- /dev/null	2014-01-30 08:06:21.701666182 +0000
+++ libgcc/config/mips/sfp-machine.h	2014-02-02 08:57:55.358362947 +0000
@@ -0,0 +1,178 @@ 
+/* softfp machine description for MIPS.
+   Copyright (C) 2009-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC 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 General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#ifdef __mips64
+#define _FP_W_TYPE_SIZE		64
+#define _FP_W_TYPE		unsigned long long
+#define _FP_WS_TYPE		signed long long
+#define _FP_I_TYPE		long long
+
+typedef int TItype __attribute__ ((mode (TI)));
+typedef unsigned int UTItype __attribute__ ((mode (TI)));
+#define TI_BITS (__CHAR_BIT__ * (int) sizeof (TItype))
+
+#define _FP_MUL_MEAT_S(R,X,Y)				\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)				\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)				\
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_udiv_norm(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_1_udiv_norm(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_2_udiv(Q,R,X,Y)
+
+#ifdef __mips_nan2008
+# define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
+# define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1)
+# define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1
+#else
+# define _FP_NANFRAC_S		(_FP_QNANBIT_S - 1)
+# define _FP_NANFRAC_D		(_FP_QNANBIT_D - 1)
+# define _FP_NANFRAC_Q		(_FP_QNANBIT_Q - 1), -1
+#endif
+#else
+#define _FP_W_TYPE_SIZE		32
+#define _FP_W_TYPE		unsigned int
+#define _FP_WS_TYPE		signed int
+#define _FP_I_TYPE		int
+
+#define _FP_MUL_MEAT_S(R,X,Y)				\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)				\
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)				\
+  _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_udiv_norm(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_4_udiv(Q,R,X,Y)
+
+#ifdef __mips_nan2008
+# define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
+# define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1), -1
+# define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#else
+# define _FP_NANFRAC_S		(_FP_QNANBIT_S - 1)
+# define _FP_NANFRAC_D		(_FP_QNANBIT_D - 1), -1
+# define _FP_NANFRAC_Q		(_FP_QNANBIT_Q - 1), -1, -1, -1
+#endif
+#endif
+
+/* The type of the result of a floating point comparison.  This must
+   match __libgcc_cmp_return__ in GCC for the target.  */
+typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__)));
+#define CMPtype __gcc_CMPtype
+
+#define _FP_NANSIGN_S		0
+#define _FP_NANSIGN_D		0
+#define _FP_NANSIGN_Q		0
+
+#define _FP_KEEPNANFRACP 1
+#ifdef __mips_nan2008
+# define _FP_QNANNEGATEDP 0
+#else
+# define _FP_QNANNEGATEDP 1
+#endif
+
+/* Comment from glibc: */
+/* From my experiments it seems X is chosen unless one of the
+   NaNs is sNaN,  in which case the result is NANSIGN/NANFRAC.  */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
+  do {								\
+    if ((_FP_FRAC_HIGH_RAW_##fs(X) |				\
+	 _FP_FRAC_HIGH_RAW_##fs(Y)) & _FP_QNANBIT_##fs)		\
+      {								\
+	R##_s = _FP_NANSIGN_##fs;				\
+	_FP_FRAC_SET_##wc(R,_FP_NANFRAC_##fs);			\
+      }								\
+    else							\
+      {								\
+	R##_s = X##_s;						\
+	_FP_FRAC_COPY_##wc(R,X);				\
+      }								\
+    R##_c = FP_CLS_NAN;						\
+  } while (0)
+
+#ifdef __mips_hard_float
+#define FP_EX_INVALID           0x40
+#define FP_EX_DIVZERO           0x20
+#define FP_EX_OVERFLOW          0x10
+#define FP_EX_UNDERFLOW         0x08
+#define FP_EX_INEXACT           0x04
+#define FP_EX_ALL \
+	(FP_EX_INVALID | FP_EX_DIVZERO | FP_EX_OVERFLOW | FP_EX_UNDERFLOW \
+	 | FP_EX_INEXACT)
+
+#define FP_EX_ENABLE_SHIFT	5
+#define FP_EX_CAUSE_SHIFT	10
+
+#define FP_RND_NEAREST		0x0
+#define FP_RND_ZERO		0x1
+#define FP_RND_PINF		0x2
+#define FP_RND_MINF		0x3
+#define FP_RND_MASK		0x3
+
+#define _FP_DECL_EX \
+  unsigned long int _fcsr __attribute__ ((unused)) = FP_RND_NEAREST
+
+#define FP_INIT_ROUNDMODE			\
+  do {						\
+    _fcsr = __builtin_mips_get_fcsr ();		\
+  } while (0)
+
+#define FP_ROUNDMODE (_fcsr & FP_RND_MASK)
+
+#define FP_TRAPPING_EXCEPTIONS ((_fcsr >> FP_EX_ENABLE_SHIFT) & FP_EX_ALL)
+
+#define FP_HANDLE_EXCEPTIONS				\
+  do {							\
+    _fcsr &= ~(FP_EX_ALL << FP_EX_CAUSE_SHIFT);		\
+    /* Also clear Unimplemented Operation.  */		\
+    _fcsr &= ~(1 << 17);				\
+    _fcsr |= _fex | (_fex << FP_EX_CAUSE_SHIFT);	\
+    __builtin_mips_set_fcsr (_fcsr);			\
+  } while (0);
+
+#else
+#define FP_EX_INVALID           (1 << 4)
+#define FP_EX_DIVZERO           (1 << 3)
+#define FP_EX_OVERFLOW          (1 << 2)
+#define FP_EX_UNDERFLOW         (1 << 1)
+#define FP_EX_INEXACT           (1 << 0)
+#endif
+
+#define	__LITTLE_ENDIAN	1234
+#define	__BIG_ENDIAN	4321
+
+#if defined _MIPSEB
+# define __BYTE_ORDER __BIG_ENDIAN
+#else
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
+/* Define ALIASNAME as a strong alias for NAME.  */
+# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+# define _strong_alias(name, aliasname) \
+  extern __typeof (name) aliasname __attribute__ ((alias (#name)));
Index: libgcc/config/mips/t-mips64
===================================================================
--- /dev/null	2014-01-30 08:06:21.701666182 +0000
+++ libgcc/config/mips/t-mips64	2014-02-02 08:37:35.139153157 +0000
@@ -0,0 +1,1 @@ 
+softfp_int_modes += ti
Index: libgcc/config/mips/t-softfp-tf
===================================================================
--- /dev/null	2014-01-30 08:06:21.701666182 +0000
+++ libgcc/config/mips/t-softfp-tf	2014-02-02 08:37:35.139153157 +0000
@@ -0,0 +1,3 @@ 
+softfp_float_modes += tf
+softfp_extensions += sftf dftf
+softfp_truncations += tfsf tfdf
Index: libgcc/config/mips/t-tpbit
===================================================================
--- libgcc/config/mips/t-tpbit	2014-02-02 08:29:06.963467177 +0000
+++ /dev/null	2014-01-30 08:06:21.701666182 +0000
@@ -1,4 +0,0 @@ 
-ifeq ($(long_double_type_size),128)
-TPBIT = true
-TPBIT_CFLAGS = -DQUIET_NAN_NEGATED
-endif