Просмотр исходного кода

ppc: add fenv support from glibc

For ppc SPE we had fenv support before that commit.
Now add it to classic ppc cpu support.
Ported over from GNU C Library and tested in Qemu System
Emulation for MACPPC.
Waldemar Brodkorb 9 часов назад
Родитель
Сommit
359fcd62fc

+ 1 - 1
Makefile.in

@@ -263,7 +263,7 @@ HEADERS_RM-$(UCLIBC_HAS_ARGP)                += argp.h
 HEADERS_RM-$(UCLIBC_HAS_BSD_ERR)             += err.h
 HEADERS_RM-$(UCLIBC_HAS_CRYPT)               += crypt.h
 HEADERS_RM-$(UCLIBC_HAS_EPOLL)               += sys/epoll.h
-HEADERS_RM-$(UCLIBC_HAS_FENV)                += fenv.h bits/fenv.h bits/fenvinline.h
+HEADERS_RM-$(UCLIBC_HAS_FENV)                += fenv.h bits/fenv.h
 HEADERS_RM-$(UCLIBC_HAS_FLOATS)              += complex.h fpu_control.h ieee754.h \
 	math.h \
 	tgmath.h \

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

@@ -174,7 +174,7 @@ config UCLIBC_HAS_FENV
 		   TARGET_mips || \
 		   TARGET_nds32 || \
 		   TARGET_or1k || \
-		   (TARGET_powerpc && CONFIG_E500) || \
+		   TARGET_powerpc || \
 		   TARGET_riscv32 || \
 		   TARGET_riscv64 || \
 		   (TARGET_sh && (CONFIG_SH4 || CONFIG_SH4A)) || \

+ 1 - 6
include/fenv.h

@@ -108,12 +108,6 @@ extern int fesetenv (const fenv_t *__envp) __THROW;
    according to saved exceptions.  */
 extern int feupdateenv (const fenv_t *__envp) __THROW;
 
-
-/* Include optimization.  */
-#ifdef __OPTIMIZE__
-# include <bits/fenvinline.h>
-#endif
-
 #ifdef __USE_GNU
 
 /* Enable individual exceptions.  Will not enable more exceptions than
@@ -128,6 +122,7 @@ extern int fedisableexcept (int __excepts) __THROW;
 
 /* Return enabled exceptions.  */
 extern int fegetexcept (void) __THROW;
+
 #endif
 
 __END_DECLS

+ 87 - 54
libc/sysdeps/linux/powerpc/bits/fenv.h

@@ -1,5 +1,4 @@
-/* Copyright (C) 1997, 1998, 1999, 2004, 2006 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
+/* Copyright (C) 1997-2026 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,7 +12,7 @@
 
    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/>.  */
+   <https://www.gnu.org/licenses/>.  */
 
 #ifndef _FENV_H
 # error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
@@ -28,31 +27,35 @@
 enum
   {
     FE_INEXACT = 1 << (63 - 42),
-#define FE_INEXACT	FE_INEXACT
+#define FE_INEXACT     FE_INEXACT
     FE_INVALID = 1 << (63 - 43),
-#define FE_INVALID	FE_INVALID
+#define FE_INVALID     FE_INVALID
     FE_DIVBYZERO = 1 << (63 - 44),
-#define FE_DIVBYZERO	FE_DIVBYZERO
+#define FE_DIVBYZERO   FE_DIVBYZERO
     FE_UNDERFLOW = 1 << (63 - 45),
-#define FE_UNDERFLOW	FE_UNDERFLOW
+#define FE_UNDERFLOW   FE_UNDERFLOW
     FE_OVERFLOW = 1 << (63 - 46)
-#define FE_OVERFLOW	FE_OVERFLOW
+#define FE_OVERFLOW    FE_OVERFLOW
   };
 
-#else /* PowerPC 6xx floating-point.  */
+#else /* PowerPC floating-point.  */
 
 /* Define bits representing the exception.  We use the bit positions of
    the appropriate bits in the FPSCR...  */
 enum
   {
-    FE_INEXACT = 1 << (31 - 6),
-#define FE_INEXACT	FE_INEXACT
-    FE_DIVBYZERO = 1 << (31 - 5),
-#define FE_DIVBYZERO	FE_DIVBYZERO
-    FE_UNDERFLOW = 1 << (31 - 4),
-#define FE_UNDERFLOW	FE_UNDERFLOW
-    FE_OVERFLOW = 1 << (31 - 3),
-#define FE_OVERFLOW	FE_OVERFLOW
+    FE_INEXACT =
+#define FE_INEXACT	(1 << (31 - 6))
+      FE_INEXACT,
+    FE_DIVBYZERO =
+#define FE_DIVBYZERO	(1 << (31 - 5))
+      FE_DIVBYZERO,
+    FE_UNDERFLOW =
+#define FE_UNDERFLOW	(1 << (31 - 4))
+      FE_UNDERFLOW,
+    FE_OVERFLOW =
+#define FE_OVERFLOW	(1 << (31 - 3))
+      FE_OVERFLOW,
 
     /* ... except for FE_INVALID, for which we use bit 31. FE_INVALID
        actually corresponds to bits 7 through 12 and 21 through 23
@@ -60,8 +63,9 @@ enum
        says that it must be a power of 2.  Instead we use bit 2 which
        is the summary bit for all the FE_INVALID exceptions, which
        kind of makes sense.  */
-    FE_INVALID = 1 << (31 - 2),
-#define FE_INVALID	FE_INVALID
+    FE_INVALID =
+#define FE_INVALID	(1 << (31 - 2))
+      FE_INVALID,
 
 #ifdef __USE_GNU
     /* Breakdown of the FE_INVALID bits. Setting FE_INVALID on an
@@ -70,50 +74,59 @@ enum
        these bits is set.  Note, though, that you can't disable or
        enable these exceptions individually.  */
 
-    /* Operation with SNaN. */
-    FE_INVALID_SNAN = 1 << (31 - 7),
-# define FE_INVALID_SNAN	FE_INVALID_SNAN
+    /* Operation with a sNaN.  */
+    FE_INVALID_SNAN =
+# define FE_INVALID_SNAN	(1 << (31 - 7))
+      FE_INVALID_SNAN,
 
     /* Inf - Inf */
-    FE_INVALID_ISI = 1 << (31 - 8),
-# define FE_INVALID_ISI		FE_INVALID_ISI
+    FE_INVALID_ISI =
+# define FE_INVALID_ISI	(1 << (31 - 8))
+      FE_INVALID_ISI,
 
     /* Inf / Inf */
-    FE_INVALID_IDI = 1 << (31 - 9),
-# define FE_INVALID_IDI		FE_INVALID_IDI
+    FE_INVALID_IDI =
+# define FE_INVALID_IDI	(1 << (31 - 9))
+      FE_INVALID_IDI,
 
     /* 0 / 0 */
-    FE_INVALID_ZDZ = 1 << (31 - 10),
-# define FE_INVALID_ZDZ		FE_INVALID_ZDZ
+    FE_INVALID_ZDZ =
+# define FE_INVALID_ZDZ	(1 << (31 - 10))
+      FE_INVALID_ZDZ,
 
     /* Inf * 0 */
-    FE_INVALID_IMZ = 1 << (31 - 11),
-# define FE_INVALID_IMZ		FE_INVALID_IMZ
+    FE_INVALID_IMZ =
+# define FE_INVALID_IMZ	(1 << (31 - 11))
+      FE_INVALID_IMZ,
 
-    /* Comparison with NaN or SNaN.  */
-    FE_INVALID_COMPARE = 1 << (31 - 12),
-# define FE_INVALID_COMPARE	FE_INVALID_COMPARE
+    /* Comparison with a NaN.  */
+    FE_INVALID_COMPARE =
+# define FE_INVALID_COMPARE	(1 << (31 - 12))
+      FE_INVALID_COMPARE,
 
     /* Invalid operation flag for software (not set by hardware).  */
     /* Note that some chips don't have this implemented, presumably
        because no-one expected anyone to write software for them %-).  */
-    FE_INVALID_SOFTWARE = 1 << (31 - 21),
-# define FE_INVALID_SOFTWARE	FE_INVALID_SOFTWARE
+    FE_INVALID_SOFTWARE =
+# define FE_INVALID_SOFTWARE	(1 << (31 - 21))
+      FE_INVALID_SOFTWARE,
 
     /* Square root of negative number (including -Inf).  */
     /* Note that some chips don't have this implemented.  */
-    FE_INVALID_SQRT = 1 << (31 - 22),
-# define FE_INVALID_SQRT	FE_INVALID_SQRT
+    FE_INVALID_SQRT =
+# define FE_INVALID_SQRT	(1 << (31 - 22))
+      FE_INVALID_SQRT,
 
     /* Conversion-to-integer of a NaN or a number too large or too small.  */
-    FE_INVALID_INTEGER_CONVERSION = 1 << (31 - 23)
-# define FE_INVALID_INTEGER_CONVERSION	FE_INVALID_INTEGER_CONVERSION
+    FE_INVALID_INTEGER_CONVERSION =
+# define FE_INVALID_INTEGER_CONVERSION	(1 << (31 - 23))
+      FE_INVALID_INTEGER_CONVERSION
 
 # define FE_ALL_INVALID \
         (FE_INVALID_SNAN | FE_INVALID_ISI | FE_INVALID_IDI | FE_INVALID_ZDZ \
 	 | FE_INVALID_IMZ | FE_INVALID_COMPARE | FE_INVALID_SOFTWARE \
 	 | FE_INVALID_SQRT | FE_INVALID_INTEGER_CONVERSION)
-#endif /* __USE_GNU */
+#endif
   };
 
 #endif /* __CONFIG_E500__ */
@@ -126,14 +139,18 @@ enum
    appropriate macros.  */
 enum
   {
-    FE_TONEAREST = 0,
-#define FE_TONEAREST	FE_TONEAREST
-    FE_TOWARDZERO = 1,
-#define FE_TOWARDZERO	FE_TOWARDZERO
-    FE_UPWARD = 2,
-#define FE_UPWARD	FE_UPWARD
-    FE_DOWNWARD = 3
-#define FE_DOWNWARD	FE_DOWNWARD
+    FE_TONEAREST =
+#define FE_TONEAREST	0
+      FE_TONEAREST,
+    FE_TOWARDZERO =
+#define FE_TOWARDZERO	1
+      FE_TOWARDZERO,
+    FE_UPWARD =
+#define FE_UPWARD	2
+      FE_UPWARD,
+    FE_DOWNWARD =
+#define FE_DOWNWARD	3
+      FE_DOWNWARD
   };
 
 /* Type representing exception flags.  */
@@ -159,9 +176,25 @@ extern const fenv_t __fe_nonieee_env;
 # define FE_NONIEEE_ENV	(&__fe_nonieee_env)
 
 /* Floating-point environment with all exceptions enabled.  Note that
-   just evaluating this value will set the processor into 'FPU
-   exceptions imprecise recoverable' mode, which may cause a significant
-   performance penalty (but have no other visible effect).  */
-extern const fenv_t *__fe_nomask_env (void);
-# define FE_NOMASK_ENV	(__fe_nomask_env ())
-#endif /* __USE_GNU */
+   just evaluating this value does not change the processor exception mode.
+   Passing this mask to fesetenv will result in a prctl syscall to change
+   the MSR FE0/FE1 bits to "Precise Mode".  On some processors this will
+   result in slower floating point execution.  This will last until an
+   fenv or exception mask is installed that disables all FP exceptions.  */
+# define FE_NOMASK_ENV	FE_ENABLED_ENV
+
+/* Floating-point environment with all exceptions disabled.  Note that
+   just evaluating this value does not change the processor exception mode.
+   Passing this mask to fesetenv will result in a prctl syscall to change
+   the MSR FE0/FE1 bits to "Ignore Exceptions Mode".  On most processors
+   this allows the fastest possible floating point execution.*/
+# define FE_MASK_ENV	FE_DFL_ENV
+
+#endif
+
+/* Type representing floating-point control modes.  */
+typedef double femode_t;
+
+/* Default floating-point control modes.  */
+extern const femode_t __fe_dfl_mode;
+# define FE_DFL_MODE	(&__fe_dfl_mode)

+ 0 - 63
libc/sysdeps/linux/powerpc/bits/fenvinline.h

@@ -1,63 +0,0 @@
-/* Inline floating-point environment handling functions for powerpc.
-   Copyright (C) 1995, 1996, 1997, 1998, 1999, 2006
-   Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <features.h>
-
-#if defined __GNUC__ && !defined _SOFT_FLOAT && !defined __NO_MATH_INLINES
-
-/* Inline definition for fegetround.  */
-# define fegetround() \
-  (__extension__  ({ int __fegetround_result;				      \
-		     __asm__ __volatile__				      \
-		       ("mcrfs 7,7 ; mfcr %0"				      \
-			: "=r"(__fegetround_result) : : "cr7");		      \
-		     __fegetround_result & 3; }))
-
-/* The weird 'i#*X' constraints on the following suppress a gcc
-   warning when __excepts is not a constant.  Otherwise, they mean the
-   same as just plain 'i'.  */
-
-/* Inline definition for feraiseexcept.  */
-# define feraiseexcept(__excepts) \
-  ((__builtin_constant_p (__excepts)					      \
-    && ((__excepts) & ((__excepts)-1)) == 0				      \
-    && (__excepts) != FE_INVALID)					      \
-   ? ((__excepts) != 0							      \
-      ? (__extension__ ({ __asm__ __volatile__				      \
-			  ("mtfsb1 %s0"					      \
-			   : : "i#*X"(__builtin_ffs (__excepts)));	      \
-			  0; }))					      \
-      : 0)								      \
-   : (feraiseexcept) (__excepts))
-
-/* Inline definition for feclearexcept.  */
-# define feclearexcept(__excepts) \
-  ((__builtin_constant_p (__excepts)					      \
-    && ((__excepts) & ((__excepts)-1)) == 0				      \
-    && (__excepts) != FE_INVALID)					      \
-   ? ((__excepts) != 0							      \
-      ? (__extension__ ({ __asm__ __volatile__				      \
-			  ("mtfsb0 %s0"					      \
-			   : : "i#*X"(__builtin_ffs (__excepts)));	      \
-			  0; }))					      \
-      : 0)								      \
-   : (feclearexcept) (__excepts))
-
-#endif /* __GNUC__ && !_SOFT_FLOAT */
-

+ 1 - 6
libc/sysdeps/linux/powerpc/fenv.h

@@ -108,12 +108,6 @@ extern int fesetenv (const fenv_t *__envp) __THROW;
    according to saved exceptions.  */
 extern int feupdateenv (const fenv_t *__envp) __THROW;
 
-
-/* Include optimization.  */
-#ifdef __OPTIMIZE__
-# include <bits/fenvinline.h>
-#endif
-
 #ifdef __USE_GNU
 
 /* Enable individual exceptions.  Will not enable more exceptions than
@@ -128,6 +122,7 @@ extern int fedisableexcept (int __excepts) __THROW;
 
 /* Return enabled exceptions.  */
 extern int fegetexcept (void) __THROW;
+
 #endif
 
 __END_DECLS

+ 38 - 0
libm/powerpc/classic/fclrexcpt.c

@@ -0,0 +1,38 @@
+/* Clear given exceptions in current floating-point environment.
+   Copyright (C) 1997-2026 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_libc.h"
+
+int
+feclearexcept (int excepts)
+{
+  fenv_union_t u, n;
+
+  /* Get the current state.  */
+  u.fenv = fegetenv_register ();
+
+  /* Clear the relevant bits.  */
+  n.l = u.l & ~((-(excepts >> (31 - FPSCR_VX) & 1) & FE_ALL_INVALID)
+		| (excepts & FPSCR_STICKY_BITS));
+
+  /* Put the new state in effect.  */
+  if (u.l != n.l)
+    fesetenv_register (n.fenv);
+
+  /* Success.  */
+  return 0;
+}

+ 30 - 0
libm/powerpc/classic/fe_mask.c

@@ -0,0 +1,30 @@
+/* Procedure definition for FE_MASK_ENV.
+   Copyright (C) 2007-2026 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 <errno.h>
+
+/* This is a generic stub. An OS specific override is required to clear
+   the FE0/FE1 bits in the MSR.  MSR update is privileged, so this will
+   normally involve a syscall.  */
+
+const fenv_t *
+__fe_mask_env(void)
+{
+  __set_errno (ENOSYS);
+  return FE_DFL_ENV;
+}

+ 30 - 0
libm/powerpc/classic/fe_nomask.c

@@ -0,0 +1,30 @@
+/* Procedure definition for FE_NOMASK_ENV.
+   Copyright (C) 1997-2026 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_libc.h"
+#include <errno.h>
+
+/* This is a generic stub. An OS specific override is required to set
+   the FE0/FE1 bits in the MSR.  MSR update is privileged, so this will
+   normally involve a syscall.  */
+
+const fenv_t *
+__fe_nomask_env_priv (void)
+{
+  __set_errno (ENOSYS);
+  return FE_ENABLED_ENV;
+}

+ 47 - 0
libm/powerpc/classic/fedisblxcpt.c

@@ -0,0 +1,47 @@
+/* Disable floating-point exceptions.
+   Copyright (C) 2000-2026 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_libc.h"
+
+int
+fedisableexcept (int excepts)
+{
+  fenv_union_t fe, curr;
+  int result, new;
+
+  /* Get current exception mask to return.  */
+  fe.fenv = curr.fenv = fegetenv_control ();
+  result = fenv_reg_to_exceptions (fe.l);
+
+  if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID)
+    excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID;
+
+  new = fenv_exceptions_to_reg (excepts);
+
+  if (fenv_reg_to_exceptions (new) != excepts)
+    return -1;
+
+  /* Sets the new exception mask.  */
+  fe.l &= ~new;
+
+  if (fe.l != curr.l)
+    fesetenv_control (fe.fenv);
+
+  __TEST_AND_ENTER_NON_STOP (-1ULL, fe.l);
+
+  return result;
+}

+ 47 - 0
libm/powerpc/classic/feenablxcpt.c

@@ -0,0 +1,47 @@
+/* Enable floating-point exceptions.
+   Copyright (C) 2000-2026 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_libc.h"
+
+int
+feenableexcept (int excepts)
+{
+  fenv_union_t fe, curr;
+  int result, new;
+
+  /* Get current exception mask to return.  */
+  fe.fenv = curr.fenv = fegetenv_control ();
+  result = fenv_reg_to_exceptions (fe.l);
+
+  if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID)
+    excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID;
+
+  new = fenv_exceptions_to_reg (excepts);
+
+  if (fenv_reg_to_exceptions (new) != excepts)
+    return -1;
+
+  /* Sets the new exception mask.  */
+  fe.l |= new;
+
+  if (fe.l != curr.l)
+    fesetenv_control (fe.fenv);
+
+  __TEST_AND_EXIT_NON_STOP (0ULL, fe.l);
+
+  return result;
+}

+ 27 - 0
libm/powerpc/classic/fegetenv.c

@@ -0,0 +1,27 @@
+/* Store current floating-point environment.
+   Copyright (C) 1997-2026 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_libc.h"
+
+int
+fegetenv (fenv_t *envp)
+{
+  *envp = fegetenv_register ();
+
+  /* Success.  */
+  return 0;
+}

+ 28 - 0
libm/powerpc/classic/fegetexcept.c

@@ -0,0 +1,28 @@
+/* Get floating-point exceptions.
+   Copyright (C) 2000-2026 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_libc.h"
+
+int
+fegetexcept (void)
+{
+  fenv_union_t fe;
+
+  fe.fenv = fegetenv_control ();
+
+  return fenv_reg_to_exceptions (fe.l);
+}

+ 25 - 0
libm/powerpc/classic/fegetmode.c

@@ -0,0 +1,25 @@
+/* Store current floating-point control modes.  PowerPC version.
+   Copyright (C) 2016-2026 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_libc.h"
+
+int
+fegetmode (femode_t *modep)
+{
+  *modep = fegetenv_control ();
+  return 0;
+}

+ 28 - 0
libm/powerpc/classic/fegetround.c

@@ -0,0 +1,28 @@
+/* Return current rounding direction.
+   Copyright (C) 1997-2026 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_libc.h"
+
+int
+(fegetround) (void)
+{
+  fenv_union_t fe;
+
+  fe.fenv = fegetenv_control ();
+
+  return fe.l & 0x3;
+}

+ 42 - 0
libm/powerpc/classic/feholdexcpt.c

@@ -0,0 +1,42 @@
+/* Store current floating-point environment and clear exceptions.
+   Copyright (C) 1997-2026 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_libc.h"
+#include <fpu_control.h>
+
+int
+feholdexcept (fenv_t *envp)
+{
+  fenv_union_t old, new;
+
+  /* Save the currently set exceptions.  */
+  old.fenv = *envp = fegetenv_register ();
+
+  /* Clear everything except for the rounding modes and non-IEEE arithmetic
+     flag.  */
+  new.l = old.l & 0xffffffff00000007LL;
+
+  if (new.l == old.l)
+    return 0;
+
+  __TEST_AND_ENTER_NON_STOP (old.l, 0ULL);
+
+  /* Put the new state in effect.  */
+  fesetenv_register (new.fenv);
+
+  return 0;
+}

+ 35 - 0
libm/powerpc/classic/fenv_const.c

@@ -0,0 +1,35 @@
+/* Constants for fenv_bits.h.
+   Copyright (C) 1997-2026 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/>.  */
+
+/* We want to specify the bit pattern of the __fe_*_env constants, so
+   pretend they're really `long long' instead of `double'.  */
+
+/* If the default argument is used we use this value.  */
+const unsigned long long __fe_dfl_env __attribute__ ((aligned (8))) =
+0xfff8000000000000ULL;
+
+/* The same representation is used for femode_t.  */
+extern const unsigned long long __fe_dfl_mode
+  __attribute__ ((aligned (8), alias ("__fe_dfl_env")));
+
+/* Floating-point environment where none of the exceptions are masked.  */
+const unsigned long long __fe_enabled_env __attribute__ ((aligned (8))) =
+0xfff80000000000f8ULL;
+
+/* Floating-point environment with the NI bit set.  */
+const unsigned long long __fe_nonieee_env __attribute__ ((aligned (8))) =
+0xfff8000000000004ULL;

+ 304 - 0
libm/powerpc/classic/fenv_libc.h

@@ -0,0 +1,304 @@
+/* Internal libc stuff for floating point environment routines.
+   Copyright (C) 1997-2026 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
+
+#include <fenv.h>
+#include <sysdep.h>
+
+extern const fenv_t *__fe_nomask_env_priv (void);
+
+extern const fenv_t *__fe_mask_env (void) attribute_hidden;
+
+/* If the old env had any enabled exceptions and the new env has no enabled
+   exceptions, then mask SIGFPE in the MSR FE0/FE1 bits.  This may allow the
+   FPU to run faster because it always takes the default action and can not
+   generate SIGFPE.  */
+#define __TEST_AND_ENTER_NON_STOP(old, new) \
+  do { \
+    if (((old) & FPSCR_ENABLES_MASK) != 0 && ((new) & FPSCR_ENABLES_MASK) == 0) \
+      (void) __fe_mask_env (); \
+  } while (0)
+
+/* If the old env has no enabled exceptions and the new env has any enabled
+   exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits.  This will put the
+   hardware into "precise mode" and may cause the FPU to run slower on some
+   hardware.  */
+#define __TEST_AND_EXIT_NON_STOP(old, new) \
+  do { \
+    if (((old) & FPSCR_ENABLES_MASK) == 0 && ((new) & FPSCR_ENABLES_MASK) != 0) \
+      (void) __fe_nomask_env_priv (); \
+  } while (0)
+
+/* The sticky bits in the FPSCR indicating exceptions have occurred.  */
+#define FPSCR_STICKY_BITS ((FE_ALL_EXCEPT | FE_ALL_INVALID) & ~FE_INVALID)
+
+/* Equivalent to fegetenv, but returns a fenv_t instead of taking a
+   pointer.  */
+#define fegetenv_register() __builtin_mffs()
+
+/* Equivalent to fegetenv_register, but only returns bits for
+   status, exception enables, and mode.
+   Nicely, it turns out that the 'mffsl' instruction will decode to
+   'mffs' on architectures older than "power9" because the additional
+   bits set for 'mffsl' are "don't care" for 'mffs'.  'mffs' is a superset
+   of 'mffsl'.  */
+#define fegetenv_control()					\
+  ({register double __fr;						\
+    __asm__ __volatile__ (						\
+      ".machine push; .machine \"power9\"; mffsl %0; .machine pop"	\
+      : "=f" (__fr));							\
+    __fr;								\
+  })
+
+/* Starting with GCC 14 __builtin_set_fpscr_rn can be used to return the
+   FPSCR fields as a double.  This support is available
+   on Power9 when the __SET_FPSCR_RN_RETURNS_FPSCR__ macro is defined.
+   To retain backward compatibility with older GCC, we still retain the
+   old inline assembly implementation.*/
+#ifdef __SET_FPSCR_RN_RETURNS_FPSCR__
+#define __fe_mffscrn(rn)  __builtin_set_fpscr_rn (rn)
+#else
+#define __fe_mffscrn(rn)						\
+  ({register fenv_union_t __fr;						\
+    if (__builtin_constant_p (rn))					\
+      __asm__ __volatile__ (						\
+        ".machine push; .machine \"power9\"; mffscrni %0,%1; .machine pop" \
+        : "=f" (__fr.fenv) : "n" (rn));					\
+    else								\
+    {									\
+      __fr.l = (rn);							\
+      __asm__ __volatile__ (						\
+        ".machine push; .machine \"power9\"; mffscrn %0,%1; .machine pop" \
+        : "=f" (__fr.fenv) : "f" (__fr.fenv));				\
+    }									\
+    __fr.fenv;								\
+  })
+#endif
+
+/* Like fegetenv_control, but also sets the rounding mode.  */
+/* 'mffscrn' will decode to 'mffs' on ARCH < 3_00, which is still necessary
+   but not sufficient, because it does not set the rounding mode.
+   Explicitly set the rounding mode when 'mffscrn' actually doesn't.  */
+#define fegetenv_and_set_rn(rn)						\
+  ({register fenv_union_t __fr;						\
+    __fr.fenv = __fe_mffscrn (rn);					\
+    __fr.fenv;								\
+  })
+
+/* Equivalent to fesetenv, but takes a fenv_t instead of a pointer.  */
+#define fesetenv_register(env) \
+	do { \
+	  double d = (env); \
+	    __builtin_mtfsf (0xff, d); \
+	} while(0)
+
+/* Set the last 2 nibbles of the FPSCR, which contain the
+   exception enables and the rounding mode.
+   'fegetenv_control' retrieves these bits by reading the FPSCR.  */
+#define fesetenv_control(env) __builtin_mtfsf (0b00000011, (env));
+
+/* This very handy macro:
+   - Sets the rounding mode to 'round to nearest';
+   - Sets the processor into IEEE mode; and
+   - Prevents exceptions from being raised for inexact results.
+   These things happen to be exactly what you need for typical elementary
+   functions.  */
+#define relax_fenv_state() \
+	do { \
+	   if (GLRO(dl_hwcap) & PPC_FEATURE_HAS_DFP) \
+	     __asm__ volatile (".machine push; .machine \"power6\"; " \
+		  "mtfsfi 7,0,1; .machine pop"); \
+	   __asm__ volatile ("mtfsfi 7,0"); \
+	} while(0)
+
+/* Set/clear a particular FPSCR bit (for instance,
+   reset_fpscr_bit(FPSCR_VE);
+   prevents INVALID exceptions from being raised).  */
+#define set_fpscr_bit(x) __asm__ volatile ("mtfsb1 %0" : : "n"(x))
+#define reset_fpscr_bit(x) __asm__ volatile ("mtfsb0 %0" : : "n"(x))
+
+typedef union
+{
+  fenv_t fenv;
+  unsigned long long l;
+} fenv_union_t;
+
+
+static inline int
+__fesetround_inline (int round)
+{
+  if ((unsigned int) round < 2)
+    {
+       __asm__ volatile ("mtfsb0 30");
+       if ((unsigned int) round == 0)
+         __asm__ volatile ("mtfsb0 31");
+       else
+         __asm__ volatile ("mtfsb1 31");
+    }
+  else
+    {
+       __asm__ volatile ("mtfsb1 30");
+       if ((unsigned int) round == 2)
+         __asm__ volatile ("mtfsb0 31");
+       else
+         __asm__ volatile ("mtfsb1 31");
+    }
+  return 0;
+}
+
+/* Same as __fesetround_inline, and it also disable the floating-point
+   inexact execption (bit 60 - XE, assuming NI is 0).  It does not check
+   if ROUND is a valid value.  */
+static inline void
+__fesetround_inline_disable_inexact (const int round)
+{
+  __asm__ volatile ("mtfsfi 7,%0" : : "n" (round));
+}
+
+#define FPSCR_MASK(bit) (1 << (31 - (bit)))
+
+/* Definitions of all the FPSCR bit numbers */
+enum {
+  FPSCR_FX = 0,    /* exception summary */
+#define FPSCR_FX_MASK (FPSCR_MASK (FPSCR_FX))
+  FPSCR_FEX,       /* enabled exception summary */
+#define FPSCR_FEX_MASK (FPSCR_MASK FPSCR_FEX))
+  FPSCR_VX,        /* invalid operation summary */
+#define FPSCR_VX_MASK (FPSCR_MASK (FPSCR_VX))
+  FPSCR_OX,        /* overflow */
+#define FPSCR_OX_MASK (FPSCR_MASK (FPSCR_OX))
+  FPSCR_UX,        /* underflow */
+#define FPSCR_UX_MASK (FPSCR_MASK (FPSCR_UX))
+  FPSCR_ZX,        /* zero divide */
+#define FPSCR_ZX_MASK (FPSCR_MASK (FPSCR_ZX))
+  FPSCR_XX,        /* inexact */
+#define FPSCR_XX_MASK (FPSCR_MASK (FPSCR_XX))
+  FPSCR_VXSNAN,    /* invalid operation for sNaN */
+#define FPSCR_VXSNAN_MASK (FPSCR_MASK (FPSCR_VXSNAN))
+  FPSCR_VXISI,     /* invalid operation for Inf-Inf */
+#define FPSCR_VXISI_MASK (FPSCR_MASK (FPSCR_VXISI))
+  FPSCR_VXIDI,     /* invalid operation for Inf/Inf */
+#define FPSCR_VXIDI_MASK (FPSCR_MASK (FPSCR_VXIDI))
+  FPSCR_VXZDZ,     /* invalid operation for 0/0 */
+#define FPSCR_VXZDZ_MASK (FPSCR_MASK (FPSCR_VXZDZ))
+  FPSCR_VXIMZ,     /* invalid operation for Inf*0 */
+#define FPSCR_VXIMZ_MASK (FPSCR_MASK (FPSCR_VXIMZ))
+  FPSCR_VXVC,      /* invalid operation for invalid compare */
+#define FPSCR_VXVC_MASK (FPSCR_MASK (FPSCR_VXVC))
+  FPSCR_FR,        /* fraction rounded [fraction was incremented by round] */
+#define FPSCR_FR_MASK (FPSCR_MASK (FPSCR_FR))
+  FPSCR_FI,        /* fraction inexact */
+#define FPSCR_FI_MASK (FPSCR_MASK (FPSCR_FI))
+  FPSCR_FPRF_C,    /* result class descriptor */
+#define FPSCR_FPRF_C_MASK (FPSCR_MASK (FPSCR_FPRF_C))
+  FPSCR_FPRF_FL,   /* result less than (usually, less than 0) */
+#define FPSCR_FPRF_FL_MASK (FPSCR_MASK (FPSCR_FPRF_FL))
+  FPSCR_FPRF_FG,   /* result greater than */
+#define FPSCR_FPRF_FG_MASK (FPSCR_MASK (FPSCR_FPRF_FG))
+  FPSCR_FPRF_FE,   /* result equal to */
+#define FPSCR_FPRF_FE_MASK (FPSCR_MASK (FPSCR_FPRF_FE))
+  FPSCR_FPRF_FU,   /* result unordered */
+#define FPSCR_FPRF_FU_MASK (FPSCR_MASK (FPSCR_FPRF_FU))
+  FPSCR_20,        /* reserved */
+  FPSCR_VXSOFT,    /* invalid operation set by software */
+#define FPSCR_VXSOFT_MASK (FPSCR_MASK (FPSCR_VXSOFT))
+  FPSCR_VXSQRT,    /* invalid operation for square root */
+#define FPSCR_VXSQRT_MASK (FPSCR_MASK (FPSCR_VXSQRT))
+  FPSCR_VXCVI,     /* invalid operation for invalid integer convert */
+#define FPSCR_VXCVI_MASK (FPSCR_MASK (FPSCR_VXCVI))
+  FPSCR_VE,        /* invalid operation exception enable */
+#define FPSCR_VE_MASK (FPSCR_MASK (FPSCR_VE))
+  FPSCR_OE,        /* overflow exception enable */
+#define FPSCR_OE_MASK (FPSCR_MASK (FPSCR_OE))
+  FPSCR_UE,        /* underflow exception enable */
+#define FPSCR_UE_MASK (FPSCR_MASK (FPSCR_UE))
+  FPSCR_ZE,        /* zero divide exception enable */
+#define FPSCR_ZE_MASK (FPSCR_MASK (FPSCR_ZE))
+  FPSCR_XE,        /* inexact exception enable */
+#define FPSCR_XE_MASK (FPSCR_MASK (FPSCR_XE))
+#ifdef _ARCH_PWR6
+  FPSCR_29,        /* Reserved in ISA 2.05  */
+#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_29))
+#else
+  FPSCR_NI,        /* non-IEEE mode (typically, no denormalised numbers) */
+#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_NI))
+#endif /* _ARCH_PWR6 */
+  /* the remaining two least-significant bits keep the rounding mode */
+  FPSCR_RN_hi,
+#define FPSCR_RN_hi_MASK (FPSCR_MASK (FPSCR_RN_hi))
+  FPSCR_RN_lo
+#define FPSCR_RN_lo_MASK (FPSCR_MASK (FPSCR_RN_lo))
+};
+
+#define FPSCR_RN_MASK (FPSCR_RN_hi_MASK|FPSCR_RN_lo_MASK)
+#define FPSCR_ENABLES_MASK \
+  (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK)
+#define FPSCR_BASIC_EXCEPTIONS_MASK \
+  (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK)
+#define FPSCR_EXCEPTIONS_MASK (FPSCR_BASIC_EXCEPTIONS_MASK| \
+  FPSCR_VXSNAN_MASK|FPSCR_VXISI_MASK|FPSCR_VXIDI_MASK|FPSCR_VXZDZ_MASK| \
+  FPSCR_VXIMZ_MASK|FPSCR_VXVC_MASK|FPSCR_VXSOFT_MASK|FPSCR_VXSQRT_MASK| \
+  FPSCR_VXCVI_MASK)
+#define FPSCR_FPRF_MASK \
+  (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \
+   FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK)
+#define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK)
+#define FPSCR_STATUS_MASK (FPSCR_FR_MASK|FPSCR_FI_MASK|FPSCR_FPRF_MASK)
+
+/* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits
+   in the FPSCR, albeit shifted to different but corresponding locations.
+   Similarly, the exception indicator bits in the FPSCR correspond one-to-one
+   with the exception enable bits. It is thus possible to map the FENV(1)
+   exceptions directly to the FPSCR enables with a simple mask and shift,
+   and vice versa. */
+#define FPSCR_EXCEPT_TO_ENABLE_SHIFT 22
+
+static inline int
+fenv_reg_to_exceptions (unsigned long long l)
+{
+  return (((int)l) & FPSCR_ENABLES_MASK) << FPSCR_EXCEPT_TO_ENABLE_SHIFT;
+}
+
+static inline unsigned long long
+fenv_exceptions_to_reg (int excepts)
+{
+  return (unsigned long long)
+    (excepts & FE_ALL_EXCEPT) >> FPSCR_EXCEPT_TO_ENABLE_SHIFT;
+}
+
+#ifdef _ARCH_PWR6
+  /* Not supported in ISA 2.05.  Provided for source compat only.  */
+# define FPSCR_NI 29
+#endif /* _ARCH_PWR6 */
+
+/* This operation (i) sets the appropriate FPSCR bits for its
+   parameter, (ii) converts sNaN to the corresponding qNaN, and (iii)
+   otherwise passes its parameter through unchanged (in particular, -0
+   and +0 stay as they were).  The `obvious' way to do this is optimised
+   out by gcc.  */
+#define f_wash(x) \
+   ({ double d; __asm__ volatile ("fmul %0,%1,%2" \
+			      : "=f"(d) \
+			      : "f" (x), "f"((float)1.0)); d; })
+#define f_washf(x) \
+   ({ float f; __asm__ volatile ("fmuls %0,%1,%2" \
+			     : "=f"(f) \
+			     : "f" (x), "f"((float)1.0)); f; })
+
+#endif /* fenv_libc.h */

+ 200 - 0
libm/powerpc/classic/fenv_private.h

@@ -0,0 +1,200 @@
+/* Private floating point rounding and exceptions handling. PowerPC version.
+   Copyright (C) 2013-2026 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 POWERPC_FENV_PRIVATE_H
+#define POWERPC_FENV_PRIVATE_H 1
+
+#include <fenv.h>
+#include <fenv_libc.h>
+#include <fpu_control.h>
+
+#ifdef _ARCH_PWR8
+/* There is no performance advantage to non-stop mode.  */
+/* The odd syntax here is to innocuously reference the given variables
+   to prevent warnings about unused variables.  */
+#define __TEST_AND_BEGIN_NON_STOP(old, new) do {} while ((old) * (new) * 0 != 0)
+#define __TEST_AND_END_NON_STOP(old, new) do {} while ((old) * (new) * 0 != 0)
+#else
+#define __TEST_AND_BEGIN_NON_STOP __TEST_AND_ENTER_NON_STOP
+#define __TEST_AND_END_NON_STOP __TEST_AND_EXIT_NON_STOP
+#endif
+
+static __always_inline void
+libc_feholdexcept_setround_ppc (fenv_t *envp, int r)
+{
+  fenv_union_t old, new;
+
+  old.fenv = *envp = fegetenv_register ();
+
+  __TEST_AND_BEGIN_NON_STOP (old.l, 0ULL);
+
+  /* Clear everything and set the rounding mode.  */
+  new.l = r;
+  fesetenv_register (new.fenv);
+}
+
+static __always_inline unsigned long long
+__libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask,
+	unsigned long long new_mask)
+{
+  fenv_union_t old, new;
+
+  new.fenv = *envp;
+  old.fenv = fegetenv_register ();
+
+  /* Merge bits while masking unwanted bits from new and old env.  */
+  new.l = (old.l & old_mask) | (new.l & new_mask);
+
+  __TEST_AND_END_NON_STOP (old.l, new.l);
+  __TEST_AND_BEGIN_NON_STOP (old.l, new.l);
+
+  /* If requesting to keep status, replace control, and merge exceptions,
+     and exceptions haven't changed, we can just set new control instead
+     of the whole FPSCR.  */
+  if ((old_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK))
+      == (FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK) &&
+      (new_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK))
+      == (FPSCR_CONTROL_MASK|FPSCR_EXCEPTIONS_MASK) &&
+      (old.l & FPSCR_EXCEPTIONS_MASK) == (new.l & FPSCR_EXCEPTIONS_MASK))
+  {
+    fesetenv_control (new.fenv);
+  }
+  else
+    /* Atomically enable and raise (if appropriate) exceptions set in `new'.  */
+    fesetenv_register (new.fenv);
+
+  return old.l;
+}
+
+static __always_inline void
+libc_fesetenv_ppc (const fenv_t *envp)
+{
+  /* Replace the entire environment.  */
+  __libc_femergeenv_ppc (envp, 0LL, -1LL);
+}
+
+static __always_inline void
+libc_feresetround_ppc (fenv_t *envp)
+{
+  fenv_union_t new = { .fenv = *envp };
+  fegetenv_and_set_rn (new.l & FPSCR_RN_MASK);
+}
+
+static __always_inline int
+libc_feupdateenv_test_ppc (fenv_t *envp, int ex)
+{
+  return __libc_femergeenv_ppc (envp, ~FPSCR_CONTROL_MASK,
+				~FPSCR_STATUS_MASK) & ex;
+}
+
+static __always_inline void
+libc_feupdateenv_ppc (fenv_t *e)
+{
+  libc_feupdateenv_test_ppc (e, 0);
+}
+
+#define libc_feholdexceptf           libc_feholdexcept_ppc
+#define libc_feholdexcept            libc_feholdexcept_ppc
+#define libc_feholdexcept_setroundf  libc_feholdexcept_setround_ppc
+#define libc_feholdexcept_setround   libc_feholdexcept_setround_ppc
+#define libc_fetestexceptf           libc_fetestexcept_ppc
+#define libc_fetestexcept            libc_fetestexcept_ppc
+#define libc_fesetroundf             libc_fesetround_ppc
+#define libc_fesetround              libc_fesetround_ppc
+#define libc_fesetenvf               libc_fesetenv_ppc
+#define libc_fesetenv                libc_fesetenv_ppc
+#define libc_feupdateenv_testf       libc_feupdateenv_test_ppc
+#define libc_feupdateenv_test        libc_feupdateenv_test_ppc
+#define libc_feupdateenvf            libc_feupdateenv_ppc
+#define libc_feupdateenv             libc_feupdateenv_ppc
+#define libc_feholdsetroundf         libc_feholdsetround_ppc
+#define libc_feholdsetround          libc_feholdsetround_ppc
+#define libc_feresetroundf           libc_feresetround_ppc
+#define libc_feresetround            libc_feresetround_ppc
+
+
+/* We have support for rounding mode context.  */
+#define HAVE_RM_CTX 1
+
+static __always_inline void
+libc_feholdsetround_ppc_ctx (struct rm_ctx *ctx, int r)
+{
+  fenv_union_t old;
+
+  ctx->env = old.fenv = fegetenv_and_set_rn (r);
+  ctx->updated_status = (r != (old.l & FPSCR_RN_MASK));
+}
+
+static __always_inline void
+libc_feholdsetround_noex_ppc_ctx (struct rm_ctx *ctx, int r)
+{
+  fenv_union_t old, new;
+
+  old.fenv = fegetenv_register ();
+
+  new.l = (old.l & ~(FPSCR_ENABLES_MASK|FPSCR_RN_MASK)) | r;
+
+  ctx->env = old.fenv;
+  if (unlikely (new.l != old.l))
+    {
+      __TEST_AND_BEGIN_NON_STOP (old.l, 0ULL);
+      fesetenv_control (new.fenv);
+      ctx->updated_status = true;
+    }
+  else
+    ctx->updated_status = false;
+}
+
+static __always_inline void
+libc_fesetenv_ppc_ctx (struct rm_ctx *ctx)
+{
+  libc_fesetenv_ppc (&ctx->env);
+}
+
+static __always_inline void
+libc_feupdateenv_ppc_ctx (struct rm_ctx *ctx)
+{
+  if (unlikely (ctx->updated_status))
+    libc_feresetround_ppc (&ctx->env);
+}
+
+static __always_inline void
+libc_feresetround_ppc_ctx (struct rm_ctx *ctx)
+{
+  if (unlikely (ctx->updated_status))
+    libc_feresetround_ppc (&ctx->env);
+}
+
+#define libc_fesetenv_ctx                libc_fesetenv_ppc_ctx
+#define libc_fesetenvf_ctx               libc_fesetenv_ppc_ctx
+#define libc_fesetenvl_ctx               libc_fesetenv_ppc_ctx
+#define libc_feholdsetround_ctx          libc_feholdsetround_ppc_ctx
+#define libc_feholdsetroundf_ctx         libc_feholdsetround_ppc_ctx
+#define libc_feholdsetroundl_ctx         libc_feholdsetround_ppc_ctx
+#define libc_feholdsetround_noex_ctx     libc_feholdsetround_noex_ppc_ctx
+#define libc_feholdsetround_noexf_ctx    libc_feholdsetround_noex_ppc_ctx
+#define libc_feholdsetround_noexl_ctx    libc_feholdsetround_noex_ppc_ctx
+#define libc_feresetround_ctx            libc_feresetround_ppc_ctx
+#define libc_feresetroundf_ctx           libc_feresetround_ppc_ctx
+#define libc_feresetroundl_ctx           libc_feresetround_ppc_ctx
+#define libc_feupdateenv_ctx             libc_feupdateenv_ppc_ctx
+#define libc_feupdateenvf_ctx            libc_feupdateenv_ppc_ctx
+#define libc_feupdateenvl_ctx            libc_feupdateenv_ppc_ctx
+
+#include_next <fenv_private.h>
+
+#endif

+ 37 - 0
libm/powerpc/classic/fesetenv.c

@@ -0,0 +1,37 @@
+/* Install given floating-point environment.
+   Copyright (C) 1997-2026 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_libc.h"
+#include <fpu_control.h>
+
+int
+fesetenv (const fenv_t *envp)
+{
+  fenv_union_t old, new;
+
+  /* get the currently set exceptions.  */
+  new.fenv = *envp;
+  old.fenv = fegetenv_control ();
+
+  __TEST_AND_EXIT_NON_STOP (old.l, new.l);
+  __TEST_AND_ENTER_NON_STOP (old.l, new.l);
+
+  fesetenv_register (new.fenv);
+
+  /* Success.  */
+  return 0;
+}

+ 46 - 0
libm/powerpc/classic/fesetexcept.c

@@ -0,0 +1,46 @@
+/* Set given exception flags.  PowerPC version.
+   Copyright (C) 2016-2026 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_libc.h"
+
+int
+fesetexcept (int excepts)
+{
+  fenv_union_t u, n;
+
+  u.fenv = fegetenv_register ();
+  n.l = (u.l
+	 | (excepts & FPSCR_STICKY_BITS)
+	 /* Turn FE_INVALID into FE_INVALID_SOFTWARE.  */
+	 | (excepts >> ((31 - FPSCR_VX) - (31 - FPSCR_VXSOFT))
+	    & FE_INVALID_SOFTWARE));
+  if (n.l != u.l)
+    {
+      if (n.l & fenv_exceptions_to_reg (excepts))
+	/* Setting the exception flags may trigger a trap.  ISO C 23 § 7.6.4.4
+	    does not allow it.   */
+	return -1;
+
+      fesetenv_register (n.fenv);
+
+      /* Deal with FE_INVALID_SOFTWARE not being implemented on some chips.  */
+      if (excepts & FE_INVALID)
+	feraiseexcept (FE_INVALID);
+    }
+
+  return 0;
+}

+ 40 - 0
libm/powerpc/classic/fesetmode.c

@@ -0,0 +1,40 @@
+/* Install given floating-point control modes.  PowerPC version.
+   Copyright (C) 2016-2026 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_libc.h"
+#include <fpu_control.h>
+
+int
+fesetmode (const femode_t *modep)
+{
+  fenv_union_t old, new;
+
+  /* Logic regarding enabled exceptions as in fesetenv.  */
+
+  new.fenv = *modep;
+  old.fenv = fegetenv_control ();
+  new.l = (new.l & ~FPSCR_STATUS_MASK) | (old.l & FPSCR_STATUS_MASK);
+
+  if (old.l == new.l)
+    return 0;
+
+  __TEST_AND_EXIT_NON_STOP (old.l, new.l);
+  __TEST_AND_ENTER_NON_STOP (old.l, new.l);
+
+  fesetenv_control (new.fenv);
+  return 0;
+}

+ 27 - 0
libm/powerpc/classic/fesetround.c

@@ -0,0 +1,27 @@
+/* Set current rounding direction.
+   Copyright (C) 1997-2026 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_libc.h"
+
+int
+fesetround (int round)
+{
+  if ((unsigned int) round > 3)
+    return 1;
+  else
+    return __fesetround_inline(round);
+}

+ 43 - 0
libm/powerpc/classic/feupdateenv.c

@@ -0,0 +1,43 @@
+/* Install given floating-point environment and raise exceptions.
+   Copyright (C) 1997-2026 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_libc.h"
+#include <fpu_control.h>
+
+int
+feupdateenv (const fenv_t *envp)
+{
+  fenv_union_t old, new;
+
+  /* Save the currently set exceptions.  */
+  new.fenv = *envp;
+  old.fenv = fegetenv_register ();
+
+  /* Restore rounding mode and exception enable from *envp and merge
+     exceptions.  Leave fraction rounded/inexact and FP result/CC bits
+     unchanged.  */
+  new.l = (old.l & 0xffffffff1fffff00LL) | (new.l & 0x1ff80fff);
+
+  __TEST_AND_EXIT_NON_STOP (old.l, new.l);
+  __TEST_AND_ENTER_NON_STOP (old.l, new.l);
+
+  /* Atomically enable and raise (if appropriate) exceptions set in `new'. */
+  fesetenv_register (new.fenv);
+
+  /* Success.  */
+  return 0;
+}

+ 33 - 0
libm/powerpc/classic/fgetexcptflg.c

@@ -0,0 +1,33 @@
+/* Store current representation for exceptions.
+   Copyright (C) 1997-2026 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_libc.h"
+
+int
+fegetexceptflag (fexcept_t *flagp, int excepts)
+{
+  fenv_union_t u;
+
+  /* Get the current state.  */
+  u.fenv = fegetenv_register ();
+
+  /* Return (all of) it.  */
+  *flagp = u.l & excepts & FE_ALL_EXCEPT;
+
+  /* Success.  */
+  return 0;
+}

+ 28 - 0
libm/powerpc/classic/fix-fp-int-compare-invalid.h

@@ -0,0 +1,28 @@
+/* Fix for missing "invalid" exceptions from floating-point
+   comparisons.  PowerPC version.
+   Copyright (C) 2016-2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef FIX_FP_INT_COMPARE_INVALID_H
+#define FIX_FP_INT_COMPARE_INVALID_H	1
+
+/* As of GCC 5, comparisons use unordered comparison instructions when
+   they should use ordered comparisons
+   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58684>.  */
+#define FIX_COMPARE_INVALID 1
+
+#endif /* fix-fp-int-compare-invalid.h */

+ 56 - 0
libm/powerpc/classic/fraiseexcpt.c

@@ -0,0 +1,56 @@
+/* Raise given exceptions.
+   Copyright (C) 1997-2026 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_libc.h"
+
+int
+feraiseexcept (int excepts)
+{
+  fenv_union_t u;
+
+  /* Raise exceptions represented by EXCEPTS.  It is the responsibility of
+     the OS to ensure that if multiple exceptions occur they are fed back
+     to this process in the proper way; this can happen in hardware,
+     anyway (in particular, inexact with overflow or underflow). */
+
+  /* Get the current state.  */
+  u.fenv = fegetenv_register ();
+
+  /* Add the exceptions */
+  u.l = (u.l
+	 | (excepts & FPSCR_STICKY_BITS)
+	 /* Turn FE_INVALID into FE_INVALID_SOFTWARE.  */
+	 | (excepts >> ((31 - FPSCR_VX) - (31 - FPSCR_VXSOFT))
+	    & FE_INVALID_SOFTWARE));
+
+  /* Store the new status word (along with the rest of the environment),
+     triggering any appropriate exceptions.  */
+  fesetenv_register (u.fenv);
+
+  if ((excepts & FE_INVALID))
+    {
+      /* For some reason, some PowerPC chips (the 601, in particular)
+	 don't have FE_INVALID_SOFTWARE implemented.  Detect this
+	 case and raise FE_INVALID_SNAN instead.  */
+      u.fenv = fegetenv_register ();
+      if ((u.l & FE_INVALID) == 0)
+	set_fpscr_bit (FPSCR_VXSNAN);
+    }
+
+  /* Success.  */
+  return 0;
+}

+ 61 - 0
libm/powerpc/classic/fsetexcptflg.c

@@ -0,0 +1,61 @@
+/* Set floating-point environment exception handling.
+   Copyright (C) 1997-2026 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_libc.h"
+
+int
+fesetexceptflag (const fexcept_t *flagp, int excepts)
+{
+  fenv_union_t u, n;
+  fexcept_t flag;
+
+  /* Get the current state.  */
+  u.fenv = fegetenv_register ();
+
+  /* Ignore exceptions not listed in 'excepts'.  */
+  flag = *flagp & excepts;
+
+  /* Replace the exception status */
+  int excepts_mask = FPSCR_STICKY_BITS & excepts;
+  if ((excepts & FE_INVALID) != 0)
+    excepts_mask |= FE_ALL_INVALID;
+  n.l = ((u.l & ~excepts_mask)
+	 | (flag & FPSCR_STICKY_BITS)
+	 /* Turn FE_INVALID into FE_INVALID_SOFTWARE.  */
+	 | (flag >> ((31 - FPSCR_VX) - (31 - FPSCR_VXSOFT))
+	    & FE_INVALID_SOFTWARE));
+
+  /* Store the new status word (along with the rest of the environment).
+     This may cause floating-point exceptions if the restored state
+     requests it.  */
+  if (n.l != u.l)
+    {
+      if (n.l & fenv_exceptions_to_reg (excepts))
+	/* Setting the exception flags may trigger a trap.  ISO C 23 § 7.6.4.4
+	    does not allow it.   */
+	return -1;
+
+      fesetenv_register (n.fenv);
+    }
+
+  /* Deal with FE_INVALID_SOFTWARE not being implemented on some chips.  */
+  if (flag & FE_INVALID)
+    feraiseexcept(FE_INVALID);
+
+  /* Success.  */
+  return 0;
+}

+ 31 - 0
libm/powerpc/classic/ftestexcept.c

@@ -0,0 +1,31 @@
+/* Test exception in current environment.
+   Copyright (C) 1997-2026 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_libc.h"
+
+int
+fetestexcept (int excepts)
+{
+  fenv_union_t u;
+
+  /* Get the current state.  */
+  u.fenv = fegetenv_register ();
+
+  /* The FE_INVALID bit is dealt with correctly by the hardware, so we can
+     just:  */
+  return u.l & excepts;
+}