From 618001c26e224fd4aff72b8e5530498acbad747a Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Mon, 31 Mar 2025 19:32:48 +0200 Subject: aarch64: add fenv support from glibc --- libm/aarch64/Makefile.arch | 16 +++ libm/aarch64/fclrexcpt.c | 35 ++++++ libm/aarch64/fedisblxcpt.c | 34 +++++ libm/aarch64/feenablxcpt.c | 45 +++++++ libm/aarch64/fegetenv.c | 30 +++++ libm/aarch64/fegetexcept.c | 26 ++++ libm/aarch64/fegetmode.c | 26 ++++ libm/aarch64/fegetround.c | 35 ++++++ libm/aarch64/feholdexcpt.c | 25 ++++ libm/aarch64/fenv_private.h | 300 ++++++++++++++++++++++++++++++++++++++++++++ libm/aarch64/fesetenv.c | 73 +++++++++++ libm/aarch64/fesetexcept.c | 33 +++++ libm/aarch64/fesetmode.c | 33 +++++ libm/aarch64/fesetround.c | 29 +++++ libm/aarch64/feupdateenv.c | 84 +++++++++++++ libm/aarch64/fgetexcptflg.c | 25 ++++ libm/aarch64/fraiseexcpt.c | 89 +++++++++++++ libm/aarch64/fsetexcptflg.c | 39 ++++++ libm/aarch64/ftestexcept.c | 24 ++++ 19 files changed, 1001 insertions(+) create mode 100644 libm/aarch64/Makefile.arch create mode 100644 libm/aarch64/fclrexcpt.c create mode 100644 libm/aarch64/fedisblxcpt.c create mode 100644 libm/aarch64/feenablxcpt.c create mode 100644 libm/aarch64/fegetenv.c create mode 100644 libm/aarch64/fegetexcept.c create mode 100644 libm/aarch64/fegetmode.c create mode 100644 libm/aarch64/fegetround.c create mode 100644 libm/aarch64/feholdexcpt.c create mode 100644 libm/aarch64/fenv_private.h create mode 100644 libm/aarch64/fesetenv.c create mode 100644 libm/aarch64/fesetexcept.c create mode 100644 libm/aarch64/fesetmode.c create mode 100644 libm/aarch64/fesetround.c create mode 100644 libm/aarch64/feupdateenv.c create mode 100644 libm/aarch64/fgetexcptflg.c create mode 100644 libm/aarch64/fraiseexcpt.c create mode 100644 libm/aarch64/fsetexcptflg.c create mode 100644 libm/aarch64/ftestexcept.c (limited to 'libm') diff --git a/libm/aarch64/Makefile.arch b/libm/aarch64/Makefile.arch new file mode 100644 index 000000000..bd38690be --- /dev/null +++ b/libm/aarch64/Makefile.arch @@ -0,0 +1,16 @@ +# Makefile for uClibc-ng +# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +ifeq ($(UCLIBC_HAS_FENV),y) +libm_ARCH_SRC:=$(wildcard $(libm_ARCH_DIR)/*.c) +libm_ARCH_OBJ:=$(patsubst $(libm_ARCH_DIR)/%.c,$(libm_ARCH_OUT)/%.o,$(libm_ARCH_SRC)) +endif + +libm_ARCH_OBJS:=$(libm_ARCH_OBJ) + +ifeq ($(DOPIC),y) +libm-a-y+=$(libm_ARCH_OBJS:.o=.os) +else +libm-a-y+=$(libm_ARCH_OBJS) +endif +libm-so-y+=$(libm_ARCH_OBJS:.o=.os) diff --git a/libm/aarch64/fclrexcpt.c b/libm/aarch64/fclrexcpt.c new file mode 100644 index 000000000..3dbd9a8bb --- /dev/null +++ b/libm/aarch64/fclrexcpt.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +feclearexcept (int excepts) +{ + fpu_fpsr_t fpsr; + fpu_fpsr_t fpsr_new; + + excepts &= FE_ALL_EXCEPT; + + _FPU_GETFPSR (fpsr); + fpsr_new = fpsr & ~excepts; + + if (fpsr != fpsr_new) + _FPU_SETFPSR (fpsr_new); + + return 0; +} diff --git a/libm/aarch64/fedisblxcpt.c b/libm/aarch64/fedisblxcpt.c new file mode 100644 index 000000000..a36873690 --- /dev/null +++ b/libm/aarch64/fedisblxcpt.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2001-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +fedisableexcept (int excepts) +{ + fpu_control_t fpcr; + fpu_control_t fpcr_new; + + _FPU_GETCW (fpcr); + excepts &= FE_ALL_EXCEPT; + fpcr_new = fpcr & ~(excepts << FE_EXCEPT_SHIFT); + + if (fpcr != fpcr_new) + _FPU_SETCW (fpcr_new); + + return (fpcr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT; +} diff --git a/libm/aarch64/feenablxcpt.c b/libm/aarch64/feenablxcpt.c new file mode 100644 index 000000000..b5aa3bdc6 --- /dev/null +++ b/libm/aarch64/feenablxcpt.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2001-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +feenableexcept (int excepts) +{ + fpu_control_t fpcr; + fpu_control_t fpcr_new; + fpu_control_t updated_fpcr; + + _FPU_GETCW (fpcr); + excepts &= FE_ALL_EXCEPT; + fpcr_new = fpcr | (excepts << FE_EXCEPT_SHIFT); + + if (fpcr != fpcr_new) + { + _FPU_SETCW (fpcr_new); + + /* Trapping exceptions are optional in AArch64; the relevant enable + bits in FPCR are RES0 hence the absence of support can be detected + by reading back the FPCR and comparing with the required value. */ + _FPU_GETCW (updated_fpcr); + + if (fpcr_new & ~updated_fpcr) + return -1; + } + + return (fpcr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT; +} diff --git a/libm/aarch64/fegetenv.c b/libm/aarch64/fegetenv.c new file mode 100644 index 000000000..a85575eb8 --- /dev/null +++ b/libm/aarch64/fegetenv.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +fegetenv (fenv_t *envp) +{ + fpu_control_t fpcr; + fpu_fpsr_t fpsr; + _FPU_GETCW (fpcr); + _FPU_GETFPSR (fpsr); + envp->__fpcr = fpcr; + envp->__fpsr = fpsr; + return 0; +} diff --git a/libm/aarch64/fegetexcept.c b/libm/aarch64/fegetexcept.c new file mode 100644 index 000000000..a9eac299c --- /dev/null +++ b/libm/aarch64/fegetexcept.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2001-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +fegetexcept (void) +{ + fpu_control_t fpcr; + _FPU_GETCW (fpcr); + return (fpcr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT; +} diff --git a/libm/aarch64/fegetmode.c b/libm/aarch64/fegetmode.c new file mode 100644 index 000000000..8393e6d05 --- /dev/null +++ b/libm/aarch64/fegetmode.c @@ -0,0 +1,26 @@ +/* Store current floating-point control modes. AArch64 version. + Copyright (C) 2016-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +fegetmode (femode_t *modep) +{ + _FPU_GETCW (*modep); + return 0; +} diff --git a/libm/aarch64/fegetround.c b/libm/aarch64/fegetround.c new file mode 100644 index 000000000..1f34c6918 --- /dev/null +++ b/libm/aarch64/fegetround.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +/* Return the floating-point rounding mode. */ + +static inline int +get_rounding_mode (void) +{ + fpu_control_t fpcr; + + _FPU_GETCW (fpcr); + return fpcr & _FPU_FPCR_RM_MASK; +} + +int +fegetround (void) +{ + return get_rounding_mode (); +} diff --git a/libm/aarch64/feholdexcpt.c b/libm/aarch64/feholdexcpt.c new file mode 100644 index 000000000..09c8cd38b --- /dev/null +++ b/libm/aarch64/feholdexcpt.c @@ -0,0 +1,25 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include "fenv_private.h" + +int +feholdexcept (fenv_t *envp) +{ + libc_feholdexcept_aarch64 (envp); + return 0; +} diff --git a/libm/aarch64/fenv_private.h b/libm/aarch64/fenv_private.h new file mode 100644 index 000000000..5afb790ea --- /dev/null +++ b/libm/aarch64/fenv_private.h @@ -0,0 +1,300 @@ +/* Private floating point rounding and exceptions handling. AArch64 version. + Copyright (C) 2014-2025 Free Software Foundation, Inc. + + 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 + . */ + +#ifndef AARCH64_FENV_PRIVATE_H +#define AARCH64_FENV_PRIVATE_H 1 + +#include +#include + +static __always_inline void +libc_feholdexcept_aarch64 (fenv_t *envp) +{ + fpu_control_t fpcr; + fpu_control_t new_fpcr; + fpu_fpsr_t fpsr; + fpu_fpsr_t new_fpsr; + + _FPU_GETCW (fpcr); + _FPU_GETFPSR (fpsr); + envp->__fpcr = fpcr; + envp->__fpsr = fpsr; + + /* Clear exception flags and set all exceptions to non-stop. */ + new_fpcr = fpcr & ~(FE_ALL_EXCEPT << FE_EXCEPT_SHIFT); + new_fpsr = fpsr & ~FE_ALL_EXCEPT; + + if (unlikely (new_fpcr != fpcr)) + _FPU_SETCW (new_fpcr); + + if (new_fpsr != fpsr) + _FPU_SETFPSR (new_fpsr); +} + +#define libc_feholdexcept libc_feholdexcept_aarch64 +#define libc_feholdexceptf libc_feholdexcept_aarch64 +#define libc_feholdexceptl libc_feholdexcept_aarch64 + +static __always_inline void +libc_fesetround_aarch64 (int round) +{ + fpu_control_t fpcr; + + _FPU_GETCW (fpcr); + + /* Check whether rounding modes are different. */ + round = (fpcr ^ round) & _FPU_FPCR_RM_MASK; + + /* Set new rounding mode if different. */ + if (unlikely (round != 0)) + _FPU_SETCW (fpcr ^ round); +} + +#define libc_fesetround libc_fesetround_aarch64 +#define libc_fesetroundf libc_fesetround_aarch64 +#define libc_fesetroundl libc_fesetround_aarch64 + +static __always_inline void +libc_feholdexcept_setround_aarch64 (fenv_t *envp, int round) +{ + fpu_control_t fpcr; + fpu_control_t new_fpcr; + fpu_fpsr_t fpsr; + fpu_fpsr_t new_fpsr; + + _FPU_GETCW (fpcr); + _FPU_GETFPSR (fpsr); + envp->__fpcr = fpcr; + envp->__fpsr = fpsr; + + /* Clear exception flags, set all exceptions to non-stop, + and set new rounding mode. */ + new_fpcr = fpcr & ~((FE_ALL_EXCEPT << FE_EXCEPT_SHIFT) | _FPU_FPCR_RM_MASK); + new_fpcr |= round; + new_fpsr = fpsr & ~FE_ALL_EXCEPT; + + if (unlikely (new_fpcr != fpcr)) + _FPU_SETCW (new_fpcr); + + if (new_fpsr != fpsr) + _FPU_SETFPSR (new_fpsr); +} + +#define libc_feholdexcept_setround libc_feholdexcept_setround_aarch64 +#define libc_feholdexcept_setroundf libc_feholdexcept_setround_aarch64 +#define libc_feholdexcept_setroundl libc_feholdexcept_setround_aarch64 + +static __always_inline int +libc_fetestexcept_aarch64 (int ex) +{ + fpu_fpsr_t fpsr; + + _FPU_GETFPSR (fpsr); + return fpsr & ex & FE_ALL_EXCEPT; +} + +#define libc_fetestexcept libc_fetestexcept_aarch64 +#define libc_fetestexceptf libc_fetestexcept_aarch64 +#define libc_fetestexceptl libc_fetestexcept_aarch64 + +static __always_inline void +libc_fesetenv_aarch64 (const fenv_t *envp) +{ + fpu_control_t fpcr; + fpu_control_t new_fpcr; + + _FPU_GETCW (fpcr); + new_fpcr = envp->__fpcr; + + if (unlikely (fpcr != new_fpcr)) + _FPU_SETCW (new_fpcr); + + _FPU_SETFPSR (envp->__fpsr); +} + +#define libc_fesetenv libc_fesetenv_aarch64 +#define libc_fesetenvf libc_fesetenv_aarch64 +#define libc_fesetenvl libc_fesetenv_aarch64 +#define libc_feresetround_noex libc_fesetenv_aarch64 +#define libc_feresetround_noexf libc_fesetenv_aarch64 +#define libc_feresetround_noexl libc_fesetenv_aarch64 + +static __always_inline int +libc_feupdateenv_test_aarch64 (const fenv_t *envp, int ex) +{ + fpu_control_t fpcr; + fpu_control_t new_fpcr; + fpu_fpsr_t fpsr; + fpu_fpsr_t new_fpsr; + int excepts; + + _FPU_GETCW (fpcr); + _FPU_GETFPSR (fpsr); + + /* Merge current exception flags with the saved fenv. */ + excepts = fpsr & FE_ALL_EXCEPT; + new_fpcr = envp->__fpcr; + new_fpsr = envp->__fpsr | excepts; + + if (unlikely (fpcr != new_fpcr)) + _FPU_SETCW (new_fpcr); + + if (fpsr != new_fpsr) + _FPU_SETFPSR (new_fpsr); + + /* Raise the exceptions if enabled in the new FP state. */ + if (unlikely (excepts & (new_fpcr >> FE_EXCEPT_SHIFT))) + feraiseexcept (excepts); + + return excepts & ex; +} + +#define libc_feupdateenv_test libc_feupdateenv_test_aarch64 +#define libc_feupdateenv_testf libc_feupdateenv_test_aarch64 +#define libc_feupdateenv_testl libc_feupdateenv_test_aarch64 + +static __always_inline void +libc_feupdateenv_aarch64 (const fenv_t *envp) +{ + libc_feupdateenv_test_aarch64 (envp, 0); +} + +#define libc_feupdateenv libc_feupdateenv_aarch64 +#define libc_feupdateenvf libc_feupdateenv_aarch64 +#define libc_feupdateenvl libc_feupdateenv_aarch64 + +static __always_inline void +libc_feholdsetround_aarch64 (fenv_t *envp, int round) +{ + fpu_control_t fpcr; + fpu_fpsr_t fpsr; + + _FPU_GETCW (fpcr); + _FPU_GETFPSR (fpsr); + envp->__fpcr = fpcr; + envp->__fpsr = fpsr; + + /* Check whether rounding modes are different. */ + round = (fpcr ^ round) & _FPU_FPCR_RM_MASK; + + /* Set new rounding mode if different. */ + if (unlikely (round != 0)) + _FPU_SETCW (fpcr ^ round); +} + +#define libc_feholdsetround libc_feholdsetround_aarch64 +#define libc_feholdsetroundf libc_feholdsetround_aarch64 +#define libc_feholdsetroundl libc_feholdsetround_aarch64 + +static __always_inline void +libc_feresetround_aarch64 (fenv_t *envp) +{ + fpu_control_t fpcr; + int round; + + _FPU_GETCW (fpcr); + + /* Check whether rounding modes are different. */ + round = (envp->__fpcr ^ fpcr) & _FPU_FPCR_RM_MASK; + + /* Restore the rounding mode if it was changed. */ + if (unlikely (round != 0)) + _FPU_SETCW (fpcr ^ round); +} + +#define libc_feresetround libc_feresetround_aarch64 +#define libc_feresetroundf libc_feresetround_aarch64 +#define libc_feresetroundl libc_feresetround_aarch64 + +/* We have support for rounding mode context. */ +#define HAVE_RM_CTX 1 + +static __always_inline void +libc_feholdsetround_aarch64_ctx (struct rm_ctx *ctx, int r) +{ + fpu_control_t fpcr; + int round; + + _FPU_GETCW (fpcr); + ctx->env.__fpcr = fpcr; + + /* Check whether rounding modes are different. */ + round = (fpcr ^ r) & _FPU_FPCR_RM_MASK; + ctx->updated_status = round != 0; + + /* Set the rounding mode if changed. */ + if (unlikely (round != 0)) + _FPU_SETCW (fpcr ^ round); +} + +#define libc_feholdsetround_ctx libc_feholdsetround_aarch64_ctx +#define libc_feholdsetroundf_ctx libc_feholdsetround_aarch64_ctx +#define libc_feholdsetroundl_ctx libc_feholdsetround_aarch64_ctx + +static __always_inline void +libc_feresetround_aarch64_ctx (struct rm_ctx *ctx) +{ + /* Restore the rounding mode if updated. */ + if (unlikely (ctx->updated_status)) + _FPU_SETCW (ctx->env.__fpcr); +} + +#define libc_feresetround_ctx libc_feresetround_aarch64_ctx +#define libc_feresetroundf_ctx libc_feresetround_aarch64_ctx +#define libc_feresetroundl_ctx libc_feresetround_aarch64_ctx + +static __always_inline void +libc_feholdsetround_noex_aarch64_ctx (struct rm_ctx *ctx, int r) +{ + fpu_control_t fpcr; + fpu_fpsr_t fpsr; + int round; + + _FPU_GETCW (fpcr); + _FPU_GETFPSR (fpsr); + ctx->env.__fpcr = fpcr; + ctx->env.__fpsr = fpsr; + + /* Check whether rounding modes are different. */ + round = (fpcr ^ r) & _FPU_FPCR_RM_MASK; + ctx->updated_status = round != 0; + + /* Set the rounding mode if changed. */ + if (unlikely (round != 0)) + _FPU_SETCW (fpcr ^ round); +} + +#define libc_feholdsetround_noex_ctx libc_feholdsetround_noex_aarch64_ctx +#define libc_feholdsetround_noexf_ctx libc_feholdsetround_noex_aarch64_ctx +#define libc_feholdsetround_noexl_ctx libc_feholdsetround_noex_aarch64_ctx + +static __always_inline void +libc_feresetround_noex_aarch64_ctx (struct rm_ctx *ctx) +{ + /* Restore the rounding mode if updated. */ + if (unlikely (ctx->updated_status)) + _FPU_SETCW (ctx->env.__fpcr); + + /* Write new FPSR to restore exception flags. */ + _FPU_SETFPSR (ctx->env.__fpsr); +} + +#define libc_feresetround_noex_ctx libc_feresetround_noex_aarch64_ctx +#define libc_feresetround_noexf_ctx libc_feresetround_noex_aarch64_ctx +#define libc_feresetround_noexl_ctx libc_feresetround_noex_aarch64_ctx + +#endif diff --git a/libm/aarch64/fesetenv.c b/libm/aarch64/fesetenv.c new file mode 100644 index 000000000..eb7a08da0 --- /dev/null +++ b/libm/aarch64/fesetenv.c @@ -0,0 +1,73 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +fesetenv (const fenv_t *envp) +{ + fpu_control_t fpcr; + fpu_control_t fpcr_new; + fpu_control_t updated_fpcr; + fpu_fpsr_t fpsr; + fpu_fpsr_t fpsr_new; + + _FPU_GETCW (fpcr); + + if ((envp != FE_DFL_ENV) && (envp != FE_NOMASK_ENV)) + { + /* The new FPCR/FPSR are valid, so don't merge the reserved flags. */ + fpcr_new = envp->__fpcr; + + if (fpcr != fpcr_new) + _FPU_SETCW (fpcr_new); + + _FPU_SETFPSR (envp->__fpsr); + return 0; + } + + _FPU_GETFPSR (fpsr); + fpcr_new = fpcr & _FPU_RESERVED; + fpsr_new = fpsr & _FPU_FPSR_RESERVED; + + if (envp == FE_DFL_ENV) + { + fpcr_new |= _FPU_DEFAULT; + fpsr_new |= _FPU_FPSR_DEFAULT; + } + else + { + fpcr_new |= _FPU_FPCR_IEEE; + fpsr_new |= _FPU_FPSR_IEEE; + } + + _FPU_SETFPSR (fpsr_new); + + if (fpcr != fpcr_new) + { + _FPU_SETCW (fpcr_new); + + /* Trapping exceptions are optional in AArch64; the relevant enable + bits in FPCR are RES0 hence the absence of support can be detected + by reading back the FPCR and comparing with the required value. */ + _FPU_GETCW (updated_fpcr); + + return fpcr_new & ~updated_fpcr; + } + + return 0; +} diff --git a/libm/aarch64/fesetexcept.c b/libm/aarch64/fesetexcept.c new file mode 100644 index 000000000..14a0b4232 --- /dev/null +++ b/libm/aarch64/fesetexcept.c @@ -0,0 +1,33 @@ +/* Set given exception flags. AArch64 version. + Copyright (C) 2016-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +fesetexcept (int excepts) +{ + fpu_fpsr_t fpsr; + fpu_fpsr_t fpsr_new; + + _FPU_GETFPSR (fpsr); + fpsr_new = fpsr | (excepts & FE_ALL_EXCEPT); + if (fpsr != fpsr_new) + _FPU_SETFPSR (fpsr_new); + + return 0; +} diff --git a/libm/aarch64/fesetmode.c b/libm/aarch64/fesetmode.c new file mode 100644 index 000000000..34e7c9316 --- /dev/null +++ b/libm/aarch64/fesetmode.c @@ -0,0 +1,33 @@ +/* Install given floating-point control modes. AArch64 version. + Copyright (C) 2016-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +fesetmode (const femode_t *modep) +{ + fpu_control_t fpcr, fpcr_new; + _FPU_GETCW (fpcr); + if (modep == FE_DFL_MODE) + fpcr_new = (fpcr & _FPU_RESERVED) | _FPU_DEFAULT; + else + fpcr_new = *modep; + if (fpcr != fpcr_new) + _FPU_SETCW (fpcr_new); + return 0; +} diff --git a/libm/aarch64/fesetround.c b/libm/aarch64/fesetround.c new file mode 100644 index 000000000..63a558258 --- /dev/null +++ b/libm/aarch64/fesetround.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include "fenv_private.h" +#include + +int +fesetround (int round) +{ + if (round & ~_FPU_FPCR_RM_MASK) + return 1; + + libc_fesetround_aarch64 (round); + return 0; +} diff --git a/libm/aarch64/feupdateenv.c b/libm/aarch64/feupdateenv.c new file mode 100644 index 000000000..2b4e62ecc --- /dev/null +++ b/libm/aarch64/feupdateenv.c @@ -0,0 +1,84 @@ +/* Copyright (C) 2009-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +feupdateenv (const fenv_t *envp) +{ + fpu_control_t fpcr; + fpu_control_t fpcr_new; + fpu_control_t updated_fpcr; + fpu_fpsr_t fpsr; + fpu_fpsr_t fpsr_new; + int excepts; + + _FPU_GETCW (fpcr); + _FPU_GETFPSR (fpsr); + excepts = fpsr & FE_ALL_EXCEPT; + + if ((envp != FE_DFL_ENV) && (envp != FE_NOMASK_ENV)) + { + fpcr_new = envp->__fpcr; + fpsr_new = envp->__fpsr | excepts; + + if (fpcr != fpcr_new) + _FPU_SETCW (fpcr_new); + + if (fpsr != fpsr_new) + _FPU_SETFPSR (fpsr_new); + + if (excepts & (fpcr_new >> FE_EXCEPT_SHIFT)) + return feraiseexcept (excepts); + + return 0; + } + + fpcr_new = fpcr & _FPU_RESERVED; + fpsr_new = fpsr & (_FPU_FPSR_RESERVED | FE_ALL_EXCEPT); + + if (envp == FE_DFL_ENV) + { + fpcr_new |= _FPU_DEFAULT; + fpsr_new |= _FPU_FPSR_DEFAULT; + } + else + { + fpcr_new |= _FPU_FPCR_IEEE; + fpsr_new |= _FPU_FPSR_IEEE; + } + + _FPU_SETFPSR (fpsr_new); + + if (fpcr != fpcr_new) + { + _FPU_SETCW (fpcr_new); + + /* Trapping exceptions are optional in AArch64; the relevant enable + bits in FPCR are RES0 hence the absence of support can be detected + by reading back the FPCR and comparing with the required value. */ + _FPU_GETCW (updated_fpcr); + + if (fpcr_new & ~updated_fpcr) + return 1; + } + + if (excepts & (fpcr_new >> FE_EXCEPT_SHIFT)) + return feraiseexcept (excepts); + + return 0; +} diff --git a/libm/aarch64/fgetexcptflg.c b/libm/aarch64/fgetexcptflg.c new file mode 100644 index 000000000..2c8920989 --- /dev/null +++ b/libm/aarch64/fgetexcptflg.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2001-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include "fenv_private.h" + +int +fegetexceptflag (fexcept_t *flagp, int excepts) +{ + *flagp = libc_fetestexcept_aarch64 (excepts); + return 0; +} diff --git a/libm/aarch64/fraiseexcpt.c b/libm/aarch64/fraiseexcpt.c new file mode 100644 index 000000000..6a016d046 --- /dev/null +++ b/libm/aarch64/fraiseexcpt.c @@ -0,0 +1,89 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include +#include +#include + +int +feraiseexcept (int excepts) +{ + uint64_t fpsr; + const float fp_zero = 0.0; + const float fp_one = 1.0; + const float fp_max = FLT_MAX; + const float fp_min = FLT_MIN; + const float fp_1e32 = 1.0e32f; + const float fp_two = 2.0; + const float fp_three = 3.0; + + /* Raise exceptions represented by EXCEPTS. But we must raise only + one signal at a time. It is important that if the OVERFLOW or + UNDERFLOW exception and the inexact exception are given at the + same time, the OVERFLOW or UNDERFLOW exception precedes the + INEXACT exception. + + After each exception we read from the FPSR, to force the + exception to be raised immediately. */ + + if (FE_INVALID & excepts) + __asm__ __volatile__ ( + "ldr s0, %1\n\t" + "fdiv s0, s0, s0\n\t" + "mrs %0, fpsr" : "=r" (fpsr) + : "m" (fp_zero) + : "d0"); + + if (FE_DIVBYZERO & excepts) + __asm__ __volatile__ ( + "ldr s0, %1\n\t" + "ldr s1, %2\n\t" + "fdiv s0, s0, s1\n\t" + "mrs %0, fpsr" : "=r" (fpsr) + : "m" (fp_one), "m" (fp_zero) + : "d0", "d1"); + + if (FE_OVERFLOW & excepts) + /* There's no way to raise overflow without also raising inexact. */ + __asm__ __volatile__ ( + "ldr s0, %1\n\t" + "ldr s1, %2\n\t" + "fadd s0, s0, s1\n\t" + "mrs %0, fpsr" : "=r" (fpsr) + : "m" (fp_max), "m" (fp_1e32) + : "d0", "d1"); + + if (FE_UNDERFLOW & excepts) + __asm__ __volatile__ ( + "ldr s0, %1\n\t" + "ldr s1, %2\n\t" + "fdiv s0, s0, s1\n\t" + "mrs %0, fpsr" : "=r" (fpsr) + : "m" (fp_min), "m" (fp_three) + : "d0", "d1"); + + if (FE_INEXACT & excepts) + __asm__ __volatile__ ( + "ldr s0, %1\n\t" + "ldr s1, %2\n\t" + "fdiv s0, s0, s1\n\t" + "mrs %0, fpsr" : "=r" (fpsr) + : "m" (fp_two), "m" (fp_three) + : "d0", "d1"); + + return 0; +} diff --git a/libm/aarch64/fsetexcptflg.c b/libm/aarch64/fsetexcptflg.c new file mode 100644 index 000000000..a78623d14 --- /dev/null +++ b/libm/aarch64/fsetexcptflg.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include + +int +fesetexceptflag (const fexcept_t *flagp, int excepts) +{ + fpu_fpsr_t fpsr; + fpu_fpsr_t fpsr_new; + + /* Get the current environment. */ + _FPU_GETFPSR (fpsr); + excepts &= FE_ALL_EXCEPT; + + /* Set the desired exception mask. */ + fpsr_new = fpsr & ~excepts; + fpsr_new |= *flagp & excepts; + + /* Save state back to the FPU. */ + if (fpsr != fpsr_new) + _FPU_SETFPSR (fpsr_new); + + return 0; +} diff --git a/libm/aarch64/ftestexcept.c b/libm/aarch64/ftestexcept.c new file mode 100644 index 000000000..eecb93406 --- /dev/null +++ b/libm/aarch64/ftestexcept.c @@ -0,0 +1,24 @@ +/* Copyright (C) 1997-2025 Free Software Foundation, Inc. + + 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 + . */ + +#include +#include "fenv_private.h" + +int +fetestexcept (int excepts) +{ + return libc_fetestexcept_aarch64 (excepts); +} -- cgit v1.2.3