Page MenuHomeFreeBSD

D59288.diff
No OneTemporary

D59288.diff

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

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)

Event Timeline