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);
+}

Reply via email to