This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH 8/8] Create and use libc_feholdsetround, libc_feresetround{,_noex}.
- From: Richard Henderson <rth at twiddle dot net>
- To: libc-alpha at sourceware dot org
- Cc: joseph at codesourcery dot com
- Date: Wed, 7 Mar 2012 14:11:02 -0800
- Subject: [PATCH 8/8] Create and use libc_feholdsetround, libc_feresetround{,_noex}.
- References: <1331158262-17508-1-git-send-email-rth@twiddle.net>
The x86_64 optimized version gets to avoid the function call
to __feraiseexcept as for libc_feupdateenv.
* math/math_private.h (libc_feholdsetround, libc_feholdsetroundf,
libc_feholdsetroundl, libc_feresetround, libc_feresetroundf,
libc_feresetroundl, libc_feresetround_noex, libc_feresetround_noexf,
libc_feresetround_noexl): New.
(SET_RESTORE_ROUND, SET_RESTORE_ROUNDF, SET_RESTORE_ROUNDL,
SET_RESTORE_ENV_ROUND, SET_RESTORE_ENV_ROUNDF,
SET_RESTORE_ENV_ROUNDL): Use them.
* sysdeps/x86_64/fpu/math_private.h (libc_feholdsetround,
libc_feholdsetroundf, libc_feresetround, libc_feresetroundf): New.
---
math/math_private.h | 63 ++++++++++++++++++++++++++++++-------
sysdeps/x86_64/fpu/math_private.h | 23 +++++++++++++
2 files changed, 74 insertions(+), 12 deletions(-)
diff --git a/math/math_private.h b/math/math_private.h
index c9cb4e8..4241f93 100644
--- a/math/math_private.h
+++ b/math/math_private.h
@@ -449,30 +449,69 @@ default_libc_feupdateenv (fenv_t *e)
# define libc_feupdateenvl default_libc_feupdateenv
#endif
+/* Save and set the rounding mode. The use of fenv_t to store the old mode
+ allows a target-specific version of this function to avoid converting the
+ rounding mode from the fpu format. By default we have no choice but to
+ manipulate the entire env. */
+
+#ifndef libc_feholdsetround
+# define libc_feholdsetround libc_feholdexcept_setround
+#endif
+#ifndef libc_feholdsetroundf
+# define libc_feholdsetroundf libc_feholdexcept_setroundf
+#endif
+#ifndef libc_feholdsetroundl
+# define libc_feholdsetroundl libc_feholdexcept_setroundl
+#endif
+
+/* ... and the reverse. */
+
+#ifndef libc_feresetround
+# define libc_feresetround libc_feupdateenv
+#endif
+#ifndef libc_feresetroundf
+# define libc_feresetroundf libc_feupdateenvf
+#endif
+#ifndef libc_feresetroundl
+# define libc_feresetroundl libc_feupdateenvl
+#endif
+
+/* ... and a version that may also discard exceptions. */
+
+#ifndef libc_feresetround_noex
+# define libc_feresetround_noex libc_fesetenv
+#endif
+#ifndef libc_feresetround_noexf
+# define libc_feresetround_noexf libc_fesetenvf
+#endif
+#ifndef libc_feresetround_noexl
+# define libc_feresetround_noexl libc_fesetenvl
+#endif
+
/* Save and restore the rounding mode within a lexical block. */
#define SET_RESTORE_ROUND(RM) \
- fenv_t __libc_save_rm __attribute__((cleanup(libc_feupdateenv))); \
- libc_feholdexcept_setround (&__libc_save_rm, (RM))
+ fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetround))); \
+ libc_feholdsetround (&__libc_save_rm, (RM))
#define SET_RESTORE_ROUNDF(RM) \
- fenv_t __libc_save_rm __attribute__((cleanup(libc_feupdateenvf))); \
- libc_feholdexcept_setroundf (&__libc_save_rm, (RM))
+ fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetroundf))); \
+ libc_feholdsetroundf (&__libc_save_rm, (RM))
#define SET_RESTORE_ROUNDL(RM) \
- fenv_t __libc_save_rm __attribute__((cleanup(libc_feupdateenvl))); \
- libc_feholdexcept_setroundl (&__libc_save_rm, (RM))
+ fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetroundl))); \
+ libc_feholdsetroundl (&__libc_save_rm, (RM))
/* Save and restore the rounding mode within a lexical block, and also
the set of exceptions raised within the block may be discarded. */
#define SET_RESTORE_ENV_ROUND(RM) \
- fenv_t __libc_save_rm __attribute__((cleanup(libc_fesetenv))); \
- libc_feholdexcept_setround (&__libc_save_rm, (RM))
+ fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetround_noex))); \
+ libc_feholdsetround (&__libc_save_rm, (RM))
#define SET_RESTORE_ENV_ROUNDF(RM) \
- fenv_t __libc_save_rm __attribute__((cleanup(libc_fesetenvf))); \
- libc_feholdexcept_setroundf (&__libc_save_rm, (RM))
+ fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetround_noexf))); \
+ libc_feholdsetroundf (&__libc_save_rm, (RM))
#define SET_RESTORE_ENV_ROUNDL(RM) \
- fenv_t __libc_save_rm __attribute__((cleanup(libc_fesetenvl))); \
- libc_feholdexcept_setroundl (&__libc_save_rm, (RM))
+ fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetround_noexl))); \
+ libc_feholdsetroundl (&__libc_save_rm, (RM))
#define __nan(str) \
(__builtin_constant_p (str) && str[0] == '\0' ? NAN : __nan (str))
diff --git a/sysdeps/x86_64/fpu/math_private.h b/sysdeps/x86_64/fpu/math_private.h
index 44b72d8..97032ab 100644
--- a/sysdeps/x86_64/fpu/math_private.h
+++ b/sysdeps/x86_64/fpu/math_private.h
@@ -202,6 +202,29 @@ libc_feupdateenv (fenv_t *e)
#define libc_feupdateenv libc_feupdateenv
#define libc_feupdateenvf libc_feupdateenv
+static inline void __attribute__((always_inline))
+libc_feholdsetround (fenv_t *e, int r)
+{
+ unsigned int mxcsr;
+ asm (STMXCSR " %0" : "=m" (*&mxcsr));
+ e->__mxcsr = mxcsr;
+ mxcsr = (mxcsr & ~0x6000) | (r << 3);
+ asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr));
+}
+#define libc_feholdsetround libc_feholdsetround
+#define libc_feholdsetroundf libc_feholdsetround
+
+static inline void __attribute__((always_inline))
+libc_feresetround (fenv_t *e)
+{
+ unsigned int mxcsr;
+ asm (STMXCSR " %0" : "=m" (*&mxcsr));
+ mxcsr = (mxcsr & ~0x6000) | (e->__mxcsr & 0x6000);
+ asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr));
+}
+#define libc_feresetround libc_feresetround
+#define libc_feresetroundf libc_feresetround
+
#include <math/math_private.h>
#endif /* X86_64_MATH_PRIVATE_H */
--
1.7.7.6