Now that we switched the clang and have FPU suuport in the kernel we
can actually start using hardware floating-point instructions in
userland. It is possible to this without breaking the ABI by using
the -mfloat-abi=softfp option. I am considering to make this the
default. But before we do that we must make the floating-point
environment functions in libc and libm aware of the hardware FPU state
such that things like rounding modes and floating-point exceptions
work. The diff below tries to achieve this in a way that supports
both soft-float and hard-float. That means we can continue to mix
clang and (base) gcc code.
There is one complication. Trapping of floating point exceptions is
optional for ARMv7. I've chosen not to implement trapping mode as I
believe all the hardware OpenBSD runs on doesn't support it. This
means that the functions that enable trapping mode, fpsetmask(3) and
feenableexcept(3) are no-ops. I also made the feenableexcept(3)
function return -1 to indicate that the operation didn't succeed.
This is how the GNU version of this function behaves. I probably
should change the man page to reflect this.
Note that the current soft-float code does implement trapping mode.
So there is a change of behaviour here.
The plan is still to switch to the hardfp ABI at some point in the
future. But I think softfp is a useful intermediate step.
Thoughts? ok?
Index: lib/libm/arch/arm/fenv.c
===================================================================
RCS file: /cvs/src/lib/libm/arch/arm/fenv.c,v
retrieving revision 1.4
diff -u -p -r1.4 fenv.c
--- lib/libm/arch/arm/fenv.c 12 Sep 2016 19:47:01 -0000 1.4
+++ lib/libm/arch/arm/fenv.c 17 Feb 2018 16:57:26 -0000
@@ -22,7 +22,6 @@
extern fp_except _softfloat_float_exception_flags;
extern fp_except _softfloat_float_exception_mask;
extern fp_rnd _softfloat_float_rounding_mode;
-extern void _softfloat_float_raise(fp_except);
/*
* The following constant represents the default floating-point environment
@@ -46,12 +45,18 @@ fenv_t __fe_dfl_env = {
int
feclearexcept(int excepts)
{
+ unsigned int fpscr;
+
excepts &= FE_ALL_EXCEPT;
/* Clear the requested floating-point exceptions */
_softfloat_float_exception_flags &= ~excepts;
- return (0);
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr &= ~excepts;
+ __asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
+
+ return 0;
}
DEF_STD(feclearexcept);
@@ -63,12 +68,16 @@ DEF_STD(feclearexcept);
int
fegetexceptflag(fexcept_t *flagp, int excepts)
{
+ unsigned int fpscr;
+
excepts &= FE_ALL_EXCEPT;
/* Store the results in flagp */
- *flagp = _softfloat_float_exception_flags & excepts;
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr |= _softfloat_float_exception_flags;
+ *flagp = fpscr & excepts;
- return (0);
+ return 0;
}
/*
@@ -81,9 +90,8 @@ feraiseexcept(int excepts)
excepts &= FE_ALL_EXCEPT;
fesetexceptflag((fexcept_t *)&excepts, excepts);
- _softfloat_float_raise(excepts);
- return (0);
+ return 0;
}
DEF_STD(feraiseexcept);
@@ -95,13 +103,20 @@ DEF_STD(feraiseexcept);
int
fesetexceptflag(const fexcept_t *flagp, int excepts)
{
+ unsigned int fpscr;
+
excepts &= FE_ALL_EXCEPT;
/* Set the requested status flags */
_softfloat_float_exception_flags &= ~excepts;
_softfloat_float_exception_flags |= *flagp & excepts;
- return (0);
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr &= ~excepts;
+ fpscr |= *flagp & excepts;
+ __asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
+
+ return 0;
}
DEF_STD(fesetexceptflag);
@@ -113,9 +128,14 @@ DEF_STD(fesetexceptflag);
int
fetestexcept(int excepts)
{
+ unsigned int fpscr;
+
excepts &= FE_ALL_EXCEPT;
- return (_softfloat_float_exception_flags & excepts);
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr |= _softfloat_float_exception_flags;
+
+ return fpscr & excepts;
}
DEF_STD(fetestexcept);
@@ -125,7 +145,11 @@ DEF_STD(fetestexcept);
int
fegetround(void)
{
- return (_softfloat_float_rounding_mode & _ROUND_MASK);
+ unsigned int fpscr;
+
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+
+ return (fpscr >> 22) & _ROUND_MASK;
}
DEF_STD(fegetround);
@@ -137,15 +161,22 @@ DEF_STD(fegetround);
int
fesetround(int round)
{
+ unsigned int fpscr;
+
/* Check whether requested rounding direction is supported */
if (round & ~_ROUND_MASK)
- return (-1);
+ return -1;
/* Set the rounding direction */
_softfloat_float_rounding_mode &= ~_ROUND_MASK;
_softfloat_float_rounding_mode |= round;
- return (0);
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr &= ~(_ROUND_MASK << 22);
+ fpscr |= round << 22;
+ __asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
+
+ return 0;
}
DEF_STD(fesetround);
@@ -156,16 +187,21 @@ DEF_STD(fesetround);
int
fegetenv(fenv_t *envp)
{
+ unsigned int fpscr;
+
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr |= _softfloat_float_exception_flags;
+
/* Store the current floating-point sticky flags */
- envp->__sticky = _softfloat_float_exception_flags;
+ envp->__sticky = fpscr & FE_ALL_EXCEPT;
/* Store the current floating-point masks */
- envp->__mask = _softfloat_float_exception_mask;
+ envp->__mask = 0;
/* Store the current floating-point control register */
- envp->__round = _softfloat_float_rounding_mode;
+ envp->__round = (fpscr >> 22) & _ROUND_MASK;
- return (0);
+ return 0;
}
DEF_STD(fegetenv);
@@ -178,6 +214,8 @@ DEF_STD(fegetenv);
int
feholdexcept(fenv_t *envp)
{
+ unsigned int fpscr;
+
/* Store the current floating-point environment */
fegetenv(envp);
@@ -187,7 +225,11 @@ feholdexcept(fenv_t *envp)
/* Mask all exceptions */
_softfloat_float_exception_mask &= ~FE_ALL_EXCEPT;
- return (0);
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr &= ~(FE_ALL_EXCEPT << 8 | FE_ALL_EXCEPT);
+ __asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
+
+ return 0;
}
DEF_STD(feholdexcept);
@@ -202,16 +244,26 @@ DEF_STD(feholdexcept);
int
fesetenv(const fenv_t *envp)
{
+ unsigned int fpscr;
+
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr &= ~(_ROUND_MASK << 22 | FE_ALL_EXCEPT << 8 | FE_ALL_EXCEPT);
+
/* Load the floating-point sticky flags */
+ fpscr |= envp->__sticky & FE_ALL_EXCEPT;
_softfloat_float_exception_flags = envp->__sticky & FE_ALL_EXCEPT;
/* Load the floating-point masks */
+ fpscr |= (envp->__mask & FE_ALL_EXCEPT) << 8;
_softfloat_float_exception_mask = envp->__mask & FE_ALL_EXCEPT;
/* Load the floating-point rounding mode */
+ fpscr |= (envp->__round & _ROUND_MASK) << 22;
_softfloat_float_rounding_mode = envp->__round & _ROUND_MASK;
- return (0);
+ __asm volatile("vmsr fpscr, %0" :: "r" (fpscr));
+
+ return 0;
}
DEF_STD(fesetenv);
@@ -226,15 +278,18 @@ DEF_STD(fesetenv);
int
feupdateenv(const fenv_t *envp)
{
- int excepts = _softfloat_float_exception_flags;
+ unsigned int fpscr;
+
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr |= _softfloat_float_exception_flags;
/* Install new floating-point environment */
fesetenv(envp);
/* Raise any previously accumulated exceptions */
- feraiseexcept(excepts);
+ feraiseexcept(fpscr & FE_ALL_EXCEPT);
- return (0);
+ return 0;
}
DEF_STD(feupdateenv);
@@ -244,32 +299,17 @@ DEF_STD(feupdateenv);
int
feenableexcept(int mask)
{
- int omask;
-
- mask &= FE_ALL_EXCEPT;
-
- omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT;
- _softfloat_float_exception_mask |= mask;
-
- return (omask);
-
+ return -1;
}
int
fedisableexcept(int mask)
{
- unsigned int omask;
-
- mask &= FE_ALL_EXCEPT;
-
- omask = _softfloat_float_exception_mask & FE_ALL_EXCEPT;
- _softfloat_float_exception_mask &= ~mask;
-
- return (omask);
+ return 0;
}
int
fegetexcept(void)
{
- return (_softfloat_float_exception_mask & FE_ALL_EXCEPT);
+ return 0;
}
Index: lib/libc/arch/arm/Makefile.inc
===================================================================
RCS file: /cvs/src/lib/libc/arch/arm/Makefile.inc,v
retrieving revision 1.7
diff -u -p -r1.7 Makefile.inc
--- lib/libc/arch/arm/Makefile.inc 17 Sep 2016 20:13:48 -0000 1.7
+++ lib/libc/arch/arm/Makefile.inc 17 Feb 2018 16:57:26 -0000
@@ -7,6 +7,9 @@ CERROR= cerror.S
CPPFLAGS += -DSOFTFLOAT
+# Override softfloat implementations of FP mode control functions
+.PATH: ${LIBCSRCDIR}/arch/${MACHINE_CPU}/gen
+
SOFTFLOAT_BITS=32
.include <arch/arm/softfloat/Makefile.inc>
Index: lib/libc/arch/arm/gen/fpgetmask.c
===================================================================
RCS file: lib/libc/arch/arm/gen/fpgetmask.c
diff -N lib/libc/arch/arm/gen/fpgetmask.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/libc/arch/arm/gen/fpgetmask.c 17 Feb 2018 16:57:26 -0000
@@ -0,0 +1,26 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2018 Mark Kettenis <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ieeefp.h>
+
+__weak_alias(_fpgetmask,fpgetmask);
+
+fp_except
+fpgetmask(void)
+{
+ return 0;
+}
Index: lib/libc/arch/arm/gen/fpgetround.c
===================================================================
RCS file: lib/libc/arch/arm/gen/fpgetround.c
diff -N lib/libc/arch/arm/gen/fpgetround.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/libc/arch/arm/gen/fpgetround.c 17 Feb 2018 16:57:26 -0000
@@ -0,0 +1,37 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2018 Mark Kettenis <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include <softfloat.h>
+#include <stdint.h>
+
+__weak_alias(_fpgetround,fpgetround);
+
+fp_rnd
+fpgetround(void)
+{
+ uint32_t fpscr;
+
+ __asm volatile("vmrs %0, fpscr" : "=r" (fpscr));
+
+ return ((fpscr >> 22) & 3);
+}
+DEF_WEAK(fpgetround);
Index: lib/libc/arch/arm/gen/fpgetsticky.c
===================================================================
RCS file: lib/libc/arch/arm/gen/fpgetsticky.c
diff -N lib/libc/arch/arm/gen/fpgetsticky.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/libc/arch/arm/gen/fpgetsticky.c 17 Feb 2018 16:57:26 -0000
@@ -0,0 +1,38 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2018 Mark Kettenis <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include <softfloat.h>
+
+#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
+
+__weak_alias(_fpgetsticky,fpgetsticky);
+
+fp_except
+fpgetsticky(void)
+{
+ fp_except old;
+
+ __asm volatile("vmrs %0, fpscr" : "=r" (old));
+ old |= float_exception_flags;
+
+ return (old & FP_X_MASK);
+}
Index: lib/libc/arch/arm/gen/fpsetmask.c
===================================================================
RCS file: lib/libc/arch/arm/gen/fpsetmask.c
diff -N lib/libc/arch/arm/gen/fpsetmask.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/libc/arch/arm/gen/fpsetmask.c 17 Feb 2018 16:57:26 -0000
@@ -0,0 +1,26 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2018 Mark Kettenis <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ieeefp.h>
+
+__weak_alias(_fpsetmask,fpsetmask);
+
+fp_except
+fpsetmask(fp_except mask)
+{
+ return 0;
+}
Index: lib/libc/arch/arm/gen/fpsetround.c
===================================================================
RCS file: lib/libc/arch/arm/gen/fpsetround.c
diff -N lib/libc/arch/arm/gen/fpsetround.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/libc/arch/arm/gen/fpsetround.c 17 Feb 2018 16:57:26 -0000
@@ -0,0 +1,41 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2018 Mark Kettenis <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include <softfloat.h>
+#include <stdint.h>
+
+__weak_alias(_fpsetround,fpsetround);
+
+fp_rnd
+fpsetround(fp_rnd rnd_dir)
+{
+ uint32_t old, new;
+
+ __asm volatile("vmrs %0, fpscr" : "=r" (old));
+ new = old & ~(3 << 22);
+ new |= (rnd_dir & 3) << 22;
+ __asm volatile("vmsr fpscr, %0" :: "r" (new));
+
+ float_rounding_mode = rnd_dir;
+
+ return ((old >> 22) & 3);
+}
Index: lib/libc/arch/arm/gen/fpsetsticky.c
===================================================================
RCS file: lib/libc/arch/arm/gen/fpsetsticky.c
diff -N lib/libc/arch/arm/gen/fpsetsticky.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/libc/arch/arm/gen/fpsetsticky.c 17 Feb 2018 16:57:26 -0000
@@ -0,0 +1,43 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2018 Mark Kettenis <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include <softfloat.h>
+
+#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
+
+__weak_alias(_fpsetsticky,fpsetsticky);
+
+fp_except
+fpsetsticky(fp_except except)
+{
+ fp_except old, new;
+
+ __asm volatile("vmrs %0, fpscr" : "=r" (old));
+ new = old & ~(FP_X_MASK);
+ new |= (except & FP_X_MASK);
+ __asm volatile("vmsr fpscr, %0" :: "r" (new));
+
+ old |= float_exception_flags;
+ float_exception_flags = except;
+
+ return (old & FP_X_MASK);
+}