Skip to content

Commit

Permalink
aarch64/fenv: fix fenv_t (#319)
Browse files Browse the repository at this point in the history
* aarch64: copy `aarch64/fenv.h` from FreeBSD

https://github.com/freebsd/freebsd-src/blob/de1aa3dab23c06fec962a14da3e7b4755c5880cf/lib/msun/aarch64/fenv.h

* aarch64: clean code

* arm: remove AARCH64 ifdef
  • Loading branch information
inkydragon authored Feb 10, 2025
1 parent 5a88ede commit 1eeb139
Show file tree
Hide file tree
Showing 3 changed files with 251 additions and 5 deletions.
4 changes: 3 additions & 1 deletion include/openlibm_fenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#include <fenv.h>
#else /* !OPENLIBM_USE_HOST_FENV_H */

#if defined(__aarch64__) || defined(__arm__)
#if defined(__aarch64__)
#include <openlibm_fenv_aarch64.h>
#elif defined(__arm__)
#include <openlibm_fenv_arm.h>
#elif defined(__x86_64__)
#include <openlibm_fenv_amd64.h>
Expand Down
247 changes: 247 additions & 0 deletions include/openlibm_fenv_aarch64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
/*-
* Copyright (c) 2004-2005 David Schultz <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#ifndef _FENV_H_
#define _FENV_H_

#include <stdint.h>

#include "cdefs-compat.h"

#ifndef __fenv_static
#define __fenv_static static
#endif

/* The high 32 bits contain fpcr, low 32 contain fpsr. */
typedef __uint64_t fenv_t;
typedef __uint64_t fexcept_t;

/* Exception flags */
#define FE_INVALID 0x00000001
#define FE_DIVBYZERO 0x00000002
#define FE_OVERFLOW 0x00000004
#define FE_UNDERFLOW 0x00000008
#define FE_INEXACT 0x00000010
#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \
FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)

/*
* Rounding modes
*
* We can't just use the hardware bit values here, because that would
* make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
*/
#define FE_TONEAREST 0x0
#define FE_UPWARD 0x1
#define FE_DOWNWARD 0x2
#define FE_TOWARDZERO 0x3
#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
FE_UPWARD | FE_TOWARDZERO)
#define _ROUND_SHIFT 22

__BEGIN_DECLS

/* Default floating-point environment */
extern const fenv_t __fe_dfl_env;
#define FE_DFL_ENV (&__fe_dfl_env)

/* 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)

#define __mrs_fpcr(__r) __asm __volatile("mrs %0, fpcr" : "=r" (__r))
#define __msr_fpcr(__r) __asm __volatile("msr fpcr, %0" : : "r" (__r))

#define __mrs_fpsr(__r) __asm __volatile("mrs %0, fpsr" : "=r" (__r))
#define __msr_fpsr(__r) __asm __volatile("msr fpsr, %0" : : "r" (__r))


__fenv_static inline int
feclearexcept(int __excepts)
{
fexcept_t __r;

__mrs_fpsr(__r);
__r &= ~__excepts;
__msr_fpsr(__r);
return (0);
}

__fenv_static inline int
fegetexceptflag(fexcept_t *__flagp, int __excepts)
{
fexcept_t __r;

__mrs_fpsr(__r);
*__flagp = __r & __excepts;
return (0);
}

__fenv_static inline int
fesetexceptflag(const fexcept_t *__flagp, int __excepts)
{
fexcept_t __r;

__mrs_fpsr(__r);
__r &= ~__excepts;
__r |= *__flagp & __excepts;
__msr_fpsr(__r);
return (0);
}

__fenv_static inline int
feraiseexcept(int __excepts)
{
fexcept_t __r;

__mrs_fpsr(__r);
__r |= __excepts;
__msr_fpsr(__r);
return (0);
}

__fenv_static inline int
fetestexcept(int __excepts)
{
fexcept_t __r;

__mrs_fpsr(__r);
return (__r & __excepts);
}

__fenv_static inline int
fegetround(void)
{
fenv_t __r;

__mrs_fpcr(__r);
return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
}

__fenv_static inline int
fesetround(int __round)
{
fenv_t __r;

if (__round & ~_ROUND_MASK)
return (-1);
__mrs_fpcr(__r);
__r &= ~(_ROUND_MASK << _ROUND_SHIFT);
__r |= __round << _ROUND_SHIFT;
__msr_fpcr(__r);
return (0);
}

__fenv_static inline int
fegetenv(fenv_t *__envp)
{
__uint64_t fpcr;
__uint64_t fpsr;

__mrs_fpcr(fpcr);
__mrs_fpsr(fpsr);
*__envp = fpsr | (fpcr << 32);

return (0);
}

__fenv_static inline int
feholdexcept(fenv_t *__envp)
{
fenv_t __r;

__mrs_fpcr(__r);
*__envp = __r << 32;
__r &= ~(_ENABLE_MASK);
__msr_fpcr(__r);

__mrs_fpsr(__r);
*__envp |= (__uint32_t)__r;
__r &= ~(_ENABLE_MASK);
__msr_fpsr(__r);
return (0);
}

__fenv_static inline int
fesetenv(const fenv_t *__envp)
{

__msr_fpcr((*__envp) >> 32);
__msr_fpsr((fenv_t)(__uint32_t)*__envp);
return (0);
}

__fenv_static inline int
feupdateenv(const fenv_t *__envp)
{
fexcept_t __r;

__mrs_fpsr(__r);
fesetenv(__envp);
feraiseexcept(__r & FE_ALL_EXCEPT);
return (0);
}

#if __BSD_VISIBLE

/* We currently provide no external definitions of the functions below. */

static inline int
feenableexcept(int __mask)
{
fenv_t __old_r, __new_r;

__mrs_fpcr(__old_r);
__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
__msr_fpcr(__new_r);
return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
}

static inline int
fedisableexcept(int __mask)
{
fenv_t __old_r, __new_r;

__mrs_fpcr(__old_r);
__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
__msr_fpcr(__new_r);
return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
}

static inline int
fegetexcept(void)
{
fenv_t __r;

__mrs_fpcr(__r);
return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
}

#endif /* __BSD_VISIBLE */

__END_DECLS

#endif /* !_FENV_H_ */
5 changes: 1 addition & 4 deletions include/openlibm_fenv_arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,9 @@ extern const fenv_t __fe_dfl_env;
#define _FPUSW_SHIFT 16
#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT)

#if defined(__aarch64__)
#define __rfs(__fpsr) __asm __volatile("mrs %0,fpsr" : "=r" (*(__fpsr)))
#define __wfs(__fpsr) __asm __volatile("msr fpsr,%0" : : "r" (__fpsr))
/* Test for hardware support for ARM floating point operations, explicitly
checking for float and double support, see "ARM C Language Extensions", 6.5.1 */
#elif defined(__ARM_FP) && (__ARM_FP & 0x0C) != 0
#if defined(__ARM_FP) && (__ARM_FP & 0x0C) != 0
#define __rfs(__fpsr) __asm __volatile("vmrs %0,fpscr" : "=&r" (*(__fpsr)))
#define __wfs(__fpsr) __asm __volatile("vmsr fpscr,%0" : : "r" (__fpsr))
#else
Expand Down

0 comments on commit 1eeb139

Please sign in to comment.