libm: Implement femode_t, fegetmode(), and fesetmode() as per C23

Reviewed by:	kargl, kib
Approved by:	fuz (mentor)
MFC after:	1 month
Differential Revision:	https://reviews.freebsd.org/D59288
This commit is contained in:
Faraz Vahedi committed 2026-09-03 03:05:22 +03:30
1 parent 9d59ca793f
commit d8b6461f8c
19 files changed
+532 -3

No files matched your search

+2 -1
View File
@@ -187,7 +187,7 @@ MAN= acos.3 acosh.3 acospi.3 asin.3 asinh.3 asinpi.3 \
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+=feclearexcept.3 fegetexceptflag.3 feclearexcept.3 feraiseexcept.3 \
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
+3
View File
@@ -329,6 +329,9 @@ FBSD_1.9 {
atanpi;
atanpif;
atanpil;
__fe_dfl_mode;
fegetmode;
fesetmode;
fmaximum;
fmaximumf;
fmaximuml;
+13
View File
@@ -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 @@ int
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)
{
+29
View File
@@ -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 @@ __BEGIN_DECLS
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 feraiseexcept(int);
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 @@ int fegetexcept(void);
#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 @@ __fesetround_int(int __round)
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)
{
+18
View File
@@ -41,6 +41,12 @@ const fenv_t __fe_dfl_env = {
__INITIAL_MXCSR__
};
const femode_t __fe_dfl_mode = {
.__control = __INITIAL_FPUCW__,
.__reserved = 0,
.__mxcsr = __INITIAL_MXCSR__
};
int
(feclearexcept)(int excepts)
{
@@ -99,6 +105,18 @@ int
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)
{
+2
View File
@@ -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)
+42
View File
@@ -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 @@ int
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_feraiseexcept(int __excepts);
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_feraiseexcept(int __excepts);
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 @@ int
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)
{
+33
View File
@@ -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 @@ __BEGIN_DECLS
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 feraiseexcept(int __excepts);
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 feraiseexcept(int);
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 @@ int fegetexcept(void);
#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 @@ __fesetround_int(int __round)
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)
{
+18
View File
@@ -41,6 +41,12 @@ const fenv_t __fe_dfl_env = {
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 @@ int
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)
{
+70
View File
@@ -0,0 +1,70 @@
.\"
.\" Copyright (c) 2026 Faraz Vahedi <[email protected]>
.\"
.\" 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 .
+3 -1
View File
@@ -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 @@ function returns 0 on success and non-zero otherwise;
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
+48 -1
View File
@@ -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 @@ The
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 @@ double sqrt(double n) {
.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 @@ Except as noted below,
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 @@ It supersedes the non-standard routines defined in
.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"
+13
View File
@@ -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 @@ int
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)
{
+31
View File
@@ -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 @@ __BEGIN_DECLS
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 feraiseexcept(int);
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 @@ int feupdateenv(const fenv_t *);
#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 @@ __fesetround_int(int __round)
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)
{
+13
View File
@@ -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 @@ int
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)
{
+33
View File
@@ -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 @@ __BEGIN_DECLS
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 feraiseexcept(int);
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 @@ int feupdateenv(const fenv_t *);
#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 @@ __fesetround_int(int __round)
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)
{
+20
View File
@@ -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 @@ fesetround(int __round)
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)
{
+63
View File
@@ -332,6 +332,68 @@ ATF_TC_BODY(fegsetround, tc)
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_TCS(tp)
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);
+78
View File
@@ -90,12 +90,27 @@ typedef struct {
} 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 fegetexceptflag(fexcept_t *, int);
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 @@ int fesetenv(const fenv_t *);
#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 @@ __fesetround_int(int __round)
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 @@ __fesetround_int(int __round)
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)
{