This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 8/8] Create and use libc_feholdsetround, libc_feresetround{,_noex}.


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]