mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
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:
19 files changed
+532
-3
No files matched your search
+2
-1
@@ -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
|
||||
|
||||
@@ -329,6 +329,9 @@ FBSD_1.9 {
|
||||
atanpi;
|
||||
atanpif;
|
||||
atanpil;
|
||||
__fe_dfl_mode;
|
||||
fegetmode;
|
||||
fesetmode;
|
||||
fmaximum;
|
||||
fmaximumf;
|
||||
fmaximuml;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 .
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user