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

login
register
mail settings
Submitter Richard Sandiford
Date Feb. 6, 2014, 8:12 p.m.
Message ID <87mwi46lvu.fsf@talisman.default>
Download mbox | patch
Permalink /patch/317528/
State New
Headers show

Comments

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

OK, done in the patch below.  I went for the same style of configuration
macros as softfp, but like you say we might need to tweak it when other
targets start using it.

Ian: the short(ish) version is that I switched MIPS over from fpbit.c
to softfp in order to handle exceptions for TFmode with -mhard-float.
This fixes some c11-atomic-exec-5.c failures.  The setup we now want
for hard-float is:

(1) conversions between SF/DF and DI/TI are provided by libgcc2.c,
      which unlike softfp and fpbit.c can take advantage of the FPU
(2) other SF and DF functions are provided by the new functions added below
(3) all functions involving TF are provided by softfp.  

The longer version is that, for historical reasons, hard-float MIPS
provides a full set of libgcc floating-point routines, even if there's
hardware support for them.  For example, __addsf3 is defined even though
that's just ADD.S.  It used to be that all the functions in (2) were
provided by fpbit.c, but it's not currently possible to have softfp
provide (2) and (3) but not (1).

One fix would have been to tweak the softfp_exclude_libgcc2 handling
so that softfp could provide only (2) and (3).  But with that setup --
and also with the old setup -- conversions to and from DImode and TImode
would use fast hardware support but conversions to and from SImode wouldn't.
libgcc_s.so would also be bloated with large emulated routines that
would never normally be called.  So the idea was instead to define
simple C functions for (2) that can exploit the hardware instructions.
E.g. __addsf3 does just become an ADD.S and a return instruction.

>> +#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.

Gah, forgot about that sorry.

Tested on mips64-linux-gnu and mipsisa64-sde-elf.  OK to install?

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/t-hardfp: New file.
	* config/t-hardfp-sfdf: Likewise.
	* config/hardfp.c: Likewise.
Ian Lance Taylor - Feb. 6, 2014, 9:58 p.m.
Richard Sandiford <rdsandiford@googlemail.com> writes:

> 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/t-hardfp: New file.
> 	* config/t-hardfp-sfdf: Likewise.
> 	* config/hardfp.c: Likewise.

This is OK.

Thanks.

Ian

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-05 18:42:03.047324269 +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} t-hardfp-sfdf t-hardfp"
+	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/t-hardfp
===================================================================
--- /dev/null	2014-01-30 08:06:21.701666182 +0000
+++ libgcc/config/t-hardfp	2014-02-05 18:52:53.066823761 +0000
@@ -0,0 +1,81 @@ 
+# 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.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# For historical reasons, some targets provide a full set of FP routines
+# even if there is native hardware support for some of them.  This file
+# is used to define functions that can be implemented directly in hardware.
+# For example, an __adddf3 defined by this file will use an FPU addition.
+#
+# The following variables should be set up before including this file:
+#
+# hardfp_float_modes: a list of hardware floating-point modes.
+#                     e.g. sf df
+# hardfp_int_modes: a list of integer modes for which to define conversions;
+#		    usually this is "si", since libgcc2.c provides routines
+#		    for wider modes
+# hardfp_extensions: a list of extensions between hardware floating-point modes,
+#                    e.g. sfdf
+# hardfp_truncations: a list of truncations between hardware floating-point
+#                     modes, e.g. dfsf
+
+# Functions parameterized by a floating-point mode M.
+hardfp_func_bases := addM3 subM3 negM2 mulM3 divM3
+hardfp_func_bases += eqM2 neM2 geM2 gtM2 leM2 ltM2 unordM2
+
+# Functions parameterized by both a floating-point mode M and an integer mode N.
+hardfp_int_func_bases := fixMN floatNM floatunNM
+hardfp_func_bases += $(foreach n, $(hardfp_int_modes), \
+			       $(subst N,$(n),$(hardfp_int_func_bases)))
+
+# Get the full list of functions.
+hardfp_func_list := $(foreach m, $(hardfp_float_modes), \
+	      	 	      $(subst M,$(m),$(hardfp_func_bases)))
+hardfp_func_list += $(foreach pair, $(hardfp_extensions), \
+		    	      $(subst M,$(pair),extendM2))
+hardfp_func_list += $(foreach pair, $(hardfp_truncations), \
+		    	      $(subst M,$(pair),truncM2))
+
+# Regexp for matching a floating-point mode.
+hardfp_mode_regexp := $(shell echo $(hardfp_float_modes) | sed 's/ /\\|/g')
+
+# Regexp for matching the end of a function name, after the last
+# floating-point mode.
+hardfp_suffix_regexp := $(shell echo $(hardfp_int_modes) 2 3 | sed 's/ /\\|/g')
+
+# Add -D options to define:
+#   FUNC: the function name (e.g. __addsf3)
+#   OP:   the function name without the leading __ and with the last
+#            floating-point mode removed (e.g. add3)
+#   TYPE: the last floating-point mode (e.g. sf)
+hardfp_defines_for = \
+  $(shell echo $1 | \
+    sed 's/\(.*\)\($(hardfp_mode_regexp)\)\($(hardfp_suffix_regexp)\|\)$$/-DFUNC=__& -DOP_\1\3 -DTYPE=\2/')
+
+hardfp-o = $(patsubst %,%$(objext),$(hardfp_func_list))
+$(hardfp-o): %$(objext): $(srcdir)/config/hardfp.c
+	@echo "Mode = $(hardfp_mode_regexp)"
+	@echo "Suffix = $(hardfp_suffix_regexp)"
+	$(gcc_compile) $(call hardfp_defines_for, $*) -c $< $(vis_hide) -Wno-missing-prototypes
+libgcc-objects += $(hardfp-o)
+
+ifeq ($(enable_shared),yes)
+hardfp-s-o = $(patsubst %,%_s$(objext),$(hardfp_func_list))
+$(hardfp-s-o): %_s$(objext): $(srcdir)/config/hardfp.c
+	$(gcc_s_compile) $(call hardfp_defines_for, $*) -c $< -Wno-missing-prototypes
+libgcc-s-objects += $(hardfp-s-o)
+endif
Index: libgcc/config/t-hardfp-sfdf
===================================================================
--- /dev/null	2014-01-30 08:06:21.701666182 +0000
+++ libgcc/config/t-hardfp-sfdf	2014-02-05 18:54:04.655440891 +0000
@@ -0,0 +1,23 @@ 
+# 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.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+hardfp_float_modes := sf df
+# di and ti are provided by libgcc2.c where needed.
+hardfp_int_modes := si
+hardfp_extensions := sfdf
+hardfp_truncations := dfsf
Index: libgcc/config/hardfp.c
===================================================================
--- /dev/null	2014-01-30 08:06:21.701666182 +0000
+++ libgcc/config/hardfp.c	2014-02-05 18:19:52.023156539 +0000
@@ -0,0 +1,62 @@ 
+/* Dummy floating-point routines for 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) || defined (OP_ne2)
+int FUNC (TYPE x, TYPE y) { return x == y ? 0 : 1; }
+#elif defined (OP_ge2)
+int FUNC (TYPE x, TYPE y) { return x >= y ? 0 : -1; }
+#elif defined (OP_gt2)
+int FUNC (TYPE x, TYPE y) { return x > y ? 1 : 0; }
+#elif defined (OP_le2)
+int FUNC (TYPE x, TYPE y) { return x <= y ? 0 : 1; }
+#elif defined (OP_lt2)
+int FUNC (TYPE x, TYPE y) { return x < y ? -1 : 0; }
+#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