Browse Source

mips/mips64: add fenv support from glibc

Waldemar Brodkorb 5 months ago
parent
commit
6b5950e859

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

@@ -167,6 +167,7 @@ config UCLIBC_HAS_FENV
 		   TARGET_aarch64 || \
 		   TARGET_aarch64 || \
 		   TARGET_arm || \
 		   TARGET_arm || \
 		   TARGET_metag || \
 		   TARGET_metag || \
+		   TARGET_mips || \
 		   TARGET_nds32 || \
 		   TARGET_nds32 || \
 		   (TARGET_powerpc && CONFIG_E500) || \
 		   (TARGET_powerpc && CONFIG_E500) || \
 		   TARGET_x86_64
 		   TARGET_x86_64

+ 58 - 24
libc/sysdeps/linux/mips/bits/fenv.h

@@ -1,5 +1,4 @@
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
+/* Copyright (C) 1998-2025 Free Software Foundation, Inc.
 
 
    The GNU C Library is free software; you can redistribute it and/or
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    modify it under the terms of the GNU Lesser General Public
@@ -12,31 +11,38 @@
    Lesser General Public License for more details.
    Lesser General Public License for more details.
 
 
    You should have received a copy of the GNU Lesser General Public
    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
 #ifndef _FENV_H
 # error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
 # error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
 #endif
 #endif
 
 
 
 
+#ifdef __mips_hard_float
+
 /* Define bits representing the exception.  We use the bit positions
 /* Define bits representing the exception.  We use the bit positions
    of the appropriate bits in the FPU control word.  */
    of the appropriate bits in the FPU control word.  */
 enum
 enum
   {
   {
-    FE_INEXACT = 0x04,
-#define FE_INEXACT	FE_INEXACT
-    FE_UNDERFLOW = 0x08,
-#define FE_UNDERFLOW	FE_UNDERFLOW
-    FE_OVERFLOW = 0x10,
-#define FE_OVERFLOW	FE_OVERFLOW
-    FE_DIVBYZERO = 0x20,
-#define FE_DIVBYZERO	FE_DIVBYZERO
-    FE_INVALID = 0x40,
-#define FE_INVALID	FE_INVALID
+    FE_INEXACT =
+# define FE_INEXACT	0x04
+      FE_INEXACT,
+    FE_UNDERFLOW =
+# define FE_UNDERFLOW	0x08
+      FE_UNDERFLOW,
+    FE_OVERFLOW =
+# define FE_OVERFLOW	0x10
+      FE_OVERFLOW,
+    FE_DIVBYZERO =
+# define FE_DIVBYZERO	0x20
+      FE_DIVBYZERO,
+    FE_INVALID =
+# define FE_INVALID	0x40
+      FE_INVALID,
   };
   };
 
 
-#define FE_ALL_EXCEPT \
+# define FE_ALL_EXCEPT \
 	(FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID)
 	(FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID)
 
 
 /* The MIPS FPU supports all of the four defined rounding modes.  We
 /* The MIPS FPU supports all of the four defined rounding modes.  We
@@ -44,16 +50,38 @@ enum
    for the appropriate macros.  */
    for the appropriate macros.  */
 enum
 enum
   {
   {
-    FE_TONEAREST = 0x0,
-#define FE_TONEAREST	FE_TONEAREST
-    FE_TOWARDZERO = 0x1,
-#define FE_TOWARDZERO	FE_TOWARDZERO
-    FE_UPWARD = 0x2,
-#define FE_UPWARD	FE_UPWARD
-    FE_DOWNWARD = 0x3
-#define FE_DOWNWARD	FE_DOWNWARD
+    FE_TONEAREST =
+# define FE_TONEAREST	0x0
+      FE_TONEAREST,
+    FE_TOWARDZERO =
+# define FE_TOWARDZERO	0x1
+      FE_TOWARDZERO,
+    FE_UPWARD =
+# define FE_UPWARD	0x2
+      FE_UPWARD,
+    FE_DOWNWARD =
+# define FE_DOWNWARD	0x3
+      FE_DOWNWARD
   };
   };
 
 
+#else
+
+/* In the soft-float case, only rounding to nearest is supported, with
+   no exceptions.  */
+
+enum
+  {
+    __FE_UNDEFINED = -1,
+
+    FE_TONEAREST =
+# define FE_TONEAREST	0x0
+      FE_TONEAREST
+  };
+
+# define FE_ALL_EXCEPT 0
+
+#endif
+
 
 
 /* Type representing exception flags.  */
 /* Type representing exception flags.  */
 typedef unsigned short int fexcept_t;
 typedef unsigned short int fexcept_t;
@@ -70,7 +98,13 @@ fenv_t;
 /* If the default argument is used we use this value.  */
 /* If the default argument is used we use this value.  */
 #define FE_DFL_ENV	((const fenv_t *) -1)
 #define FE_DFL_ENV	((const fenv_t *) -1)
 
 
-#ifdef __USE_GNU
+#if defined __USE_GNU && defined __mips_hard_float
 /* Floating-point environment where none of the exception is masked.  */
 /* Floating-point environment where none of the exception is masked.  */
 # define FE_NOMASK_ENV  ((const fenv_t *) -2)
 # define FE_NOMASK_ENV  ((const fenv_t *) -2)
 #endif
 #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)

+ 50 - 18
libc/sysdeps/linux/mips/fpu_control.h

@@ -1,7 +1,5 @@
 /* FPU control word bits.  Mips version.
 /* FPU control word bits.  Mips version.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Olaf Flebbe and Ralf Baechle.
+   Copyright (C) 1996-2025 Free Software Foundation, Inc.
 
 
    The GNU C Library is free software; you can redistribute it and/or
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    modify it under the terms of the GNU Lesser General Public
@@ -14,8 +12,8 @@
    Lesser General Public License for more details.
    Lesser General Public License for more details.
 
 
    You should have received a copy of the GNU Lesser General Public
    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
 #ifndef _FPU_CONTROL_H
 #define _FPU_CONTROL_H
 #define _FPU_CONTROL_H
@@ -28,7 +26,10 @@
  *           causing unimplemented operation exception.  This bit is only
  *           causing unimplemented operation exception.  This bit is only
  *           available for MIPS III and newer.
  *           available for MIPS III and newer.
  * 23     -> Condition bit
  * 23     -> Condition bit
- * 22-18  -> reserved (read as 0, write with 0)
+ * 22-21  -> reserved for architecture implementers
+ * 20     -> reserved (read as 0, write with 0)
+ * 19     -> IEEE 754-2008 non-arithmetic ABS.fmt and NEG.fmt enable
+ * 18     -> IEEE 754-2008 recommended NaN encoding enable
  * 17     -> cause bit for unimplemented operation
  * 17     -> cause bit for unimplemented operation
  * 16     -> cause bit for invalid exception
  * 16     -> cause bit for invalid exception
  * 15     -> cause bit for division by zero exception
  * 15     -> cause bit for division by zero exception
@@ -57,43 +58,74 @@
 
 
 #include <features.h>
 #include <features.h>
 
 
-/* masking of interrupts */
+#ifdef __mips_soft_float
+
+#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 /* __mips_soft_float */
+
+/* Masks for interrupts.  */
 #define _FPU_MASK_V     0x0800  /* Invalid operation */
 #define _FPU_MASK_V     0x0800  /* Invalid operation */
 #define _FPU_MASK_Z     0x0400  /* Division by zero  */
 #define _FPU_MASK_Z     0x0400  /* Division by zero  */
 #define _FPU_MASK_O     0x0200  /* Overflow          */
 #define _FPU_MASK_O     0x0200  /* Overflow          */
 #define _FPU_MASK_U     0x0100  /* Underflow         */
 #define _FPU_MASK_U     0x0100  /* Underflow         */
 #define _FPU_MASK_I     0x0080  /* Inexact operation */
 #define _FPU_MASK_I     0x0080  /* Inexact operation */
 
 
-/* flush denormalized numbers to zero */
+/* Flush denormalized numbers to zero.  */
 #define _FPU_FLUSH_TZ   0x1000000
 #define _FPU_FLUSH_TZ   0x1000000
 
 
-/* rounding control */
+/* IEEE 754-2008 compliance control.  */
+#define _FPU_ABS2008    0x80000
+#define _FPU_NAN2008    0x40000
+
+/* Rounding control.  */
 #define _FPU_RC_NEAREST 0x0     /* RECOMMENDED */
 #define _FPU_RC_NEAREST 0x0     /* RECOMMENDED */
 #define _FPU_RC_ZERO    0x1
 #define _FPU_RC_ZERO    0x1
 #define _FPU_RC_UP      0x2
 #define _FPU_RC_UP      0x2
 #define _FPU_RC_DOWN    0x3
 #define _FPU_RC_DOWN    0x3
+/* Mask for rounding control.  */
+#define _FPU_RC_MASK	0x3
 
 
-#define _FPU_RESERVED 0xfe3c0000  /* Reserved bits in cw */
+#define _FPU_RESERVED 0xfe8c0000  /* Reserved bits in cw, incl ABS/NAN2008.  */
 
 
 
 
 /* The fdlibm code requires strict IEEE double precision arithmetic,
 /* The fdlibm code requires strict IEEE double precision arithmetic,
    and no interrupts for exceptions, rounding to nearest.  */
    and no interrupts for exceptions, rounding to nearest.  */
+#ifdef __mips_nan2008
+# define _FPU_DEFAULT 0x000C0000
+#else
+# define _FPU_DEFAULT 0x00000000
+#endif
 
 
-#define _FPU_DEFAULT  0x00000000
-
-/* IEEE:  same as above, but exceptions */
-#define _FPU_IEEE     0x00000F80
+/* IEEE: same as above, but exceptions.  */
+#ifdef __mips_nan2008
+# define _FPU_IEEE    0x000C0F80
+#else
+# define _FPU_IEEE    0x00000F80
+#endif
 
 
 /* Type of the control word.  */
 /* Type of the control word.  */
 typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__SI__)));
 typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__SI__)));
 
 
 /* Macros for accessing the hardware control word.  */
 /* Macros for accessing the hardware control word.  */
-#define _FPU_GETCW(cw) __asm__ ("cfc1 %0,$31" : "=r" (cw))
-#define _FPU_SETCW(cw) __asm__ ("ctc1 %0,$31" : : "r" (cw))
+extern fpu_control_t __mips_fpu_getcw (void) __THROW;
+extern void __mips_fpu_setcw (fpu_control_t) __THROW;
+#ifdef __mips16
+# define _FPU_GETCW(cw) do { (cw) = __mips_fpu_getcw (); } while (0)
+# define _FPU_SETCW(cw) __mips_fpu_setcw (cw)
+#else
+# define _FPU_GETCW(cw) __asm__ volatile ("cfc1 %0,$31" : "=r" (cw))
+# define _FPU_SETCW(cw) __asm__ volatile ("ctc1 %0,$31" : : "r" (cw))
+#endif
 
 
-#if 0
 /* Default control word set at startup.  */
 /* Default control word set at startup.  */
 extern fpu_control_t __fpu_control;
 extern fpu_control_t __fpu_control;
-#endif
+
+#endif /* __mips_soft_float */
 
 
 #endif	/* fpu_control.h */
 #endif	/* fpu_control.h */

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

+ 44 - 0
libm/mips/fclrexcpt.c

@@ -0,0 +1,44 @@
+/* Clear given exceptions in current floating-point environment.
+   Copyright (C) 1998-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 "fenv_libc.h"
+#include <fpu_control.h>
+
+int
+feclearexcept (int excepts)
+{
+  int cw;
+
+  /* Mask out unsupported bits/exceptions.  */
+  excepts &= FE_ALL_EXCEPT;
+
+  /* Read the complete control word.  */
+  _FPU_GETCW (cw);
+
+  /* Clear exception flag bits and cause bits. If the cause bit is not
+     cleared, the next CTC instruction (just below) will re-generate the
+     exception.  */
+
+  cw &= ~(excepts | (excepts << CAUSE_SHIFT));
+
+  /* Put the new data in effect.  */
+  _FPU_SETCW (cw);
+
+  /* Success.  */
+  return 0;
+}

+ 38 - 0
libm/mips/fedisblxcpt.c

@@ -0,0 +1,38 @@
+/* Disable floating-point exceptions.
+   Copyright (C) 2000-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 "fenv_libc.h"
+#include <fpu_control.h>
+
+int
+fedisableexcept (int excepts)
+{
+  unsigned int new_exc, old_exc;
+
+  /* Get the current control word.  */
+  _FPU_GETCW (new_exc);
+
+  old_exc = (new_exc & ENABLE_MASK) >> ENABLE_SHIFT;
+
+  excepts &= FE_ALL_EXCEPT;
+
+  new_exc &= ~(excepts << ENABLE_SHIFT);
+  _FPU_SETCW (new_exc);
+
+  return old_exc;
+}

+ 38 - 0
libm/mips/feenablxcpt.c

@@ -0,0 +1,38 @@
+/* Enable floating-point exceptions.
+   Copyright (C) 2000-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 "fenv_libc.h"
+#include <fpu_control.h>
+
+int
+feenableexcept (int excepts)
+{
+  unsigned int new_exc, old_exc;
+
+  /* Get the current control word.  */
+  _FPU_GETCW (new_exc);
+
+  old_exc = (new_exc & ENABLE_MASK) >> ENABLE_SHIFT;
+
+  excepts &= FE_ALL_EXCEPT;
+
+  new_exc |= excepts << ENABLE_SHIFT;
+  _FPU_SETCW (new_exc);
+
+  return old_exc;
+}

+ 28 - 0
libm/mips/fegetenv.c

@@ -0,0 +1,28 @@
+/* Store current floating-point environment.
+   Copyright (C) 1998-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>
+
+int
+fegetenv (fenv_t *envp)
+{
+  _FPU_GETCW (*envp);
+
+  /* Success.  */
+  return 0;
+}

+ 31 - 0
libm/mips/fegetexcept.c

@@ -0,0 +1,31 @@
+/* Get enabled floating-point exceptions.
+   Copyright (C) 2000-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 "fenv_libc.h"
+#include <fpu_control.h>
+
+int
+fegetexcept (void)
+{
+  unsigned int exc;
+
+  /* Get the current control word.  */
+  _FPU_GETCW (exc);
+
+  return (exc & ENABLE_MASK) >> ENABLE_SHIFT;
+}

+ 26 - 0
libm/mips/fegetmode.c

@@ -0,0 +1,26 @@
+/* Store current floating-point control modes.  MIPS 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>
+
+int
+fegetmode (femode_t *modep)
+{
+  _FPU_GETCW (*modep);
+  return 0;
+}

+ 30 - 0
libm/mips/fegetround.c

@@ -0,0 +1,30 @@
+/* Return current rounding direction.
+   Copyright (C) 1998-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>
+
+int
+fegetround (void)
+{
+  int cw;
+
+  /* Get control word.  */
+  _FPU_GETCW (cw);
+
+  return cw & _FPU_RC_MASK;
+}

+ 35 - 0
libm/mips/feholdexcpt.c

@@ -0,0 +1,35 @@
+/* Store current floating-point environment and clear exceptions.
+   Copyright (C) 2000-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>
+
+int
+feholdexcept (fenv_t *envp)
+{
+  fpu_control_t cw;
+
+  /* Save the current state.  */
+  _FPU_GETCW (cw);
+  envp->__fp_control_register = cw;
+
+  /* Clear all exception enable bits and flags.  */
+  cw &= ~(_FPU_MASK_V|_FPU_MASK_Z|_FPU_MASK_O|_FPU_MASK_U|_FPU_MASK_I|FE_ALL_EXCEPT);
+  _FPU_SETCW (cw);
+
+  return 0;
+}

+ 29 - 0
libm/mips/fenv_libc.h

@@ -0,0 +1,29 @@
+/* Copyright (C) 2000-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 _FENV_LIBC_H
+#define _FENV_LIBC_H    1
+
+/* Mask for enabling exceptions and for the CAUSE bits.  */
+#define ENABLE_MASK	0x00F80U
+#define CAUSE_MASK	0x1F000U
+
+/* Shift for FE_* flags to get up to the ENABLE bits and the CAUSE bits.  */
+#define	ENABLE_SHIFT	5
+#define	CAUSE_SHIFT	10
+
+
+#endif /* _FENV_LIBC_H */

+ 238 - 0
libm/mips/fenv_private.h

@@ -0,0 +1,238 @@
+/* Internal math stuff.  MIPS version.
+   Copyright (C) 2013-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 MIPS_FENV_PRIVATE_H
+#define MIPS_FENV_PRIVATE_H 1
+
+/* Inline functions to speed up the math library implementation.  The
+   default versions of these routines are in generic/fenv_private.h
+   and call fesetround, feholdexcept, etc.  These routines use inlined
+   code instead.  */
+
+#include <fenv.h>
+#include "fenv_libc.h"
+#include <fpu_control.h>
+
+#define _FPU_MASK_ALL (_FPU_MASK_V | _FPU_MASK_Z | _FPU_MASK_O \
+		       |_FPU_MASK_U | _FPU_MASK_I | FE_ALL_EXCEPT)
+
+static __always_inline void
+libc_feholdexcept_mips (fenv_t *envp)
+{
+  fpu_control_t cw;
+
+  /* Save the current state.  */
+  _FPU_GETCW (cw);
+  envp->__fp_control_register = cw;
+
+  /* Clear all exception enable bits and flags.  */
+  cw &= ~(_FPU_MASK_ALL);
+  _FPU_SETCW (cw);
+}
+#define libc_feholdexcept libc_feholdexcept_mips
+#define libc_feholdexceptf libc_feholdexcept_mips
+#define libc_feholdexceptl libc_feholdexcept_mips
+
+static __always_inline void
+libc_fesetround_mips (int round)
+{
+  fpu_control_t cw;
+
+  /* Get current state.  */
+  _FPU_GETCW (cw);
+
+  /* Set rounding bits.  */
+  cw &= ~_FPU_RC_MASK;
+  cw |= round;
+
+  /* Set new state.  */
+  _FPU_SETCW (cw);
+}
+#define libc_fesetround libc_fesetround_mips
+#define libc_fesetroundf libc_fesetround_mips
+#define libc_fesetroundl libc_fesetround_mips
+
+static __always_inline void
+libc_feholdexcept_setround_mips (fenv_t *envp, int round)
+{
+  fpu_control_t cw;
+
+  /* Save the current state.  */
+  _FPU_GETCW (cw);
+  envp->__fp_control_register = cw;
+
+  /* Clear all exception enable bits and flags.  */
+  cw &= ~(_FPU_MASK_ALL);
+
+  /* Set rounding bits.  */
+  cw &= ~_FPU_RC_MASK;
+  cw |= round;
+
+  /* Set new state.  */
+  _FPU_SETCW (cw);
+}
+#define libc_feholdexcept_setround libc_feholdexcept_setround_mips
+#define libc_feholdexcept_setroundf libc_feholdexcept_setround_mips
+#define libc_feholdexcept_setroundl libc_feholdexcept_setround_mips
+
+#define libc_feholdsetround libc_feholdexcept_setround_mips
+#define libc_feholdsetroundf libc_feholdexcept_setround_mips
+#define libc_feholdsetroundl libc_feholdexcept_setround_mips
+
+static __always_inline void
+libc_fesetenv_mips (fenv_t *envp)
+{
+  fpu_control_t cw __attribute__ ((unused));
+
+  /* Read current state to flush fpu pipeline.  */
+  _FPU_GETCW (cw);
+
+  _FPU_SETCW (envp->__fp_control_register);
+}
+#define libc_fesetenv libc_fesetenv_mips
+#define libc_fesetenvf libc_fesetenv_mips
+#define libc_fesetenvl libc_fesetenv_mips
+
+static __always_inline int
+libc_feupdateenv_test_mips (fenv_t *envp, int excepts)
+{
+  /* int ret = fetestexcept (excepts); feupdateenv (envp); return ret; */
+  int cw, temp;
+
+  /* Get current control word.  */
+  _FPU_GETCW (cw);
+
+  /* Set flag bits (which are accumulative), and *also* set the
+     cause bits.  The setting of the cause bits is what actually causes
+     the hardware to generate the exception, if the corresponding enable
+     bit is set as well.  */
+  temp = cw & FE_ALL_EXCEPT;
+  temp |= envp->__fp_control_register | (temp << CAUSE_SHIFT);
+
+  /* Set new state.  */
+  _FPU_SETCW (temp);
+
+  return cw & excepts & FE_ALL_EXCEPT;
+}
+#define libc_feupdateenv_test libc_feupdateenv_test_mips
+#define libc_feupdateenv_testf libc_feupdateenv_test_mips
+#define libc_feupdateenv_testl libc_feupdateenv_test_mips
+
+static __always_inline void
+libc_feupdateenv_mips (fenv_t *envp)
+{
+  libc_feupdateenv_test_mips (envp, 0);
+}
+#define libc_feupdateenv libc_feupdateenv_mips
+#define libc_feupdateenvf libc_feupdateenv_mips
+#define libc_feupdateenvl libc_feupdateenv_mips
+
+#define libc_feresetround libc_feupdateenv_mips
+#define libc_feresetroundf libc_feupdateenv_mips
+#define libc_feresetroundl libc_feupdateenv_mips
+
+static __always_inline int
+libc_fetestexcept_mips (int excepts)
+{
+  int cw;
+
+  /* Get current control word.  */
+  _FPU_GETCW (cw);
+
+  return cw & excepts & FE_ALL_EXCEPT;
+}
+#define libc_fetestexcept libc_fetestexcept_mips
+#define libc_fetestexceptf libc_fetestexcept_mips
+#define libc_fetestexceptl libc_fetestexcept_mips
+
+/*  Enable support for rounding mode context.  */
+#define HAVE_RM_CTX 1
+
+static __always_inline void
+libc_feholdexcept_setround_mips_ctx (struct rm_ctx *ctx, int round)
+{
+  fpu_control_t old, new;
+
+  /* Save the current state.  */
+  _FPU_GETCW (old);
+  ctx->env.__fp_control_register = old;
+
+  /* Clear all exception enable bits and flags.  */
+  new = old & ~(_FPU_MASK_ALL);
+
+  /* Set rounding bits.  */
+  new = (new & ~_FPU_RC_MASK) | round;
+
+  if (__glibc_unlikely (new != old))
+    {
+      _FPU_SETCW (new);
+      ctx->updated_status = true;
+    }
+  else
+    ctx->updated_status = false;
+}
+#define libc_feholdexcept_setround_ctx   libc_feholdexcept_setround_mips_ctx
+#define libc_feholdexcept_setroundf_ctx  libc_feholdexcept_setround_mips_ctx
+#define libc_feholdexcept_setroundl_ctx  libc_feholdexcept_setround_mips_ctx
+
+static __always_inline void
+libc_fesetenv_mips_ctx (struct rm_ctx *ctx)
+{
+  libc_fesetenv_mips (&ctx->env);
+}
+#define libc_fesetenv_ctx                libc_fesetenv_mips_ctx
+#define libc_fesetenvf_ctx               libc_fesetenv_mips_ctx
+#define libc_fesetenvl_ctx               libc_fesetenv_mips_ctx
+
+static __always_inline void
+libc_feupdateenv_mips_ctx (struct rm_ctx *ctx)
+{
+  if (__glibc_unlikely (ctx->updated_status))
+    libc_feupdateenv_test_mips (&ctx->env, 0);
+}
+#define libc_feupdateenv_ctx             libc_feupdateenv_mips_ctx
+#define libc_feupdateenvf_ctx            libc_feupdateenv_mips_ctx
+#define libc_feupdateenvl_ctx            libc_feupdateenv_mips_ctx
+#define libc_feresetround_ctx            libc_feupdateenv_mips_ctx
+#define libc_feresetroundf_ctx           libc_feupdateenv_mips_ctx
+#define libc_feresetroundl_ctx           libc_feupdateenv_mips_ctx
+
+static __always_inline void
+libc_feholdsetround_mips_ctx (struct rm_ctx *ctx, int round)
+{
+  fpu_control_t old, new;
+
+  /* Save the current state.  */
+  _FPU_GETCW (old);
+  ctx->env.__fp_control_register = old;
+
+  /* Set rounding bits.  */
+  new = (old & ~_FPU_RC_MASK) | round;
+
+  if (__glibc_unlikely (new != old))
+    {
+      _FPU_SETCW (new);
+      ctx->updated_status = true;
+    }
+  else
+    ctx->updated_status = false;
+}
+#define libc_feholdsetround_ctx          libc_feholdsetround_mips_ctx
+#define libc_feholdsetroundf_ctx         libc_feholdsetround_mips_ctx
+#define libc_feholdsetroundl_ctx         libc_feholdsetround_mips_ctx
+
+#endif

+ 38 - 0
libm/mips/fesetenv.c

@@ -0,0 +1,38 @@
+/* Install given floating-point environment.
+   Copyright (C) 1998-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>
+
+int
+fesetenv (const fenv_t *envp)
+{
+  fpu_control_t cw;
+
+  /* Read first current state to flush fpu pipeline.  */
+  _FPU_GETCW (cw);
+
+  if (envp == FE_DFL_ENV)
+    _FPU_SETCW (_FPU_DEFAULT);
+  else if (envp == FE_NOMASK_ENV)
+    _FPU_SETCW (_FPU_IEEE);
+  else
+    _FPU_SETCW (envp->__fp_control_register);
+
+  /* Success.  */
+  return 0;
+}

+ 31 - 0
libm/mips/fesetexcept.c

@@ -0,0 +1,31 @@
+/* Set given exception flags.  MIPS 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>
+
+int
+fesetexcept (int excepts)
+{
+  fpu_control_t temp;
+
+  _FPU_GETCW (temp);
+  temp |= excepts & FE_ALL_EXCEPT;
+  _FPU_SETCW (temp);
+
+  return 0;
+}

+ 37 - 0
libm/mips/fesetmode.c

@@ -0,0 +1,37 @@
+/* Install given floating-point control modes.  MIPS 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>
+
+#define FCSR_STATUS 0xfe83f07c
+
+int
+fesetmode (const femode_t *modep)
+{
+  fpu_control_t cw;
+
+  _FPU_GETCW (cw);
+  cw &= FCSR_STATUS;
+  if (modep == FE_DFL_MODE)
+    cw |= _FPU_DEFAULT;
+  else
+    cw |= *modep & ~FCSR_STATUS;
+  _FPU_SETCW (cw);
+
+  return 0;
+}

+ 40 - 0
libm/mips/fesetround.c

@@ -0,0 +1,40 @@
+/* Set current rounding direction.
+   Copyright (C) 1998-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>
+
+int
+fesetround (int round)
+{
+  fpu_control_t cw;
+
+  if ((round & ~_FPU_RC_MASK) != 0)
+    /* ROUND is no valid rounding mode.  */
+    return 1;
+
+  /* Get current state.  */
+  _FPU_GETCW (cw);
+
+  /* Set rounding bits.  */
+  cw &= ~_FPU_RC_MASK;
+  cw |= round;
+  /* Set new state.  */
+  _FPU_SETCW (cw);
+
+  return 0;
+}

+ 40 - 0
libm/mips/feupdateenv.c

@@ -0,0 +1,40 @@
+/* Install given floating-point environment and raise exceptions.
+   Copyright (C) 1998-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>
+
+int
+feupdateenv (const fenv_t *envp)
+{
+  int temp;
+
+  /* Save current exceptions.  */
+  _FPU_GETCW (temp);
+  temp &= FE_ALL_EXCEPT;
+
+  /* Install new environment.  */
+  fesetenv (envp);
+
+  /* Raise the saved exception.  Incidentally for us the implementation
+     defined format of the values in objects of type fexcept_t is the
+     same as the ones specified using the FE_* constants.  */
+  feraiseexcept (temp);
+
+  /* Success.  */
+  return 0;
+}

+ 37 - 0
libm/mips/fgetexcptflg.c

@@ -0,0 +1,37 @@
+/* Store current representation for exceptions.
+   Copyright (C) 1998-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>
+
+int
+fegetexceptflag (fexcept_t *flagp, int excepts)
+{
+  fpu_control_t temp;
+
+  /* Get the current exceptions.  */
+  _FPU_GETCW (temp);
+
+  /* We only save the relevant bits here. In particular, care has to be
+     taken with the CAUSE bits, as an inadvertent restore later on could
+     generate unexpected exceptions.  */
+
+  *flagp = temp & excepts & FE_ALL_EXCEPT;
+
+  /* Success.  */
+  return 0;
+}

+ 42 - 0
libm/mips/fraiseexcpt.c

@@ -0,0 +1,42 @@
+/* Raise given exceptions.
+   Copyright (C) 2000-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 "fenv_libc.h"
+#include <fpu_control.h>
+
+int
+feraiseexcept (int excepts)
+{
+  fpu_control_t cw;
+
+  /* Get current state.  */
+  _FPU_GETCW (cw);
+
+  /* Set flag bits (which are accumulative), and *also* set the
+     cause bits. The setting of the cause bits is what actually causes
+     the hardware to generate the exception, if the corresponding enable
+     bit is set as well.  */
+
+  excepts &= FE_ALL_EXCEPT;
+  cw |= excepts | (excepts << CAUSE_SHIFT);
+
+  /* Set new state.  */
+  _FPU_SETCW (cw);
+
+  return 0;
+}

+ 40 - 0
libm/mips/fsetexcptflg.c

@@ -0,0 +1,40 @@
+/* Set floating-point environment exception handling.
+   Copyright (C) 1998-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>
+
+int
+fesetexceptflag (const fexcept_t *flagp, int excepts)
+{
+  fpu_control_t temp;
+
+  /* Get the current exceptions.  */
+  _FPU_GETCW (temp);
+
+  /* Make sure the flags we want restored are legal.  */
+  excepts &= FE_ALL_EXCEPT;
+
+  /* Now clear the bits called for, and copy them in from flagp. Note that
+     we ignore all non-flag bits from *flagp, so they don't matter.  */
+  temp = (temp & ~excepts) | (*flagp & excepts);
+
+  _FPU_SETCW (temp);
+
+  /* Success.  */
+  return 0;
+}

+ 30 - 0
libm/mips/ftestexcept.c

@@ -0,0 +1,30 @@
+/* Test exception in current environment.
+   Copyright (C) 1998-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>
+
+int
+fetestexcept (int excepts)
+{
+  int cw;
+
+  /* Get current control word.  */
+  _FPU_GETCW (cw);
+
+  return cw & excepts & FE_ALL_EXCEPT;
+}