This is the mail archive of the 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] [RFC] Change SET_RESTORE_ROUND to just set the rounding mode

Hi all,

While debugging why exp (-7.4444006192138124e+02) does *not* generate an
underflow exception on PowerPC and does on i32/x86_64 I found the issue
is related on how the rounding mode is being set on the two architectures.

The rounding mode is set using the macro SET_RESTORE_ROUND:

  fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetround)));    \
  libc_feholdsetround (&__libc_save_rm, (RM))

And libc_feresetround and libc_feholdsetround could be redefined depending
on the architecture. For SSE2 or higher on i32/x86_64 it will be redefined
to libc_feresetround_sse and this function only sets the rounding mode,
not changing any behavior on how the FP exception are being generated.

The issue is for PowerPC the default implementation default_libc_feholdexcept_setround 
is being used and the function set the rounding mode *and* hold any FP
exception. This make the exp underflow exception to be generate but ignored
on PowerPC.

So SET_RESTORE_ROUND generic implementation does not really follow
what it proposes: I believe the correct implementation would be *just* set
the rounding mode and not touch any FP exceptions behavior. The macro
SET_RESTORE_ROUND_NOEX handles the case where FP exception may be ignored.

I propose the following patch to change SET_RESTORE_ROUND default behavior
to just set/reset the rounding mode without touching any FP exception
generation behavior.

I tested on PPC64 and x86_64. I didn't open a specific bugzilla, but I
intend to do so.

Any comments, tips, advices?


2013-03-07  Adhemerval Zanella  <>

	* sysdeps/generic/math_private.h (default_libc_fegetround): New.
	(libc_fegetround): New.
	(libc_fegetroundf): New.
	(libc_fegetroundl): New.
	(libc_setround_cleanup): New.
	(libc_setround_cleanupf): New.
	(libc_setround_cleanupl): New.
	(SET_RESTORE_ROUND): Change to just set the rounding mode and not
	any exception generation behavior.
	* include/fenv.h (fegetround): Add libm_hidden_proto. 
	* math/fegetround.c (fegetround): Add libm_hidden_def.
	* sysdeps/i386/fpu/fegetround.c (fegetround): Likewise.
	* sysdeps/powerpc/fpu/fegetround.c (fegetround): Likewise.
	* sysdeps/s390/fpu/fegetround.c (fegetround): Likewise.
	* sysdeps/sh/sh4/fpu/fegetround.c (fegetround): Likewise.
	* sysdeps/sparc/fpu/fegetround.c (fegetround): Likewise.
	* sysdeps/x86_64/fpu/fegetround.c (fegetround): Likewise.

diff --git a/include/fenv.h b/include/fenv.h
index ed6d139..8911788 100644
--- a/include/fenv.h
+++ b/include/fenv.h
@@ -16,6 +16,7 @@ extern int __feupdateenv (const fenv_t *__envp);
 libm_hidden_proto (feraiseexcept)
 libm_hidden_proto (fegetenv)
 libm_hidden_proto (fesetenv)
+libm_hidden_proto (fegetround)
 libm_hidden_proto (fesetround)
 libm_hidden_proto (feholdexcept)
 libm_hidden_proto (feupdateenv)
diff --git a/math/fegetround.c b/math/fegetround.c
index deb3c5d..a82187a 100644
--- a/math/fegetround.c
+++ b/math/fegetround.c
@@ -24,4 +24,5 @@ fegetround (void)
   return 0;
+libm_hidden_def (fesetround)
 stub_warning (fegetround)
diff --git a/sysdeps/generic/math_private.h b/sysdeps/generic/math_private.h
index 7661788..25ba651 100644
--- a/sysdeps/generic/math_private.h
+++ b/sysdeps/generic/math_private.h
@@ -401,6 +401,22 @@ default_libc_feholdexcept (fenv_t *e)
 # define libc_feholdexceptl default_libc_feholdexcept
+static __always_inline int
+default_libc_fegetround (void)
+  return fegetround ();
+#ifndef libc_fegetround
+# define libc_fegetround  default_libc_fegetround
+#ifndef libc_fegetroundf
+# define libc_fegetroundf default_libc_fegetround
+#ifndef libc_fegetroundl
+# define libc_fegetroundl default_libc_fegetround
 static __always_inline void
 default_libc_fesetround (int r)
@@ -543,15 +559,39 @@ default_libc_feupdateenv_test (fenv_t *e, int ex)
 /* Save and restore the rounding mode within a lexical block.  */
+/* Helper functions because __atribute__(cleanup) expects a pointer to a type
+   compatible with the variable.  */
+static __always_inline void
+libc_setround_cleanup (int *r)
+  (void) libc_fesetround (*r);
+static __always_inline void
+libc_setround_cleanupf (int *r)
+  (void) libc_fesetroundf (*r);
+static __always_inline void
+libc_setround_cleanupl (int *r)
+  (void) libc_fesetroundl (*r);
-  fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetround)));	\
-  libc_feholdsetround (&__libc_save_rm, (RM))
+  int __libc_save_round __attribute__((cleanup(libc_setround_cleanup)));	\
+  __libc_save_round = libc_fegetround ();	\
+  libc_fesetround ((RM))
-  fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetroundf)));	\
-  libc_feholdsetroundf (&__libc_save_rm, (RM))
+  int __libc_save_round __attribute__((cleanup(libc_setround_cleanupf)));	\
+  __libc_save_round = libc_fegetroundf ();	\
+  libc_fesetroundf ((RM))
-  fenv_t __libc_save_rm __attribute__((cleanup(libc_feresetroundl)));	\
-  libc_feholdsetroundl (&__libc_save_rm, (RM))
+  int __libc_save_round __attribute__((cleanup(libc_setround_cleanupl)));	\
+  __libc_save_round = libc_fegetroundl ();	\
+  libc_fesetroundl ((RM))
 /* Save and restore the rounding mode within a lexical block, and also
    the set of exceptions raised within the block may be discarded.  */
diff --git a/sysdeps/i386/fpu/fegetround.c b/sysdeps/i386/fpu/fegetround.c
index d0170d3..cd96ae9 100644
--- a/sysdeps/i386/fpu/fegetround.c
+++ b/sysdeps/i386/fpu/fegetround.c
@@ -28,3 +28,4 @@ fegetround (void)
   return cw & 0xc00;
+libm_hidden_def (fegetround)
diff --git a/sysdeps/powerpc/fpu/fegetround.c b/sysdeps/powerpc/fpu/fegetround.c
index bcb6caa..078911f 100644
--- a/sysdeps/powerpc/fpu/fegetround.c
+++ b/sysdeps/powerpc/fpu/fegetround.c
@@ -24,3 +24,4 @@ fegetround (void)
   return __fegetround();
+libm_hidden_def (fegetround)
diff --git a/sysdeps/s390/fpu/fegetround.c b/sysdeps/s390/fpu/fegetround.c
index 4843a56..94482f6 100644
--- a/sysdeps/s390/fpu/fegetround.c
+++ b/sysdeps/s390/fpu/fegetround.c
@@ -29,3 +29,4 @@ fegetround (void)
   return cw & FPC_RM_MASK;
+libm_hidden_def (fegetround)
diff --git a/sysdeps/sh/sh4/fpu/fegetround.c b/sysdeps/sh/sh4/fpu/fegetround.c
index be4833f..8a81a6d 100644
--- a/sysdeps/sh/sh4/fpu/fegetround.c
+++ b/sysdeps/sh/sh4/fpu/fegetround.c
@@ -30,3 +30,4 @@ fegetround (void)
   return cw & 0x1;
+libm_hidden_def (fesetround)
diff --git a/sysdeps/sparc/fpu/fegetround.c b/sysdeps/sparc/fpu/fegetround.c
index c4987e8..c2d5f5a 100644
--- a/sysdeps/sparc/fpu/fegetround.c
+++ b/sysdeps/sparc/fpu/fegetround.c
@@ -27,3 +27,4 @@ fegetround (void)
   return tmp & __FE_ROUND_MASK;
+libm_hidden_def (fegetround)
diff --git a/sysdeps/x86_64/fpu/fegetround.c b/sysdeps/x86_64/fpu/fegetround.c
index 1a52b7e..c7cd046 100644
--- a/sysdeps/x86_64/fpu/fegetround.c
+++ b/sysdeps/x86_64/fpu/fegetround.c
@@ -30,3 +30,4 @@ fegetround (void)
   return cw & 0xc00;
+libm_hidden_def (fegetround)

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