Browse Source

arm: add fenv support from glibc

Waldemar Brodkorb 6 days ago
parent
commit
c7405bd4ce

+ 1 - 0
extra/Configs/Config.in.arch

@@ -165,6 +165,7 @@ config UCLIBC_HAS_FENV
 	depends on UCLIBC_HAS_FLOATS
 	depends on TARGET_i386 || \
 		   TARGET_aarch64 || \
+		   TARGET_arm || \
 		   TARGET_metag || \
 		   TARGET_nds32 || \
 		   (TARGET_powerpc && CONFIG_E500) || \

+ 48 - 59
libc/sysdeps/linux/arm/bits/fenv.h

@@ -1,5 +1,4 @@
-/* Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
+/* Copyright (C) 2004-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
@@ -12,87 +11,77 @@
    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
-   <http://www.gnu.org/licenses/>.  */
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
 
 #ifndef _FENV_H
 # error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
 #endif
 
-#ifdef __MAVERICK__
-
 /* Define bits representing exceptions in the FPU status word.  */
 enum
   {
-    FE_INVALID = 1,
-#define FE_INVALID FE_INVALID
-    FE_OVERFLOW = 4,
-#define FE_OVERFLOW FE_OVERFLOW
-    FE_UNDERFLOW = 8,
-#define FE_UNDERFLOW FE_UNDERFLOW
-    FE_INEXACT = 16,
-#define FE_INEXACT FE_INEXACT
+    FE_INVALID =
+#define FE_INVALID	1
+      FE_INVALID,
+    FE_DIVBYZERO =
+#define FE_DIVBYZERO	2
+      FE_DIVBYZERO,
+    FE_OVERFLOW =
+#define FE_OVERFLOW	4
+      FE_OVERFLOW,
+    FE_UNDERFLOW =
+#define FE_UNDERFLOW	8
+      FE_UNDERFLOW,
+    FE_INEXACT =
+#define FE_INEXACT	16
+      FE_INEXACT,
   };
 
 /* Amount to shift by to convert an exception to a mask bit.  */
-#define FE_EXCEPT_SHIFT    5
+#define FE_EXCEPT_SHIFT	8
 
 /* All supported exceptions.  */
-#define FE_ALL_EXCEPT  \
-	(FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)
-
-/* IEEE rounding modes.  */
-enum
-  {
-    FE_TONEAREST = 0,
-#define FE_TONEAREST    FE_TONEAREST
-    FE_TOWARDZERO = 0x400,
-#define FE_TOWARDZERO   FE_TOWARDZERO
-    FE_DOWNWARD = 0x800,
-#define FE_DOWNWARD     FE_DOWNWARD
-    FE_UPWARD = 0xc00,
-#define FE_UPWARD       FE_UPWARD
-  };
-
-#define FE_ROUND_MASK (FE_UPWARD)
-
-#else /* !__MAVERICK__ */
+#define FE_ALL_EXCEPT	\
+	(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)
 
-/* Define bits representing exceptions in the FPU status word.  */
+/* VFP supports all of the four defined rounding modes.  */
 enum
   {
-    FE_INVALID = 1,
-#define FE_INVALID FE_INVALID
-    FE_DIVBYZERO = 2,
-#define FE_DIVBYZERO FE_DIVBYZERO
-    FE_OVERFLOW = 4,
-#define FE_OVERFLOW FE_OVERFLOW
-    FE_UNDERFLOW = 8,
-#define FE_UNDERFLOW FE_UNDERFLOW
-  };
-
-/* Amount to shift by to convert an exception to a mask bit.  */
-#define FE_EXCEPT_SHIFT	16
-
-/* All supported exceptions.  */
-#define FE_ALL_EXCEPT	\
-	(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW)
-
-/* The ARM FPU basically only supports round-to-nearest.  Other rounding
-   modes exist, but you have to encode them in the actual instruction.  */
+    FE_TONEAREST =
 #define FE_TONEAREST	0
-
-#endif /* __MAVERICK__ */
+      FE_TONEAREST,
+    FE_UPWARD =
+#define FE_UPWARD	0x400000
+      FE_UPWARD,
+    FE_DOWNWARD =
+#define FE_DOWNWARD	0x800000
+      FE_DOWNWARD,
+    FE_TOWARDZERO =
+#define FE_TOWARDZERO	0xc00000
+      FE_TOWARDZERO
+  };
 
 /* Type representing exception flags. */
-typedef unsigned long int fexcept_t;
+typedef unsigned int fexcept_t;
 
 /* Type representing floating-point environment.  */
 typedef struct
   {
-    unsigned long int __cw;
+    unsigned int __cw;
   }
 fenv_t;
 
 /* If the default argument is used we use this value.  */
-#define FE_DFL_ENV	((fenv_t *) -1l)
+#define FE_DFL_ENV	((const fenv_t *) -1l)
+
+#ifdef __USE_GNU
+/* Floating-point environment where none of the exceptions are masked.  */
+# define FE_NOMASK_ENV  ((const fenv_t *) -2)
+#endif
+
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)

+ 32 - 160
libc/sysdeps/linux/arm/fpu_control.h

@@ -1,6 +1,5 @@
-/* FPU control word definitions.  ARM version.
-   Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
+/* FPU control word definitions.  ARM VFP version.
+   Copyright (C) 2004-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
@@ -13,13 +12,22 @@
    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
-   <http://www.gnu.org/licenses/>.  */
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
 
 #ifndef _FPU_CONTROL_H
 #define _FPU_CONTROL_H
 
-#ifdef __VFP_FP__
+#if !(defined(_LIBC) && !defined(_LIBC_TEST)) && defined(__SOFTFP__)
+
+#define _FPU_RESERVED 0xffffffff
+#define _FPU_DEFAULT  0x00000000
+typedef unsigned int fpu_control_t;
+#define _FPU_GETCW(cw) (cw) = 0
+#define _FPU_SETCW(cw) (void) (cw)
+extern fpu_control_t __fpu_control;
+
+#else
 
 /* masking of interrupts */
 #define _FPU_MASK_IM	0x00000100	/* invalid operation */
@@ -28,175 +36,39 @@
 #define _FPU_MASK_UM	0x00000800	/* underflow */
 #define _FPU_MASK_PM	0x00001000	/* inexact */
 
+#define _FPU_MASK_NZCV	0xf0000000	/* NZCV flags */
+#define _FPU_MASK_RM	0x00c00000	/* rounding mode */
+#define _FPU_MASK_EXCEPT 0x00001f1f	/* all exception flags */
+
 /* Some bits in the FPSCR are not yet defined.  They must be preserved when
    modifying the contents.  */
-#define _FPU_RESERVED	0x0e08e0e0
+#define _FPU_RESERVED	0x00086060
 #define _FPU_DEFAULT    0x00000000
-/* Default + exceptions enabled. */
+
+/* Default + exceptions enabled.  */
 #define _FPU_IEEE	(_FPU_DEFAULT | 0x00001f00)
 
 /* Type of the control word.  */
 typedef unsigned int fpu_control_t;
 
 /* Macros for accessing the hardware control word.  */
+#ifdef __SOFTFP__
 /* This is fmrx %0, fpscr.  */
-#define _FPU_GETCW(cw) \
+# define _FPU_GETCW(cw) \
   __asm__ __volatile__ ("mrc p10, 7, %0, cr1, cr0, 0" : "=r" (cw))
 /* This is fmxr fpscr, %0.  */
-#define _FPU_SETCW(cw) \
+# define _FPU_SETCW(cw) \
   __asm__ __volatile__ ("mcr p10, 7, %0, cr1, cr0, 0" : : "r" (cw))
+#else
+# define _FPU_GETCW(cw) \
+  __asm__ __volatile__ ("vmrs %0, fpscr" : "=r" (cw))
+# define _FPU_SETCW(cw) \
+  __asm__ __volatile__ ("vmsr fpscr, %0" : : "r" (cw))
+#endif
 
-#elif defined __MAVERICK__
-
-/* DSPSC register: (from EP9312 User's Guide)
- *
- * bits 31..29	- DAID
- * bits 28..26	- HVID
- * bits 25..24	- RSVD
- * bit  23	- ISAT
- * bit  22	- UI
- * bit  21	- INT
- * bit  20	- AEXC
- * bits 19..18	- SAT
- * bits 17..16	- FCC
- * bit  15	- V
- * bit  14	- FWDEN
- * bit  13	- Invalid
- * bit	12	- Denorm
- * bits 11..10	- RM
- * bits 9..5	- IXE, UFE, OFE, RSVD, IOE
- * bits 4..0	- IX, UF, OF, RSVD, IO
- */
-
-/* masking of interrupts */
-#define _FPU_MASK_IM	(1 << 5)	/* invalid operation */
-#define _FPU_MASK_ZM	0		/* divide by zero */
-#define _FPU_MASK_OM	(1 << 7)	/* overflow */
-#define _FPU_MASK_UM	(1 << 8)	/* underflow */
-#define _FPU_MASK_PM	(1 << 9)	/* inexact */
-#define _FPU_MASK_DM	0		/* denormalized operation */
-
-#define _FPU_RESERVED	0xfffff000	/* These bits are reserved.  */
-
-#define _FPU_DEFAULT	0x00b00000	/* Default value.  */
-#define _FPU_IEEE	0x00b003a0	/* Default + exceptions enabled. */
-
-/* Type of the control word.  */
-typedef unsigned int fpu_control_t;
-
-/* Macros for accessing the hardware control word.  */
-#define _FPU_GETCW(cw) ({			\
-	register int __t1, __t2;		\
-						\
-	__asm__ __volatile__ (			\
-	"cfmvr64l	%1, mvdx0\n\t"		\
-	"cfmvr64h	%2, mvdx0\n\t"		\
-	"cfmv32sc	mvdx0, dspsc\n\t"	\
-	"cfmvr64l	%0, mvdx0\n\t"		\
-	"cfmv64lr	mvdx0, %1\n\t"		\
-	"cfmv64hr	mvdx0, %2"		\
-	: "=r" (cw), "=r" (__t1), "=r" (__t2)	\
-	);					\
-})
-
-#define _FPU_SETCW(cw) ({			\
-	register int __t0, __t1, __t2;		\
-						\
-	__asm__ __volatile__ (			\
-	"cfmvr64l	%1, mvdx0\n\t"		\
-	"cfmvr64h	%2, mvdx0\n\t"		\
-	"cfmv64lr	mvdx0, %0\n\t"		\
-	"cfmvsc32	dspsc, mvdx0\n\t"	\
-	"cfmv64lr	mvdx0, %1\n\t"		\
-	"cfmv64hr	mvdx0, %2"		\
-	: "=r" (__t0), "=r" (__t1), "=r" (__t2)	\
-	: "0" (cw)				\
-	);					\
-})
-
-#else /* !__MAVERICK__ */
-
-/* We have a slight terminology confusion here.  On the ARM, the register
- * we're interested in is actually the FPU status word - the FPU control
- * word is something different (which is implementation-defined and only
- * accessible from supervisor mode.)
- *
- * The FPSR looks like this:
- *
- *     31-24        23-16          15-8              7-0
- * | system ID | trap enable | system control | exception flags |
- *
- * We ignore the system ID bits; for interest's sake they are:
- *
- *  0000	"old" FPE
- *  1000	FPPC hardware
- *  0001	FPE 400
- *  1001	FPA hardware
- *
- * The trap enable and exception flags are both structured like this:
- *
- *     7 - 5     4     3     2     1     0
- * | reserved | INX | UFL | OFL | DVZ | IVO |
- *
- * where a `1' bit in the enable byte means that the trap can occur, and
- * a `1' bit in the flags byte means the exception has occurred.
- *
- * The exceptions are:
- *
- *  IVO - invalid operation
- *  DVZ - divide by zero
- *  OFL - overflow
- *  UFL - underflow
- *  INX - inexact (do not use; implementations differ)
- *
- * The system control byte looks like this:
- *
- *     7-5      4    3    2    1    0
- * | reserved | AC | EP | SO | NE | ND |
- *
- * where the bits mean
- *
- *  ND - no denormalised numbers (force them all to zero)
- *  NE - enable NaN exceptions
- *  SO - synchronous operation
- *  EP - use expanded packed-decimal format
- *  AC - use alternate definition for C flag on compare operations
- */
-
-/* masking of interrupts */
-#define _FPU_MASK_IM	0x00010000	/* invalid operation */
-#define _FPU_MASK_ZM	0x00020000	/* divide by zero */
-#define _FPU_MASK_OM	0x00040000	/* overflow */
-#define _FPU_MASK_UM	0x00080000	/* underflow */
-#define _FPU_MASK_PM	0x00100000	/* inexact */
-#define _FPU_MASK_DM	0x00000000	/* denormalized operation */
-
-/* The system id bytes cannot be changed.
-   Only the bottom 5 bits in the trap enable byte can be changed.
-   Only the bottom 5 bits in the system control byte can be changed.
-   Only the bottom 5 bits in the exception flags are used.
-   The exception flags are set by the fpu, but can be zeroed by the user. */
-#define _FPU_RESERVED	0xffe0e0e0	/* These bits are reserved.  */
-
-/* The fdlibm code requires strict IEEE double precision arithmetic,
-   no interrupts for exceptions, rounding to nearest.  Changing the
-   rounding mode will break long double I/O.  Turn on the AC bit,
-   the compiler generates code that assumes it is on.  */
-#define _FPU_DEFAULT	0x00001000	/* Default value.  */
-#define _FPU_IEEE	0x001f1000	/* Default + exceptions enabled. */
-
-/* Type of the control word.  */
-typedef unsigned int fpu_control_t;
-
-/* Macros for accessing the hardware control word.  */
-#define _FPU_GETCW(cw) __asm__ ("rfs %0" : "=r" (cw))
-#define _FPU_SETCW(cw) __asm__ ("wfs %0" : : "r" (cw))
-
-#endif /* __MAVERICK__ */
-
-#if 0
 /* Default control word set at startup.  */
 extern fpu_control_t __fpu_control;
-#endif
+
+#endif /* __SOFTFP__ */
 
 #endif /* _FPU_CONTROL_H */

+ 16 - 0
libm/arm/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)

+ 58 - 0
libm/arm/arm-features.h

@@ -0,0 +1,58 @@
+/* Macros to test for CPU features on ARM.  Generic ARM version.
+   Copyright (C) 2012-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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARM_ARM_FEATURES_H
+#define _ARM_ARM_FEATURES_H 1
+
+/* An OS-specific arm-features.h file should define ARM_HAVE_VFP to
+   an appropriate expression for testing at runtime whether the VFP
+   hardware is present.  We'll then redefine it to a constant if we
+   know at compile time that we can assume VFP.  */
+
+#ifndef __SOFTFP__
+/* The compiler is generating VFP instructions, so we're already
+   assuming the hardware exists.  */
+# undef ARM_HAVE_VFP
+# define ARM_HAVE_VFP	1
+#endif
+
+/* An OS-specific arm-features.h file may define ARM_ASSUME_NO_IWMMXT
+   to indicate at compile time that iWMMXt hardware is never present
+   at runtime (or that we never care about its state) and so need not
+   be checked for.  */
+
+/* A more-specific arm-features.h file may define ARM_ALWAYS_BX to indicate
+   that instructions using pc as a destination register must never be used,
+   so a "bx" (or "blx") instruction is always required.  */
+
+/* The log2 of the minimum alignment required for an address that
+   is the target of a computed branch (i.e. a "bx" instruction).
+   A more-specific arm-features.h file may define this to set a more
+   stringent requirement.
+
+   Using this only makes sense for code in ARM mode (where instructions
+   always have a fixed size of four bytes), or for Thumb-mode code that is
+   specifically aligning all the related branch targets to match (since
+   Thumb instructions might be either two or four bytes).  */
+#ifndef ARM_BX_ALIGN_LOG2
+# define ARM_BX_ALIGN_LOG2	2
+#endif
+
+/* An OS-specific arm-features.h file may define ARM_NO_INDEX_REGISTER to
+   indicate that the two-register addressing modes must never be used.  */
+
+#endif  /* arm-features.h */

+ 41 - 0
libm/arm/fclrexcpt.c

@@ -0,0 +1,41 @@
+/* Clear given exceptions in current floating-point environment.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+
+int
+feclearexcept (int excepts)
+{
+  fpu_control_t fpscr, new_fpscr;
+
+  /* Fail if a VFP unit isn't present unless nothing needs to be done.  */
+  if (!ARM_HAVE_VFP)
+    return (excepts != 0);
+
+  _FPU_GETCW (fpscr);
+  excepts &= FE_ALL_EXCEPT;
+  new_fpscr = fpscr & ~excepts;
+
+  /* Write new exception flags if changed.  */
+  if (new_fpscr != fpscr)
+    _FPU_SETCW (new_fpscr);
+
+  return 0;
+}

+ 41 - 0
libm/arm/fedisblxcpt.c

@@ -0,0 +1,41 @@
+/* Disable floating-point exceptions.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+
+int
+fedisableexcept (int excepts)
+{
+  fpu_control_t fpscr, new_fpscr;
+
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return -1;
+
+  _FPU_GETCW (fpscr);
+  excepts &= FE_ALL_EXCEPT;
+  new_fpscr = fpscr & ~(excepts << FE_EXCEPT_SHIFT);
+
+  /* Write new exceptions if changed.  */
+  if (new_fpscr != fpscr)
+    _FPU_SETCW (new_fpscr);
+
+  return (fpscr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
+}

+ 49 - 0
libm/arm/feenablxcpt.c

@@ -0,0 +1,49 @@
+/* Enable floating-point exceptions.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+
+int
+feenableexcept (int excepts)
+{
+  fpu_control_t fpscr, new_fpscr, updated_fpscr;
+
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return -1;
+
+  _FPU_GETCW (fpscr);
+  excepts &= FE_ALL_EXCEPT;
+  new_fpscr = fpscr | (excepts << FE_EXCEPT_SHIFT);
+
+  if (new_fpscr != fpscr)
+    {
+      _FPU_SETCW (new_fpscr);
+
+      /* Not all VFP architectures support trapping exceptions, so
+	 test whether the relevant bits were set and fail if not.  */
+      _FPU_GETCW (updated_fpscr);
+
+      if (new_fpscr & ~updated_fpscr)
+	return -1;
+    }
+
+  return (fpscr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
+}

+ 35 - 0
libm/arm/fegetenv.c

@@ -0,0 +1,35 @@
+/* Store current floating-point environment.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+
+int
+fegetenv (fenv_t *envp)
+{
+  fpu_control_t fpscr;
+
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
+
+  _FPU_GETCW (fpscr);
+  envp->__cw = fpscr;
+  return 0;
+}

+ 35 - 0
libm/arm/fegetexcept.c

@@ -0,0 +1,35 @@
+/* Get floating-point exceptions.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+
+int
+fegetexcept (void)
+{
+  fpu_control_t fpscr;
+
+  /* Return with all exceptions disabled if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 0;
+
+  _FPU_GETCW (fpscr);
+
+  return (fpscr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
+}

+ 28 - 0
libm/arm/fegetmode.c

@@ -0,0 +1,28 @@
+/* Store current floating-point control modes.  ARM 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+int
+fegetmode (femode_t *modep)
+{
+  if (ARM_HAVE_VFP)
+    _FPU_GETCW (*modep);
+  return 0;
+}

+ 42 - 0
libm/arm/fegetround.c

@@ -0,0 +1,42 @@
+/* Return current rounding direction.
+   Copyright (C) 2004-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
+   <https://www.gnu.org/licenses/>.  */
+
+#include "arm-features.h"
+#include <fenv.h>
+#include <fpu_control.h>
+
+/* Return the floating-point rounding mode.  */
+
+static inline int
+get_rounding_mode (void)
+{
+  fpu_control_t fpscr;
+
+  /* FE_TONEAREST is the only supported rounding mode
+     if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return FE_TONEAREST;
+
+  _FPU_GETCW (fpscr);
+  return fpscr & _FPU_MASK_RM;
+}
+
+int
+fegetround (void)
+{
+  return get_rounding_mode ();
+}

+ 31 - 0
libm/arm/feholdexcpt.c

@@ -0,0 +1,31 @@
+/* Store current floating-point environment and clear exceptions.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include "fenv_private.h"
+#include "arm-features.h"
+
+
+int
+feholdexcept (fenv_t *envp)
+{
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
+
+  libc_feholdexcept_vfp (envp);
+  return 0;
+}

+ 248 - 0
libm/arm/fenv_private.h

@@ -0,0 +1,248 @@
+/* Private floating point rounding and exceptions handling.  ARM VFP 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef ARM_FENV_PRIVATE_H
+#define ARM_FENV_PRIVATE_H 1
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+static __always_inline void
+libc_feholdexcept_vfp (fenv_t *envp)
+{
+  fpu_control_t fpscr;
+
+  _FPU_GETCW (fpscr);
+  envp->__cw = fpscr;
+
+  /* Clear exception flags and set all exceptions to non-stop.  */
+  fpscr &= ~_FPU_MASK_EXCEPT;
+  _FPU_SETCW (fpscr);
+}
+
+static __always_inline void
+libc_fesetround_vfp (int round)
+{
+  fpu_control_t fpscr;
+
+  _FPU_GETCW (fpscr);
+
+  /* Set new rounding mode if different.  */
+  if (unlikely ((fpscr & _FPU_MASK_RM) != round))
+    _FPU_SETCW ((fpscr & ~_FPU_MASK_RM) | round);
+}
+
+static __always_inline void
+libc_feholdexcept_setround_vfp (fenv_t *envp, int round)
+{
+  fpu_control_t fpscr;
+
+  _FPU_GETCW (fpscr);
+  envp->__cw = fpscr;
+
+  /* Clear exception flags, set all exceptions to non-stop,
+     and set new rounding mode.  */
+  fpscr &= ~(_FPU_MASK_EXCEPT | _FPU_MASK_RM);
+  _FPU_SETCW (fpscr | round);
+}
+
+static __always_inline void
+libc_feholdsetround_vfp (fenv_t *envp, int round)
+{
+  fpu_control_t fpscr;
+
+  _FPU_GETCW (fpscr);
+  envp->__cw = fpscr;
+
+  /* Set new rounding mode if different.  */
+  if (unlikely ((fpscr & _FPU_MASK_RM) != round))
+    _FPU_SETCW ((fpscr & ~_FPU_MASK_RM) | round);
+}
+
+static __always_inline void
+libc_feresetround_vfp (fenv_t *envp)
+{
+  fpu_control_t fpscr, round;
+
+  _FPU_GETCW (fpscr);
+
+  /* Check whether rounding modes are different.  */
+  round = (envp->__cw ^ fpscr) & _FPU_MASK_RM;
+
+  /* Restore the rounding mode if it was changed.  */
+  if (unlikely (round != 0))
+    _FPU_SETCW (fpscr ^ round);
+}
+
+static __always_inline int
+libc_fetestexcept_vfp (int ex)
+{
+  fpu_control_t fpscr;
+
+  _FPU_GETCW (fpscr);
+  return fpscr & ex & FE_ALL_EXCEPT;
+}
+
+static __always_inline void
+libc_fesetenv_vfp (const fenv_t *envp)
+{
+  fpu_control_t fpscr, new_fpscr;
+
+  _FPU_GETCW (fpscr);
+  new_fpscr = envp->__cw;
+
+  /* Write new FPSCR if different (ignoring NZCV flags).  */
+  if (unlikely (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0))
+    _FPU_SETCW (new_fpscr);
+}
+
+static __always_inline int
+libc_feupdateenv_test_vfp (const fenv_t *envp, int ex)
+{
+  fpu_control_t fpscr, new_fpscr;
+  int excepts;
+
+  _FPU_GETCW (fpscr);
+
+  /* Merge current exception flags with the saved fenv.  */
+  excepts = fpscr & FE_ALL_EXCEPT;
+  new_fpscr = envp->__cw | excepts;
+
+  /* Write new FPSCR if different (ignoring NZCV flags).  */
+  if (unlikely (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0))
+    _FPU_SETCW (new_fpscr);
+
+  /* Raise the exceptions if enabled in the new FP state.  */
+  if (unlikely (excepts & (new_fpscr >> FE_EXCEPT_SHIFT)))
+    feraiseexcept (excepts);
+
+  return excepts & ex;
+}
+
+static __always_inline void
+libc_feupdateenv_vfp (const fenv_t *envp)
+{
+  libc_feupdateenv_test_vfp (envp, 0);
+}
+
+static __always_inline void
+libc_feholdsetround_vfp_ctx (struct rm_ctx *ctx, int r)
+{
+  fpu_control_t fpscr, round;
+
+  _FPU_GETCW (fpscr);
+  ctx->updated_status = false;
+  ctx->env.__cw = fpscr;
+
+  /* Check whether rounding modes are different.  */
+  round = (fpscr ^ r) & _FPU_MASK_RM;
+
+  /* Set the rounding mode if changed.  */
+  if (unlikely (round != 0))
+    {
+      ctx->updated_status = true;
+      _FPU_SETCW (fpscr ^ round);
+    }
+}
+
+static __always_inline void
+libc_feresetround_vfp_ctx (struct rm_ctx *ctx)
+{
+  /* Restore the rounding mode if updated.  */
+  if (unlikely (ctx->updated_status))
+    {
+      fpu_control_t fpscr;
+
+      _FPU_GETCW (fpscr);
+      fpscr = (fpscr & ~_FPU_MASK_RM) | (ctx->env.__cw & _FPU_MASK_RM);
+      _FPU_SETCW (fpscr);
+    }
+}
+
+static __always_inline void
+libc_fesetenv_vfp_ctx (struct rm_ctx *ctx)
+{
+  fpu_control_t fpscr, new_fpscr;
+
+  _FPU_GETCW (fpscr);
+  new_fpscr = ctx->env.__cw;
+
+  /* Write new FPSCR if different (ignoring NZCV flags).  */
+  if (unlikely (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0))
+    _FPU_SETCW (new_fpscr);
+}
+
+#ifndef __SOFTFP__
+
+# define libc_feholdexcept  libc_feholdexcept_vfp
+# define libc_feholdexceptf libc_feholdexcept_vfp
+# define libc_feholdexceptl libc_feholdexcept_vfp
+
+# define libc_fesetround  libc_fesetround_vfp
+# define libc_fesetroundf libc_fesetround_vfp
+# define libc_fesetroundl libc_fesetround_vfp
+
+# define libc_feresetround  libc_feresetround_vfp
+# define libc_feresetroundf libc_feresetround_vfp
+# define libc_feresetroundl libc_feresetround_vfp
+
+# define libc_feresetround_noex  libc_fesetenv_vfp
+# define libc_feresetround_noexf libc_fesetenv_vfp
+# define libc_feresetround_noexl libc_fesetenv_vfp
+
+# define libc_feholdexcept_setround  libc_feholdexcept_setround_vfp
+# define libc_feholdexcept_setroundf libc_feholdexcept_setround_vfp
+# define libc_feholdexcept_setroundl libc_feholdexcept_setround_vfp
+
+# define libc_feholdsetround  libc_feholdsetround_vfp
+# define libc_feholdsetroundf libc_feholdsetround_vfp
+# define libc_feholdsetroundl libc_feholdsetround_vfp
+
+# define libc_fetestexcept  libc_fetestexcept_vfp
+# define libc_fetestexceptf libc_fetestexcept_vfp
+# define libc_fetestexceptl libc_fetestexcept_vfp
+
+# define libc_fesetenv  libc_fesetenv_vfp
+# define libc_fesetenvf libc_fesetenv_vfp
+# define libc_fesetenvl libc_fesetenv_vfp
+
+# define libc_feupdateenv  libc_feupdateenv_vfp
+# define libc_feupdateenvf libc_feupdateenv_vfp
+# define libc_feupdateenvl libc_feupdateenv_vfp
+
+# define libc_feupdateenv_test  libc_feupdateenv_test_vfp
+# define libc_feupdateenv_testf libc_feupdateenv_test_vfp
+# define libc_feupdateenv_testl libc_feupdateenv_test_vfp
+
+/* We have support for rounding mode context.  */
+#define HAVE_RM_CTX 1
+
+# define libc_feholdsetround_ctx	libc_feholdsetround_vfp_ctx
+# define libc_feresetround_ctx		libc_feresetround_vfp_ctx
+# define libc_feresetround_noex_ctx	libc_fesetenv_vfp_ctx
+
+# define libc_feholdsetroundf_ctx	libc_feholdsetround_vfp_ctx
+# define libc_feresetroundf_ctx		libc_feresetround_vfp_ctx
+# define libc_feresetround_noexf_ctx	libc_fesetenv_vfp_ctx
+
+# define libc_feholdsetroundl_ctx	libc_feholdsetround_vfp_ctx
+# define libc_feresetroundl_ctx		libc_feresetround_vfp_ctx
+# define libc_feresetround_noexl_ctx	libc_fesetenv_vfp_ctx
+
+#endif
+
+#endif /* ARM_FENV_PRIVATE_H */

+ 62 - 0
libm/arm/fesetenv.c

@@ -0,0 +1,62 @@
+/* Install given floating-point environment.
+   Copyright (C) 2004-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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+
+int
+fesetenv (const fenv_t *envp)
+{
+  fpu_control_t fpscr, new_fpscr, updated_fpscr;
+
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
+
+  _FPU_GETCW (fpscr);
+
+  if ((envp != FE_DFL_ENV) && (envp != FE_NOMASK_ENV))
+    {
+      /* The new FPSCR is valid, so don't merge the reserved flags.  */
+      new_fpscr = envp->__cw;
+
+      /* Write new FPSCR if different (ignoring NZCV flags).  */
+      if (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0)
+	_FPU_SETCW (new_fpscr);
+
+      return 0;
+    }
+
+  /* Preserve the reserved FPSCR flags.  */
+  new_fpscr = fpscr & _FPU_RESERVED;
+  new_fpscr |= (envp == FE_DFL_ENV) ? _FPU_DEFAULT : _FPU_IEEE;
+
+  if (((new_fpscr ^ fpscr) & ~_FPU_MASK_NZCV) != 0)
+    {
+      _FPU_SETCW (new_fpscr);
+
+      /* Not all VFP architectures support trapping exceptions, so
+	 test whether the relevant bits were set and fail if not.  */
+      _FPU_GETCW (updated_fpscr);
+
+      return new_fpscr & ~updated_fpscr;
+    }
+
+  return 0;
+}

+ 37 - 0
libm/arm/fesetexcept.c

@@ -0,0 +1,37 @@
+/* Set given exception flags.  ARM 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+int
+fesetexcept (int excepts)
+{
+  fpu_control_t fpscr, new_fpscr;
+
+  /* Fail if a VFP unit isn't present unless nothing needs to be done.  */
+  if (!ARM_HAVE_VFP)
+    return (excepts != 0);
+
+  _FPU_GETCW (fpscr);
+  new_fpscr = fpscr | (excepts & FE_ALL_EXCEPT);
+  if (new_fpscr != fpscr)
+    _FPU_SETCW (new_fpscr);
+
+  return 0;
+}

+ 44 - 0
libm/arm/fesetmode.c

@@ -0,0 +1,44 @@
+/* Install given floating-point control modes.  ARM 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+/* NZCV flags, QC bit, IDC bit and bits for IEEE exception status.  */
+#define FPU_STATUS_BITS 0xf800009f
+
+int
+fesetmode (const femode_t *modep)
+{
+  fpu_control_t fpscr, new_fpscr;
+
+  if (!ARM_HAVE_VFP)
+    /* Nothing to do.  */
+    return 0;
+
+  _FPU_GETCW (fpscr);
+  if (modep == FE_DFL_MODE)
+    new_fpscr = (fpscr & (_FPU_RESERVED | FPU_STATUS_BITS)) | _FPU_DEFAULT;
+  else
+    new_fpscr = (fpscr & FPU_STATUS_BITS) | (*modep & ~FPU_STATUS_BITS);
+
+  if (((new_fpscr ^ fpscr) & ~_FPU_MASK_NZCV) != 0)
+    _FPU_SETCW (new_fpscr);
+
+  return 0;
+}

+ 35 - 0
libm/arm/fesetround.c

@@ -0,0 +1,35 @@
+/* Set current rounding direction.
+   Copyright (C) 2004-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
+   <https://www.gnu.org/licenses/>.  */
+
+#include "fenv_private.h"
+#include "arm-features.h"
+
+
+int
+fesetround (int round)
+{
+  /* FE_TONEAREST is the only supported rounding mode
+     if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return (round == FE_TONEAREST) ? 0 : 1;
+
+  if (round & ~_FPU_MASK_RM)
+    return 1;
+
+  libc_fesetround_vfp (round);
+  return 0;
+}

+ 73 - 0
libm/arm/feupdateenv.c

@@ -0,0 +1,73 @@
+/* Install given floating-point environment and raise exceptions.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+
+int
+feupdateenv (const fenv_t *envp)
+{
+  fpu_control_t fpscr, new_fpscr, updated_fpscr;
+  int excepts;
+
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
+
+  _FPU_GETCW (fpscr);
+  excepts = fpscr & FE_ALL_EXCEPT;
+
+  if ((envp != FE_DFL_ENV) && (envp != FE_NOMASK_ENV))
+    {
+      /* Merge current exception flags with the saved fenv.  */
+      new_fpscr = envp->__cw | excepts;
+
+      /* Write new FPSCR if different (ignoring NZCV flags).  */
+      if (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0)
+	_FPU_SETCW (new_fpscr);
+
+      /* Raise the exceptions if enabled in the new FP state.  */
+      if (excepts & (new_fpscr >> FE_EXCEPT_SHIFT))
+	return feraiseexcept (excepts);
+
+      return 0;
+    }
+
+  /* Preserve the reserved FPSCR flags.  */
+  new_fpscr = fpscr & (_FPU_RESERVED | FE_ALL_EXCEPT);
+  new_fpscr |= (envp == FE_DFL_ENV) ? _FPU_DEFAULT : _FPU_IEEE;
+
+  if (((new_fpscr ^ fpscr) & ~_FPU_MASK_NZCV) != 0)
+    {
+      _FPU_SETCW (new_fpscr);
+
+      /* Not all VFP architectures support trapping exceptions, so
+	 test whether the relevant bits were set and fail if not.  */
+      _FPU_GETCW (updated_fpscr);
+
+      if (new_fpscr & ~updated_fpscr)
+	return 1;
+    }
+
+  /* Raise the exceptions if enabled in the new FP state.  */
+  if (excepts & (new_fpscr >> FE_EXCEPT_SHIFT))
+    return feraiseexcept (excepts);
+
+  return 0;
+}

+ 31 - 0
libm/arm/fgetexcptflg.c

@@ -0,0 +1,31 @@
+/* Store current representation for exceptions.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include "fenv_private.h"
+#include "arm-features.h"
+
+
+int
+fegetexceptflag (fexcept_t *flagp, int excepts)
+{
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
+
+  *flagp = libc_fetestexcept_vfp (excepts);
+  return 0;
+}

+ 103 - 0
libm/arm/fraiseexcpt.c

@@ -0,0 +1,103 @@
+/* Raise given exceptions.
+   Copyright (C) 2004-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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fpu_control.h>
+#include <fenv.h>
+#include <float.h>
+#include "arm-features.h"
+
+
+int
+feraiseexcept (int excepts)
+{
+  /* Fail if a VFP unit isn't present unless nothing needs to be done.  */
+  if (!ARM_HAVE_VFP)
+    return (excepts != 0);
+  else
+    {
+      fpu_control_t fpscr;
+      const float fp_zero = 0.0, fp_one = 1.0, fp_max = FLT_MAX,
+                  fp_min = FLT_MIN, fp_1e32 = 1.0e32f, fp_two = 2.0,
+		  fp_three = 3.0;
+
+      /* Raise exceptions represented by EXPECTS.  But we must raise only
+	 one signal at a time.  It is important that if the overflow/underflow
+	 exception and the inexact exception are given at the same time,
+	 the overflow/underflow exception follows the inexact exception.  After
+	 each exception we read from the fpscr, to force the exception to be
+	 raised immediately.  */
+
+      /* There are additional complications because this file may be compiled
+         without VFP support enabled, and we also can't assume that the
+	 assembler has VFP instructions enabled. To get around this we use the
+	 generic coprocessor mnemonics and avoid asking GCC to put float values
+	 in VFP registers.  */
+
+      /* First: invalid exception.  */
+      if (FE_INVALID & excepts)
+	__asm__ __volatile__ (
+	  "ldc p10, cr0, %1\n\t"                        /* flds s0, %1  */
+	  "cdp p10, 8, cr0, cr0, cr0, 0\n\t"            /* fdivs s0, s0, s0  */
+	  "mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr)  /* fmrx %0, fpscr  */
+			                : "m" (fp_zero)
+					: "s0");
+
+      /* Next: division by zero.  */
+      if (FE_DIVBYZERO & excepts)
+	__asm__ __volatile__ (
+	  "ldc p10, cr0, %1\n\t"                        /* flds s0, %1  */
+	  "ldcl p10, cr0, %2\n\t"                       /* flds s1, %2  */
+	  "cdp p10, 8, cr0, cr0, cr0, 1\n\t"            /* fdivs s0, s0, s1  */
+	  "mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr)  /* fmrx %0, fpscr  */
+			                : "m" (fp_one), "m" (fp_zero)
+					: "s0", "s1");
+
+      /* Next: overflow.  */
+      if (FE_OVERFLOW & excepts)
+	/* There's no way to raise overflow without also raising inexact.  */
+	__asm__ __volatile__ (
+	  "ldc p10, cr0, %1\n\t"                        /* flds s0, %1  */
+	  "ldcl p10, cr0, %2\n\t"                       /* flds s1, %2  */
+	  "cdp p10, 3, cr0, cr0, cr0, 1\n\t"            /* fadds s0, s0, s1  */
+	  "mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr)  /* fmrx %0, fpscr  */
+			                : "m" (fp_max), "m" (fp_1e32)
+					: "s0", "s1");
+
+      /* Next: underflow.  */
+      if (FE_UNDERFLOW & excepts)
+	__asm__ __volatile__ (
+	  "ldc p10, cr0, %1\n\t"                        /* flds s0, %1  */
+	  "ldcl p10, cr0, %2\n\t"                       /* flds s1, %2  */
+	  "cdp p10, 8, cr0, cr0, cr0, 1\n\t"            /* fdivs s0, s0, s1  */
+	  "mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr)  /* fmrx %0, fpscr  */
+			                : "m" (fp_min), "m" (fp_three)
+					: "s0", "s1");
+
+      /* Last: inexact.  */
+      if (FE_INEXACT & excepts)
+	__asm__ __volatile__ (
+	  "ldc p10, cr0, %1\n\t"                        /* flds s0, %1  */
+	  "ldcl p10, cr0, %2\n\t"                       /* flds s1, %2  */
+	  "cdp p10, 8, cr0, cr0, cr0, 1\n\t"            /* fdivs s0, s0, s1  */
+	  "mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr)  /* fmrx %0, fpscr  */
+			                : "m" (fp_two), "m" (fp_three)
+					: "s0", "s1");
+
+      /* Success.  */
+      return 0;
+    }
+}

+ 44 - 0
libm/arm/fsetexcptflg.c

@@ -0,0 +1,44 @@
+/* Set floating-point environment exception handling.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include "arm-features.h"
+
+
+int
+fesetexceptflag (const fexcept_t *flagp, int excepts)
+{
+  fpu_control_t fpscr, new_fpscr;
+
+  /* Fail if a VFP unit isn't present unless nothing needs to be done.  */
+  if (!ARM_HAVE_VFP)
+    return (excepts != 0);
+
+  _FPU_GETCW (fpscr);
+  excepts &= FE_ALL_EXCEPT;
+
+  /* Set the desired exception mask.  */
+  new_fpscr = fpscr & ~excepts;
+  new_fpscr |= *flagp & excepts;
+
+  /* Write new exception flags if changed.  */
+  if (new_fpscr != fpscr)
+    _FPU_SETCW (new_fpscr);
+
+  return 0;
+}

+ 30 - 0
libm/arm/ftestexcept.c

@@ -0,0 +1,30 @@
+/* Test exception in current environment.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include "fenv_private.h"
+#include "arm-features.h"
+
+
+int
+fetestexcept (int excepts)
+{
+  /* Return no exception flags if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 0;
+
+  return libc_fetestexcept_vfp (excepts);
+}