diff mbox series

[1/2] or1k: Add hard float support

Message ID 20240329074044.1961252-2-shorne@gmail.com
State New
Headers show
Series OpenRISC glibc hard float support | expand

Commit Message

Stafford Horne March 29, 2024, 7:40 a.m. UTC
This patch adds hardware floating point support to OpenRISC.  Hardware
floating point toolchain builds are enabled by passing the machine
specific argument -mhard-float to gcc via CFLAGS.  With this enabled GCC
generates floating point instructions for single-precision operations
and exports __or1k_hard_float__.

There are 2 main parts to this patch.

 - Implement fenv functions to update the FPCSR flags keeping it in sync
   with sfp (software floating point).
 - Update machine context functions to store and restore the FPCSR
   state.

*On mcontext_t ABI*

This patch adds __fpcsr to mcontext_t.  This is an ABI change, but also
an ABI fix.  The linux kernel has always defined padding in mcontext_t
that was was missing from the glibc ABI.  This unused space is has now
been re-purposed for storing the FPCSR.  This patch brings OpenRISC
glibc in line with the Linux kernel and other libc implementation
(musl).

*Hard float ABI*

The calling conventions and types do not change with OpenRISC hard-float
so glibc hard-float builds continue to use dynamic linker
/lib/ld-linux-or1k.so.1.

*Testing*

I have tested this patch both with hard-float and soft-float builds and
the test results look fine to me.  Results are as follows:

Hard Float

    # failures
    FAIL: elf/tst-sprof-basic      (Not checked, seen in other ports too)
    FAIL: gmon/tst-gmon-pie        (GCC PIE bug)
    FAIL: gmon/tst-gmon-pie-gprof  (GCC PIE bug)
    FAIL: nptl/tst-cond24          (timeouts)
    FAIL: nptl/tst-mutex10         (timeouts)

    # summary
	  5 FAIL
       4279 PASS
	 83 UNSUPPORTED
	 16 XFAIL
	  2 XPASS

    # versions
    Toolchain: or1k-smhfpu-linux-gnu
    Compiler:  gcc version 14.0.1 20240324 (experimental) [master r14-9649-gbb04a11418f] (GCC)
    Binutils:  GNU assembler version 2.42.0 (or1k-smhfpu-linux-gnu) using BFD version (GNU Binutils) 2.42.0.20240324
    Linux:     Linux buildroot 6.8.0-rc5-00003-g9158c6253560-dirty #78 SMP Fri Mar 22 16:56:54 GMT 2024 openrisc GNU/Linux

Soft Float

    # failures
    FAIL: elf/tst-sprof-basic
    FAIL: gmon/tst-gmon-pie
    FAIL: gmon/tst-gmon-pie-gprof
    FAIL: iconvdata/iconv-test     (timeout, passed when run manually)
    FAIL: nptl/tst-mutex10

    # summary
	  5 FAIL
       4281 PASS
	 81 UNSUPPORTED
	 16 XFAIL
	  2 XPASS

    # versions
    Toolchain: or1k-smh-linux-gnu
    Compiler:  gcc version 14.0.1 20240324 (experimental) [master r14-9649-gbb04a11418f] (GCC)
    Binutils:  GNU assembler version 2.42.0 (or1k-smh-linux-gnu) using BFD version (GNU Binutils) 2.42.0.20240324
    Linux:     Linux buildroot 6.8.0-rc5-00003-g9158c6253560-dirty #78 SMP Fri Mar 22 16:56:54 GMT 2024 openrisc GNU/Linux

Documentation: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf
---
 sysdeps/or1k/fpu/fclrexcpt.c                  |   44 +
 sysdeps/or1k/fpu/fegetenv.c                   |   32 +
 sysdeps/or1k/fpu/fegetmode.c                  |   29 +
 sysdeps/or1k/fpu/fegetround.c                 |   29 +
 sysdeps/or1k/fpu/feholdexcpt.c                |   33 +
 sysdeps/or1k/fpu/fenv_private.h               |  199 +++
 sysdeps/or1k/fpu/fesetenv.c                   |   32 +
 sysdeps/or1k/fpu/fesetexcept.c                |   35 +
 sysdeps/or1k/fpu/fesetmode.c                  |   39 +
 sysdeps/or1k/fpu/fesetround.c                 |   39 +
 sysdeps/or1k/fpu/feupdateenv.c                |   33 +
 sysdeps/or1k/fpu/fgetexcptflg.c               |   29 +
 .../or1k/fpu/fix-fp-int-convert-overflow.h    |   38 +
 sysdeps/or1k/fpu/fraiseexcpt.c                |   67 +
 sysdeps/or1k/fpu/fsetexcptflg.c               |   43 +
 sysdeps/or1k/fpu/ftestexcept.c                |   27 +
 sysdeps/or1k/fpu/get-rounding-mode.h          |   38 +
 sysdeps/or1k/fpu/libm-test-ulps               | 1115 +++++++++++++++++
 sysdeps/or1k/fpu/libm-test-ulps-name          |    1 +
 sysdeps/or1k/fpu_control.h                    |   61 +
 sysdeps/or1k/libm-test-ulps-name              |    1 -
 sysdeps/or1k/math-tests-snan-payload.h        |   26 +
 sysdeps/or1k/math-tests-trap.h                |   27 +
 sysdeps/or1k/{ => nofpu}/libm-test-ulps       |    0
 sysdeps/or1k/nofpu/libm-test-ulps-name        |    1 +
 sysdeps/or1k/sfp-machine.h                    |   18 +-
 sysdeps/unix/sysv/linux/or1k/getcontext.S     |    6 +
 sysdeps/unix/sysv/linux/or1k/setcontext.S     |    6 +
 sysdeps/unix/sysv/linux/or1k/swapcontext.S    |   12 +
 sysdeps/unix/sysv/linux/or1k/sys/ucontext.h   |    1 +
 sysdeps/unix/sysv/linux/or1k/ucontext_i.sym   |    3 +
 31 files changed, 2062 insertions(+), 2 deletions(-)
 create mode 100644 sysdeps/or1k/fpu/fclrexcpt.c
 create mode 100644 sysdeps/or1k/fpu/fegetenv.c
 create mode 100644 sysdeps/or1k/fpu/fegetmode.c
 create mode 100644 sysdeps/or1k/fpu/fegetround.c
 create mode 100644 sysdeps/or1k/fpu/feholdexcpt.c
 create mode 100644 sysdeps/or1k/fpu/fenv_private.h
 create mode 100644 sysdeps/or1k/fpu/fesetenv.c
 create mode 100644 sysdeps/or1k/fpu/fesetexcept.c
 create mode 100644 sysdeps/or1k/fpu/fesetmode.c
 create mode 100644 sysdeps/or1k/fpu/fesetround.c
 create mode 100644 sysdeps/or1k/fpu/feupdateenv.c
 create mode 100644 sysdeps/or1k/fpu/fgetexcptflg.c
 create mode 100644 sysdeps/or1k/fpu/fix-fp-int-convert-overflow.h
 create mode 100644 sysdeps/or1k/fpu/fraiseexcpt.c
 create mode 100644 sysdeps/or1k/fpu/fsetexcptflg.c
 create mode 100644 sysdeps/or1k/fpu/ftestexcept.c
 create mode 100644 sysdeps/or1k/fpu/get-rounding-mode.h
 create mode 100644 sysdeps/or1k/fpu/libm-test-ulps
 create mode 100644 sysdeps/or1k/fpu/libm-test-ulps-name
 create mode 100644 sysdeps/or1k/fpu_control.h
 delete mode 100644 sysdeps/or1k/libm-test-ulps-name
 create mode 100644 sysdeps/or1k/math-tests-snan-payload.h
 create mode 100644 sysdeps/or1k/math-tests-trap.h
 rename sysdeps/or1k/{ => nofpu}/libm-test-ulps (100%)
 create mode 100644 sysdeps/or1k/nofpu/libm-test-ulps-name

Comments

Adhemerval Zanella Netto April 16, 2024, 2:04 p.m. UTC | #1
On 29/03/24 04:40, Stafford Horne wrote:
> This patch adds hardware floating point support to OpenRISC.  Hardware
> floating point toolchain builds are enabled by passing the machine
> specific argument -mhard-float to gcc via CFLAGS.  With this enabled GCC
> generates floating point instructions for single-precision operations
> and exports __or1k_hard_float__.
> 
> There are 2 main parts to this patch.
> 
>  - Implement fenv functions to update the FPCSR flags keeping it in sync
>    with sfp (software floating point).
>  - Update machine context functions to store and restore the FPCSR
>    state.
> 
> *On mcontext_t ABI*
> 
> This patch adds __fpcsr to mcontext_t.  This is an ABI change, but also
> an ABI fix.  The linux kernel has always defined padding in mcontext_t
> that was was missing from the glibc ABI.  This unused space is has now
> been re-purposed for storing the FPCSR.  This patch brings OpenRISC
> glibc in line with the Linux kernel and other libc implementation
> (musl).
> 
> *Hard float ABI*
> 
> The calling conventions and types do not change with OpenRISC hard-float
> so glibc hard-float builds continue to use dynamic linker
> /lib/ld-linux-or1k.so.1.
> 
> *Testing*
> 
> I have tested this patch both with hard-float and soft-float builds and
> the test results look fine to me.  Results are as follows:
> 
> Hard Float
> 
>     # failures
>     FAIL: elf/tst-sprof-basic      (Not checked, seen in other ports too)
>     FAIL: gmon/tst-gmon-pie        (GCC PIE bug)
>     FAIL: gmon/tst-gmon-pie-gprof  (GCC PIE bug)
>     FAIL: nptl/tst-cond24          (timeouts)
>     FAIL: nptl/tst-mutex10         (timeouts)
> 
>     # summary
> 	  5 FAIL
>        4279 PASS
> 	 83 UNSUPPORTED
> 	 16 XFAIL
> 	  2 XPASS
> 
>     # versions
>     Toolchain: or1k-smhfpu-linux-gnu
>     Compiler:  gcc version 14.0.1 20240324 (experimental) [master r14-9649-gbb04a11418f] (GCC)
>     Binutils:  GNU assembler version 2.42.0 (or1k-smhfpu-linux-gnu) using BFD version (GNU Binutils) 2.42.0.20240324
>     Linux:     Linux buildroot 6.8.0-rc5-00003-g9158c6253560-dirty #78 SMP Fri Mar 22 16:56:54 GMT 2024 openrisc GNU/Linux
> 
> Soft Float
> 
>     # failures
>     FAIL: elf/tst-sprof-basic
>     FAIL: gmon/tst-gmon-pie
>     FAIL: gmon/tst-gmon-pie-gprof
>     FAIL: iconvdata/iconv-test     (timeout, passed when run manually)
>     FAIL: nptl/tst-mutex10
> 
>     # summary
> 	  5 FAIL
>        4281 PASS
> 	 81 UNSUPPORTED
> 	 16 XFAIL
> 	  2 XPASS
> 
>     # versions
>     Toolchain: or1k-smh-linux-gnu
>     Compiler:  gcc version 14.0.1 20240324 (experimental) [master r14-9649-gbb04a11418f] (GCC)
>     Binutils:  GNU assembler version 2.42.0 (or1k-smh-linux-gnu) using BFD version (GNU Binutils) 2.42.0.20240324
>     Linux:     Linux buildroot 6.8.0-rc5-00003-g9158c6253560-dirty #78 SMP Fri Mar 22 16:56:54 GMT 2024 openrisc GNU/Linux
> 
> Documentation: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf

If I understond correctly the OpenRISC hard-float ABIs uses the same
parameter passing ABI from soft-fp, similar of what ARM does with
-mfloat-abi=softfp.  So the the shared objects built with/without
-mhard-float should be interoperable, assuming hardware has hard-fp
support.

However it does solve the potential problem a binary built with softfp
loading a hardfp built shared object, or even trying to link with a
static object with different ABI (and assuming a hardware without
hard-fp support)..  It means that loader and ldconfig won't recognize 
shared objects with different floating-point objects if they are installed
on the same system.

I don't think we have a strong policy regarding this, and historical
there were ABI variants that followed this (like powerpc soft and hard),
but most ABIs that support soft/hard floating-point usually advertise it 
through ElfXX_Ehdr::e_flags.

For instance, with arm:

$ cat << EOF > lib.c
float foo_float (float x, float y)
{
  return x + y;
}

double foo_double (double x, double y)
{
  return x + y;
}
EOF
$ arm-glibc-linux-gnueabi-gcc -shared -o lib.so lib.c
$ readelf -h lib.so | grep Flags
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
$ arm-glibc-linux-gnueabihf-gcc -shared -o lib.so lib.c
$ readelf -h lib.so | grep Flags
  Flags:                             0x5000400, Version5 EABI, hard-float ABI

This is similar for RISC-V rv64imac-lp64 vs rv64imafdc-lp64d, where the
former also defined a soft-float ABI (Flags 0x1) while the latter a
a hard-float (Flags: 0x5).

With a different ABI, it prevents possible issues with mcontext_t change
and related functions (for instance, when a hard-float binary runs on
a soft-fp built libc.so and start to see that the fpcsr is not save/restore).

And it seems that OpenRISCV also support a double-precision (-mdouble-float),
but I think it does not really require a distinction between single and
double (as RISC-V does and it would require a different ABI for support
it [1]).

[1] https://sourceware.org/bugzilla/show_bug.cgi?id=30963

> ---
>  sysdeps/or1k/fpu/fclrexcpt.c                  |   44 +
>  sysdeps/or1k/fpu/fegetenv.c                   |   32 +
>  sysdeps/or1k/fpu/fegetmode.c                  |   29 +
>  sysdeps/or1k/fpu/fegetround.c                 |   29 +
>  sysdeps/or1k/fpu/feholdexcpt.c                |   33 +
>  sysdeps/or1k/fpu/fenv_private.h               |  199 +++
>  sysdeps/or1k/fpu/fesetenv.c                   |   32 +
>  sysdeps/or1k/fpu/fesetexcept.c                |   35 +
>  sysdeps/or1k/fpu/fesetmode.c                  |   39 +
>  sysdeps/or1k/fpu/fesetround.c                 |   39 +
>  sysdeps/or1k/fpu/feupdateenv.c                |   33 +
>  sysdeps/or1k/fpu/fgetexcptflg.c               |   29 +
>  .../or1k/fpu/fix-fp-int-convert-overflow.h    |   38 +
>  sysdeps/or1k/fpu/fraiseexcpt.c                |   67 +
>  sysdeps/or1k/fpu/fsetexcptflg.c               |   43 +
>  sysdeps/or1k/fpu/ftestexcept.c                |   27 +
>  sysdeps/or1k/fpu/get-rounding-mode.h          |   38 +
>  sysdeps/or1k/fpu/libm-test-ulps               | 1115 +++++++++++++++++
>  sysdeps/or1k/fpu/libm-test-ulps-name          |    1 +
>  sysdeps/or1k/fpu_control.h                    |   61 +
>  sysdeps/or1k/libm-test-ulps-name              |    1 -
>  sysdeps/or1k/math-tests-snan-payload.h        |   26 +
>  sysdeps/or1k/math-tests-trap.h                |   27 +
>  sysdeps/or1k/{ => nofpu}/libm-test-ulps       |    0
>  sysdeps/or1k/nofpu/libm-test-ulps-name        |    1 +
>  sysdeps/or1k/sfp-machine.h                    |   18 +-
>  sysdeps/unix/sysv/linux/or1k/getcontext.S     |    6 +
>  sysdeps/unix/sysv/linux/or1k/setcontext.S     |    6 +
>  sysdeps/unix/sysv/linux/or1k/swapcontext.S    |   12 +
>  sysdeps/unix/sysv/linux/or1k/sys/ucontext.h   |    1 +
>  sysdeps/unix/sysv/linux/or1k/ucontext_i.sym   |    3 +
>  31 files changed, 2062 insertions(+), 2 deletions(-)
>  create mode 100644 sysdeps/or1k/fpu/fclrexcpt.c
>  create mode 100644 sysdeps/or1k/fpu/fegetenv.c
>  create mode 100644 sysdeps/or1k/fpu/fegetmode.c
>  create mode 100644 sysdeps/or1k/fpu/fegetround.c
>  create mode 100644 sysdeps/or1k/fpu/feholdexcpt.c
>  create mode 100644 sysdeps/or1k/fpu/fenv_private.h
>  create mode 100644 sysdeps/or1k/fpu/fesetenv.c
>  create mode 100644 sysdeps/or1k/fpu/fesetexcept.c
>  create mode 100644 sysdeps/or1k/fpu/fesetmode.c
>  create mode 100644 sysdeps/or1k/fpu/fesetround.c
>  create mode 100644 sysdeps/or1k/fpu/feupdateenv.c
>  create mode 100644 sysdeps/or1k/fpu/fgetexcptflg.c
>  create mode 100644 sysdeps/or1k/fpu/fix-fp-int-convert-overflow.h
>  create mode 100644 sysdeps/or1k/fpu/fraiseexcpt.c
>  create mode 100644 sysdeps/or1k/fpu/fsetexcptflg.c
>  create mode 100644 sysdeps/or1k/fpu/ftestexcept.c
>  create mode 100644 sysdeps/or1k/fpu/get-rounding-mode.h
>  create mode 100644 sysdeps/or1k/fpu/libm-test-ulps
>  create mode 100644 sysdeps/or1k/fpu/libm-test-ulps-name
>  create mode 100644 sysdeps/or1k/fpu_control.h
>  delete mode 100644 sysdeps/or1k/libm-test-ulps-name
>  create mode 100644 sysdeps/or1k/math-tests-snan-payload.h
>  create mode 100644 sysdeps/or1k/math-tests-trap.h
>  rename sysdeps/or1k/{ => nofpu}/libm-test-ulps (100%)
>  create mode 100644 sysdeps/or1k/nofpu/libm-test-ulps-name
> 
> diff --git a/sysdeps/or1k/fpu/fclrexcpt.c b/sysdeps/or1k/fpu/fclrexcpt.c
> new file mode 100644
> index 0000000000..44224f9c24
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fclrexcpt.c
> @@ -0,0 +1,44 @@
> +/* Clear given exceptions in current floating-point environment.
> +   OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +
> +int
> +feclearexcept (int excepts)
> +{
> +  fpu_control_t cw;
> +  fpu_control_t cw_new;
> +
> +  /* Mask out unsupported bits/exceptions.  */
> +  excepts &= FE_ALL_EXCEPT;
> +
> +  /* Read the complete control word.  */
> +  _FPU_GETCW (cw);
> +
> +  cw_new = cw & ~excepts;
> +
> +  /* Put the new data in effect.  */
> +  if (cw != cw_new)
> +    _FPU_SETCW (cw_new);
> +
> +  /* Success.  */
> +  return 0;
> +}
> +libm_hidden_def (feclearexcept)
> diff --git a/sysdeps/or1k/fpu/fegetenv.c b/sysdeps/or1k/fpu/fegetenv.c
> new file mode 100644
> index 0000000000..70c75aa0bf
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fegetenv.c
> @@ -0,0 +1,32 @@
> +/* Store current floating-point environment.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +
> +int
> +__fegetenv (fenv_t *envp)
> +{
> +  _FPU_GETCW (*envp);
> +
> +  /* Success.  */
> +  return 0;
> +}
> +libm_hidden_def (__fegetenv)
> +weak_alias (__fegetenv, fegetenv)
> +libm_hidden_weak (fegetenv)
> diff --git a/sysdeps/or1k/fpu/fegetmode.c b/sysdeps/or1k/fpu/fegetmode.c
> new file mode 100644
> index 0000000000..7fffd2e0b5
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fegetmode.c
> @@ -0,0 +1,29 @@
> +/* Store current floating-point control modes.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +
> +int
> +fegetmode (femode_t *modep)
> +{
> +  _FPU_GETCW (*modep);
> +
> +  /* Success.  */
> +  return 0;
> +}
> diff --git a/sysdeps/or1k/fpu/fegetround.c b/sysdeps/or1k/fpu/fegetround.c
> new file mode 100644
> index 0000000000..7e993b980a
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fegetround.c
> @@ -0,0 +1,29 @@
> +/* Return current rounding direction.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <get-rounding-mode.h>
> +
> +int
> +__fegetround (void)
> +{
> +  return get_rounding_mode ();
> +}
> +libm_hidden_def (__fegetround)
> +weak_alias (__fegetround, fegetround)
> +libm_hidden_weak (fegetround)
> diff --git a/sysdeps/or1k/fpu/feholdexcpt.c b/sysdeps/or1k/fpu/feholdexcpt.c
> new file mode 100644
> index 0000000000..0036e41ba2
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/feholdexcpt.c
> @@ -0,0 +1,33 @@
> +/* Store current floating-point environment and clear exceptions.
> +   OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fenv_private.h>
> +
> +int
> +__feholdexcept (fenv_t *envp)
> +{
> +  libc_feholdexcept_or1k (envp);
> +
> +  /* Success.  */
> +  return 0;
> +}
> +libm_hidden_def (__feholdexcept)
> +weak_alias (__feholdexcept, feholdexcept)
> +libm_hidden_weak (feholdexcept)
> diff --git a/sysdeps/or1k/fpu/fenv_private.h b/sysdeps/or1k/fpu/fenv_private.h
> new file mode 100644
> index 0000000000..4f401e7a5a
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fenv_private.h
> @@ -0,0 +1,199 @@
> +/* Private floating point rounding and exceptions handling.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef OR1K_FENV_PRIVATE_H
> +#define OR1K_FENV_PRIVATE_H 1
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +
> +static __always_inline void
> +libc_feholdexcept_or1k (fenv_t *envp)
> +{
> +  fpu_control_t cw;
> +  fpu_control_t cw_new;
> +
> +  /* Get and store the environment.  */
> +  _FPU_GETCW (cw);
> +  *envp = cw;
> +
> +  /* Clear the exception status flags.  */
> +  cw_new = cw & ~FE_ALL_EXCEPT;
> +
> +  if (cw != cw_new)
> +    _FPU_SETCW (cw_new);
> +}
> +
> +#define libc_feholdexcept  libc_feholdexcept_or1k
> +#define libc_feholdexceptf libc_feholdexcept_or1k
> +#define libc_feholdexceptl libc_feholdexcept_or1k
> +
> +static __always_inline void
> +libc_fesetround_or1k (int round)
> +{
> +  fpu_control_t cw;
> +  fpu_control_t cw_new;
> +
> +  _FPU_GETCW (cw);
> +  cw_new = cw & ~_FPU_FPCSR_RM_MASK;
> +  cw_new |= round;
> +  if (cw != cw_new)
> +    _FPU_SETCW (cw_new);
> +}
> +
> +#define libc_fesetround  libc_fesetround_or1k
> +#define libc_fesetroundf libc_fesetround_or1k
> +#define libc_fesetroundl libc_fesetround_or1k
> +
> +static __always_inline void
> +libc_feholdexcept_setround_or1k (fenv_t *envp, int round)
> +{
> +  fpu_control_t cw;
> +  fpu_control_t cw_new;
> +
> +  /* Get and store the environment.  */
> +  _FPU_GETCW (cw);
> +  *envp = cw;
> +
> +  /* Clear the status flags and rounding mode.  */
> +  cw_new = cw & ~(FE_ALL_EXCEPT | _FPU_FPCSR_RM_MASK);
> +
> +  /* Set rounding mode.  */
> +  cw_new |= round;
> +
> +  if (cw != cw_new)
> +    _FPU_SETCW (cw_new);
> +}
> +
> +#define libc_feholdexcept_setround  libc_feholdexcept_setround_or1k
> +#define libc_feholdexcept_setroundf libc_feholdexcept_setround_or1k
> +#define libc_feholdexcept_setroundl libc_feholdexcept_setround_or1k
> +
> +static __always_inline int
> +libc_fetestexcept_or1k (int ex)
> +{
> +  fpu_control_t cw;
> +
> +  /* Get current control word.  */
> +  _FPU_GETCW (cw);
> +
> +  /* Check if any of the queried exception flags are set.  */
> +  return cw & ex & FE_ALL_EXCEPT;
> +}
> +
> +#define libc_fetestexcept  libc_fetestexcept_or1k
> +#define libc_fetestexceptf libc_fetestexcept_or1k
> +#define libc_fetestexceptl libc_fetestexcept_or1k
> +
> +static __always_inline void
> +libc_fesetenv_or1k (const fenv_t *envp)
> +{
> +  if (envp == FE_DFL_ENV)
> +    _FPU_SETCW (_FPU_DEFAULT);
> +  else
> +    _FPU_SETCW (*envp);
> +}
> +
> +#define libc_fesetenv  libc_fesetenv_or1k
> +#define libc_fesetenvf libc_fesetenv_or1k
> +#define libc_fesetenvl libc_fesetenv_or1k
> +#define libc_feresetround_noex  libc_fesetenv_or1k
> +#define libc_feresetround_noexf libc_fesetenv_or1k
> +#define libc_feresetround_noexl libc_fesetenv_or1k
> +
> +static __always_inline int
> +libc_feupdateenv_test_or1k (const fenv_t *envp, int ex)
> +{
> +  fpu_control_t cw;
> +  fpu_control_t cw_new;
> +  int excepts;
> +
> +  /* Get current control word.  */
> +  _FPU_GETCW (cw);
> +
> +  /* Merge current exception flags with the passed fenv.  */
> +  excepts = cw & FE_ALL_EXCEPT;
> +  cw_new = (envp == FE_DFL_ENV ? _FPU_DEFAULT : *envp) | excepts;
> +
> +  if (__glibc_unlikely (cw != cw_new))
> +    _FPU_SETCW (cw_new);
> +
> +  /* Raise the exceptions if enabled in the new FP state.  */
> +  if (__glibc_unlikely (excepts))
> +    __feraiseexcept (excepts);
> +
> +  return excepts & ex;
> +}
> +
> +#define libc_feupdateenv_test  libc_feupdateenv_test_or1k
> +#define libc_feupdateenv_testf libc_feupdateenv_test_or1k
> +#define libc_feupdateenv_testl libc_feupdateenv_test_or1k
> +
> +static __always_inline void
> +libc_feupdateenv_or1k (const fenv_t *envp)
> +{
> +  libc_feupdateenv_test_or1k (envp, 0);
> +}
> +
> +#define libc_feupdateenv  libc_feupdateenv_or1k
> +#define libc_feupdateenvf libc_feupdateenv_or1k
> +#define libc_feupdateenvl libc_feupdateenv_or1k
> +
> +static __always_inline void
> +libc_feholdsetround_or1k (fenv_t *envp, int round)
> +{
> +  fpu_control_t cw;
> +
> +  _FPU_GETCW (cw);
> +  *envp = cw;
> +
> +  /* Check whether rounding modes are different.  */
> +  round = (cw ^ round) & _FPU_FPCSR_RM_MASK;
> +
> +  /* Set new rounding mode if different.  */
> +  if (__glibc_unlikely (round != 0))
> +    _FPU_SETCW (cw ^ round);
> +}
> +
> +#define libc_feholdsetround  libc_feholdsetround_or1k
> +#define libc_feholdsetroundf libc_feholdsetround_or1k
> +#define libc_feholdsetroundl libc_feholdsetround_or1k
> +
> +static __always_inline void
> +libc_feresetround_or1k (fenv_t *envp)
> +{
> +  fpu_control_t cw;
> +  int round;
> +
> +  _FPU_GETCW (cw);
> +
> +  /* Check whether rounding modes are different.  */
> +  round = (*envp ^ cw) & _FPU_FPCSR_RM_MASK;
> +
> +  /* Restore the rounding mode if it was changed.  */
> +  if (__glibc_unlikely (round != 0))
> +    _FPU_SETCW (cw ^ round);
> +}
> +
> +#define libc_feresetround  libc_feresetround_or1k
> +#define libc_feresetroundf libc_feresetround_or1k
> +#define libc_feresetroundl libc_feresetround_or1k
> +
> +#include_next <fenv_private.h>
> +
> +#endif
> diff --git a/sysdeps/or1k/fpu/fesetenv.c b/sysdeps/or1k/fpu/fesetenv.c
> new file mode 100644
> index 0000000000..742ca719e0
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fesetenv.c
> @@ -0,0 +1,32 @@
> +/* Install given floating-point environment.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fenv_private.h>
> +
> +int
> +__fesetenv (const fenv_t *envp)
> +{
> +  libc_fesetenv_or1k (envp);
> +
> +  /* Success.  */
> +  return 0;
> +}
> +libm_hidden_def (__fesetenv)
> +weak_alias (__fesetenv, fesetenv)
> +libm_hidden_weak (fesetenv)
> diff --git a/sysdeps/or1k/fpu/fesetexcept.c b/sysdeps/or1k/fpu/fesetexcept.c
> new file mode 100644
> index 0000000000..43734eac18
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fesetexcept.c
> @@ -0,0 +1,35 @@
> +/* Set given exception flags.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +
> +int
> +fesetexcept (int excepts)
> +{
> +  fpu_control_t cw;
> +  fpu_control_t cw_new;
> +
> +  _FPU_GETCW (cw);
> +  cw_new = cw | (excepts & FE_ALL_EXCEPT);
> +  if (cw != cw_new)
> +    _FPU_SETCW (cw_new);
> +
> +  /* Success.  */
> +  return 0;
> +}
> diff --git a/sysdeps/or1k/fpu/fesetmode.c b/sysdeps/or1k/fpu/fesetmode.c
> new file mode 100644
> index 0000000000..d4556927ce
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fesetmode.c
> @@ -0,0 +1,39 @@
> +/* Install given floating-point control modes.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +
> +int
> +fesetmode (const femode_t *modep)
> +{
> +  fpu_control_t cw;
> +  fpu_control_t cw_new;
> +
> +  _FPU_GETCW (cw);
> +  cw_new = cw & ~_FPU_FPCSR_RM_MASK;
> +  if (modep == FE_DFL_MODE)
> +    cw_new |= (_FPU_DEFAULT & _FPU_FPCSR_RM_MASK);
> +  else
> +    cw_new |= (*modep & _FPU_FPCSR_RM_MASK);
> +  if (cw != cw_new)
> +    _FPU_SETCW (cw_new);
> +
> +  /* Success.  */
> +  return 0;
> +}
> diff --git a/sysdeps/or1k/fpu/fesetround.c b/sysdeps/or1k/fpu/fesetround.c
> new file mode 100644
> index 0000000000..c2ada98f1b
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fesetround.c
> @@ -0,0 +1,39 @@
> +/* Set current rounding direction.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fenv_private.h>
> +
> +int
> +__fesetround (int round)
> +{
> +  switch (round)
> +    {
> +    case FE_TONEAREST:
> +    case FE_TOWARDZERO:
> +    case FE_DOWNWARD:
> +    case FE_UPWARD:
> +      libc_fesetround_or1k (round);
> +      return 0;
> +    default:
> +      return round; /* A nonzero value.  */
> +    }
> +}
> +libm_hidden_def (__fesetround)
> +weak_alias (__fesetround, fesetround)
> +libm_hidden_weak (fesetround)
> diff --git a/sysdeps/or1k/fpu/feupdateenv.c b/sysdeps/or1k/fpu/feupdateenv.c
> new file mode 100644
> index 0000000000..3355bf6596
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/feupdateenv.c
> @@ -0,0 +1,33 @@
> +/* Install given floating-point environment and raise exceptions.
> +   OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fenv_private.h>
> +
> +int
> +__feupdateenv (const fenv_t *envp)
> +{
> +  libc_feupdateenv_or1k (envp);
> +
> +  /* Success.  */
> +  return 0;
> +}
> +libm_hidden_def (__feupdateenv)
> +weak_alias (__feupdateenv, feupdateenv)
> +libm_hidden_weak (feupdateenv)
> diff --git a/sysdeps/or1k/fpu/fgetexcptflg.c b/sysdeps/or1k/fpu/fgetexcptflg.c
> new file mode 100644
> index 0000000000..a954f6a2f1
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fgetexcptflg.c
> @@ -0,0 +1,29 @@
> +/* Store current state of exceptions.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fenv_private.h>
> +
> +int
> +fegetexceptflag (fexcept_t *flagp, int excepts)
> +{
> +  *flagp = libc_fetestexcept_or1k (excepts);
> +
> +  /* Success.  */
> +  return 0;
> +}
> diff --git a/sysdeps/or1k/fpu/fix-fp-int-convert-overflow.h b/sysdeps/or1k/fpu/fix-fp-int-convert-overflow.h
> new file mode 100644
> index 0000000000..78104289c0
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fix-fp-int-convert-overflow.h
> @@ -0,0 +1,38 @@
> +/* Fix for conversion of floating point to integer overflow.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef FIX_FP_INT_CONVERT_OVERFLOW_H
> +#define FIX_FP_INT_CONVERT_OVERFLOW_H	1
> +
> +/* The generic libgcc2.c conversions from floating point to long long
> +   may not raise the correct exceptions on overflow (and may raise
> +   spurious "inexact" exceptions even in non-overflow cases, see
> +   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59412>).  */
> +#define FIX_FLT_LONG_CONVERT_OVERFLOW 0
> +#define FIX_FLT_LLONG_CONVERT_OVERFLOW 1
> +
> +#define FIX_DBL_LONG_CONVERT_OVERFLOW 0
> +#define FIX_DBL_LLONG_CONVERT_OVERFLOW 1
> +
> +#define FIX_LDBL_LONG_CONVERT_OVERFLOW 0
> +#define FIX_LDBL_LLONG_CONVERT_OVERFLOW 0
> +
> +#define FIX_FLT128_LONG_CONVERT_OVERFLOW 0
> +#define FIX_FLT128_LLONG_CONVERT_OVERFLOW 0
> +
> +#endif /* fix-fp-int-convert-overflow.h */
> diff --git a/sysdeps/or1k/fpu/fraiseexcpt.c b/sysdeps/or1k/fpu/fraiseexcpt.c
> new file mode 100644
> index 0000000000..bbacfd50bc
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fraiseexcpt.c
> @@ -0,0 +1,67 @@
> +/* Raise given exceptions.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +#include <float.h>
> +#include <math.h>
> +
> +int
> +__feraiseexcept (int excepts)
> +{
> +  if (excepts == 0)
> +    return 0;
> +
> +  /* Raise exceptions represented by EXPECTS.  */
> +
> +  if (excepts & FE_INEXACT)
> +  {
> +    float d = 1.0, x = 3.0;
> +    __asm__ volatile ("lf.div.s %0, %0, %1" : "+r" (d) : "r" (x));
> +  }
> +
> +  if (excepts & FE_UNDERFLOW)
> +  {
> +    float d = FLT_MIN;
> +    __asm__ volatile ("lf.mul.s %0, %0, %0" : "+r" (d));
> +  }
> +
> +  if (excepts & FE_OVERFLOW)
> +  {
> +    float d = FLT_MAX;
> +    __asm__ volatile ("lf.mul.s %0, %0, %0" : "+r" (d) : "r" (d));
> +  }
> +
> +  if (excepts & FE_DIVBYZERO)
> +  {
> +    float d = 1.0, x = 0.0;
> +    __asm__ volatile ("lf.div.s %0, %0, %1" : "+r" (d) : "r" (x));
> +  }
> +
> +  if (excepts & FE_INVALID)
> +  {
> +    float d = HUGE_VAL, x = 0.0;
> +    __asm__ volatile ("lf.mul.s %0, %1, %0" : "+r" (d) : "r" (x));
> +  }
> +
> +  /* Success.  */
> +  return 0;
> +}
> +libm_hidden_def (__feraiseexcept)
> +weak_alias (__feraiseexcept, feraiseexcept)
> +libm_hidden_weak (feraiseexcept)
> diff --git a/sysdeps/or1k/fpu/fsetexcptflg.c b/sysdeps/or1k/fpu/fsetexcptflg.c
> new file mode 100644
> index 0000000000..c327e4c5d1
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/fsetexcptflg.c
> @@ -0,0 +1,43 @@
> +/* Set floating-point environment exception handling.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +
> +int
> +fesetexceptflag (const fexcept_t *flagp, int excepts)
> +{
> +  fpu_control_t cw;
> +  fpu_control_t cw_new;
> +
> +  /* Get the current exceptions.  */
> +  _FPU_GETCW (cw);
> +
> +  /* Make sure the flags we want restored are legal.  */
> +  excepts &= FE_ALL_EXCEPT;
> +
> +  /* Now set selected bits from flagp. Note that we ignore all non-flag
> +     bits from *flagp, so they don't matter.  */
> +  cw_new = (cw & ~excepts) | (*flagp & excepts);
> +
> +  if (cw != cw_new)
> +    _FPU_SETCW (cw_new);
> +
> +  /* Success.  */
> +  return 0;
> +}
> diff --git a/sysdeps/or1k/fpu/ftestexcept.c b/sysdeps/or1k/fpu/ftestexcept.c
> new file mode 100644
> index 0000000000..59f06afa22
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/ftestexcept.c
> @@ -0,0 +1,27 @@
> +/* Test exception in current environment.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fenv.h>
> +#include <fenv_private.h>
> +
> +int
> +fetestexcept (int excepts)
> +{
> +  return libc_fetestexcept_or1k (excepts);
> +}
> +libm_hidden_def (fetestexcept)
> diff --git a/sysdeps/or1k/fpu/get-rounding-mode.h b/sysdeps/or1k/fpu/get-rounding-mode.h
> new file mode 100644
> index 0000000000..a66d553be8
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/get-rounding-mode.h
> @@ -0,0 +1,38 @@
> +/* Determine floating-point rounding mode within libc.  OpenRISC version.
> +
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _OR1K_GET_ROUNDING_MODE_H
> +#define _OR1K_GET_ROUNDING_MODE_H	1
> +
> +#include <fenv.h>
> +#include <fpu_control.h>
> +
> +/* Return the floating-point rounding mode.  */
> +
> +static inline int
> +get_rounding_mode (void)
> +{
> +  fpu_control_t cw;
> +
> +  _FPU_GETCW (cw);
> +  return cw & _FPU_FPCSR_RM_MASK;
> +}
> +
> +#endif /* get-rounding-mode.h */
> diff --git a/sysdeps/or1k/fpu/libm-test-ulps b/sysdeps/or1k/fpu/libm-test-ulps
> new file mode 100644
> index 0000000000..948ec01cdc
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/libm-test-ulps
> @@ -0,0 +1,1115 @@
> +# Begin of automatic generation
> +
> +# Maximal error of functions:
> +Function: "acos":
> +double: 1
> +float: 1
> +
> +Function: "acos_downward":
> +double: 1
> +float: 1
> +
> +Function: "acos_towardzero":
> +double: 1
> +float: 1
> +
> +Function: "acos_upward":
> +double: 1
> +float: 1
> +
> +Function: "acosh":
> +double: 2
> +float: 2
> +
> +Function: "acosh_downward":
> +double: 2
> +float: 2
> +
> +Function: "acosh_towardzero":
> +double: 2
> +float: 2
> +
> +Function: "acosh_upward":
> +double: 2
> +float: 2
> +
> +Function: "asin":
> +double: 1
> +float: 1
> +
> +Function: "asin_downward":
> +double: 1
> +float: 1
> +
> +Function: "asin_towardzero":
> +double: 1
> +float: 1
> +
> +Function: "asin_upward":
> +double: 2
> +float: 1
> +
> +Function: "asinh":
> +double: 2
> +float: 2
> +
> +Function: "asinh_downward":
> +double: 3
> +float: 3
> +
> +Function: "asinh_towardzero":
> +double: 2
> +float: 2
> +
> +Function: "asinh_upward":
> +double: 3
> +float: 3
> +
> +Function: "atan":
> +double: 1
> +float: 1
> +
> +Function: "atan2":
> +float: 2
> +
> +Function: "atan2_downward":
> +double: 5
> +float: 2
> +
> +Function: "atan2_towardzero":
> +double: 5
> +float: 2
> +
> +Function: "atan2_upward":
> +double: 8
> +float: 2
> +
> +Function: "atan_downward":
> +double: 1
> +float: 2
> +
> +Function: "atan_towardzero":
> +double: 1
> +float: 1
> +
> +Function: "atan_upward":
> +double: 1
> +float: 2
> +
> +Function: "atanh":
> +double: 2
> +float: 2
> +
> +Function: "atanh_downward":
> +double: 3
> +float: 3
> +
> +Function: "atanh_towardzero":
> +double: 2
> +float: 2
> +
> +Function: "atanh_upward":
> +double: 3
> +float: 3
> +
> +Function: "cabs":
> +double: 1
> +
> +Function: "cabs_downward":
> +double: 1
> +
> +Function: "cabs_towardzero":
> +double: 1
> +
> +Function: "cabs_upward":
> +double: 1
> +
> +Function: Real part of "cacos":
> +double: 1
> +float: 2
> +
> +Function: Imaginary part of "cacos":
> +double: 2
> +float: 2
> +
> +Function: Real part of "cacos_downward":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "cacos_downward":
> +double: 5
> +float: 3
> +
> +Function: Real part of "cacos_towardzero":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "cacos_towardzero":
> +double: 4
> +float: 2
> +
> +Function: Real part of "cacos_upward":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "cacos_upward":
> +double: 5
> +float: 7
> +
> +Function: Real part of "cacosh":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "cacosh":
> +double: 1
> +float: 2
> +
> +Function: Real part of "cacosh_downward":
> +double: 4
> +float: 2
> +
> +Function: Imaginary part of "cacosh_downward":
> +double: 3
> +float: 3
> +
> +Function: Real part of "cacosh_towardzero":
> +double: 4
> +float: 2
> +
> +Function: Imaginary part of "cacosh_towardzero":
> +double: 3
> +float: 2
> +
> +Function: Real part of "cacosh_upward":
> +double: 4
> +float: 3
> +
> +Function: Imaginary part of "cacosh_upward":
> +double: 3
> +float: 2
> +
> +Function: "carg":
> +float: 1
> +
> +Function: "carg_downward":
> +double: 5
> +float: 2
> +
> +Function: "carg_towardzero":
> +double: 5
> +float: 2
> +
> +Function: "carg_upward":
> +double: 8
> +float: 2
> +
> +Function: Real part of "casin":
> +double: 1
> +float: 1
> +
> +Function: Imaginary part of "casin":
> +double: 2
> +float: 2
> +
> +Function: Real part of "casin_downward":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "casin_downward":
> +double: 5
> +float: 3
> +
> +Function: Real part of "casin_towardzero":
> +double: 3
> +float: 1
> +
> +Function: Imaginary part of "casin_towardzero":
> +double: 4
> +float: 2
> +
> +Function: Real part of "casin_upward":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "casin_upward":
> +double: 5
> +float: 7
> +
> +Function: Real part of "casinh":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "casinh":
> +double: 1
> +float: 1
> +
> +Function: Real part of "casinh_downward":
> +double: 5
> +float: 3
> +
> +Function: Imaginary part of "casinh_downward":
> +double: 3
> +float: 2
> +
> +Function: Real part of "casinh_towardzero":
> +double: 4
> +float: 2
> +
> +Function: Imaginary part of "casinh_towardzero":
> +double: 3
> +float: 1
> +
> +Function: Real part of "casinh_upward":
> +double: 5
> +float: 7
> +
> +Function: Imaginary part of "casinh_upward":
> +double: 3
> +float: 2
> +
> +Function: Real part of "catan":
> +double: 1
> +float: 1
> +
> +Function: Imaginary part of "catan":
> +double: 1
> +float: 1
> +
> +Function: Real part of "catan_downward":
> +double: 1
> +float: 2
> +
> +Function: Imaginary part of "catan_downward":
> +double: 2
> +float: 2
> +
> +Function: Real part of "catan_towardzero":
> +double: 1
> +float: 2
> +
> +Function: Imaginary part of "catan_towardzero":
> +double: 2
> +float: 2
> +
> +Function: Real part of "catan_upward":
> +double: 2
> +float: 1
> +
> +Function: Imaginary part of "catan_upward":
> +double: 2
> +float: 2
> +
> +Function: Real part of "catanh":
> +double: 1
> +float: 1
> +
> +Function: Imaginary part of "catanh":
> +double: 1
> +float: 1
> +
> +Function: Real part of "catanh_downward":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "catanh_downward":
> +double: 1
> +float: 2
> +
> +Function: Real part of "catanh_towardzero":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "catanh_towardzero":
> +double: 1
> +float: 2
> +
> +Function: Real part of "catanh_upward":
> +double: 4
> +float: 4
> +
> +Function: Imaginary part of "catanh_upward":
> +double: 2
> +float: 1
> +
> +Function: "cbrt":
> +double: 4
> +float: 1
> +
> +Function: "cbrt_downward":
> +double: 4
> +float: 1
> +
> +Function: "cbrt_towardzero":
> +double: 3
> +float: 1
> +
> +Function: "cbrt_upward":
> +double: 5
> +float: 1
> +
> +Function: Real part of "ccos":
> +double: 1
> +float: 1
> +
> +Function: Imaginary part of "ccos":
> +double: 1
> +float: 1
> +
> +Function: Real part of "ccos_downward":
> +double: 3
> +float: 1
> +
> +Function: Imaginary part of "ccos_downward":
> +double: 3
> +float: 3
> +
> +Function: Real part of "ccos_towardzero":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "ccos_towardzero":
> +double: 3
> +float: 3
> +
> +Function: Real part of "ccos_upward":
> +double: 1
> +float: 2
> +
> +Function: Imaginary part of "ccos_upward":
> +double: 2
> +float: 2
> +
> +Function: Real part of "ccosh":
> +double: 2
> +float: 1
> +
> +Function: Imaginary part of "ccosh":
> +double: 1
> +float: 1
> +
> +Function: Real part of "ccosh_downward":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "ccosh_downward":
> +double: 3
> +float: 3
> +
> +Function: Real part of "ccosh_towardzero":
> +double: 3
> +float: 3
> +
> +Function: Imaginary part of "ccosh_towardzero":
> +double: 3
> +float: 3
> +
> +Function: Real part of "ccosh_upward":
> +double: 1
> +float: 2
> +
> +Function: Imaginary part of "ccosh_upward":
> +double: 2
> +float: 2
> +
> +Function: Real part of "cexp":
> +double: 2
> +float: 1
> +
> +Function: Imaginary part of "cexp":
> +double: 1
> +float: 2
> +
> +Function: Real part of "cexp_downward":
> +double: 4
> +float: 2
> +
> +Function: Imaginary part of "cexp_downward":
> +double: 3
> +float: 3
> +
> +Function: Real part of "cexp_towardzero":
> +double: 4
> +float: 2
> +
> +Function: Imaginary part of "cexp_towardzero":
> +double: 3
> +float: 3
> +
> +Function: Real part of "cexp_upward":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "cexp_upward":
> +double: 3
> +float: 2
> +
> +Function: Real part of "clog":
> +double: 3
> +float: 3
> +
> +Function: Imaginary part of "clog":
> +double: 1
> +float: 1
> +
> +Function: Real part of "clog10":
> +double: 3
> +float: 4
> +
> +Function: Imaginary part of "clog10":
> +double: 2
> +float: 2
> +
> +Function: Real part of "clog10_downward":
> +double: 7
> +float: 5
> +
> +Function: Imaginary part of "clog10_downward":
> +double: 8
> +float: 4
> +
> +Function: Real part of "clog10_towardzero":
> +double: 5
> +float: 5
> +
> +Function: Imaginary part of "clog10_towardzero":
> +double: 8
> +float: 4
> +
> +Function: Real part of "clog10_upward":
> +double: 6
> +float: 5
> +
> +Function: Imaginary part of "clog10_upward":
> +double: 5
> +float: 4
> +
> +Function: Real part of "clog_downward":
> +double: 4
> +float: 3
> +
> +Function: Imaginary part of "clog_downward":
> +double: 5
> +float: 2
> +
> +Function: Real part of "clog_towardzero":
> +double: 8
> +float: 4
> +
> +Function: Imaginary part of "clog_towardzero":
> +double: 5
> +float: 3
> +
> +Function: Real part of "clog_upward":
> +double: 8
> +float: 3
> +
> +Function: Imaginary part of "clog_upward":
> +double: 8
> +float: 2
> +
> +Function: "cos":
> +double: 1
> +float: 1
> +
> +Function: "cos_downward":
> +double: 1
> +float: 1
> +
> +Function: "cos_towardzero":
> +double: 4
> +float: 1
> +
> +Function: "cos_upward":
> +double: 4
> +float: 1
> +
> +Function: "cosh":
> +double: 2
> +float: 2
> +
> +Function: "cosh_downward":
> +double: 3
> +float: 1
> +
> +Function: "cosh_towardzero":
> +double: 3
> +float: 1
> +
> +Function: "cosh_upward":
> +double: 2
> +float: 2
> +
> +Function: Real part of "cpow":
> +double: 2
> +float: 5
> +
> +Function: Imaginary part of "cpow":
> +float: 2
> +
> +Function: Real part of "cpow_downward":
> +double: 5
> +float: 8
> +
> +Function: Imaginary part of "cpow_downward":
> +double: 2
> +float: 2
> +
> +Function: Real part of "cpow_towardzero":
> +double: 5
> +float: 8
> +
> +Function: Imaginary part of "cpow_towardzero":
> +double: 2
> +float: 2
> +
> +Function: Real part of "cpow_upward":
> +double: 4
> +float: 1
> +
> +Function: Imaginary part of "cpow_upward":
> +double: 2
> +float: 2
> +
> +Function: Real part of "csin":
> +double: 1
> +float: 1
> +
> +Function: Real part of "csin_downward":
> +double: 3
> +float: 3
> +
> +Function: Imaginary part of "csin_downward":
> +double: 3
> +float: 1
> +
> +Function: Real part of "csin_towardzero":
> +double: 3
> +float: 3
> +
> +Function: Imaginary part of "csin_towardzero":
> +double: 3
> +float: 1
> +
> +Function: Real part of "csin_upward":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "csin_upward":
> +double: 1
> +float: 2
> +
> +Function: Real part of "csinh":
> +float: 1
> +
> +Function: Imaginary part of "csinh":
> +double: 1
> +float: 1
> +
> +Function: Real part of "csinh_downward":
> +double: 3
> +float: 1
> +
> +Function: Imaginary part of "csinh_downward":
> +double: 3
> +float: 3
> +
> +Function: Real part of "csinh_towardzero":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "csinh_towardzero":
> +double: 3
> +float: 3
> +
> +Function: Real part of "csinh_upward":
> +double: 1
> +float: 2
> +
> +Function: Imaginary part of "csinh_upward":
> +double: 2
> +float: 2
> +
> +Function: Real part of "csqrt":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "csqrt":
> +double: 2
> +float: 2
> +
> +Function: Real part of "csqrt_downward":
> +double: 5
> +float: 4
> +
> +Function: Imaginary part of "csqrt_downward":
> +double: 4
> +float: 3
> +
> +Function: Real part of "csqrt_towardzero":
> +double: 4
> +float: 3
> +
> +Function: Imaginary part of "csqrt_towardzero":
> +double: 4
> +float: 3
> +
> +Function: Real part of "csqrt_upward":
> +double: 5
> +float: 4
> +
> +Function: Imaginary part of "csqrt_upward":
> +double: 3
> +float: 3
> +
> +Function: Real part of "ctan":
> +double: 1
> +float: 1
> +
> +Function: Imaginary part of "ctan":
> +double: 2
> +float: 2
> +
> +Function: Real part of "ctan_downward":
> +double: 6
> +float: 5
> +
> +Function: Imaginary part of "ctan_downward":
> +double: 3
> +float: 2
> +
> +Function: Real part of "ctan_towardzero":
> +double: 5
> +float: 3
> +
> +Function: Imaginary part of "ctan_towardzero":
> +double: 3
> +float: 2
> +
> +Function: Real part of "ctan_upward":
> +double: 2
> +float: 4
> +
> +Function: Imaginary part of "ctan_upward":
> +double: 2
> +float: 1
> +
> +Function: Real part of "ctanh":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "ctanh":
> +double: 2
> +float: 2
> +
> +Function: Real part of "ctanh_downward":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "ctanh_downward":
> +double: 6
> +float: 5
> +
> +Function: Real part of "ctanh_towardzero":
> +double: 3
> +float: 2
> +
> +Function: Imaginary part of "ctanh_towardzero":
> +double: 5
> +float: 3
> +
> +Function: Real part of "ctanh_upward":
> +double: 2
> +float: 2
> +
> +Function: Imaginary part of "ctanh_upward":
> +double: 2
> +float: 3
> +
> +Function: "erf":
> +double: 1
> +float: 1
> +
> +Function: "erf_downward":
> +double: 1
> +float: 1
> +
> +Function: "erf_towardzero":
> +double: 1
> +float: 1
> +
> +Function: "erf_upward":
> +double: 1
> +float: 1
> +
> +Function: "erfc":
> +double: 5
> +float: 3
> +
> +Function: "erfc_downward":
> +double: 5
> +float: 6
> +
> +Function: "erfc_towardzero":
> +double: 3
> +float: 4
> +
> +Function: "erfc_upward":
> +double: 5
> +float: 6
> +
> +Function: "exp":
> +double: 1
> +float: 1
> +
> +Function: "exp10":
> +double: 2
> +float: 1
> +
> +Function: "exp10_downward":
> +double: 3
> +float: 1
> +
> +Function: "exp10_towardzero":
> +double: 3
> +float: 1
> +
> +Function: "exp10_upward":
> +double: 2
> +float: 1
> +
> +Function: "exp2":
> +double: 1
> +
> +Function: "exp2_downward":
> +double: 1
> +
> +Function: "exp2_towardzero":
> +double: 1
> +
> +Function: "exp2_upward":
> +double: 1
> +float: 1
> +
> +Function: "exp_downward":
> +double: 1
> +float: 1
> +
> +Function: "exp_towardzero":
> +double: 1
> +float: 1
> +
> +Function: "exp_upward":
> +double: 1
> +float: 1
> +
> +Function: "expm1":
> +double: 1
> +float: 1
> +
> +Function: "expm1_downward":
> +double: 1
> +float: 1
> +
> +Function: "expm1_towardzero":
> +double: 1
> +float: 2
> +
> +Function: "expm1_upward":
> +double: 1
> +float: 1
> +
> +Function: "gamma":
> +double: 4
> +float: 7
> +
> +Function: "gamma_downward":
> +double: 7
> +float: 7
> +
> +Function: "gamma_towardzero":
> +double: 7
> +float: 7
> +
> +Function: "gamma_upward":
> +double: 5
> +float: 6
> +
> +Function: "hypot":
> +double: 1
> +float: 1
> +
> +Function: "hypot_downward":
> +double: 1
> +
> +Function: "hypot_towardzero":
> +double: 1
> +
> +Function: "hypot_upward":
> +double: 1
> +
> +Function: "j0":
> +double: 2
> +float: 9
> +
> +Function: "j0_downward":
> +double: 5
> +float: 9
> +
> +Function: "j0_towardzero":
> +double: 6
> +float: 9
> +
> +Function: "j0_upward":
> +double: 9
> +float: 9
> +
> +Function: "j1":
> +double: 4
> +float: 9
> +
> +Function: "j1_downward":
> +double: 5
> +float: 8
> +
> +Function: "j1_towardzero":
> +double: 4
> +float: 8
> +
> +Function: "j1_upward":
> +double: 9
> +float: 9
> +
> +Function: "jn":
> +double: 4
> +float: 4
> +
> +Function: "jn_downward":
> +double: 7
> +float: 9
> +
> +Function: "jn_towardzero":
> +double: 7
> +float: 9
> +
> +Function: "jn_upward":
> +double: 7
> +float: 9
> +
> +Function: "lgamma":
> +double: 4
> +float: 7
> +
> +Function: "lgamma_downward":
> +double: 7
> +float: 7
> +
> +Function: "lgamma_towardzero":
> +double: 7
> +float: 7
> +
> +Function: "lgamma_upward":
> +double: 5
> +float: 6
> +
> +Function: "log10":
> +double: 2
> +float: 2
> +
> +Function: "log10_downward":
> +double: 2
> +float: 3
> +
> +Function: "log10_towardzero":
> +double: 2
> +float: 1
> +
> +Function: "log10_upward":
> +double: 2
> +float: 2
> +
> +Function: "log1p":
> +double: 1
> +float: 1
> +
> +Function: "log1p_downward":
> +double: 2
> +float: 2
> +
> +Function: "log1p_towardzero":
> +double: 2
> +float: 2
> +
> +Function: "log1p_upward":
> +double: 2
> +float: 2
> +
> +Function: "log2":
> +float: 1
> +
> +Function: "log2_downward":
> +double: 1
> +
> +Function: "log2_towardzero":
> +double: 1
> +
> +Function: "log2_upward":
> +double: 1
> +
> +Function: "pow":
> +double: 1
> +
> +Function: "pow_downward":
> +double: 1
> +float: 1
> +
> +Function: "pow_towardzero":
> +double: 1
> +float: 1
> +
> +Function: "pow_upward":
> +double: 1
> +float: 1
> +
> +Function: "sin":
> +double: 1
> +float: 1
> +
> +Function: "sin_downward":
> +double: 4
> +float: 1
> +
> +Function: "sin_towardzero":
> +double: 3
> +float: 1
> +
> +Function: "sin_upward":
> +double: 7
> +float: 1
> +
> +Function: "sincos":
> +double: 1
> +
> +Function: "sincos_downward":
> +double: 1
> +float: 1
> +
> +Function: "sincos_towardzero":
> +double: 4
> +float: 1
> +
> +Function: "sincos_upward":
> +double: 1
> +float: 1
> +
> +Function: "sinh":
> +double: 2
> +float: 2
> +
> +Function: "sinh_downward":
> +double: 3
> +float: 3
> +
> +Function: "sinh_towardzero":
> +double: 3
> +float: 2
> +
> +Function: "sinh_upward":
> +double: 3
> +float: 3
> +
> +Function: "tan":
> +float: 1
> +
> +Function: "tan_downward":
> +double: 1
> +float: 2
> +
> +Function: "tan_towardzero":
> +double: 1
> +float: 1
> +
> +Function: "tan_upward":
> +double: 1
> +float: 1
> +
> +Function: "tanh":
> +double: 2
> +float: 2
> +
> +Function: "tanh_downward":
> +double: 3
> +float: 3
> +
> +Function: "tanh_towardzero":
> +double: 2
> +float: 2
> +
> +Function: "tanh_upward":
> +double: 3
> +float: 3
> +
> +Function: "tgamma":
> +double: 9
> +float: 8
> +
> +Function: "tgamma_downward":
> +double: 9
> +float: 9
> +
> +Function: "tgamma_towardzero":
> +double: 9
> +float: 8
> +
> +Function: "tgamma_upward":
> +double: 9
> +float: 8
> +
> +Function: "y0":
> +double: 3
> +float: 9
> +
> +Function: "y0_downward":
> +double: 3
> +float: 9
> +
> +Function: "y0_towardzero":
> +double: 4
> +float: 9
> +
> +Function: "y0_upward":
> +double: 3
> +float: 9
> +
> +Function: "y1":
> +double: 3
> +float: 9
> +
> +Function: "y1_downward":
> +double: 6
> +float: 9
> +
> +Function: "y1_towardzero":
> +double: 3
> +float: 9
> +
> +Function: "y1_upward":
> +double: 7
> +float: 9
> +
> +Function: "yn":
> +double: 3
> +float: 3
> +
> +Function: "yn_downward":
> +double: 6
> +float: 8
> +
> +Function: "yn_towardzero":
> +double: 8
> +float: 8
> +
> +Function: "yn_upward":
> +double: 8
> +float: 8
> +
> +# end of automatic generation
> diff --git a/sysdeps/or1k/fpu/libm-test-ulps-name b/sysdeps/or1k/fpu/libm-test-ulps-name
> new file mode 100644
> index 0000000000..7f72f7a873
> --- /dev/null
> +++ b/sysdeps/or1k/fpu/libm-test-ulps-name
> @@ -0,0 +1 @@
> +OpenRISC hard-float
> diff --git a/sysdeps/or1k/fpu_control.h b/sysdeps/or1k/fpu_control.h
> new file mode 100644
> index 0000000000..4ac03db7a9
> --- /dev/null
> +++ b/sysdeps/or1k/fpu_control.h
> @@ -0,0 +1,61 @@
> +/* FPU control word bits.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library.  If not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _FPU_CONTROL_H
> +#define _FPU_CONTROL_H
> +
> +#ifndef __or1k_hard_float__
> +
> +# define _FPU_RESERVED 0xffffffff
> +# define _FPU_DEFAULT  0x00000000
> +# define _FPU_GETCW(cw) (cw) = 0
> +# define _FPU_SETCW(cw) (void) (cw)
> +
> +#else /* __or1k_hard_float__ */
> +
> +/* Layout of FPCSR:
> +
> + +-----------+----------------------------+-----+----+
> + |  32 - 12  | 11 10  9  8  7  6  5  4  3 | 2-1 |  0 |
> + +-----------+----------------------------+-----+----+
> + |  Reserved | DZ IN IV IX  Z QN SN UN OV | RM  | EE |
> + +-----------+----------------------------+-----+----+
> +
> + */
> +
> +# define _FPU_RESERVED 0xfffff000
> +/* Default: rounding to nearest with exceptions disabled.  */
> +# define _FPU_DEFAULT  0
> +/* IEEE: Same as above with exceptions enabled.  */
> +# define _FPU_IEEE     (_FPU_DEFAULT | 1)
> +
> +# define _FPU_FPCSR_RM_MASK (0x3 << 1)
> +
> +/* Macros for accessing the hardware control word.  */
> +# define _FPU_GETCW(cw) __asm__ volatile ("l.mfspr %0,r0,20" : "=r" (cw))
> +# define _FPU_SETCW(cw) __asm__ volatile ("l.mtspr r0,%0,20" : : "r" (cw))
> +
> +#endif /* __or1k_hard_float__ */
> +
> +/* Type of the control word.  */
> +typedef unsigned int fpu_control_t;
> +
> +/* Default control word set at startup.  */
> +extern fpu_control_t __fpu_control;
> +
> +#endif	/* fpu_control.h */
> diff --git a/sysdeps/or1k/libm-test-ulps-name b/sysdeps/or1k/libm-test-ulps-name
> deleted file mode 100644
> index 0af6591fd9..0000000000
> --- a/sysdeps/or1k/libm-test-ulps-name
> +++ /dev/null
> @@ -1 +0,0 @@
> -OpenRISC
> diff --git a/sysdeps/or1k/math-tests-snan-payload.h b/sysdeps/or1k/math-tests-snan-payload.h
> new file mode 100644
> index 0000000000..62467a371c
> --- /dev/null
> +++ b/sysdeps/or1k/math-tests-snan-payload.h
> @@ -0,0 +1,26 @@
> +/* Configuration for math tests: sNaN payloads.  OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef OR1K_MATH_TESTS_SNAN_PAYLOAD_H
> +#define OR1K_MATH_TESTS_SNAN_PAYLOAD_H 1
> +
> +/* OpenRISC floating-point instructions do not preserve NaN
> +   payloads.  */
> +#define SNAN_TESTS_PRESERVE_PAYLOAD	0
> +
> +#endif /* math-tests-snan-payload.h */
> diff --git a/sysdeps/or1k/math-tests-trap.h b/sysdeps/or1k/math-tests-trap.h
> new file mode 100644
> index 0000000000..a95b42d66d
> --- /dev/null
> +++ b/sysdeps/or1k/math-tests-trap.h
> @@ -0,0 +1,27 @@
> +/* Configuration for math tests: support for enabling exception traps.
> +   OpenRISC version.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef OR1K_MATH_TESTS_TRAP_H
> +#define OR1K_MATH_TESTS_TRAP_H 1
> +
> +#include <fenv.h>
> +
> +#define EXCEPTION_ENABLE_SUPPORTED(EXCEPT)	((EXCEPT) == 0)
> +
> +#endif /* math-tests-trap.h */
> diff --git a/sysdeps/or1k/libm-test-ulps b/sysdeps/or1k/nofpu/libm-test-ulps
> similarity index 100%
> rename from sysdeps/or1k/libm-test-ulps
> rename to sysdeps/or1k/nofpu/libm-test-ulps
> diff --git a/sysdeps/or1k/nofpu/libm-test-ulps-name b/sysdeps/or1k/nofpu/libm-test-ulps-name
> new file mode 100644
> index 0000000000..76c66a0e53
> --- /dev/null
> +++ b/sysdeps/or1k/nofpu/libm-test-ulps-name
> @@ -0,0 +1 @@
> +OpenRISC soft-float
> diff --git a/sysdeps/or1k/sfp-machine.h b/sysdeps/or1k/sfp-machine.h
> index d17fd37730..e58e683969 100644
> --- a/sysdeps/or1k/sfp-machine.h
> +++ b/sysdeps/or1k/sfp-machine.h
> @@ -36,7 +36,6 @@
>  #define _FP_MUL_MEAT_DW_Q(R,X,Y)				\
>    _FP_MUL_MEAT_DW_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
>  
> -
>  #define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_loop(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)
> @@ -90,4 +89,21 @@
>  
>  #define FP_ROUNDMODE (_fpcsr & FP_RND_MASK)
>  
> +#ifdef __or1k_hard_float__
> +#define FP_INIT_ROUNDMODE					\
> +do {								\
> +  __asm__ volatile ("l.mfspr %0,r0,20" : "=r" (_fpcsr));	\
> +} while (0)
> +
> +#define FP_HANDLE_EXCEPTIONS					\
> +do {								\
> +  if (__builtin_expect (_fex, 0))				\
> +    {								\
> +      _fpcsr &= ~FP_EX_ALL;					\
> +      _fpcsr |= _fex;						\
> +      __asm__ volatile ("l.mtspr r0,%0,20" : : "r" (_fpcsr));	\
> +    }								\
> +} while (0)
> +#endif /* __or1k_hard_float__ */
> +
>  #define _FP_TININESS_AFTER_ROUNDING 0
> diff --git a/sysdeps/unix/sysv/linux/or1k/getcontext.S b/sysdeps/unix/sysv/linux/or1k/getcontext.S
> index a25b377bda..397b9e4c60 100644
> --- a/sysdeps/unix/sysv/linux/or1k/getcontext.S
> +++ b/sysdeps/unix/sysv/linux/or1k/getcontext.S
> @@ -46,6 +46,12 @@ ENTRY(__getcontext)
>  	l.sw	(UCONTEXT_MCONTEXT + 28*4)(r3), r28
>  	l.sw	(UCONTEXT_MCONTEXT + 30*4)(r3), r30
>  
> +#ifdef __or1k_hard_float__
> +	/* Store the floating point state.  */
> +	l.mfspr	r4, r0, 20
> +	l.sw	(MCONTEXT_FPCSR)(r3), r4
> +#endif /* __or1k_hard_float__ */
> +
>  	/* Get signal mask.  */
>  	/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
>  	l.ori	r6, r0, _NSIG8
> diff --git a/sysdeps/unix/sysv/linux/or1k/setcontext.S b/sysdeps/unix/sysv/linux/or1k/setcontext.S
> index d28a0ac0aa..4bf258b6f1 100644
> --- a/sysdeps/unix/sysv/linux/or1k/setcontext.S
> +++ b/sysdeps/unix/sysv/linux/or1k/setcontext.S
> @@ -40,6 +40,12 @@ ENTRY(__setcontext)
>  	l.bf	1f
>  	 l.nop
>  
> +#ifdef __or1k_hard_float__
> +	/* Restore the floating point state.  */
> +	l.lwz	r28, (MCONTEXT_FPCSR)(r30)
> +	l.mtspr	r0, r28, 20
> +#endif /* __or1k_hard_float__ */
> +
>  	/* Restore argument registers, for the makecontext case.  */
>  	l.lwz	r3, (UCONTEXT_MCONTEXT +  3*4)(r30)
>  	l.lwz	r4, (UCONTEXT_MCONTEXT +  4*4)(r30)
> diff --git a/sysdeps/unix/sysv/linux/or1k/swapcontext.S b/sysdeps/unix/sysv/linux/or1k/swapcontext.S
> index d09651a5b2..dfc788812c 100644
> --- a/sysdeps/unix/sysv/linux/or1k/swapcontext.S
> +++ b/sysdeps/unix/sysv/linux/or1k/swapcontext.S
> @@ -45,6 +45,12 @@ ENTRY(__swapcontext)
>  	l.sw	(UCONTEXT_MCONTEXT + 28*4)(r3), r28
>  	l.sw	(UCONTEXT_MCONTEXT + 30*4)(r3), r30
>  
> +#ifdef __or1k_hard_float__
> +	/* Store the floating point state.  */
> +	l.mfspr	r6, r0, 20
> +	l.sw	(MCONTEXT_FPCSR)(r3), r6
> +#endif /* __or1k_hard_float__ */
> +
>  	/* Store ucp to non-argument syscall preserved register.  */
>  	l.ori	r30, r4, 0
>  
> @@ -82,6 +88,12 @@ ENTRY(__swapcontext)
>  	l.bf	1f
>  	 l.nop
>  
> +#ifdef __or1k_hard_float__
> +	/* Restore the floating point state.  */
> +	l.lwz	r28, (MCONTEXT_FPCSR)(r30)
> +	l.mtspr	r0, r28, 20
> +#endif /* __or1k_hard_float__ */
> +
>  	/* Restore argument registers, for the makecontext case.  */
>  	l.lwz	r3, (UCONTEXT_MCONTEXT +  3*4)(r30)
>  	l.lwz	r4, (UCONTEXT_MCONTEXT +  4*4)(r30)
> diff --git a/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h b/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h
> index b17e919154..1b428592ee 100644
> --- a/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h
> +++ b/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h
> @@ -38,6 +38,7 @@ typedef struct
>      unsigned long int __gprs[__NGREG];
>      unsigned long int __pc;
>      unsigned long int __sr;
> +    unsigned long int __fpcsr;
>    } mcontext_t;
>  
>  /* Userlevel context.  */
> diff --git a/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym b/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym
> index a8d4db080f..45cd72527d 100644
> --- a/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym
> +++ b/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym
> @@ -13,6 +13,7 @@ _NSIG8				(_NSIG / 8)
>  -- Offsets of the fields in the ucontext_t structure.
>  #define ucontext(member)	offsetof (ucontext_t, member)
>  #define stack(member)		ucontext (uc_stack.member)
> +#define mcontext(member)	ucontext (uc_mcontext.member)
>  
>  UCONTEXT_LINK			ucontext (uc_link)
>  UCONTEXT_STACK			ucontext (uc_stack)
> @@ -23,4 +24,6 @@ STACK_SP			stack (ss_sp)
>  STACK_SIZE			stack (ss_size)
>  STACK_FLAGS			stack (ss_flags)
>  
> +MCONTEXT_FPCSR			mcontext (__fpcsr)
> +
>  UCONTEXT_SIZE			sizeof (ucontext_t)
Richard Henderson April 16, 2024, 2:53 p.m. UTC | #2
On 4/16/24 07:04, Adhemerval Zanella Netto wrote:
> If I understond correctly the OpenRISC hard-float ABIs uses the same
> parameter passing ABI from soft-fp, similar of what ARM does with
> -mfloat-abi=softfp.  So the the shared objects built with/without
> -mhard-float should be interoperable, assuming hardware has hard-fp
> support.
> 
> However it does solve the potential problem a binary built with softfp
> loading a hardfp built shared object, or even trying to link with a
> static object with different ABI (and assuming a hardware without
> hard-fp support)..  It means that loader and ldconfig won't recognize
> shared objects with different floating-point objects if they are installed
> on the same system.
> 
> I don't think we have a strong policy regarding this, and historical
> there were ABI variants that followed this (like powerpc soft and hard),
> but most ABIs that support soft/hard floating-point usually advertise it
> through ElfXX_Ehdr::e_flags.
> 
> For instance, with arm:
> 
> $ cat << EOF > lib.c
> float foo_float (float x, float y)
> {
>    return x + y;
> }
> 
> double foo_double (double x, double y)
> {
>    return x + y;
> }
> EOF
> $ arm-glibc-linux-gnueabi-gcc -shared -o lib.so lib.c
> $ readelf -h lib.so | grep Flags
>    Flags:                             0x5000200, Version5 EABI, soft-float ABI
> $ arm-glibc-linux-gnueabihf-gcc -shared -o lib.so lib.c
> $ readelf -h lib.so | grep Flags
>    Flags:                             0x5000400, Version5 EABI, hard-float ABI

The typical reason for wanting an e_flags bit is because those architectures want the 
parameter passing to change when floating-point registers are available.

But for OpenRISC there is no separate floating-point register set.  All floating-point 
operations use the same general-purpose registers as for all integer operations.  So there 
is no point in a new parameter passing ABI.


r~
Adhemerval Zanella Netto April 16, 2024, 4:20 p.m. UTC | #3
On 16/04/24 11:53, Richard Henderson wrote:
> On 4/16/24 07:04, Adhemerval Zanella Netto wrote:
>> If I understond correctly the OpenRISC hard-float ABIs uses the same
>> parameter passing ABI from soft-fp, similar of what ARM does with
>> -mfloat-abi=softfp.  So the the shared objects built with/without
>> -mhard-float should be interoperable, assuming hardware has hard-fp
>> support.
>>
>> However it does solve the potential problem a binary built with softfp
>> loading a hardfp built shared object, or even trying to link with a
>> static object with different ABI (and assuming a hardware without
>> hard-fp support)..  It means that loader and ldconfig won't recognize
>> shared objects with different floating-point objects if they are installed
>> on the same system.
>>
>> I don't think we have a strong policy regarding this, and historical
>> there were ABI variants that followed this (like powerpc soft and hard),
>> but most ABIs that support soft/hard floating-point usually advertise it
>> through ElfXX_Ehdr::e_flags.
>>
>> For instance, with arm:
>>
>> $ cat << EOF > lib.c
>> float foo_float (float x, float y)
>> {
>>    return x + y;
>> }
>>
>> double foo_double (double x, double y)
>> {
>>    return x + y;
>> }
>> EOF
>> $ arm-glibc-linux-gnueabi-gcc -shared -o lib.so lib.c
>> $ readelf -h lib.so | grep Flags
>>    Flags:                             0x5000200, Version5 EABI, soft-float ABI
>> $ arm-glibc-linux-gnueabihf-gcc -shared -o lib.so lib.c
>> $ readelf -h lib.so | grep Flags
>>    Flags:                             0x5000400, Version5 EABI, hard-float ABI
> 
> The typical reason for wanting an e_flags bit is because those architectures want the parameter passing to change when floating-point registers are available.
> 
> But for OpenRISC there is no separate floating-point register set.  All floating-point operations use the same general-purpose registers as for all integer operations.  So there is no point in a new parameter passing ABI.

Right, it was not clear from patch without dig into the ABI documen
itself.  So the only thing I am not sure is the mcontext_t change.  
Other ABIs added a symbol version to proper handle it, so maybe 
OpenRISC would need something similar.
Richard Henderson April 16, 2024, 7:56 p.m. UTC | #4
On 4/16/24 09:20, Adhemerval Zanella Netto wrote:
> Right, it was not clear from patch without dig into the ABI documen
> itself.  So the only thing I am not sure is the mcontext_t change.
> Other ABIs added a symbol version to proper handle it, so maybe
> OpenRISC would need something similar.

Yes, I think some compat symbols are needed for getcontext et al, since the size of 
ucontext_t changes.

I think softfloat glibc should populate the same field (with zero, since neither 
exceptions nor rounding are supported).


r~
Stafford Horne April 16, 2024, 8:37 p.m. UTC | #5
On Tue, Apr 16, 2024 at 12:56:11PM -0700, Richard Henderson wrote:
> On 4/16/24 09:20, Adhemerval Zanella Netto wrote:
> > Right, it was not clear from patch without dig into the ABI documen
> > itself.  So the only thing I am not sure is the mcontext_t change.
> > Other ABIs added a symbol version to proper handle it, so maybe
> > OpenRISC would need something similar.
> 
> Yes, I think some compat symbols are needed for getcontext et al, since the
> size of ucontext_t changes.

Just to re-iterate, the size of ucontext_t provided by the kernel never changed.

But the change of ucontext_t in glibc changing causes issues.

With the glibc ucontext_t size change there will be a problem with running
old compiled applications on new versions of glibc if this hard-float series is
added as is.  I will see if we can add some versioning to ensure binaries will
not break when running on new glibc versions after this series.

> I think softfloat glibc should populate the same field (with zero, since
> neither exceptions nor rounding are supported).

Let me double check this is the case.

-Stafford
diff mbox series

Patch

diff --git a/sysdeps/or1k/fpu/fclrexcpt.c b/sysdeps/or1k/fpu/fclrexcpt.c
new file mode 100644
index 0000000000..44224f9c24
--- /dev/null
+++ b/sysdeps/or1k/fpu/fclrexcpt.c
@@ -0,0 +1,44 @@ 
+/* Clear given exceptions in current floating-point environment.
+   OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+int
+feclearexcept (int excepts)
+{
+  fpu_control_t cw;
+  fpu_control_t cw_new;
+
+  /* Mask out unsupported bits/exceptions.  */
+  excepts &= FE_ALL_EXCEPT;
+
+  /* Read the complete control word.  */
+  _FPU_GETCW (cw);
+
+  cw_new = cw & ~excepts;
+
+  /* Put the new data in effect.  */
+  if (cw != cw_new)
+    _FPU_SETCW (cw_new);
+
+  /* Success.  */
+  return 0;
+}
+libm_hidden_def (feclearexcept)
diff --git a/sysdeps/or1k/fpu/fegetenv.c b/sysdeps/or1k/fpu/fegetenv.c
new file mode 100644
index 0000000000..70c75aa0bf
--- /dev/null
+++ b/sysdeps/or1k/fpu/fegetenv.c
@@ -0,0 +1,32 @@ 
+/* Store current floating-point environment.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+int
+__fegetenv (fenv_t *envp)
+{
+  _FPU_GETCW (*envp);
+
+  /* Success.  */
+  return 0;
+}
+libm_hidden_def (__fegetenv)
+weak_alias (__fegetenv, fegetenv)
+libm_hidden_weak (fegetenv)
diff --git a/sysdeps/or1k/fpu/fegetmode.c b/sysdeps/or1k/fpu/fegetmode.c
new file mode 100644
index 0000000000..7fffd2e0b5
--- /dev/null
+++ b/sysdeps/or1k/fpu/fegetmode.c
@@ -0,0 +1,29 @@ 
+/* Store current floating-point control modes.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+int
+fegetmode (femode_t *modep)
+{
+  _FPU_GETCW (*modep);
+
+  /* Success.  */
+  return 0;
+}
diff --git a/sysdeps/or1k/fpu/fegetround.c b/sysdeps/or1k/fpu/fegetround.c
new file mode 100644
index 0000000000..7e993b980a
--- /dev/null
+++ b/sysdeps/or1k/fpu/fegetround.c
@@ -0,0 +1,29 @@ 
+/* Return current rounding direction.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <get-rounding-mode.h>
+
+int
+__fegetround (void)
+{
+  return get_rounding_mode ();
+}
+libm_hidden_def (__fegetround)
+weak_alias (__fegetround, fegetround)
+libm_hidden_weak (fegetround)
diff --git a/sysdeps/or1k/fpu/feholdexcpt.c b/sysdeps/or1k/fpu/feholdexcpt.c
new file mode 100644
index 0000000000..0036e41ba2
--- /dev/null
+++ b/sysdeps/or1k/fpu/feholdexcpt.c
@@ -0,0 +1,33 @@ 
+/* Store current floating-point environment and clear exceptions.
+   OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fenv_private.h>
+
+int
+__feholdexcept (fenv_t *envp)
+{
+  libc_feholdexcept_or1k (envp);
+
+  /* Success.  */
+  return 0;
+}
+libm_hidden_def (__feholdexcept)
+weak_alias (__feholdexcept, feholdexcept)
+libm_hidden_weak (feholdexcept)
diff --git a/sysdeps/or1k/fpu/fenv_private.h b/sysdeps/or1k/fpu/fenv_private.h
new file mode 100644
index 0000000000..4f401e7a5a
--- /dev/null
+++ b/sysdeps/or1k/fpu/fenv_private.h
@@ -0,0 +1,199 @@ 
+/* Private floating point rounding and exceptions handling.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef OR1K_FENV_PRIVATE_H
+#define OR1K_FENV_PRIVATE_H 1
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+static __always_inline void
+libc_feholdexcept_or1k (fenv_t *envp)
+{
+  fpu_control_t cw;
+  fpu_control_t cw_new;
+
+  /* Get and store the environment.  */
+  _FPU_GETCW (cw);
+  *envp = cw;
+
+  /* Clear the exception status flags.  */
+  cw_new = cw & ~FE_ALL_EXCEPT;
+
+  if (cw != cw_new)
+    _FPU_SETCW (cw_new);
+}
+
+#define libc_feholdexcept  libc_feholdexcept_or1k
+#define libc_feholdexceptf libc_feholdexcept_or1k
+#define libc_feholdexceptl libc_feholdexcept_or1k
+
+static __always_inline void
+libc_fesetround_or1k (int round)
+{
+  fpu_control_t cw;
+  fpu_control_t cw_new;
+
+  _FPU_GETCW (cw);
+  cw_new = cw & ~_FPU_FPCSR_RM_MASK;
+  cw_new |= round;
+  if (cw != cw_new)
+    _FPU_SETCW (cw_new);
+}
+
+#define libc_fesetround  libc_fesetround_or1k
+#define libc_fesetroundf libc_fesetround_or1k
+#define libc_fesetroundl libc_fesetround_or1k
+
+static __always_inline void
+libc_feholdexcept_setround_or1k (fenv_t *envp, int round)
+{
+  fpu_control_t cw;
+  fpu_control_t cw_new;
+
+  /* Get and store the environment.  */
+  _FPU_GETCW (cw);
+  *envp = cw;
+
+  /* Clear the status flags and rounding mode.  */
+  cw_new = cw & ~(FE_ALL_EXCEPT | _FPU_FPCSR_RM_MASK);
+
+  /* Set rounding mode.  */
+  cw_new |= round;
+
+  if (cw != cw_new)
+    _FPU_SETCW (cw_new);
+}
+
+#define libc_feholdexcept_setround  libc_feholdexcept_setround_or1k
+#define libc_feholdexcept_setroundf libc_feholdexcept_setround_or1k
+#define libc_feholdexcept_setroundl libc_feholdexcept_setround_or1k
+
+static __always_inline int
+libc_fetestexcept_or1k (int ex)
+{
+  fpu_control_t cw;
+
+  /* Get current control word.  */
+  _FPU_GETCW (cw);
+
+  /* Check if any of the queried exception flags are set.  */
+  return cw & ex & FE_ALL_EXCEPT;
+}
+
+#define libc_fetestexcept  libc_fetestexcept_or1k
+#define libc_fetestexceptf libc_fetestexcept_or1k
+#define libc_fetestexceptl libc_fetestexcept_or1k
+
+static __always_inline void
+libc_fesetenv_or1k (const fenv_t *envp)
+{
+  if (envp == FE_DFL_ENV)
+    _FPU_SETCW (_FPU_DEFAULT);
+  else
+    _FPU_SETCW (*envp);
+}
+
+#define libc_fesetenv  libc_fesetenv_or1k
+#define libc_fesetenvf libc_fesetenv_or1k
+#define libc_fesetenvl libc_fesetenv_or1k
+#define libc_feresetround_noex  libc_fesetenv_or1k
+#define libc_feresetround_noexf libc_fesetenv_or1k
+#define libc_feresetround_noexl libc_fesetenv_or1k
+
+static __always_inline int
+libc_feupdateenv_test_or1k (const fenv_t *envp, int ex)
+{
+  fpu_control_t cw;
+  fpu_control_t cw_new;
+  int excepts;
+
+  /* Get current control word.  */
+  _FPU_GETCW (cw);
+
+  /* Merge current exception flags with the passed fenv.  */
+  excepts = cw & FE_ALL_EXCEPT;
+  cw_new = (envp == FE_DFL_ENV ? _FPU_DEFAULT : *envp) | excepts;
+
+  if (__glibc_unlikely (cw != cw_new))
+    _FPU_SETCW (cw_new);
+
+  /* Raise the exceptions if enabled in the new FP state.  */
+  if (__glibc_unlikely (excepts))
+    __feraiseexcept (excepts);
+
+  return excepts & ex;
+}
+
+#define libc_feupdateenv_test  libc_feupdateenv_test_or1k
+#define libc_feupdateenv_testf libc_feupdateenv_test_or1k
+#define libc_feupdateenv_testl libc_feupdateenv_test_or1k
+
+static __always_inline void
+libc_feupdateenv_or1k (const fenv_t *envp)
+{
+  libc_feupdateenv_test_or1k (envp, 0);
+}
+
+#define libc_feupdateenv  libc_feupdateenv_or1k
+#define libc_feupdateenvf libc_feupdateenv_or1k
+#define libc_feupdateenvl libc_feupdateenv_or1k
+
+static __always_inline void
+libc_feholdsetround_or1k (fenv_t *envp, int round)
+{
+  fpu_control_t cw;
+
+  _FPU_GETCW (cw);
+  *envp = cw;
+
+  /* Check whether rounding modes are different.  */
+  round = (cw ^ round) & _FPU_FPCSR_RM_MASK;
+
+  /* Set new rounding mode if different.  */
+  if (__glibc_unlikely (round != 0))
+    _FPU_SETCW (cw ^ round);
+}
+
+#define libc_feholdsetround  libc_feholdsetround_or1k
+#define libc_feholdsetroundf libc_feholdsetround_or1k
+#define libc_feholdsetroundl libc_feholdsetround_or1k
+
+static __always_inline void
+libc_feresetround_or1k (fenv_t *envp)
+{
+  fpu_control_t cw;
+  int round;
+
+  _FPU_GETCW (cw);
+
+  /* Check whether rounding modes are different.  */
+  round = (*envp ^ cw) & _FPU_FPCSR_RM_MASK;
+
+  /* Restore the rounding mode if it was changed.  */
+  if (__glibc_unlikely (round != 0))
+    _FPU_SETCW (cw ^ round);
+}
+
+#define libc_feresetround  libc_feresetround_or1k
+#define libc_feresetroundf libc_feresetround_or1k
+#define libc_feresetroundl libc_feresetround_or1k
+
+#include_next <fenv_private.h>
+
+#endif
diff --git a/sysdeps/or1k/fpu/fesetenv.c b/sysdeps/or1k/fpu/fesetenv.c
new file mode 100644
index 0000000000..742ca719e0
--- /dev/null
+++ b/sysdeps/or1k/fpu/fesetenv.c
@@ -0,0 +1,32 @@ 
+/* Install given floating-point environment.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fenv_private.h>
+
+int
+__fesetenv (const fenv_t *envp)
+{
+  libc_fesetenv_or1k (envp);
+
+  /* Success.  */
+  return 0;
+}
+libm_hidden_def (__fesetenv)
+weak_alias (__fesetenv, fesetenv)
+libm_hidden_weak (fesetenv)
diff --git a/sysdeps/or1k/fpu/fesetexcept.c b/sysdeps/or1k/fpu/fesetexcept.c
new file mode 100644
index 0000000000..43734eac18
--- /dev/null
+++ b/sysdeps/or1k/fpu/fesetexcept.c
@@ -0,0 +1,35 @@ 
+/* Set given exception flags.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+int
+fesetexcept (int excepts)
+{
+  fpu_control_t cw;
+  fpu_control_t cw_new;
+
+  _FPU_GETCW (cw);
+  cw_new = cw | (excepts & FE_ALL_EXCEPT);
+  if (cw != cw_new)
+    _FPU_SETCW (cw_new);
+
+  /* Success.  */
+  return 0;
+}
diff --git a/sysdeps/or1k/fpu/fesetmode.c b/sysdeps/or1k/fpu/fesetmode.c
new file mode 100644
index 0000000000..d4556927ce
--- /dev/null
+++ b/sysdeps/or1k/fpu/fesetmode.c
@@ -0,0 +1,39 @@ 
+/* Install given floating-point control modes.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+int
+fesetmode (const femode_t *modep)
+{
+  fpu_control_t cw;
+  fpu_control_t cw_new;
+
+  _FPU_GETCW (cw);
+  cw_new = cw & ~_FPU_FPCSR_RM_MASK;
+  if (modep == FE_DFL_MODE)
+    cw_new |= (_FPU_DEFAULT & _FPU_FPCSR_RM_MASK);
+  else
+    cw_new |= (*modep & _FPU_FPCSR_RM_MASK);
+  if (cw != cw_new)
+    _FPU_SETCW (cw_new);
+
+  /* Success.  */
+  return 0;
+}
diff --git a/sysdeps/or1k/fpu/fesetround.c b/sysdeps/or1k/fpu/fesetround.c
new file mode 100644
index 0000000000..c2ada98f1b
--- /dev/null
+++ b/sysdeps/or1k/fpu/fesetround.c
@@ -0,0 +1,39 @@ 
+/* Set current rounding direction.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fenv_private.h>
+
+int
+__fesetround (int round)
+{
+  switch (round)
+    {
+    case FE_TONEAREST:
+    case FE_TOWARDZERO:
+    case FE_DOWNWARD:
+    case FE_UPWARD:
+      libc_fesetround_or1k (round);
+      return 0;
+    default:
+      return round; /* A nonzero value.  */
+    }
+}
+libm_hidden_def (__fesetround)
+weak_alias (__fesetround, fesetround)
+libm_hidden_weak (fesetround)
diff --git a/sysdeps/or1k/fpu/feupdateenv.c b/sysdeps/or1k/fpu/feupdateenv.c
new file mode 100644
index 0000000000..3355bf6596
--- /dev/null
+++ b/sysdeps/or1k/fpu/feupdateenv.c
@@ -0,0 +1,33 @@ 
+/* Install given floating-point environment and raise exceptions.
+   OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fenv_private.h>
+
+int
+__feupdateenv (const fenv_t *envp)
+{
+  libc_feupdateenv_or1k (envp);
+
+  /* Success.  */
+  return 0;
+}
+libm_hidden_def (__feupdateenv)
+weak_alias (__feupdateenv, feupdateenv)
+libm_hidden_weak (feupdateenv)
diff --git a/sysdeps/or1k/fpu/fgetexcptflg.c b/sysdeps/or1k/fpu/fgetexcptflg.c
new file mode 100644
index 0000000000..a954f6a2f1
--- /dev/null
+++ b/sysdeps/or1k/fpu/fgetexcptflg.c
@@ -0,0 +1,29 @@ 
+/* Store current state of exceptions.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fenv_private.h>
+
+int
+fegetexceptflag (fexcept_t *flagp, int excepts)
+{
+  *flagp = libc_fetestexcept_or1k (excepts);
+
+  /* Success.  */
+  return 0;
+}
diff --git a/sysdeps/or1k/fpu/fix-fp-int-convert-overflow.h b/sysdeps/or1k/fpu/fix-fp-int-convert-overflow.h
new file mode 100644
index 0000000000..78104289c0
--- /dev/null
+++ b/sysdeps/or1k/fpu/fix-fp-int-convert-overflow.h
@@ -0,0 +1,38 @@ 
+/* Fix for conversion of floating point to integer overflow.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef FIX_FP_INT_CONVERT_OVERFLOW_H
+#define FIX_FP_INT_CONVERT_OVERFLOW_H	1
+
+/* The generic libgcc2.c conversions from floating point to long long
+   may not raise the correct exceptions on overflow (and may raise
+   spurious "inexact" exceptions even in non-overflow cases, see
+   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59412>).  */
+#define FIX_FLT_LONG_CONVERT_OVERFLOW 0
+#define FIX_FLT_LLONG_CONVERT_OVERFLOW 1
+
+#define FIX_DBL_LONG_CONVERT_OVERFLOW 0
+#define FIX_DBL_LLONG_CONVERT_OVERFLOW 1
+
+#define FIX_LDBL_LONG_CONVERT_OVERFLOW 0
+#define FIX_LDBL_LLONG_CONVERT_OVERFLOW 0
+
+#define FIX_FLT128_LONG_CONVERT_OVERFLOW 0
+#define FIX_FLT128_LLONG_CONVERT_OVERFLOW 0
+
+#endif /* fix-fp-int-convert-overflow.h */
diff --git a/sysdeps/or1k/fpu/fraiseexcpt.c b/sysdeps/or1k/fpu/fraiseexcpt.c
new file mode 100644
index 0000000000..bbacfd50bc
--- /dev/null
+++ b/sysdeps/or1k/fpu/fraiseexcpt.c
@@ -0,0 +1,67 @@ 
+/* Raise given exceptions.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include <float.h>
+#include <math.h>
+
+int
+__feraiseexcept (int excepts)
+{
+  if (excepts == 0)
+    return 0;
+
+  /* Raise exceptions represented by EXPECTS.  */
+
+  if (excepts & FE_INEXACT)
+  {
+    float d = 1.0, x = 3.0;
+    __asm__ volatile ("lf.div.s %0, %0, %1" : "+r" (d) : "r" (x));
+  }
+
+  if (excepts & FE_UNDERFLOW)
+  {
+    float d = FLT_MIN;
+    __asm__ volatile ("lf.mul.s %0, %0, %0" : "+r" (d));
+  }
+
+  if (excepts & FE_OVERFLOW)
+  {
+    float d = FLT_MAX;
+    __asm__ volatile ("lf.mul.s %0, %0, %0" : "+r" (d) : "r" (d));
+  }
+
+  if (excepts & FE_DIVBYZERO)
+  {
+    float d = 1.0, x = 0.0;
+    __asm__ volatile ("lf.div.s %0, %0, %1" : "+r" (d) : "r" (x));
+  }
+
+  if (excepts & FE_INVALID)
+  {
+    float d = HUGE_VAL, x = 0.0;
+    __asm__ volatile ("lf.mul.s %0, %1, %0" : "+r" (d) : "r" (x));
+  }
+
+  /* Success.  */
+  return 0;
+}
+libm_hidden_def (__feraiseexcept)
+weak_alias (__feraiseexcept, feraiseexcept)
+libm_hidden_weak (feraiseexcept)
diff --git a/sysdeps/or1k/fpu/fsetexcptflg.c b/sysdeps/or1k/fpu/fsetexcptflg.c
new file mode 100644
index 0000000000..c327e4c5d1
--- /dev/null
+++ b/sysdeps/or1k/fpu/fsetexcptflg.c
@@ -0,0 +1,43 @@ 
+/* Set floating-point environment exception handling.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+int
+fesetexceptflag (const fexcept_t *flagp, int excepts)
+{
+  fpu_control_t cw;
+  fpu_control_t cw_new;
+
+  /* Get the current exceptions.  */
+  _FPU_GETCW (cw);
+
+  /* Make sure the flags we want restored are legal.  */
+  excepts &= FE_ALL_EXCEPT;
+
+  /* Now set selected bits from flagp. Note that we ignore all non-flag
+     bits from *flagp, so they don't matter.  */
+  cw_new = (cw & ~excepts) | (*flagp & excepts);
+
+  if (cw != cw_new)
+    _FPU_SETCW (cw_new);
+
+  /* Success.  */
+  return 0;
+}
diff --git a/sysdeps/or1k/fpu/ftestexcept.c b/sysdeps/or1k/fpu/ftestexcept.c
new file mode 100644
index 0000000000..59f06afa22
--- /dev/null
+++ b/sysdeps/or1k/fpu/ftestexcept.c
@@ -0,0 +1,27 @@ 
+/* Test exception in current environment.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fenv_private.h>
+
+int
+fetestexcept (int excepts)
+{
+  return libc_fetestexcept_or1k (excepts);
+}
+libm_hidden_def (fetestexcept)
diff --git a/sysdeps/or1k/fpu/get-rounding-mode.h b/sysdeps/or1k/fpu/get-rounding-mode.h
new file mode 100644
index 0000000000..a66d553be8
--- /dev/null
+++ b/sysdeps/or1k/fpu/get-rounding-mode.h
@@ -0,0 +1,38 @@ 
+/* Determine floating-point rounding mode within libc.  OpenRISC version.
+
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _OR1K_GET_ROUNDING_MODE_H
+#define _OR1K_GET_ROUNDING_MODE_H	1
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+/* Return the floating-point rounding mode.  */
+
+static inline int
+get_rounding_mode (void)
+{
+  fpu_control_t cw;
+
+  _FPU_GETCW (cw);
+  return cw & _FPU_FPCSR_RM_MASK;
+}
+
+#endif /* get-rounding-mode.h */
diff --git a/sysdeps/or1k/fpu/libm-test-ulps b/sysdeps/or1k/fpu/libm-test-ulps
new file mode 100644
index 0000000000..948ec01cdc
--- /dev/null
+++ b/sysdeps/or1k/fpu/libm-test-ulps
@@ -0,0 +1,1115 @@ 
+# Begin of automatic generation
+
+# Maximal error of functions:
+Function: "acos":
+double: 1
+float: 1
+
+Function: "acos_downward":
+double: 1
+float: 1
+
+Function: "acos_towardzero":
+double: 1
+float: 1
+
+Function: "acos_upward":
+double: 1
+float: 1
+
+Function: "acosh":
+double: 2
+float: 2
+
+Function: "acosh_downward":
+double: 2
+float: 2
+
+Function: "acosh_towardzero":
+double: 2
+float: 2
+
+Function: "acosh_upward":
+double: 2
+float: 2
+
+Function: "asin":
+double: 1
+float: 1
+
+Function: "asin_downward":
+double: 1
+float: 1
+
+Function: "asin_towardzero":
+double: 1
+float: 1
+
+Function: "asin_upward":
+double: 2
+float: 1
+
+Function: "asinh":
+double: 2
+float: 2
+
+Function: "asinh_downward":
+double: 3
+float: 3
+
+Function: "asinh_towardzero":
+double: 2
+float: 2
+
+Function: "asinh_upward":
+double: 3
+float: 3
+
+Function: "atan":
+double: 1
+float: 1
+
+Function: "atan2":
+float: 2
+
+Function: "atan2_downward":
+double: 5
+float: 2
+
+Function: "atan2_towardzero":
+double: 5
+float: 2
+
+Function: "atan2_upward":
+double: 8
+float: 2
+
+Function: "atan_downward":
+double: 1
+float: 2
+
+Function: "atan_towardzero":
+double: 1
+float: 1
+
+Function: "atan_upward":
+double: 1
+float: 2
+
+Function: "atanh":
+double: 2
+float: 2
+
+Function: "atanh_downward":
+double: 3
+float: 3
+
+Function: "atanh_towardzero":
+double: 2
+float: 2
+
+Function: "atanh_upward":
+double: 3
+float: 3
+
+Function: "cabs":
+double: 1
+
+Function: "cabs_downward":
+double: 1
+
+Function: "cabs_towardzero":
+double: 1
+
+Function: "cabs_upward":
+double: 1
+
+Function: Real part of "cacos":
+double: 1
+float: 2
+
+Function: Imaginary part of "cacos":
+double: 2
+float: 2
+
+Function: Real part of "cacos_downward":
+double: 3
+float: 2
+
+Function: Imaginary part of "cacos_downward":
+double: 5
+float: 3
+
+Function: Real part of "cacos_towardzero":
+double: 3
+float: 2
+
+Function: Imaginary part of "cacos_towardzero":
+double: 4
+float: 2
+
+Function: Real part of "cacos_upward":
+double: 2
+float: 2
+
+Function: Imaginary part of "cacos_upward":
+double: 5
+float: 7
+
+Function: Real part of "cacosh":
+double: 2
+float: 2
+
+Function: Imaginary part of "cacosh":
+double: 1
+float: 2
+
+Function: Real part of "cacosh_downward":
+double: 4
+float: 2
+
+Function: Imaginary part of "cacosh_downward":
+double: 3
+float: 3
+
+Function: Real part of "cacosh_towardzero":
+double: 4
+float: 2
+
+Function: Imaginary part of "cacosh_towardzero":
+double: 3
+float: 2
+
+Function: Real part of "cacosh_upward":
+double: 4
+float: 3
+
+Function: Imaginary part of "cacosh_upward":
+double: 3
+float: 2
+
+Function: "carg":
+float: 1
+
+Function: "carg_downward":
+double: 5
+float: 2
+
+Function: "carg_towardzero":
+double: 5
+float: 2
+
+Function: "carg_upward":
+double: 8
+float: 2
+
+Function: Real part of "casin":
+double: 1
+float: 1
+
+Function: Imaginary part of "casin":
+double: 2
+float: 2
+
+Function: Real part of "casin_downward":
+double: 3
+float: 2
+
+Function: Imaginary part of "casin_downward":
+double: 5
+float: 3
+
+Function: Real part of "casin_towardzero":
+double: 3
+float: 1
+
+Function: Imaginary part of "casin_towardzero":
+double: 4
+float: 2
+
+Function: Real part of "casin_upward":
+double: 3
+float: 2
+
+Function: Imaginary part of "casin_upward":
+double: 5
+float: 7
+
+Function: Real part of "casinh":
+double: 2
+float: 2
+
+Function: Imaginary part of "casinh":
+double: 1
+float: 1
+
+Function: Real part of "casinh_downward":
+double: 5
+float: 3
+
+Function: Imaginary part of "casinh_downward":
+double: 3
+float: 2
+
+Function: Real part of "casinh_towardzero":
+double: 4
+float: 2
+
+Function: Imaginary part of "casinh_towardzero":
+double: 3
+float: 1
+
+Function: Real part of "casinh_upward":
+double: 5
+float: 7
+
+Function: Imaginary part of "casinh_upward":
+double: 3
+float: 2
+
+Function: Real part of "catan":
+double: 1
+float: 1
+
+Function: Imaginary part of "catan":
+double: 1
+float: 1
+
+Function: Real part of "catan_downward":
+double: 1
+float: 2
+
+Function: Imaginary part of "catan_downward":
+double: 2
+float: 2
+
+Function: Real part of "catan_towardzero":
+double: 1
+float: 2
+
+Function: Imaginary part of "catan_towardzero":
+double: 2
+float: 2
+
+Function: Real part of "catan_upward":
+double: 2
+float: 1
+
+Function: Imaginary part of "catan_upward":
+double: 2
+float: 2
+
+Function: Real part of "catanh":
+double: 1
+float: 1
+
+Function: Imaginary part of "catanh":
+double: 1
+float: 1
+
+Function: Real part of "catanh_downward":
+double: 2
+float: 2
+
+Function: Imaginary part of "catanh_downward":
+double: 1
+float: 2
+
+Function: Real part of "catanh_towardzero":
+double: 2
+float: 2
+
+Function: Imaginary part of "catanh_towardzero":
+double: 1
+float: 2
+
+Function: Real part of "catanh_upward":
+double: 4
+float: 4
+
+Function: Imaginary part of "catanh_upward":
+double: 2
+float: 1
+
+Function: "cbrt":
+double: 4
+float: 1
+
+Function: "cbrt_downward":
+double: 4
+float: 1
+
+Function: "cbrt_towardzero":
+double: 3
+float: 1
+
+Function: "cbrt_upward":
+double: 5
+float: 1
+
+Function: Real part of "ccos":
+double: 1
+float: 1
+
+Function: Imaginary part of "ccos":
+double: 1
+float: 1
+
+Function: Real part of "ccos_downward":
+double: 3
+float: 1
+
+Function: Imaginary part of "ccos_downward":
+double: 3
+float: 3
+
+Function: Real part of "ccos_towardzero":
+double: 3
+float: 2
+
+Function: Imaginary part of "ccos_towardzero":
+double: 3
+float: 3
+
+Function: Real part of "ccos_upward":
+double: 1
+float: 2
+
+Function: Imaginary part of "ccos_upward":
+double: 2
+float: 2
+
+Function: Real part of "ccosh":
+double: 2
+float: 1
+
+Function: Imaginary part of "ccosh":
+double: 1
+float: 1
+
+Function: Real part of "ccosh_downward":
+double: 3
+float: 2
+
+Function: Imaginary part of "ccosh_downward":
+double: 3
+float: 3
+
+Function: Real part of "ccosh_towardzero":
+double: 3
+float: 3
+
+Function: Imaginary part of "ccosh_towardzero":
+double: 3
+float: 3
+
+Function: Real part of "ccosh_upward":
+double: 1
+float: 2
+
+Function: Imaginary part of "ccosh_upward":
+double: 2
+float: 2
+
+Function: Real part of "cexp":
+double: 2
+float: 1
+
+Function: Imaginary part of "cexp":
+double: 1
+float: 2
+
+Function: Real part of "cexp_downward":
+double: 4
+float: 2
+
+Function: Imaginary part of "cexp_downward":
+double: 3
+float: 3
+
+Function: Real part of "cexp_towardzero":
+double: 4
+float: 2
+
+Function: Imaginary part of "cexp_towardzero":
+double: 3
+float: 3
+
+Function: Real part of "cexp_upward":
+double: 2
+float: 2
+
+Function: Imaginary part of "cexp_upward":
+double: 3
+float: 2
+
+Function: Real part of "clog":
+double: 3
+float: 3
+
+Function: Imaginary part of "clog":
+double: 1
+float: 1
+
+Function: Real part of "clog10":
+double: 3
+float: 4
+
+Function: Imaginary part of "clog10":
+double: 2
+float: 2
+
+Function: Real part of "clog10_downward":
+double: 7
+float: 5
+
+Function: Imaginary part of "clog10_downward":
+double: 8
+float: 4
+
+Function: Real part of "clog10_towardzero":
+double: 5
+float: 5
+
+Function: Imaginary part of "clog10_towardzero":
+double: 8
+float: 4
+
+Function: Real part of "clog10_upward":
+double: 6
+float: 5
+
+Function: Imaginary part of "clog10_upward":
+double: 5
+float: 4
+
+Function: Real part of "clog_downward":
+double: 4
+float: 3
+
+Function: Imaginary part of "clog_downward":
+double: 5
+float: 2
+
+Function: Real part of "clog_towardzero":
+double: 8
+float: 4
+
+Function: Imaginary part of "clog_towardzero":
+double: 5
+float: 3
+
+Function: Real part of "clog_upward":
+double: 8
+float: 3
+
+Function: Imaginary part of "clog_upward":
+double: 8
+float: 2
+
+Function: "cos":
+double: 1
+float: 1
+
+Function: "cos_downward":
+double: 1
+float: 1
+
+Function: "cos_towardzero":
+double: 4
+float: 1
+
+Function: "cos_upward":
+double: 4
+float: 1
+
+Function: "cosh":
+double: 2
+float: 2
+
+Function: "cosh_downward":
+double: 3
+float: 1
+
+Function: "cosh_towardzero":
+double: 3
+float: 1
+
+Function: "cosh_upward":
+double: 2
+float: 2
+
+Function: Real part of "cpow":
+double: 2
+float: 5
+
+Function: Imaginary part of "cpow":
+float: 2
+
+Function: Real part of "cpow_downward":
+double: 5
+float: 8
+
+Function: Imaginary part of "cpow_downward":
+double: 2
+float: 2
+
+Function: Real part of "cpow_towardzero":
+double: 5
+float: 8
+
+Function: Imaginary part of "cpow_towardzero":
+double: 2
+float: 2
+
+Function: Real part of "cpow_upward":
+double: 4
+float: 1
+
+Function: Imaginary part of "cpow_upward":
+double: 2
+float: 2
+
+Function: Real part of "csin":
+double: 1
+float: 1
+
+Function: Real part of "csin_downward":
+double: 3
+float: 3
+
+Function: Imaginary part of "csin_downward":
+double: 3
+float: 1
+
+Function: Real part of "csin_towardzero":
+double: 3
+float: 3
+
+Function: Imaginary part of "csin_towardzero":
+double: 3
+float: 1
+
+Function: Real part of "csin_upward":
+double: 2
+float: 2
+
+Function: Imaginary part of "csin_upward":
+double: 1
+float: 2
+
+Function: Real part of "csinh":
+float: 1
+
+Function: Imaginary part of "csinh":
+double: 1
+float: 1
+
+Function: Real part of "csinh_downward":
+double: 3
+float: 1
+
+Function: Imaginary part of "csinh_downward":
+double: 3
+float: 3
+
+Function: Real part of "csinh_towardzero":
+double: 3
+float: 2
+
+Function: Imaginary part of "csinh_towardzero":
+double: 3
+float: 3
+
+Function: Real part of "csinh_upward":
+double: 1
+float: 2
+
+Function: Imaginary part of "csinh_upward":
+double: 2
+float: 2
+
+Function: Real part of "csqrt":
+double: 2
+float: 2
+
+Function: Imaginary part of "csqrt":
+double: 2
+float: 2
+
+Function: Real part of "csqrt_downward":
+double: 5
+float: 4
+
+Function: Imaginary part of "csqrt_downward":
+double: 4
+float: 3
+
+Function: Real part of "csqrt_towardzero":
+double: 4
+float: 3
+
+Function: Imaginary part of "csqrt_towardzero":
+double: 4
+float: 3
+
+Function: Real part of "csqrt_upward":
+double: 5
+float: 4
+
+Function: Imaginary part of "csqrt_upward":
+double: 3
+float: 3
+
+Function: Real part of "ctan":
+double: 1
+float: 1
+
+Function: Imaginary part of "ctan":
+double: 2
+float: 2
+
+Function: Real part of "ctan_downward":
+double: 6
+float: 5
+
+Function: Imaginary part of "ctan_downward":
+double: 3
+float: 2
+
+Function: Real part of "ctan_towardzero":
+double: 5
+float: 3
+
+Function: Imaginary part of "ctan_towardzero":
+double: 3
+float: 2
+
+Function: Real part of "ctan_upward":
+double: 2
+float: 4
+
+Function: Imaginary part of "ctan_upward":
+double: 2
+float: 1
+
+Function: Real part of "ctanh":
+double: 2
+float: 2
+
+Function: Imaginary part of "ctanh":
+double: 2
+float: 2
+
+Function: Real part of "ctanh_downward":
+double: 3
+float: 2
+
+Function: Imaginary part of "ctanh_downward":
+double: 6
+float: 5
+
+Function: Real part of "ctanh_towardzero":
+double: 3
+float: 2
+
+Function: Imaginary part of "ctanh_towardzero":
+double: 5
+float: 3
+
+Function: Real part of "ctanh_upward":
+double: 2
+float: 2
+
+Function: Imaginary part of "ctanh_upward":
+double: 2
+float: 3
+
+Function: "erf":
+double: 1
+float: 1
+
+Function: "erf_downward":
+double: 1
+float: 1
+
+Function: "erf_towardzero":
+double: 1
+float: 1
+
+Function: "erf_upward":
+double: 1
+float: 1
+
+Function: "erfc":
+double: 5
+float: 3
+
+Function: "erfc_downward":
+double: 5
+float: 6
+
+Function: "erfc_towardzero":
+double: 3
+float: 4
+
+Function: "erfc_upward":
+double: 5
+float: 6
+
+Function: "exp":
+double: 1
+float: 1
+
+Function: "exp10":
+double: 2
+float: 1
+
+Function: "exp10_downward":
+double: 3
+float: 1
+
+Function: "exp10_towardzero":
+double: 3
+float: 1
+
+Function: "exp10_upward":
+double: 2
+float: 1
+
+Function: "exp2":
+double: 1
+
+Function: "exp2_downward":
+double: 1
+
+Function: "exp2_towardzero":
+double: 1
+
+Function: "exp2_upward":
+double: 1
+float: 1
+
+Function: "exp_downward":
+double: 1
+float: 1
+
+Function: "exp_towardzero":
+double: 1
+float: 1
+
+Function: "exp_upward":
+double: 1
+float: 1
+
+Function: "expm1":
+double: 1
+float: 1
+
+Function: "expm1_downward":
+double: 1
+float: 1
+
+Function: "expm1_towardzero":
+double: 1
+float: 2
+
+Function: "expm1_upward":
+double: 1
+float: 1
+
+Function: "gamma":
+double: 4
+float: 7
+
+Function: "gamma_downward":
+double: 7
+float: 7
+
+Function: "gamma_towardzero":
+double: 7
+float: 7
+
+Function: "gamma_upward":
+double: 5
+float: 6
+
+Function: "hypot":
+double: 1
+float: 1
+
+Function: "hypot_downward":
+double: 1
+
+Function: "hypot_towardzero":
+double: 1
+
+Function: "hypot_upward":
+double: 1
+
+Function: "j0":
+double: 2
+float: 9
+
+Function: "j0_downward":
+double: 5
+float: 9
+
+Function: "j0_towardzero":
+double: 6
+float: 9
+
+Function: "j0_upward":
+double: 9
+float: 9
+
+Function: "j1":
+double: 4
+float: 9
+
+Function: "j1_downward":
+double: 5
+float: 8
+
+Function: "j1_towardzero":
+double: 4
+float: 8
+
+Function: "j1_upward":
+double: 9
+float: 9
+
+Function: "jn":
+double: 4
+float: 4
+
+Function: "jn_downward":
+double: 7
+float: 9
+
+Function: "jn_towardzero":
+double: 7
+float: 9
+
+Function: "jn_upward":
+double: 7
+float: 9
+
+Function: "lgamma":
+double: 4
+float: 7
+
+Function: "lgamma_downward":
+double: 7
+float: 7
+
+Function: "lgamma_towardzero":
+double: 7
+float: 7
+
+Function: "lgamma_upward":
+double: 5
+float: 6
+
+Function: "log10":
+double: 2
+float: 2
+
+Function: "log10_downward":
+double: 2
+float: 3
+
+Function: "log10_towardzero":
+double: 2
+float: 1
+
+Function: "log10_upward":
+double: 2
+float: 2
+
+Function: "log1p":
+double: 1
+float: 1
+
+Function: "log1p_downward":
+double: 2
+float: 2
+
+Function: "log1p_towardzero":
+double: 2
+float: 2
+
+Function: "log1p_upward":
+double: 2
+float: 2
+
+Function: "log2":
+float: 1
+
+Function: "log2_downward":
+double: 1
+
+Function: "log2_towardzero":
+double: 1
+
+Function: "log2_upward":
+double: 1
+
+Function: "pow":
+double: 1
+
+Function: "pow_downward":
+double: 1
+float: 1
+
+Function: "pow_towardzero":
+double: 1
+float: 1
+
+Function: "pow_upward":
+double: 1
+float: 1
+
+Function: "sin":
+double: 1
+float: 1
+
+Function: "sin_downward":
+double: 4
+float: 1
+
+Function: "sin_towardzero":
+double: 3
+float: 1
+
+Function: "sin_upward":
+double: 7
+float: 1
+
+Function: "sincos":
+double: 1
+
+Function: "sincos_downward":
+double: 1
+float: 1
+
+Function: "sincos_towardzero":
+double: 4
+float: 1
+
+Function: "sincos_upward":
+double: 1
+float: 1
+
+Function: "sinh":
+double: 2
+float: 2
+
+Function: "sinh_downward":
+double: 3
+float: 3
+
+Function: "sinh_towardzero":
+double: 3
+float: 2
+
+Function: "sinh_upward":
+double: 3
+float: 3
+
+Function: "tan":
+float: 1
+
+Function: "tan_downward":
+double: 1
+float: 2
+
+Function: "tan_towardzero":
+double: 1
+float: 1
+
+Function: "tan_upward":
+double: 1
+float: 1
+
+Function: "tanh":
+double: 2
+float: 2
+
+Function: "tanh_downward":
+double: 3
+float: 3
+
+Function: "tanh_towardzero":
+double: 2
+float: 2
+
+Function: "tanh_upward":
+double: 3
+float: 3
+
+Function: "tgamma":
+double: 9
+float: 8
+
+Function: "tgamma_downward":
+double: 9
+float: 9
+
+Function: "tgamma_towardzero":
+double: 9
+float: 8
+
+Function: "tgamma_upward":
+double: 9
+float: 8
+
+Function: "y0":
+double: 3
+float: 9
+
+Function: "y0_downward":
+double: 3
+float: 9
+
+Function: "y0_towardzero":
+double: 4
+float: 9
+
+Function: "y0_upward":
+double: 3
+float: 9
+
+Function: "y1":
+double: 3
+float: 9
+
+Function: "y1_downward":
+double: 6
+float: 9
+
+Function: "y1_towardzero":
+double: 3
+float: 9
+
+Function: "y1_upward":
+double: 7
+float: 9
+
+Function: "yn":
+double: 3
+float: 3
+
+Function: "yn_downward":
+double: 6
+float: 8
+
+Function: "yn_towardzero":
+double: 8
+float: 8
+
+Function: "yn_upward":
+double: 8
+float: 8
+
+# end of automatic generation
diff --git a/sysdeps/or1k/fpu/libm-test-ulps-name b/sysdeps/or1k/fpu/libm-test-ulps-name
new file mode 100644
index 0000000000..7f72f7a873
--- /dev/null
+++ b/sysdeps/or1k/fpu/libm-test-ulps-name
@@ -0,0 +1 @@ 
+OpenRISC hard-float
diff --git a/sysdeps/or1k/fpu_control.h b/sysdeps/or1k/fpu_control.h
new file mode 100644
index 0000000000..4ac03db7a9
--- /dev/null
+++ b/sysdeps/or1k/fpu_control.h
@@ -0,0 +1,61 @@ 
+/* FPU control word bits.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _FPU_CONTROL_H
+#define _FPU_CONTROL_H
+
+#ifndef __or1k_hard_float__
+
+# define _FPU_RESERVED 0xffffffff
+# define _FPU_DEFAULT  0x00000000
+# define _FPU_GETCW(cw) (cw) = 0
+# define _FPU_SETCW(cw) (void) (cw)
+
+#else /* __or1k_hard_float__ */
+
+/* Layout of FPCSR:
+
+ +-----------+----------------------------+-----+----+
+ |  32 - 12  | 11 10  9  8  7  6  5  4  3 | 2-1 |  0 |
+ +-----------+----------------------------+-----+----+
+ |  Reserved | DZ IN IV IX  Z QN SN UN OV | RM  | EE |
+ +-----------+----------------------------+-----+----+
+
+ */
+
+# define _FPU_RESERVED 0xfffff000
+/* Default: rounding to nearest with exceptions disabled.  */
+# define _FPU_DEFAULT  0
+/* IEEE: Same as above with exceptions enabled.  */
+# define _FPU_IEEE     (_FPU_DEFAULT | 1)
+
+# define _FPU_FPCSR_RM_MASK (0x3 << 1)
+
+/* Macros for accessing the hardware control word.  */
+# define _FPU_GETCW(cw) __asm__ volatile ("l.mfspr %0,r0,20" : "=r" (cw))
+# define _FPU_SETCW(cw) __asm__ volatile ("l.mtspr r0,%0,20" : : "r" (cw))
+
+#endif /* __or1k_hard_float__ */
+
+/* Type of the control word.  */
+typedef unsigned int fpu_control_t;
+
+/* Default control word set at startup.  */
+extern fpu_control_t __fpu_control;
+
+#endif	/* fpu_control.h */
diff --git a/sysdeps/or1k/libm-test-ulps-name b/sysdeps/or1k/libm-test-ulps-name
deleted file mode 100644
index 0af6591fd9..0000000000
--- a/sysdeps/or1k/libm-test-ulps-name
+++ /dev/null
@@ -1 +0,0 @@ 
-OpenRISC
diff --git a/sysdeps/or1k/math-tests-snan-payload.h b/sysdeps/or1k/math-tests-snan-payload.h
new file mode 100644
index 0000000000..62467a371c
--- /dev/null
+++ b/sysdeps/or1k/math-tests-snan-payload.h
@@ -0,0 +1,26 @@ 
+/* Configuration for math tests: sNaN payloads.  OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef OR1K_MATH_TESTS_SNAN_PAYLOAD_H
+#define OR1K_MATH_TESTS_SNAN_PAYLOAD_H 1
+
+/* OpenRISC floating-point instructions do not preserve NaN
+   payloads.  */
+#define SNAN_TESTS_PRESERVE_PAYLOAD	0
+
+#endif /* math-tests-snan-payload.h */
diff --git a/sysdeps/or1k/math-tests-trap.h b/sysdeps/or1k/math-tests-trap.h
new file mode 100644
index 0000000000..a95b42d66d
--- /dev/null
+++ b/sysdeps/or1k/math-tests-trap.h
@@ -0,0 +1,27 @@ 
+/* Configuration for math tests: support for enabling exception traps.
+   OpenRISC version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef OR1K_MATH_TESTS_TRAP_H
+#define OR1K_MATH_TESTS_TRAP_H 1
+
+#include <fenv.h>
+
+#define EXCEPTION_ENABLE_SUPPORTED(EXCEPT)	((EXCEPT) == 0)
+
+#endif /* math-tests-trap.h */
diff --git a/sysdeps/or1k/libm-test-ulps b/sysdeps/or1k/nofpu/libm-test-ulps
similarity index 100%
rename from sysdeps/or1k/libm-test-ulps
rename to sysdeps/or1k/nofpu/libm-test-ulps
diff --git a/sysdeps/or1k/nofpu/libm-test-ulps-name b/sysdeps/or1k/nofpu/libm-test-ulps-name
new file mode 100644
index 0000000000..76c66a0e53
--- /dev/null
+++ b/sysdeps/or1k/nofpu/libm-test-ulps-name
@@ -0,0 +1 @@ 
+OpenRISC soft-float
diff --git a/sysdeps/or1k/sfp-machine.h b/sysdeps/or1k/sfp-machine.h
index d17fd37730..e58e683969 100644
--- a/sysdeps/or1k/sfp-machine.h
+++ b/sysdeps/or1k/sfp-machine.h
@@ -36,7 +36,6 @@ 
 #define _FP_MUL_MEAT_DW_Q(R,X,Y)				\
   _FP_MUL_MEAT_DW_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
 
-
 #define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_loop(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)
@@ -90,4 +89,21 @@ 
 
 #define FP_ROUNDMODE (_fpcsr & FP_RND_MASK)
 
+#ifdef __or1k_hard_float__
+#define FP_INIT_ROUNDMODE					\
+do {								\
+  __asm__ volatile ("l.mfspr %0,r0,20" : "=r" (_fpcsr));	\
+} while (0)
+
+#define FP_HANDLE_EXCEPTIONS					\
+do {								\
+  if (__builtin_expect (_fex, 0))				\
+    {								\
+      _fpcsr &= ~FP_EX_ALL;					\
+      _fpcsr |= _fex;						\
+      __asm__ volatile ("l.mtspr r0,%0,20" : : "r" (_fpcsr));	\
+    }								\
+} while (0)
+#endif /* __or1k_hard_float__ */
+
 #define _FP_TININESS_AFTER_ROUNDING 0
diff --git a/sysdeps/unix/sysv/linux/or1k/getcontext.S b/sysdeps/unix/sysv/linux/or1k/getcontext.S
index a25b377bda..397b9e4c60 100644
--- a/sysdeps/unix/sysv/linux/or1k/getcontext.S
+++ b/sysdeps/unix/sysv/linux/or1k/getcontext.S
@@ -46,6 +46,12 @@  ENTRY(__getcontext)
 	l.sw	(UCONTEXT_MCONTEXT + 28*4)(r3), r28
 	l.sw	(UCONTEXT_MCONTEXT + 30*4)(r3), r30
 
+#ifdef __or1k_hard_float__
+	/* Store the floating point state.  */
+	l.mfspr	r4, r0, 20
+	l.sw	(MCONTEXT_FPCSR)(r3), r4
+#endif /* __or1k_hard_float__ */
+
 	/* Get signal mask.  */
 	/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
 	l.ori	r6, r0, _NSIG8
diff --git a/sysdeps/unix/sysv/linux/or1k/setcontext.S b/sysdeps/unix/sysv/linux/or1k/setcontext.S
index d28a0ac0aa..4bf258b6f1 100644
--- a/sysdeps/unix/sysv/linux/or1k/setcontext.S
+++ b/sysdeps/unix/sysv/linux/or1k/setcontext.S
@@ -40,6 +40,12 @@  ENTRY(__setcontext)
 	l.bf	1f
 	 l.nop
 
+#ifdef __or1k_hard_float__
+	/* Restore the floating point state.  */
+	l.lwz	r28, (MCONTEXT_FPCSR)(r30)
+	l.mtspr	r0, r28, 20
+#endif /* __or1k_hard_float__ */
+
 	/* Restore argument registers, for the makecontext case.  */
 	l.lwz	r3, (UCONTEXT_MCONTEXT +  3*4)(r30)
 	l.lwz	r4, (UCONTEXT_MCONTEXT +  4*4)(r30)
diff --git a/sysdeps/unix/sysv/linux/or1k/swapcontext.S b/sysdeps/unix/sysv/linux/or1k/swapcontext.S
index d09651a5b2..dfc788812c 100644
--- a/sysdeps/unix/sysv/linux/or1k/swapcontext.S
+++ b/sysdeps/unix/sysv/linux/or1k/swapcontext.S
@@ -45,6 +45,12 @@  ENTRY(__swapcontext)
 	l.sw	(UCONTEXT_MCONTEXT + 28*4)(r3), r28
 	l.sw	(UCONTEXT_MCONTEXT + 30*4)(r3), r30
 
+#ifdef __or1k_hard_float__
+	/* Store the floating point state.  */
+	l.mfspr	r6, r0, 20
+	l.sw	(MCONTEXT_FPCSR)(r3), r6
+#endif /* __or1k_hard_float__ */
+
 	/* Store ucp to non-argument syscall preserved register.  */
 	l.ori	r30, r4, 0
 
@@ -82,6 +88,12 @@  ENTRY(__swapcontext)
 	l.bf	1f
 	 l.nop
 
+#ifdef __or1k_hard_float__
+	/* Restore the floating point state.  */
+	l.lwz	r28, (MCONTEXT_FPCSR)(r30)
+	l.mtspr	r0, r28, 20
+#endif /* __or1k_hard_float__ */
+
 	/* Restore argument registers, for the makecontext case.  */
 	l.lwz	r3, (UCONTEXT_MCONTEXT +  3*4)(r30)
 	l.lwz	r4, (UCONTEXT_MCONTEXT +  4*4)(r30)
diff --git a/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h b/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h
index b17e919154..1b428592ee 100644
--- a/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h
+++ b/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h
@@ -38,6 +38,7 @@  typedef struct
     unsigned long int __gprs[__NGREG];
     unsigned long int __pc;
     unsigned long int __sr;
+    unsigned long int __fpcsr;
   } mcontext_t;
 
 /* Userlevel context.  */
diff --git a/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym b/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym
index a8d4db080f..45cd72527d 100644
--- a/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym
+++ b/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym
@@ -13,6 +13,7 @@  _NSIG8				(_NSIG / 8)
 -- Offsets of the fields in the ucontext_t structure.
 #define ucontext(member)	offsetof (ucontext_t, member)
 #define stack(member)		ucontext (uc_stack.member)
+#define mcontext(member)	ucontext (uc_mcontext.member)
 
 UCONTEXT_LINK			ucontext (uc_link)
 UCONTEXT_STACK			ucontext (uc_stack)
@@ -23,4 +24,6 @@  STACK_SP			stack (ss_sp)
 STACK_SIZE			stack (ss_size)
 STACK_FLAGS			stack (ss_flags)
 
+MCONTEXT_FPCSR			mcontext (__fpcsr)
+
 UCONTEXT_SIZE			sizeof (ucontext_t)