From 34cc08e336987a8ebc316595e3f552a4c09f1fd4 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 12 Mar 2021 17:01:37 +0000 Subject: [PATCH] Save all fpcr/fpsr bits in the AArch64 fenv_t The existing code masked off all bits that it didn't know about. To be future-proof, we should save and restore the entire fpcr/fpsr registers. Additionally, the existing fesetenv() was incorrectly setting the rounding mode in fpsr instead of fpcr. This patch stores fpcr in the high 32 bits of fenv_t and fpsr in the low bits instead of trying to interleave them in a single 32-bit field. Technically, this is an ABI break if you re-compile parts of your code or pass a fenv_t between DSOs that were compiled with different versions of fenv.h. However, I believe we should fix this since the existing code was broken and passing fenv_t across DSOs should rarely happen. Reviewed By: andrew Differential Revision: https://reviews.freebsd.org/D29160 --- lib/msun/aarch64/fenv.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/msun/aarch64/fenv.h b/lib/msun/aarch64/fenv.h index 2bd29877e5dc..2a55db3a9545 100644 --- a/lib/msun/aarch64/fenv.h +++ b/lib/msun/aarch64/fenv.h @@ -35,6 +35,7 @@ #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; @@ -156,13 +157,12 @@ fesetround(int __round) __fenv_static inline int fegetenv(fenv_t *__envp) { - fenv_t __r; + __uint64_t fpcr; + __uint64_t fpsr; - __mrs_fpcr(__r); - *__envp = __r & _ENABLE_MASK; - - __mrs_fpsr(__r); - *__envp |= __r & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT)); + __mrs_fpcr(fpcr); + __mrs_fpsr(fpsr); + *__envp = fpsr | (fpcr << 32); return (0); } @@ -173,12 +173,12 @@ feholdexcept(fenv_t *__envp) fenv_t __r; __mrs_fpcr(__r); - *__envp = __r & _ENABLE_MASK; + *__envp = __r << 32; __r &= ~(_ENABLE_MASK); __msr_fpcr(__r); __mrs_fpsr(__r); - *__envp |= __r & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT)); + *__envp |= (__uint32_t)__r; __r &= ~(_ENABLE_MASK); __msr_fpsr(__r); return (0); @@ -188,8 +188,8 @@ __fenv_static inline int fesetenv(const fenv_t *__envp) { - __msr_fpcr((*__envp) & _ENABLE_MASK); - __msr_fpsr((*__envp) & (FE_ALL_EXCEPT | (_ROUND_MASK << _ROUND_SHIFT))); + __msr_fpcr((*__envp) >> 32); + __msr_fpsr((fenv_t)(__uint32_t)*__envp); return (0); }