libroot: Flesh out glibc floating point support for ARM.

The last time someone touched this directory, there was no floating
point support configured in ARM. Now we are targeting ARMv7a+, which
always has a hard FPU, so we need this now.

With this, a haiku.hpkg can (finally) be built again (at least
under lld, anyway!)
This commit is contained in:
Augustin Cavalier
2019-06-17 20:44:56 -04:00
parent 57e40b4406
commit f1e80d365b
9 changed files with 792 additions and 77 deletions
+109 -58
View File
@@ -3,15 +3,16 @@ SubDir HAIKU_TOP src system libroot posix glibc arch arm ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch $(TARGET_ARCH) ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc libio ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc stdlib ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc math ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc libio ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ;
SubDirHdrs $(HAIKU_TOP) src system libroot posix glibc arch generic ;
UsePrivateHeaders libroot ;
if $(OPTIM) = -O0 {
OPTIM = -O ;
}
@@ -21,67 +22,116 @@ DEBUG = 0 ;
SubDirCcFlags -D_GNU_SOURCE -D_IEEE_LIBM ;
# Note: There is no *l() support yet. Our compiler says sizeof(long double) = 8,
# while there are only 96 and 128 bit implementation in glibc.
local genericSources =
lshift.c rshift.c submul_1.c
s_finite.c s_finitef.c
add_n.c sub_n.c
addmul_1.c mul_1.c
cmp.c dbl2mpn.c divrem.c
mpn2dbl.c mpn2flt.c mpn2ldbl.c
mul.c mul_n.c
s_isinf.c s_isinff.c
s_isnan.c s_isnanf.c
s_signbit.c s_signbitf.c
s_nan.c s_nanf.c
e_hypot.c e_hypotf.c
w_hypot.c w_hypotf.c
s_fpclassify.c s_fpclassifyf.c
s_clog.c s_clogf.c
s_log1p.c s_log1pf.c
s_csqrt.c s_csqrtf.c
s_floor.c s_floorf.c
s_ceil.c s_ceilf.c
s_modf.c
w_powf.c e_powf.c
w_pow.c e_pow.c slowpow.c
w_exp.c e_exp.c slowexp.c
s_frexp.c s_expm1.c
dosincos.c
doasin.c
sincos32.c
branred.c
cmp.c dbl2mpn.c divrem.c
doasin.c dosincos.c
halfulp.c
mpa.c mplog.c mpexp.c
s_sin.c
s_atan.c s_atanf.c
s_tan.c
e_asin.c e_asinl.c
w_asin.c
e_log10.c w_log10.c
e_logf.c e_logl.c
e_acos.c w_acos.c
e_atan2.c
w_atan2.c mpatan2.c mpatan.c mptan.c mpsqrt.c w_sqrt.c w_sqrtf.c
e_sqrtl.c
e_fmod.c w_fmod.c
e_log.c w_log.c
e_cosh.c w_cosh.c
e_sinh.c w_sinh.c
s_cosf.c k_cosf.c
s_sinf.c k_sinf.c
s_ldexp.c s_ldexpf.c
s_scalbnf.c s_scalbn.c
s_copysign.c s_copysignf.c
s_tanh.c s_tanf.c k_tanf.c
s_lround.c s_lroundf.c s_round.c s_roundf.c
s_rint.c s_rintf.c s_lrintf.c
e_fmodf.c w_fmodf.c
e_atan2f.c w_atan2f.c
e_rem_pio2f.c k_rem_pio2f.c
memrchr.c
mpa.c mpatan.c mpatan2.c mpexp.c mplog.c mpn2dbl.c
mpn2flt.c mpn2ldbl.c mpsqrt.c mptan.c
mul.c mul_n.c
sincos32.c
slowexp.c
slowpow.c
e_acos.c e_acosf.c # e_acosl.c
e_acosh.c e_acoshf.c # e_acoshl.c
e_asin.c e_asinf.c # e_asinl.c
e_atan2.c e_atan2f.c # e_atan2l.c
e_atanh.c e_atanhf.c # e_atanhl.c
e_cosh.c e_coshf.c # e_coshl.c
e_exp.c e_expf.c
e_fmod.c e_fmodf.c # e_fmodl.c
e_gamma_r.c e_gammaf_r.c
e_hypot.c e_hypotf.c # e_hypotl.c
e_j0.c e_j0f.c
e_j1.c e_j1f.c
e_jn.c e_jnf.c
e_lgamma_r.c e_lgammaf_r.c
e_log.c e_logf.c
e_log10.c e_log10f.c
e_pow.c e_powf.c # e_powl.c
e_rem_pio2f.c
e_remainder.c e_remainderf.c # e_remainderl.c
e_scalb.c e_scalbf.c # e_scalbl.c
e_sinh.c e_sinhf.c # e_sinhl.c
k_cos.c k_cosf.c
k_sin.c k_sinf.c
k_rem_pio2.c k_rem_pio2f.c # k_rem_pio2l.c
k_tan.c k_tanf.c
s_asinh.c s_asinhf.c # s_asinhl.c
s_atan.c s_atanf.c # s_atanl.c
s_cbrt.c s_cbrtf.c # s_cbrtl.c
s_ceil.c s_ceilf.c # s_ceill.c
s_cos.c s_cosf.c
s_copysign.c s_copysignf.c
s_erf.c s_erff.c # s_erfl.c
s_expm1f.c s_expm1.c
s_finite.c s_finitef.c # s_finitel.c
s_clog.c s_clogf.c # s_clogl.c
s_csqrt.c s_csqrtf.c # s_csqrtl.c
s_floor.c s_floorf.c # s_floorl.c
s_fabs.c s_fabsf.c
s_fdim.c s_fdimf.c
s_fma.c s_fmaf.c # s_fmal.c
s_fmax.c s_fmaxf.c
s_fmin.c s_fminf.c
s_fpclassify.c s_fpclassifyf.c # s_fpclassifyl.c
s_frexp.c s_frexpf.c # s_frexpl.c
s_ilogb.c s_ilogbf.c
s_isinf.c s_isinff.c # s_isinfl.c
s_isnan.c s_isnanf.c
s_ldexp.c s_ldexpf.c # s_ldexpl.c
s_llrint.c s_llrintf.c # s_llrintl.c
s_log1p.c s_log1pf.c
s_logb.c s_logbf.c # s_logbl.c
s_lrint.c s_lrintf.c # s_lrintl.c
s_lround.c s_lroundf.c
s_modf.c s_modff.c # s_modfl.c
s_nan.c s_nanf.c # s_nanl.c
# s_nexttoward.c s_nexttowardf.c s_nexttowardl.c
s_round.c s_roundf.c # s_roundl.c
s_rint.c s_rintf.c
s_scalbn.c s_scalbnf.c # s_scalbnl.c
s_signbit.c s_signbitf.c # s_signbitl.c
s_significand.c s_significandf.c
s_signgam.c
s_sin.c s_sinf.c # s_sinl.c
s_sincos.c s_sincosf.c
s_tan.c s_tanf.c
s_tanh.c s_tanhf.c
s_trunc.c s_truncf.c
t_exp.c
w_acos.c w_acosf.c # w_acosl.c
w_acosh.c w_acoshf.c # w_acoshl.c
w_atan2.c w_atan2f.c # w_atan2l.c
w_asin.c w_asinf.c # w_asinl.c
w_atanh.c w_atanhf.c # w_atanhl.c
w_cosh.c w_coshf.c # w_coshl.c
w_drem.c w_dremf.c # w_dreml.c
w_exp.c w_expf.c # w_expl.c
w_fmod.c w_fmodf.c # w_fmodl.c
w_hypot.c w_hypotf.c # w_hypotl.c
w_j0.c w_j0f.c
w_j1.c w_j1f.c
w_jn.c w_jnf.c
w_lgamma.c w_lgammaf.c
w_lgamma_r.c w_lgammaf_r.c
w_log.c w_logf.c # w_logl.c
w_log10.c w_log10f.c # w_log10l.c
w_pow.c w_powf.c # w_powl.c
w_remainder.c w_remainderf.c # w_remainderl.c
w_scalb.c w_scalbf.c # w_scalbl.c
w_sinh.c w_sinhf.c # w_sinhl.c
w_sqrt.c w_sqrtf.c
w_tgamma.c w_tgammaf.c # w_tgammal.c
;
local architectureObject ;
@@ -93,15 +143,16 @@ for architectureObject in [ MultiArchSubDirSetup arm ] {
$(genericSources)
;
MergeObject <$(architecture)>posix_gnu_arch_$(TARGET_ARCH)_others.o :
e_sqrt.c
e_sqrtf.c
MergeObject <$(architecture)>posix_gnu_arch_$(TARGET_ARCH)_other.o :
e_sqrt.c e_sqrtf.c # e_sqrtl.c
feholdexcpt.c fesetenv.c fesetround.c fraiseexcpt.c
;
MergeObjectFromObjects <$(architecture)>posix_gnu_arch_$(TARGET_ARCH).o
: :
<$(architecture)>posix_gnu_arch_$(TARGET_ARCH)_generic.o
<$(architecture)>posix_gnu_arch_$(TARGET_ARCH)_others.o
<$(architecture)>posix_gnu_arch_$(TARGET_ARCH)_other.o
;
SEARCH on [ FGristFiles $(genericSources) ]
@@ -0,0 +1,35 @@
/* Store current floating-point environment and clear exceptions.
Copyright (C) 1997-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <fenv_private.h>
#include <arm-features.h>
int
__feholdexcept (fenv_t *envp)
{
/* Fail if a VFP unit isn't present. */
if (!ARM_HAVE_VFP)
return 1;
libc_feholdexcept_vfp (envp);
return 0;
}
libm_hidden_def (__feholdexcept)
weak_alias (__feholdexcept, feholdexcept)
libm_hidden_weak (feholdexcept)
@@ -0,0 +1,66 @@
/* Install given floating-point environment.
Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <fenv.h>
#include <fpu_control.h>
#include <arm-features.h>
int
__fesetenv (const fenv_t *envp)
{
fpu_control_t fpscr, new_fpscr, updated_fpscr;
/* Fail if a VFP unit isn't present. */
if (!ARM_HAVE_VFP)
return 1;
_FPU_GETCW (fpscr);
if ((envp != FE_DFL_ENV) && (envp != FE_NOMASK_ENV))
{
/* The new FPSCR is valid, so don't merge the reserved flags. */
new_fpscr = envp->__cw;
/* Write new FPSCR if different (ignoring NZCV flags). */
if (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0)
_FPU_SETCW (new_fpscr);
return 0;
}
/* Preserve the reserved FPSCR flags. */
new_fpscr = fpscr & _FPU_RESERVED;
new_fpscr |= (envp == FE_DFL_ENV) ? _FPU_DEFAULT : _FPU_IEEE;
if (((new_fpscr ^ fpscr) & ~_FPU_MASK_NZCV) != 0)
{
_FPU_SETCW (new_fpscr);
/* Not all VFP architectures support trapping exceptions, so
test whether the relevant bits were set and fail if not. */
_FPU_GETCW (updated_fpscr);
return new_fpscr & ~updated_fpscr;
}
return 0;
}
libm_hidden_def (__fesetenv)
weak_alias (__fesetenv, fesetenv)
libm_hidden_weak (fesetenv)
@@ -0,0 +1,39 @@
/* Set current rounding direction.
Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <fenv_private.h>
#include <arm-features.h>
int
__fesetround (int round)
{
/* FE_TONEAREST is the only supported rounding mode
if a VFP unit isn't present. */
if (!ARM_HAVE_VFP)
return (round == FE_TONEAREST) ? 0 : 1;
if (round & ~_FPU_MASK_RM)
return 1;
libc_fesetround_vfp (round);
return 0;
}
libm_hidden_def (__fesetround)
weak_alias (__fesetround, fesetround)
libm_hidden_weak (fesetround)
@@ -0,0 +1,107 @@
/* Raise given exceptions.
Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include <fpu_control.h>
#include <fenv.h>
#include <float.h>
#include <arm-features.h>
int
__feraiseexcept (int excepts)
{
/* Fail if a VFP unit isn't present unless nothing needs to be done. */
if (!ARM_HAVE_VFP)
return (excepts != 0);
else
{
fpu_control_t fpscr;
const float fp_zero = 0.0, fp_one = 1.0, fp_max = FLT_MAX,
fp_min = FLT_MIN, fp_1e32 = 1.0e32f, fp_two = 2.0,
fp_three = 3.0;
/* Raise exceptions represented by EXPECTS. But we must raise only
one signal at a time. It is important that if the overflow/underflow
exception and the inexact exception are given at the same time,
the overflow/underflow exception follows the inexact exception. After
each exception we read from the fpscr, to force the exception to be
raised immediately. */
/* There are additional complications because this file may be compiled
without VFP support enabled, and we also can't assume that the
assembler has VFP instructions enabled. To get around this we use the
generic coprocessor mnemonics and avoid asking GCC to put float values
in VFP registers. */
/* First: invalid exception. */
if (FE_INVALID & excepts)
__asm__ __volatile__ (
"ldc p10, cr0, %1\n\t" /* flds s0, %1 */
"cdp p10, 8, cr0, cr0, cr0, 0\n\t" /* fdivs s0, s0, s0 */
"mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr) /* fmrx %0, fpscr */
: "m" (fp_zero)
: "s0");
/* Next: division by zero. */
if (FE_DIVBYZERO & excepts)
__asm__ __volatile__ (
"ldc p10, cr0, %1\n\t" /* flds s0, %1 */
"ldcl p10, cr0, %2\n\t" /* flds s1, %2 */
"cdp p10, 8, cr0, cr0, cr0, 1\n\t" /* fdivs s0, s0, s1 */
"mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr) /* fmrx %0, fpscr */
: "m" (fp_one), "m" (fp_zero)
: "s0", "s1");
/* Next: overflow. */
if (FE_OVERFLOW & excepts)
/* There's no way to raise overflow without also raising inexact. */
__asm__ __volatile__ (
"ldc p10, cr0, %1\n\t" /* flds s0, %1 */
"ldcl p10, cr0, %2\n\t" /* flds s1, %2 */
"cdp p10, 3, cr0, cr0, cr0, 1\n\t" /* fadds s0, s0, s1 */
"mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr) /* fmrx %0, fpscr */
: "m" (fp_max), "m" (fp_1e32)
: "s0", "s1");
/* Next: underflow. */
if (FE_UNDERFLOW & excepts)
__asm__ __volatile__ (
"ldc p10, cr0, %1\n\t" /* flds s0, %1 */
"ldcl p10, cr0, %2\n\t" /* flds s1, %2 */
"cdp p10, 8, cr0, cr0, cr0, 1\n\t" /* fdivs s0, s0, s1 */
"mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr) /* fmrx %0, fpscr */
: "m" (fp_min), "m" (fp_three)
: "s0", "s1");
/* Last: inexact. */
if (FE_INEXACT & excepts)
__asm__ __volatile__ (
"ldc p10, cr0, %1\n\t" /* flds s0, %1 */
"ldcl p10, cr0, %2\n\t" /* flds s1, %2 */
"cdp p10, 8, cr0, cr0, cr0, 1\n\t" /* fdivs s0, s0, s1 */
"mrc p10, 7, %0, cr1, cr0, 0" : "=r" (fpscr) /* fmrx %0, fpscr */
: "m" (fp_two), "m" (fp_three)
: "s0", "s1");
/* Success. */
return 0;
}
}
libm_hidden_def (__feraiseexcept)
weak_alias (__feraiseexcept, feraiseexcept)
libm_hidden_weak (feraiseexcept)
@@ -0,0 +1,59 @@
/* Macros to test for CPU features on ARM. Generic ARM version.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef _ARM_ARM_FEATURES_H
#define _ARM_ARM_FEATURES_H 1
/* An OS-specific arm-features.h file should define ARM_HAVE_VFP to
an appropriate expression for testing at runtime whether the VFP
hardware is present. We'll then redefine it to a constant if we
know at compile time that we can assume VFP. */
#ifndef __SOFTFP__
/* The compiler is generating VFP instructions, so we're already
assuming the hardware exists. */
# undef ARM_HAVE_VFP
# define ARM_HAVE_VFP 1
#endif
/* An OS-specific arm-features.h file may define ARM_ASSUME_NO_IWMMXT
to indicate at compile time that iWMMXt hardware is never present
at runtime (or that we never care about its state) and so need not
be checked for. */
/* A more-specific arm-features.h file may define ARM_ALWAYS_BX to indicate
that instructions using pc as a destination register must never be used,
so a "bx" (or "blx") instruction is always required. */
/* The log2 of the minimum alignment required for an address that
is the target of a computed branch (i.e. a "bx" instruction).
A more-specific arm-features.h file may define this to set a more
stringent requirement.
Using this only makes sense for code in ARM mode (where instructions
always have a fixed size of four bytes), or for Thumb-mode code that is
specifically aligning all the related branch targets to match (since
Thumb instructions might be either two or four bytes). */
#ifndef ARM_BX_ALIGN_LOG2
# define ARM_BX_ALIGN_LOG2 2
#endif
/* An OS-specific arm-features.h file may define ARM_NO_INDEX_REGISTER to
indicate that the two-register addressing modes must never be used. */
#endif /* arm-features.h */
@@ -1,4 +1,4 @@
/* Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
/* Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -12,9 +12,8 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef _FENV_H
# error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
@@ -23,36 +22,69 @@
/* Define bits representing exceptions in the FPU status word. */
enum
{
FE_INVALID = 1,
#define FE_INVALID FE_INVALID
FE_DIVBYZERO = 2,
#define FE_DIVBYZERO FE_DIVBYZERO
FE_OVERFLOW = 4,
#define FE_OVERFLOW FE_OVERFLOW
FE_UNDERFLOW = 8,
#define FE_UNDERFLOW FE_UNDERFLOW
FE_INVALID =
#define FE_INVALID 1
FE_INVALID,
FE_DIVBYZERO =
#define FE_DIVBYZERO 2
FE_DIVBYZERO,
FE_OVERFLOW =
#define FE_OVERFLOW 4
FE_OVERFLOW,
FE_UNDERFLOW =
#define FE_UNDERFLOW 8
FE_UNDERFLOW,
FE_INEXACT =
#define FE_INEXACT 16
FE_INEXACT,
};
/* Amount to shift by to convert an exception to a mask bit. */
#define FE_EXCEPT_SHIFT 16
#define FE_EXCEPT_SHIFT 8
/* All supported exceptions. */
#define FE_ALL_EXCEPT \
(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW)
(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)
/* The ARM FPU basically only supports round-to-nearest. Other rounding
modes exist, but you have to encode them in the actual instruction. */
/* VFP supports all of the four defined rounding modes. */
enum
{
FE_TONEAREST =
#define FE_TONEAREST 0
FE_TONEAREST,
FE_UPWARD =
#define FE_UPWARD 0x400000
FE_UPWARD,
FE_DOWNWARD =
#define FE_DOWNWARD 0x800000
FE_DOWNWARD,
FE_TOWARDZERO =
#define FE_TOWARDZERO 0xc00000
FE_TOWARDZERO
};
/* Type representing exception flags. */
typedef unsigned long int fexcept_t;
typedef unsigned int fexcept_t;
/* Type representing floating-point environment. */
typedef struct
{
unsigned long int __cw;
unsigned int __cw;
}
fenv_t;
/* If the default argument is used we use this value. */
#define FE_DFL_ENV ((fenv_t *) -1l)
#define FE_DFL_ENV ((const fenv_t *) -1l)
#ifdef __USE_GNU
/* Floating-point environment where none of the exceptions are masked. */
# define FE_NOMASK_ENV ((const fenv_t *) -2)
#endif
#if 0 // __GLIBC_USE (IEC_60559_BFP_EXT)
/* Type representing floating-point control modes. */
typedef unsigned int femode_t;
/* Default floating-point control modes. */
# define FE_DFL_MODE ((const femode_t *) -1L)
#endif
@@ -0,0 +1,251 @@
/* Private floating point rounding and exceptions handling. ARM VFP version.
Copyright (C) 2014-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef FENV_PRIVATE_H
#define FENV_PRIVATE_H 1
#include <fenv.h>
#include <fpu_control.h>
# define __glibc_unlikely(x) __builtin_expect ((x), 0)
static __always_inline void
libc_feholdexcept_vfp (fenv_t *envp)
{
fpu_control_t fpscr;
_FPU_GETCW (fpscr);
envp->__cw = fpscr;
/* Clear exception flags and set all exceptions to non-stop. */
fpscr &= ~_FPU_MASK_EXCEPT;
_FPU_SETCW (fpscr);
}
static __always_inline void
libc_fesetround_vfp (int round)
{
fpu_control_t fpscr;
_FPU_GETCW (fpscr);
/* Set new rounding mode if different. */
if (__glibc_unlikely ((fpscr & _FPU_MASK_RM) != round))
_FPU_SETCW ((fpscr & ~_FPU_MASK_RM) | round);
}
static __always_inline void
libc_feholdexcept_setround_vfp (fenv_t *envp, int round)
{
fpu_control_t fpscr;
_FPU_GETCW (fpscr);
envp->__cw = fpscr;
/* Clear exception flags, set all exceptions to non-stop,
and set new rounding mode. */
fpscr &= ~(_FPU_MASK_EXCEPT | _FPU_MASK_RM);
_FPU_SETCW (fpscr | round);
}
static __always_inline void
libc_feholdsetround_vfp (fenv_t *envp, int round)
{
fpu_control_t fpscr;
_FPU_GETCW (fpscr);
envp->__cw = fpscr;
/* Set new rounding mode if different. */
if (__glibc_unlikely ((fpscr & _FPU_MASK_RM) != round))
_FPU_SETCW ((fpscr & ~_FPU_MASK_RM) | round);
}
static __always_inline void
libc_feresetround_vfp (fenv_t *envp)
{
fpu_control_t fpscr, round;
_FPU_GETCW (fpscr);
/* Check whether rounding modes are different. */
round = (envp->__cw ^ fpscr) & _FPU_MASK_RM;
/* Restore the rounding mode if it was changed. */
if (__glibc_unlikely (round != 0))
_FPU_SETCW (fpscr ^ round);
}
static __always_inline int
libc_fetestexcept_vfp (int ex)
{
fpu_control_t fpscr;
_FPU_GETCW (fpscr);
return fpscr & ex & FE_ALL_EXCEPT;
}
static __always_inline void
libc_fesetenv_vfp (const fenv_t *envp)
{
fpu_control_t fpscr, new_fpscr;
_FPU_GETCW (fpscr);
new_fpscr = envp->__cw;
/* Write new FPSCR if different (ignoring NZCV flags). */
if (__glibc_unlikely (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0))
_FPU_SETCW (new_fpscr);
}
static __always_inline int
libc_feupdateenv_test_vfp (const fenv_t *envp, int ex)
{
fpu_control_t fpscr, new_fpscr;
int excepts;
_FPU_GETCW (fpscr);
/* Merge current exception flags with the saved fenv. */
excepts = fpscr & FE_ALL_EXCEPT;
new_fpscr = envp->__cw | excepts;
/* Write new FPSCR if different (ignoring NZCV flags). */
if (__glibc_unlikely (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0))
_FPU_SETCW (new_fpscr);
/* Raise the exceptions if enabled in the new FP state. */
if (__glibc_unlikely (excepts & (new_fpscr >> FE_EXCEPT_SHIFT)))
__feraiseexcept (excepts);
return excepts & ex;
}
static __always_inline void
libc_feupdateenv_vfp (const fenv_t *envp)
{
libc_feupdateenv_test_vfp (envp, 0);
}
static __always_inline void
libc_feholdsetround_vfp_ctx (struct rm_ctx *ctx, int r)
{
fpu_control_t fpscr, round;
_FPU_GETCW (fpscr);
ctx->updated_status = false;
ctx->env.__cw = fpscr;
/* Check whether rounding modes are different. */
round = (fpscr ^ r) & _FPU_MASK_RM;
/* Set the rounding mode if changed. */
if (__glibc_unlikely (round != 0))
{
ctx->updated_status = true;
_FPU_SETCW (fpscr ^ round);
}
}
static __always_inline void
libc_feresetround_vfp_ctx (struct rm_ctx *ctx)
{
/* Restore the rounding mode if updated. */
if (__glibc_unlikely (ctx->updated_status))
{
fpu_control_t fpscr;
_FPU_GETCW (fpscr);
fpscr = (fpscr & ~_FPU_MASK_RM) | (ctx->env.__cw & _FPU_MASK_RM);
_FPU_SETCW (fpscr);
}
}
static __always_inline void
libc_fesetenv_vfp_ctx (struct rm_ctx *ctx)
{
fpu_control_t fpscr, new_fpscr;
_FPU_GETCW (fpscr);
new_fpscr = ctx->env.__cw;
/* Write new FPSCR if different (ignoring NZCV flags). */
if (__glibc_unlikely (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0))
_FPU_SETCW (new_fpscr);
}
#ifndef __SOFTFP__
# define libc_feholdexcept libc_feholdexcept_vfp
# define libc_feholdexceptf libc_feholdexcept_vfp
# define libc_feholdexceptl libc_feholdexcept_vfp
# define libc_fesetround libc_fesetround_vfp
# define libc_fesetroundf libc_fesetround_vfp
# define libc_fesetroundl libc_fesetround_vfp
# define libc_feresetround libc_feresetround_vfp
# define libc_feresetroundf libc_feresetround_vfp
# define libc_feresetroundl libc_feresetround_vfp
# define libc_feresetround_noex libc_fesetenv_vfp
# define libc_feresetround_noexf libc_fesetenv_vfp
# define libc_feresetround_noexl libc_fesetenv_vfp
# define libc_feholdexcept_setround libc_feholdexcept_setround_vfp
# define libc_feholdexcept_setroundf libc_feholdexcept_setround_vfp
# define libc_feholdexcept_setroundl libc_feholdexcept_setround_vfp
# define libc_feholdsetround libc_feholdsetround_vfp
# define libc_feholdsetroundf libc_feholdsetround_vfp
# define libc_feholdsetroundl libc_feholdsetround_vfp
# define libc_fetestexcept libc_fetestexcept_vfp
# define libc_fetestexceptf libc_fetestexcept_vfp
# define libc_fetestexceptl libc_fetestexcept_vfp
# define libc_fesetenv libc_fesetenv_vfp
# define libc_fesetenvf libc_fesetenv_vfp
# define libc_fesetenvl libc_fesetenv_vfp
# define libc_feupdateenv libc_feupdateenv_vfp
# define libc_feupdateenvf libc_feupdateenv_vfp
# define libc_feupdateenvl libc_feupdateenv_vfp
# define libc_feupdateenv_test libc_feupdateenv_test_vfp
# define libc_feupdateenv_testf libc_feupdateenv_test_vfp
# define libc_feupdateenv_testl libc_feupdateenv_test_vfp
/* We have support for rounding mode context. */
#define HAVE_RM_CTX 1
# define libc_feholdsetround_ctx libc_feholdsetround_vfp_ctx
# define libc_feresetround_ctx libc_feresetround_vfp_ctx
# define libc_feresetround_noex_ctx libc_fesetenv_vfp_ctx
# define libc_feholdsetroundf_ctx libc_feholdsetround_vfp_ctx
# define libc_feresetroundf_ctx libc_feresetround_vfp_ctx
# define libc_feresetround_noexf_ctx libc_fesetenv_vfp_ctx
# define libc_feholdsetroundl_ctx libc_feholdsetround_vfp_ctx
# define libc_feresetroundl_ctx libc_feresetround_vfp_ctx
# define libc_feresetround_noexl_ctx libc_fesetenv_vfp_ctx
#endif
#endif /* FENV_PRIVATE_H */
@@ -0,0 +1,75 @@
/* FPU control word definitions. ARM VFP version.
Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef _FPU_CONTROL_H
#define _FPU_CONTROL_H
#if !(defined(_LIBC) && !defined(_LIBC_TEST)) && defined(__SOFTFP__)
#define _FPU_RESERVED 0xffffffff
#define _FPU_DEFAULT 0x00000000
typedef unsigned int fpu_control_t;
#define _FPU_GETCW(cw) (cw) = 0
#define _FPU_SETCW(cw) (void) (cw)
extern fpu_control_t __fpu_control;
#else
/* masking of interrupts */
#define _FPU_MASK_IM 0x00000100 /* invalid operation */
#define _FPU_MASK_ZM 0x00000200 /* divide by zero */
#define _FPU_MASK_OM 0x00000400 /* overflow */
#define _FPU_MASK_UM 0x00000800 /* underflow */
#define _FPU_MASK_PM 0x00001000 /* inexact */
#define _FPU_MASK_NZCV 0xf0000000 /* NZCV flags */
#define _FPU_MASK_RM 0x00c00000 /* rounding mode */
#define _FPU_MASK_EXCEPT 0x00001f1f /* all exception flags */
/* Some bits in the FPSCR are not yet defined. They must be preserved when
modifying the contents. */
#define _FPU_RESERVED 0x00086060
#define _FPU_DEFAULT 0x00000000
/* Default + exceptions enabled. */
#define _FPU_IEEE (_FPU_DEFAULT | 0x00001f00)
/* Type of the control word. */
typedef unsigned int fpu_control_t;
/* Macros for accessing the hardware control word. */
#ifdef __SOFTFP__
/* This is fmrx %0, fpscr. */
# define _FPU_GETCW(cw) \
__asm__ __volatile__ ("mrc p10, 7, %0, cr1, cr0, 0" : "=r" (cw))
/* This is fmxr fpscr, %0. */
# define _FPU_SETCW(cw) \
__asm__ __volatile__ ("mcr p10, 7, %0, cr1, cr0, 0" : : "r" (cw))
#else
# define _FPU_GETCW(cw) \
__asm__ __volatile__ ("vmrs %0, fpscr" : "=r" (cw))
# define _FPU_SETCW(cw) \
__asm__ __volatile__ ("vmsr fpscr, %0" : : "r" (cw))
#endif
/* Default control word set at startup. */
extern fpu_control_t __fpu_control;
#endif /* __SOFTFP__ */
#endif /* _FPU_CONTROL_H */