Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F169944082
D59288.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
D59288.diff
View Options
diff --git a/lib/msun/Makefile b/lib/msun/Makefile
--- a/lib/msun/Makefile
+++ b/lib/msun/Makefile
@@ -187,7 +187,7 @@
cpow.3 csqrt.3 erf.3 \
exp.3 fabs.3 fdim.3 \
feclearexcept.3 feenableexcept.3 fegetenv.3 \
- fegetround.3 fenv.3 floor.3 fma.3 \
+ fegetmode.3 fegetround.3 fenv.3 floor.3 fma.3 \
fmax.3 fmaximum.3 fmaximum_mag.3 \
fmaximum_mag_num.3 fmaximum_num.3 fmod.3 \
hypot.3 ieee.3 ieee_test.3 ilogb.3 j0.3 \
@@ -241,6 +241,7 @@
MLINKS+=feenableexcept.3 fedisableexcept.3 feenableexcept.3 fegetexcept.3
MLINKS+=fegetenv.3 feholdexcept.3 fegetenv.3 fesetenv.3 \
fegetenv.3 feupdateenv.3
+MLINKS+=fegetmode.3 fesetmode.3
MLINKS+=fegetround.3 fesetround.3
MLINKS+=floor.3 floorf.3 floor.3 floorl.3
MLINKS+=fma.3 fmaf.3 fma.3 fmal.3
diff --git a/lib/msun/Symbol.map b/lib/msun/Symbol.map
--- a/lib/msun/Symbol.map
+++ b/lib/msun/Symbol.map
@@ -329,6 +329,9 @@
atanpi;
atanpif;
atanpil;
+ __fe_dfl_mode;
+ fegetmode;
+ fesetmode;
fmaximum;
fmaximumf;
fmaximuml;
diff --git a/lib/msun/aarch64/fenv.h b/lib/msun/aarch64/fenv.h
--- a/lib/msun/aarch64/fenv.h
+++ b/lib/msun/aarch64/fenv.h
@@ -40,6 +40,7 @@
/* The high 32 bits contain fpcr, low 32 contain fpsr. */
typedef __uint64_t fenv_t;
+typedef __uint32_t femode_t;
typedef __uint64_t fexcept_t;
/* Exception flags */
@@ -71,6 +72,10 @@
extern const fenv_t __fe_dfl_env;
#define FE_DFL_ENV (&__fe_dfl_env)
+/* Default floating-point control modes */
+extern const femode_t __fe_dfl_mode;
+#define FE_DFL_MODE (&__fe_dfl_mode)
+
/* We need to be able to map status flag positions to mask flag positions */
#define _FPUSW_SHIFT 8
#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT)
@@ -88,6 +93,8 @@
int fetestexcept(int);
int fegetround(void);
int fesetround(int);
+int fegetmode(femode_t *);
+int fesetmode(const femode_t *);
int fegetenv(fenv_t *);
int feholdexcept(fenv_t *);
int fesetenv(const fenv_t *);
@@ -112,6 +119,8 @@
#define fetestexcept(a) __fetestexcept_int(a)
#define fegetround() __fegetround_int()
#define fesetround(a) __fesetround_int(a)
+#define fegetmode(m) __fegetmode_int(m)
+#define fesetmode(m) __fesetmode_int(m)
#define fegetenv(e) __fegetenv_int(e)
#define feholdexcept(e) __feholdexcept_int(e)
#define fesetenv(e) __fesetenv_int(e)
@@ -197,6 +206,26 @@
return (0);
}
+__fenv_static inline int
+__fegetmode_int(femode_t *__modep)
+{
+ __uint64_t __fpcr;
+
+ __mrs_fpcr(__fpcr);
+ *__modep = (__uint32_t)__fpcr;
+ return (0);
+}
+
+__fenv_static inline int
+__fesetmode_int(const femode_t *__modep)
+{
+ __uint64_t __fpcr;
+
+ __fpcr = *__modep;
+ __msr_fpcr(__fpcr);
+ return (0);
+}
+
__fenv_static inline int
__fegetenv_int(fenv_t *__envp)
{
diff --git a/lib/msun/aarch64/fenv.c b/lib/msun/aarch64/fenv.c
--- a/lib/msun/aarch64/fenv.c
+++ b/lib/msun/aarch64/fenv.c
@@ -32,6 +32,7 @@
* this as a default environment.
*/
const fenv_t __fe_dfl_env = 0;
+const femode_t __fe_dfl_mode = 0;
int
(feclearexcept)(int excepts)
@@ -75,6 +76,18 @@
return (__fesetround_int(round));
}
+int
+(fegetmode)(femode_t *modep)
+{
+ return (__fegetmode_int(modep));
+}
+
+int
+(fesetmode)(const femode_t *modep)
+{
+ return (__fesetmode_int(modep));
+}
+
int
(fegetenv)(fenv_t *envp)
{
diff --git a/lib/msun/amd64/fenv.c b/lib/msun/amd64/fenv.c
--- a/lib/msun/amd64/fenv.c
+++ b/lib/msun/amd64/fenv.c
@@ -41,6 +41,12 @@
__INITIAL_MXCSR__
};
+const femode_t __fe_dfl_mode = {
+ .__control = __INITIAL_FPUCW__,
+ .__reserved = 0,
+ .__mxcsr = __INITIAL_MXCSR__
+};
+
int
(feclearexcept)(int excepts)
{
@@ -99,6 +105,18 @@
return (__fesetround_int(round));
}
+int
+(fegetmode)(femode_t *modep)
+{
+ return (__fegetmode_int(modep));
+}
+
+int
+(fesetmode)(const femode_t *modep)
+{
+ return (__fesetmode_int(modep));
+}
+
int
fegetenv(fenv_t *envp)
{
diff --git a/lib/msun/arm/fenv-mangle.h b/lib/msun/arm/fenv-mangle.h
--- a/lib/msun/arm/fenv-mangle.h
+++ b/lib/msun/arm/fenv-mangle.h
@@ -41,6 +41,8 @@
#define fetestexcept FENV_MANGLE(fetestexcept)
#define fegetround FENV_MANGLE(fegetround)
#define fesetround FENV_MANGLE(fesetround)
+#define fegetmode FENV_MANGLE(fegetmode)
+#define fesetmode FENV_MANGLE(fesetmode)
#define fegetenv FENV_MANGLE(fegetenv)
#define feholdexcept FENV_MANGLE(feholdexcept)
#define fesetenv FENV_MANGLE(fesetenv)
diff --git a/lib/msun/arm/fenv.h b/lib/msun/arm/fenv.h
--- a/lib/msun/arm/fenv.h
+++ b/lib/msun/arm/fenv.h
@@ -37,6 +37,7 @@
#endif
typedef __uint32_t fenv_t;
+typedef __uint32_t femode_t;
typedef __uint32_t fexcept_t;
/* Exception flags */
@@ -79,6 +80,10 @@
extern const fenv_t __fe_dfl_env;
#define FE_DFL_ENV (&__fe_dfl_env)
+/* Default floating-point control modes */
+extern const femode_t __fe_dfl_mode;
+#define FE_DFL_MODE (&__fe_dfl_mode)
+
/* We need to be able to map status flag positions to mask flag positions */
#ifndef __ARM_PCS_VFP
#define _FPUSW_SHIFT 16
@@ -94,6 +99,8 @@
int fetestexcept(int __excepts);
int fegetround(void);
int fesetround(int __round);
+int fegetmode(femode_t *__modep);
+int fesetmode(const femode_t *__modep);
int fegetenv(fenv_t *__envp);
int feholdexcept(fenv_t *__envp);
int fesetenv(const fenv_t *__envp);
@@ -118,6 +125,8 @@
int fetestexcept(int);
int fegetround(void);
int fesetround(int);
+int fegetmode(femode_t *);
+int fesetmode(const femode_t *);
int fegetenv(fenv_t *);
int feholdexcept(fenv_t *);
int fesetenv(const fenv_t *);
@@ -145,6 +154,8 @@
#define fetestexcept(a) __fetestexcept_int(a)
#define fegetround() __fegetround_int()
#define fesetround(a) __fesetround_int(a)
+#define fegetmode(m) __fegetmode_int(m)
+#define fesetmode(m) __fesetmode_int(m)
#define fegetenv(e) __fegetenv_int(e)
#define feholdexcept(e) __feholdexcept_int(e)
#define fesetenv(e) __fesetenv_int(e)
@@ -228,6 +239,28 @@
return (0);
}
+__fenv_static inline int
+__fegetmode_int(femode_t *__modep)
+{
+ fenv_t __fpsr;
+
+ vmrs_fpscr(__fpsr);
+ *__modep = __fpsr & ~FE_ALL_EXCEPT;
+ return (0);
+}
+
+__fenv_static inline int
+__fesetmode_int(const femode_t *__modep)
+{
+ fenv_t __fpsr;
+
+ vmrs_fpscr(__fpsr);
+ __fpsr &= FE_ALL_EXCEPT;
+ __fpsr |= *__modep & ~FE_ALL_EXCEPT;
+ vmsr_fpscr(__fpsr);
+ return (0);
+}
+
__fenv_static inline int
__fegetenv_int(fenv_t *__envp)
{
diff --git a/lib/msun/arm/fenv.c b/lib/msun/arm/fenv.c
--- a/lib/msun/arm/fenv.c
+++ b/lib/msun/arm/fenv.c
@@ -43,6 +43,7 @@
* this as a default environment.
*/
const fenv_t __fe_dfl_env = 0;
+const femode_t __fe_dfl_mode = 0;
#endif
@@ -107,6 +108,18 @@
return (__fesetround_int(round));
}
+int
+(fegetmode)(femode_t *modep)
+{
+ return (__fegetmode_int(modep));
+}
+
+int
+(fesetmode)(const femode_t *modep)
+{
+ return (__fesetmode_int(modep));
+}
+
int
(fegetenv)(fenv_t *envp)
{
@@ -160,6 +173,8 @@
int __softfp_fetestexcept(int __excepts);
int __softfp_fegetround(void);
int __softfp_fesetround(int __round);
+int __softfp_fegetmode(femode_t *__modep);
+int __softfp_fesetmode(const femode_t *__modep);
int __softfp_fegetenv(fenv_t *__envp);
int __softfp_feholdexcept(fenv_t *__envp);
int __softfp_fesetenv(const fenv_t *__envp);
@@ -175,6 +190,8 @@
int __vfp_fetestexcept(int __excepts);
int __vfp_fegetround(void);
int __vfp_fesetround(int __round);
+int __vfp_fegetmode(femode_t *__modep);
+int __vfp_fesetmode(const femode_t *__modep);
int __vfp_fegetenv(fenv_t *__envp);
int __vfp_feholdexcept(fenv_t *__envp);
int __vfp_fesetenv(const fenv_t *__envp);
@@ -298,6 +315,31 @@
return (0);
}
+int
+(fegetmode)(femode_t *__modep)
+{
+ femode_t __vfp_modep;
+
+ __vfp_modep = 0;
+ if (_libc_arm_fpu_present)
+ __vfp_fegetmode(&__vfp_modep);
+ __softfp_fegetmode(__modep);
+ *__modep |= __vfp_modep;
+
+ return (0);
+}
+
+int
+(fesetmode)(const femode_t *__modep)
+{
+
+ if (_libc_arm_fpu_present)
+ __vfp_fesetmode(__modep);
+ __softfp_fesetmode(__modep);
+
+ return (0);
+}
+
int
(fegetenv)(fenv_t *__envp)
{
diff --git a/lib/msun/i387/fenv.c b/lib/msun/i387/fenv.c
--- a/lib/msun/i387/fenv.c
+++ b/lib/msun/i387/fenv.c
@@ -41,6 +41,12 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
};
+const femode_t __fe_dfl_mode = {
+ .__control = __INITIAL_NPXCW__,
+ .__reserved = 0,
+ .__mxcsr = __INITIAL_MXCSR__
+};
+
enum __sse_support __has_sse =
#ifdef __SSE__
__SSE_YES;
@@ -144,6 +150,18 @@
return (__fesetround_int(round));
}
+int
+(fegetmode)(femode_t *modep)
+{
+ return (__fegetmode_int(modep));
+}
+
+int
+(fesetmode)(const femode_t *modep)
+{
+ return (__fesetmode_int(modep));
+}
+
int
fegetenv(fenv_t *envp)
{
diff --git a/lib/msun/man/fegetmode.3 b/lib/msun/man/fegetmode.3
new file mode 100644
--- /dev/null
+++ b/lib/msun/man/fegetmode.3
@@ -0,0 +1,70 @@
+.\"
+.\" Copyright (c) 2026 Faraz Vahedi <kfv@FreeBSD.org>
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd August 31, 2026
+.Dt FEGETMODE 3
+.Os
+.Sh NAME
+.Nm fegetmode ,
+.Nm fesetmode
+.Nd save and restore floating-point control modes
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In fenv.h
+.Fd "#pragma STDC FENV_ACCESS ON"
+.Ft int
+.Fn fegetmode "femode_t *modep"
+.Ft int
+.Fn fesetmode "const femode_t *modep"
+.Sh DESCRIPTION
+The
+.Vt femode_t
+type represents the dynamic floating-point control modes,
+including the rounding direction and, where supported, exception
+masks and other implementation-defined modes.
+.Pp
+The
+.Fn fegetmode
+function stores the current control modes in the object
+pointed to by
+.Fa modep .
+.Pp
+The
+.Fn fesetmode
+function establishes the control modes represented by
+.Fa modep .
+The argument
+.Fa modep
+must point to an object set by a prior call to
+.Fn fegetmode ,
+or equal
+.Dv FE_DFL_MODE .
+.Dv FE_DFL_MODE
+expands to a pointer to the default control modes
+.Po
+installed at program startup
+.Pc .
+.Sh RETURN VALUES
+The
+.Fn fegetmode
+and
+.Fn fesetmode
+functions return 0 if they succeed, and non-zero otherwise;
+however, the present implementation always succeeds.
+.Sh SEE ALSO
+.Xr fenv 3 ,
+.Xr fegetround 3 ,
+.Xr fesetround 3
+.Sh STANDARDS
+The
+.Fn fegetmode
+and
+.Fn fesetmode
+functions conform to
+.St -isoC-2023 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 16.0 .
diff --git a/lib/msun/man/fegetround.3 b/lib/msun/man/fegetround.3
--- a/lib/msun/man/fegetround.3
+++ b/lib/msun/man/fegetround.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 8, 2004
+.Dd August 31, 2026
.Dt FEGETROUND 3
.Os
.Sh NAME
@@ -62,6 +62,8 @@
however, the present implementation always succeeds.
.Sh SEE ALSO
.Xr fenv 3 ,
+.Xr fegetmode 3 ,
+.Xr fesetmode 3 ,
.Xr fpgetround 3 ,
.Xr fpsetround 3
.Sh STANDARDS
diff --git a/lib/msun/man/fenv.3 b/lib/msun/man/fenv.3
--- a/lib/msun/man/fenv.3
+++ b/lib/msun/man/fenv.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 16, 2005
+.Dd August 31, 2026
.Dt FENV 3
.Os
.Sh NAME
@@ -31,6 +31,8 @@
.Nm feraiseexcept ,
.Nm fesetexceptflag ,
.Nm fetestexcept ,
+.Nm fegetmode ,
+.Nm fesetmode ,
.Nm fegetround ,
.Nm fesetround ,
.Nm fegetenv ,
@@ -57,6 +59,10 @@
.Ft int
.Fn fetestexcept "int excepts"
.Ft int
+.Fn fegetmode "femode_t *modep"
+.Ft int
+.Fn fesetmode "const femode_t *modep"
+.Ft int
.Fn fegetround void
.Ft int
.Fn fesetround "int round"
@@ -170,6 +176,29 @@
and
.Fn fesetround
functions query and set the rounding mode.
+.Ss Control Modes
+The
+.Vt femode_t
+type represents the collection of dynamic floating-point control modes,
+including the rounding direction and, where supported, exception masks
+and other implementation-defined modes.
+The
+.Fn fegetmode
+and
+.Fn fesetmode
+functions save and restore all the implementation's dynamic
+floating-point control modes, respectively.
+Passing
+.Dv FE_DFL_MODE
+to
+.Fn fesetmode
+restores the default control modes as installed at program startup.
+.Pp
+The macro
+.Dv FE_DFL_MODE
+expands to a pointer to the constant variable of type
+.Vt femode_t
+that is initialized with the default control modes.
.Ss Environment Control
The
.Fn fegetenv
@@ -241,11 +270,13 @@
.Xr fegetenv 3 ,
.Xr fegetexcept 3 ,
.Xr fegetexceptflag 3 ,
+.Xr fegetmode 3 ,
.Xr fegetround 3 ,
.Xr feholdexcept 3 ,
.Xr feraiseexcept 3 ,
.Xr fesetenv 3 ,
.Xr fesetexceptflag 3 ,
+.Xr fesetmode 3 ,
.Xr fesetround 3 ,
.Xr fetestexcept 3 ,
.Xr feupdateenv 3 ,
@@ -257,6 +288,16 @@
conforms to
.St -isoC-99 .
The
+.Vt femode_t
+type, the
+.Dv FE_DFL_MODE
+macro, and the
+.Fn fegetmode
+and
+.Fn fesetmode
+functions conform to
+.St -isoC-2023 .
+The
.Fn feenableexcept ,
.Fn fedisableexcept ,
and
@@ -271,6 +312,12 @@
.In ieeefp.h
and documented in
.Xr fpgetround 3 .
+The
+.Fn fegetmode
+and
+.Fn fesetmode
+functions first appeared in
+.Fx 16.0 .
.Sh CAVEATS
The FENV_ACCESS pragma can be enabled with
.Dl "#pragma STDC FENV_ACCESS ON"
diff --git a/lib/msun/powerpc/fenv.h b/lib/msun/powerpc/fenv.h
--- a/lib/msun/powerpc/fenv.h
+++ b/lib/msun/powerpc/fenv.h
@@ -37,6 +37,7 @@
#endif
typedef __uint32_t fenv_t;
+typedef __uint32_t femode_t;
typedef __uint32_t fexcept_t;
/* Exception flags */
@@ -84,6 +85,10 @@
extern const fenv_t __fe_dfl_env;
#define FE_DFL_ENV (&__fe_dfl_env)
+/* Default floating-point control modes */
+extern const femode_t __fe_dfl_mode;
+#define FE_DFL_MODE (&__fe_dfl_mode)
+
/* We need to be able to map status flag positions to mask flag positions */
#define _ENABLE_MASK ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
FE_OVERFLOW | FE_UNDERFLOW) >> _FPUSW_SHIFT)
@@ -118,6 +123,8 @@
int fetestexcept(int);
int fegetround(void);
int fesetround(int);
+int fegetmode(femode_t *);
+int fesetmode(const femode_t *);
int fegetenv(fenv_t *);
int feholdexcept(fenv_t *);
int fesetenv(const fenv_t *);
@@ -139,6 +146,8 @@
#define fetestexcept(a) __fetestexcept_int(a)
#define fegetround() __fegetround_int()
#define fesetround(a) __fesetround_int(a)
+#define fegetmode(m) __fegetmode_int(m)
+#define fesetmode(m) __fesetmode_int(m)
#define fegetenv(e) __fegetenv_int(e)
#define feholdexcept(e) __feholdexcept_int(e)
#define fesetenv(e) __fesetenv_int(e)
@@ -227,6 +236,28 @@
return (0);
}
+__fenv_static inline int
+__fegetmode_int(femode_t *__modep)
+{
+ union __fpscr __r;
+
+ __mffs(&__r);
+ *__modep = __r.__bits.__reg & ~FE_ALL_EXCEPT;
+ return (0);
+}
+
+__fenv_static inline int
+__fesetmode_int(const femode_t *__modep)
+{
+ union __fpscr __r;
+
+ __mffs(&__r);
+ __r.__bits.__reg &= FE_ALL_EXCEPT;
+ __r.__bits.__reg |= *__modep & ~FE_ALL_EXCEPT;
+ __mtfsf(__r);
+ return (0);
+}
+
__fenv_static inline int
__fegetenv_int(fenv_t *__envp)
{
diff --git a/lib/msun/powerpc/fenv.c b/lib/msun/powerpc/fenv.c
--- a/lib/msun/powerpc/fenv.c
+++ b/lib/msun/powerpc/fenv.c
@@ -29,6 +29,7 @@
#include "fenv.h"
const fenv_t __fe_dfl_env = 0x00000000;
+const femode_t __fe_dfl_mode = 0x00000000;
int
(feclearexcept)(int excepts)
@@ -72,6 +73,18 @@
return (__fesetround_int(round));
}
+int
+(fegetmode)(femode_t *modep)
+{
+ return (__fegetmode_int(modep));
+}
+
+int
+(fesetmode)(const femode_t *modep)
+{
+ return (__fesetmode_int(modep));
+}
+
int
(fegetenv)(fenv_t *envp)
{
diff --git a/lib/msun/riscv/fenv.h b/lib/msun/riscv/fenv.h
--- a/lib/msun/riscv/fenv.h
+++ b/lib/msun/riscv/fenv.h
@@ -44,6 +44,7 @@
#endif
typedef __uint64_t fenv_t;
+typedef __uint64_t femode_t;
typedef __uint64_t fexcept_t;
/* Exception flags */
@@ -72,6 +73,10 @@
extern const fenv_t __fe_dfl_env;
#define FE_DFL_ENV (&__fe_dfl_env)
+/* Default floating-point control modes */
+extern const femode_t __fe_dfl_mode;
+#define FE_DFL_MODE (&__fe_dfl_mode)
+
#ifndef __riscv_float_abi_double
#error only double hard float ABI supported
#endif
@@ -86,6 +91,8 @@
int fetestexcept(int);
int fegetround(void);
int fesetround(int);
+int fegetmode(femode_t *);
+int fesetmode(const femode_t *);
int fegetenv(fenv_t *);
int feholdexcept(fenv_t *);
int fesetenv(const fenv_t *);
@@ -107,6 +114,8 @@
#define fetestexcept(a) __fetestexcept_int(a)
#define fegetround() __fegetround_int()
#define fesetround(a) __fesetround_int(a)
+#define fegetmode(m) __fegetmode_int(m)
+#define fesetmode(m) __fesetmode_int(m)
#define fegetenv(e) __fegetenv_int(e)
#define feholdexcept(e) __feholdexcept_int(e)
#define fesetenv(e) __fesetenv_int(e)
@@ -190,6 +199,30 @@
return (0);
}
+__fenv_static inline int
+__fegetmode_int(femode_t *__modep)
+{
+ fexcept_t __fcsr;
+
+ __rfs(__fcsr);
+ *__modep = __fcsr & ~FE_ALL_EXCEPT;
+
+ return (0);
+}
+
+__fenv_static inline int
+__fesetmode_int(const femode_t *__modep)
+{
+ fexcept_t __fcsr;
+
+ __rfs(__fcsr);
+ __fcsr &= FE_ALL_EXCEPT;
+ __fcsr |= *__modep & ~FE_ALL_EXCEPT;
+ __wfs(__fcsr);
+
+ return (0);
+}
+
__fenv_static inline int
__fegetenv_int(fenv_t *__envp)
{
diff --git a/lib/msun/riscv/fenv.c b/lib/msun/riscv/fenv.c
--- a/lib/msun/riscv/fenv.c
+++ b/lib/msun/riscv/fenv.c
@@ -31,6 +31,7 @@
* this as a default environment.
*/
const fenv_t __fe_dfl_env = 0;
+const femode_t __fe_dfl_mode = 0;
int
(feclearexcept)(int excepts)
@@ -74,6 +75,18 @@
return (__fesetround_int(round));
}
+int
+(fegetmode)(femode_t *modep)
+{
+ return (__fegetmode_int(modep));
+}
+
+int
+(fesetmode)(const femode_t *modep)
+{
+ return (__fesetmode_int(modep));
+}
+
int
(fegetenv)(fenv_t *envp)
{
diff --git a/lib/msun/src/fenv-softfloat.h b/lib/msun/src/fenv-softfloat.h
--- a/lib/msun/src/fenv-softfloat.h
+++ b/lib/msun/src/fenv-softfloat.h
@@ -36,11 +36,13 @@
* you must write an <fenv.h> that provides the following:
*
* - a typedef for fenv_t, which may be an integer or struct type
+ * - a typedef for femode_t, which may be an integer or struct type
* - a typedef for fexcept_t (XXX This file assumes fexcept_t is a
* simple integer type containing the exception mask.)
* - definitions of FE_* constants for the five exceptions and four
* rounding modes in IEEE 754, as described in fenv(3)
* - a definition, and the corresponding external symbol, for FE_DFL_ENV
+ * - a definition, and the corresponding external symbol, for FE_DFL_MODE
* - a macro __set_env(env, flags, mask, rnd), which sets the given fenv_t
* from the exception flags, mask, and rounding mode
* - macros __env_flags(env), __env_mask(env), and __env_round(env), which
@@ -112,6 +114,24 @@
return (0);
}
+__fenv_static inline int
+__fegetmode_int(femode_t *__modep)
+{
+
+ __set_env(*__modep, 0, __softfloat_float_exception_mask,
+ __softfloat_float_rounding_mode);
+ return (0);
+}
+
+__fenv_static inline int
+__fesetmode_int(const femode_t *__modep)
+{
+
+ __softfloat_float_exception_mask = __env_mask(*__modep);
+ __softfloat_float_rounding_mode = __env_round(*__modep);
+ return (0);
+}
+
__fenv_static inline int
fegetenv(fenv_t *__envp)
{
diff --git a/lib/msun/tests/fenv_test.c b/lib/msun/tests/fenv_test.c
--- a/lib/msun/tests/fenv_test.c
+++ b/lib/msun/tests/fenv_test.c
@@ -332,6 +332,68 @@
ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT));
}
+/*
+ * Test fegetmode() and fesetmode().
+ *
+ * Prerequisites: fetestexcept(), feclearexcept(), fegetround(), fesetround()
+ */
+ATF_TC_WITHOUT_HEAD(fegsetmode);
+ATF_TC_BODY(fegsetmode, tc)
+{
+ femode_t mode_dfl, mode_down, mode_nomask, mode_mask;
+ int excepts;
+
+ ATF_CHECK(FE_DFL_MODE != NULL);
+ ATF_CHECK_EQ(0, fegetmode(&mode_dfl));
+ ATF_CHECK_EQ(FE_TONEAREST, fegetround());
+
+ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT));
+ raiseexcept(FE_INVALID | FE_DIVBYZERO);
+ excepts = fetestexcept(ALL_STD_EXCEPT);
+ ATF_CHECK(excepts != 0);
+
+ ATF_CHECK_EQ(0, fesetround(FE_DOWNWARD));
+ ATF_CHECK_EQ(0, fegetmode(&mode_down));
+
+ ATF_CHECK_EQ(0, fesetmode(FE_DFL_MODE));
+ ATF_CHECK_EQ(FE_TONEAREST, fegetround());
+ ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT));
+
+ ATF_CHECK_EQ(0, fesetmode(&mode_down));
+ ATF_CHECK_EQ(FE_DOWNWARD, fegetround());
+ ATF_CHECK_EQ(FE_DOWNWARD, getround());
+ ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT));
+
+ ATF_CHECK_EQ(0, fesetmode(&mode_dfl));
+ ATF_CHECK_EQ(FE_TONEAREST, fegetround());
+ ATF_CHECK_EQ(excepts, fetestexcept(ALL_STD_EXCEPT));
+
+ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT));
+ ATF_CHECK_EQ(0, fesetround(FE_TONEAREST));
+
+ /*
+ * Exception masks are control modes. Skip the restore check
+ * when the CPU ignores trap-enable bits, as on some AArch64
+ * implementations.
+ */
+ ATF_CHECK_EQ(0, fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT);
+ ATF_CHECK_EQ(0, fegetexcept() & ALL_STD_EXCEPT);
+ ATF_CHECK_EQ(0, fegetmode(&mode_nomask));
+ (void)feenableexcept(FE_INVALID);
+ if ((fegetexcept() & FE_INVALID) != 0) {
+ ATF_CHECK_EQ(0, fegetmode(&mode_mask));
+ ATF_CHECK_EQ(0, fesetmode(&mode_nomask));
+ ATF_CHECK_EQ(0, fegetexcept() & ALL_STD_EXCEPT);
+ ATF_CHECK_EQ(0, fesetmode(&mode_mask));
+ ATF_CHECK_EQ(FE_INVALID, fegetexcept() & ALL_STD_EXCEPT);
+ ATF_CHECK_EQ(0, fesetmode(FE_DFL_MODE));
+ ATF_CHECK_EQ(0, fegetexcept() & ALL_STD_EXCEPT);
+ }
+ (void)fedisableexcept(FE_ALL_EXCEPT);
+ ATF_CHECK_EQ(0, fesetround(FE_TONEAREST));
+ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT));
+}
+
/*
* Test fegetenv() and fesetenv().
*
@@ -556,6 +618,7 @@
ATF_TP_ADD_TC(tp, fegsetexceptflag);
ATF_TP_ADD_TC(tp, feraiseexcept);
ATF_TP_ADD_TC(tp, fegsetround);
+ ATF_TP_ADD_TC(tp, fegsetmode);
ATF_TP_ADD_TC(tp, fegsetenv);
ATF_TP_ADD_TC(tp, masking);
ATF_TP_ADD_TC(tp, feholdupdate);
diff --git a/lib/msun/x86/fenv.h b/lib/msun/x86/fenv.h
--- a/lib/msun/x86/fenv.h
+++ b/lib/msun/x86/fenv.h
@@ -90,12 +90,27 @@
} fenv_t;
#endif /* __i386__ */
+/*
+ * Control modes: x87 control word plus MXCSR bits other than the
+ * exception flags. fesetmode() restores those bits without changing
+ * the raised exception flags.
+ */
+typedef struct {
+ __uint16_t __control;
+ __uint16_t __reserved;
+ __uint32_t __mxcsr;
+} femode_t;
+
__BEGIN_DECLS
/* Default floating-point environment */
extern const fenv_t __fe_dfl_env;
#define FE_DFL_ENV (&__fe_dfl_env)
+/* Default floating-point control modes */
+extern const femode_t __fe_dfl_mode;
+#define FE_DFL_MODE (&__fe_dfl_mode)
+
#define __fldenvx(__env) __asm __volatile("fldenv %0" : : "m" (__env) \
: "st", "st(1)", "st(2)", "st(3)", "st(4)", \
"st(5)", "st(6)", "st(7)")
@@ -148,6 +163,8 @@
int fetestexcept(int);
int fesetround(int);
int fegetround(void);
+int fegetmode(femode_t *);
+int fesetmode(const femode_t *);
int fesetenv(const fenv_t *);
/*
@@ -164,6 +181,8 @@
#define fetestexcept(a) __fetestexcept_int(a)
#define fesetround(a) __fesetround_int(a)
#define fegetround() __fegetround_int()
+#define fegetmode(m) __fegetmode_int(m)
+#define fesetmode(m) __fesetmode_int(m)
#define fesetenv(a) __fesetenv_int(a)
#endif /* !__cplusplus */
@@ -261,6 +280,38 @@
return (0);
}
+__fenv_static inline int
+__fegetmode_int(femode_t *__modep)
+{
+
+ __fnstcw(&__modep->__control);
+ __modep->__reserved = 0;
+ if (__HAS_SSE()) {
+ __stmxcsr(&__modep->__mxcsr);
+ __modep->__mxcsr &= ~FE_ALL_EXCEPT;
+ } else
+ __modep->__mxcsr = 0;
+
+ return (0);
+}
+
+__fenv_static inline int
+__fesetmode_int(const femode_t *__modep)
+{
+ __uint32_t __mxcsr;
+
+ __fldcw(&__modep->__control);
+
+ if (__HAS_SSE()) {
+ __stmxcsr(&__mxcsr);
+ __mxcsr &= FE_ALL_EXCEPT;
+ __mxcsr |= __modep->__mxcsr & ~FE_ALL_EXCEPT;
+ __ldmxcsr(&__mxcsr);
+ }
+
+ return (0);
+}
+
__fenv_static inline int
__fesetenv_int(const fenv_t *__envp)
{
@@ -348,6 +399,33 @@
return (0);
}
+__fenv_static inline int
+__fegetmode_int(femode_t *__modep)
+{
+
+ __fnstcw(&__modep->__control);
+ __modep->__reserved = 0;
+ __stmxcsr(&__modep->__mxcsr);
+ __modep->__mxcsr &= ~FE_ALL_EXCEPT;
+
+ return (0);
+}
+
+__fenv_static inline int
+__fesetmode_int(const femode_t *__modep)
+{
+ __uint32_t __mxcsr;
+
+ __fldcw(&__modep->__control);
+
+ __stmxcsr(&__mxcsr);
+ __mxcsr &= FE_ALL_EXCEPT;
+ __mxcsr |= __modep->__mxcsr & ~FE_ALL_EXCEPT;
+ __ldmxcsr(&__mxcsr);
+
+ return (0);
+}
+
__fenv_static inline int
__fesetenv_int(const fenv_t *__envp)
{
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Sep 4, 1:28 AM (8 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37997158
Default Alt Text
D59288.diff (23 KB)
Attached To
Mode
D59288: libm: Implement femode_t, fegetmode(), and fesetmode() as per C23
Attached
Detach File
Event Timeline
Log In to Comment