diff mbox

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

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

Commit Message

Richard Sandiford Feb. 4, 2014, 6:35 p.m. UTC
"Joseph S. Myers" <joseph@codesourcery.com> writes:
> 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.

Thanks, I'd missed that.

> 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).

I agree that would work but in the end I went for a slightly different
approach.  The main reason was that although libgcc2.c provides those
good di and ti conversion routines you mentioned, it doesn't AFAICT
provide any si routines; they used to come from fpbit.c instead.
So if we're going to provide fast di and ti routines we should probably
try to do the same for si.  TBH, I also didn't fancy trying to change
anything as sensitive as that list of exclusions in t-softfp.

As you say, most of the functions with hard-float support should be used
rarely if at all.  I think the only reason we ended up providing a full
set of routines for hard-float was because, back in the bad old days when
libgcc was in gcc/, it was very difficult to tailor it to individual
multilibs.  That includes the set of exported symbols.

So here I just provide simple C functions for each operation that has
hard-float support.  We can then restrict the softfp stuff to functions
that really do need softfp support, meaning that softfp_exclude_libgcc2 := n
should always be OK.  As an added bonus it reduces the footprint of libgcc_s.so
on hard-float targets.

Tested on mips64-linux-gnu and mipsisa64-sde-elf.  I checked all the
new o32, n32 and n64 functions to make sure that they produced the
expected asm and (in particular) didn't have any recursive calls.
I also rechecked the list of exported symbols in each case.

Does this look OK?

Thanks,
Richard


libgcc/
	* configure.ac (libgcc_cv_mips_hard_float): New.
	* configure: Regenerate.
	* config.host (mips*-*-*): Use t-hardfp-sfdf rather than
	t-softfp-sfdf for hard-float targets.
	* config/mips/t-mips (LIB2_SIDITI_CONV_FUNCS): Reinstate.
	(softfp_float_modes, softfp_int_modes, softfp_extensions)
	(softfp_truncations, softfp_exclude_libgcc2): New.
	* config/mips/t-hardfp-sfdf: New file.
	* config/mips/hardfp.c: Likewise.

Comments

Joseph Myers Feb. 4, 2014, 9:41 p.m. UTC | #1
On Tue, 4 Feb 2014, Richard Sandiford wrote:

> So here I just provide simple C functions for each operation that has
> hard-float support.  We can then restrict the softfp stuff to functions
> that really do need softfp support, meaning that softfp_exclude_libgcc2 := n
> should always be OK.  As an added bonus it reduces the footprint of libgcc_s.so
> on hard-float targets.

Simple C functions are indeed the best thing for cases where the functions 
are only part of the ABI at all because of historical accident of it being 
hard to build fp-bit only for soft-float multilibs.  But they're also 
useful for more than just MIPS - 32-bit powerpc hard float could use them 
as well, for example (it seems likely there are other cases, but powerpc 
is one I know about).  So I think the implementation and a makefile 
fragment for them should be outside config/mips, although targets may need 
to configure exactly which functions to build from this set.  (For 
example, e500v1 would want simple C functions for SFmode but soft-fp for 
DFmode, and for __unordsf2; e500v2 would want soft-fp for __unordsf2 and 
__unorddf2 but otherwise simple C functions.  I don't think the initial 
patch needs to build out the full configurability, as long as the files 
are in the right place, outside config/mips.)

A patch putting the files in an architecture-independent place should 
probably then be reviewed by Ian as libgcc maintainer.

> +#elif defined (OP_eq2)
> +int FUNC (TYPE x, TYPE y) { return x == y; }
> +#elif defined (OP_ne2)
> +int FUNC (TYPE x, TYPE y) { return x != y; }
> +#elif defined (OP_ge2)
> +int FUNC (TYPE x, TYPE y) { return x >= y; }
> +#elif defined (OP_gt2)
> +int FUNC (TYPE x, TYPE y) { return x > y; }
> +#elif defined (OP_le2)
> +int FUNC (TYPE x, TYPE y) { return x <= y; }
> +#elif defined (OP_lt2)
> +int FUNC (TYPE x, TYPE y) { return x < y; }

That's not the semantics of the comparison functions.  They return an 
integer value that can be compared to 0 with the original operation to get 
the final result, rather than returning the result of the comparison 
directly.  See libgcc.texi.
diff mbox

Patch

Index: libgcc/configure.ac
===================================================================
--- libgcc/configure.ac	2014-02-04 18:11:37.078922650 +0000
+++ libgcc/configure.ac	2014-02-04 18:11:41.534950708 +0000
@@ -292,6 +292,18 @@  EOF
 eval `${CC-cc} -E conftest.c | grep host_address=`
 rm -f conftest.c
 
+case ${host} in
+mips*-*-*)
+  AC_CACHE_CHECK([whether the target is hard-float],
+		 [libgcc_cv_mips_hard_float],
+		 [AC_COMPILE_IFELSE(
+    [#ifndef __mips_hard_float
+     #error FOO
+     #endif],
+    [libgcc_cv_mips_hard_float=yes],
+    [libgcc_cv_mips_hard_float=no])])
+esac
+
 # Collect host-machine-specific information.
 . ${srcdir}/config.host
 
Index: libgcc/config.host
===================================================================
--- libgcc/config.host	2014-02-04 18:11:37.077922644 +0000
+++ libgcc/config.host	2014-02-04 18:11:41.434950078 +0000
@@ -142,7 +142,12 @@  microblaze*-*-*)
 mips*-*-*)
 	# All MIPS targets provide a full set of FP routines.
 	cpu_type=mips
-	tmake_file="mips/t-mips t-softfp-sfdf"
+	tmake_file="mips/t-mips"
+	if test "${libgcc_cv_mips_hard_float}" = yes; then
+		tmake_file="${tmake_file} mips/t-hardfp-sfdf"
+	else
+		tmake_file="${tmake_file} t-softfp-sfdf"
+	fi
 	if test "${ac_cv_sizeof_long_double}" = 16; then
 		tmake_file="${tmake_file} mips/t-softfp-tf"
 	fi
Index: libgcc/config/mips/t-mips
===================================================================
--- libgcc/config/mips/t-mips	2014-02-04 18:11:37.077922644 +0000
+++ libgcc/config/mips/t-mips	2014-02-04 18:11:41.443950135 +0000
@@ -1,1 +1,9 @@ 
+LIB2_SIDITI_CONV_FUNCS = yes
+
+softfp_float_modes :=
+softfp_int_modes := si di
+softfp_extensions :=
+softfp_truncations :=
+softfp_exclude_libgcc2 := n
+
 LIB2ADD_ST += $(srcdir)/config/mips/lib2funcs.c
Index: libgcc/config/mips/t-hardfp-sfdf
===================================================================
--- /dev/null	2014-01-30 08:06:21.701666182 +0000
+++ libgcc/config/mips/t-hardfp-sfdf	2014-02-04 18:11:41.534950708 +0000
@@ -0,0 +1,26 @@ 
+# We need to provide a full set of FP routines for backward-compatibility.
+mips-hf-bases := \
+  addM3 subM3 negM2 mulM3 divM3 \
+  eqM2 neM2 geM2 gtM2 leM2 ltM2 unordM2 \
+  fixMsi floatsiM floatunsiM
+mips-hf-modes := sf df
+
+mips-hf-funcs := $(foreach m, $(mips-hf-modes), \
+	      	 	   $(subst M,$(m),$(mips-hf-bases)))
+mips-hf-funcs += extendsfdf2 truncdfsf2
+
+mips-hf-defines-for = \
+  $(shell echo $1 | \
+    sed "s/\(.*\)\(sf\|df\)\(si\|2\|3\|\)$$/-DFUNC=__& -DOP_\1\3 -DTYPE=\2/")
+
+mips-hf-o = $(patsubst %,%$(objext),$(mips-hf-funcs))
+$(mips-hf-o): %$(objext): $(srcdir)/config/mips/hardfp.c
+	$(gcc_compile) $(call mips-hf-defines-for, $*) -c $< $(vis_hide) -Wno-missing-prototypes
+libgcc-objects += $(mips-hf-o)
+
+ifeq ($(enable_shared),yes)
+mips-hf-s-o = $(patsubst %,%_s$(objext),$(mips-hf-funcs))
+$(mips-hf-s-o): %_s$(objext): $(srcdir)/config/mips/hardfp.c
+	$(gcc_s_compile) $(call mips-hf-defines-for, $*) -c $< -Wno-missing-prototypes
+libgcc-s-objects += $(mips-hf-s-o)
+endif
Index: libgcc/config/mips/hardfp.c
===================================================================
--- /dev/null	2014-01-30 08:06:21.701666182 +0000
+++ libgcc/config/mips/hardfp.c	2014-02-04 18:11:41.534950708 +0000
@@ -0,0 +1,64 @@ 
+/* Dummy floating-point routines for MIPS hard-float code.
+   Copyright (C) 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/>.  */
+
+#define sf float
+#define df double
+
+#if defined (OP_add3)
+TYPE FUNC (TYPE x, TYPE y) { return x + y; }
+#elif defined (OP_sub3)
+TYPE FUNC (TYPE x, TYPE y) { return x - y; }
+#elif defined (OP_neg2)
+TYPE FUNC (TYPE x) { return -x; }
+#elif defined (OP_mul3)
+TYPE FUNC (TYPE x, TYPE y) { return x * y; }
+#elif defined (OP_div3)
+TYPE FUNC (TYPE x, TYPE y) { return x / y; }
+#elif defined (OP_eq2)
+int FUNC (TYPE x, TYPE y) { return x == y; }
+#elif defined (OP_ne2)
+int FUNC (TYPE x, TYPE y) { return x != y; }
+#elif defined (OP_ge2)
+int FUNC (TYPE x, TYPE y) { return x >= y; }
+#elif defined (OP_gt2)
+int FUNC (TYPE x, TYPE y) { return x > y; }
+#elif defined (OP_le2)
+int FUNC (TYPE x, TYPE y) { return x <= y; }
+#elif defined (OP_lt2)
+int FUNC (TYPE x, TYPE y) { return x < y; }
+#elif defined (OP_unord2)
+int FUNC (TYPE x, TYPE y) { return __builtin_isunordered (x, y); }
+#elif defined (OP_fixsi)
+int FUNC (TYPE x) { return (int) x; }
+#elif defined (OP_floatsi)
+TYPE FUNC (int x) { return (TYPE) x; }
+#elif defined (OP_floatunsi)
+TYPE FUNC (unsigned int x) { return (TYPE) x; }
+#elif defined (OP_extendsf2)
+TYPE FUNC (float x) { return (TYPE) x; }
+#elif defined (OP_truncdf2)
+TYPE FUNC (double x) { return (TYPE) x; }
+#else
+#error Unknown operation
+#endif