This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] [RFC] Change SET_RESTORE_ROUND to just set the rounding mode
- From: Adhemerval Zanella <azanella at linux dot vnet dot ibm dot com>
- To: "GNU C. Library" <libc-alpha at sourceware dot org>
- Date: Thu, 07 Mar 2013 12:54:18 -0300
- Subject: [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:
#define SET_RESTORE_ROUND(RM) \
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 <azanella@linux.vnet.ibm.com>
* 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.
(SET_RESTORE_ROUNDF): Likewise.
(SET_RESTORE_ROUNDL): Likewise.
* 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
#endif
+static __always_inline int
+default_libc_fegetround (void)
+{
+ return fegetround ();
+}
+
+#ifndef libc_fegetround
+# define libc_fegetround default_libc_fegetround
+#endif
+#ifndef libc_fegetroundf
+# define libc_fegetroundf default_libc_fegetround
+#endif
+#ifndef libc_fegetroundl
+# define libc_fegetroundl default_libc_fegetround
+#endif
+
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);
+}
+
#define SET_RESTORE_ROUND(RM) \
- 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))
#define SET_RESTORE_ROUNDF(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))
#define SET_RESTORE_ROUNDL(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)
--
1.7.10.4