From f1e80d365b23a31801dd69c4b84d3a9965a6f9d0 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 17 Jun 2019 20:44:56 -0400 Subject: [PATCH] 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!) --- .../libroot/posix/glibc/arch/arm/Jamfile | 167 ++++++++---- .../posix/glibc/arch/arm/feholdexcpt.c | 35 +++ .../libroot/posix/glibc/arch/arm/fesetenv.c | 66 +++++ .../libroot/posix/glibc/arch/arm/fesetround.c | 39 +++ .../posix/glibc/arch/arm/fraiseexcpt.c | 107 ++++++++ .../glibc/include/arch/arm/arm-features.h | 59 ++++ .../posix/glibc/include/arch/arm/bits/fenv.h | 70 +++-- .../glibc/include/arch/arm/fenv_private.h | 251 ++++++++++++++++++ .../glibc/include/arch/arm/fpu_control.h | 75 ++++++ 9 files changed, 792 insertions(+), 77 deletions(-) create mode 100644 src/system/libroot/posix/glibc/arch/arm/feholdexcpt.c create mode 100644 src/system/libroot/posix/glibc/arch/arm/fesetenv.c create mode 100644 src/system/libroot/posix/glibc/arch/arm/fesetround.c create mode 100644 src/system/libroot/posix/glibc/arch/arm/fraiseexcpt.c create mode 100644 src/system/libroot/posix/glibc/include/arch/arm/arm-features.h create mode 100644 src/system/libroot/posix/glibc/include/arch/arm/fenv_private.h create mode 100644 src/system/libroot/posix/glibc/include/arch/arm/fpu_control.h diff --git a/src/system/libroot/posix/glibc/arch/arm/Jamfile b/src/system/libroot/posix/glibc/arch/arm/Jamfile index 56ef3e16cc..fc6e101675 100644 --- a/src/system/libroot/posix/glibc/arch/arm/Jamfile +++ b/src/system/libroot/posix/glibc/arch/arm/Jamfile @@ -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) ] diff --git a/src/system/libroot/posix/glibc/arch/arm/feholdexcpt.c b/src/system/libroot/posix/glibc/arch/arm/feholdexcpt.c new file mode 100644 index 0000000000..8c146af1c4 --- /dev/null +++ b/src/system/libroot/posix/glibc/arch/arm/feholdexcpt.c @@ -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 + . */ + +#include +#include + + +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) diff --git a/src/system/libroot/posix/glibc/arch/arm/fesetenv.c b/src/system/libroot/posix/glibc/arch/arm/fesetenv.c new file mode 100644 index 0000000000..6c3475a479 --- /dev/null +++ b/src/system/libroot/posix/glibc/arch/arm/fesetenv.c @@ -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 + . */ + +#include +#include +#include + + +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) diff --git a/src/system/libroot/posix/glibc/arch/arm/fesetround.c b/src/system/libroot/posix/glibc/arch/arm/fesetround.c new file mode 100644 index 0000000000..379dfdca9d --- /dev/null +++ b/src/system/libroot/posix/glibc/arch/arm/fesetround.c @@ -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 + . */ + +#include +#include + + +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) diff --git a/src/system/libroot/posix/glibc/arch/arm/fraiseexcpt.c b/src/system/libroot/posix/glibc/arch/arm/fraiseexcpt.c new file mode 100644 index 0000000000..2558b21204 --- /dev/null +++ b/src/system/libroot/posix/glibc/arch/arm/fraiseexcpt.c @@ -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 + . */ + +#include +#include +#include +#include + + +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) diff --git a/src/system/libroot/posix/glibc/include/arch/arm/arm-features.h b/src/system/libroot/posix/glibc/include/arch/arm/arm-features.h new file mode 100644 index 0000000000..69c4f9d604 --- /dev/null +++ b/src/system/libroot/posix/glibc/include/arch/arm/arm-features.h @@ -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 + . */ + +#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 */ diff --git a/src/system/libroot/posix/glibc/include/arch/arm/bits/fenv.h b/src/system/libroot/posix/glibc/include/arch/arm/bits/fenv.h index 7bd242385f..d3bbbc0f06 100644 --- a/src/system/libroot/posix/glibc/include/arch/arm/bits/fenv.h +++ b/src/system/libroot/posix/glibc/include/arch/arm/bits/fenv.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 + . */ #ifndef _FENV_H # error "Never use directly; include 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 diff --git a/src/system/libroot/posix/glibc/include/arch/arm/fenv_private.h b/src/system/libroot/posix/glibc/include/arch/arm/fenv_private.h new file mode 100644 index 0000000000..a60d676b0c --- /dev/null +++ b/src/system/libroot/posix/glibc/include/arch/arm/fenv_private.h @@ -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 + . */ + +#ifndef FENV_PRIVATE_H +#define FENV_PRIVATE_H 1 + +#include +#include + +# 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 */ diff --git a/src/system/libroot/posix/glibc/include/arch/arm/fpu_control.h b/src/system/libroot/posix/glibc/include/arch/arm/fpu_control.h new file mode 100644 index 0000000000..6b1b176eae --- /dev/null +++ b/src/system/libroot/posix/glibc/include/arch/arm/fpu_control.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 + . */ + +#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 */