This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] Implement fma correctly
On Wed, Oct 13, 2010 at 12:21:03PM -0400, Ulrich Drepper wrote:
> On Wed, Oct 13, 2010 at 11:30, Richard Henderson <rth@twiddle.net> wrote:
> > The x86 kernel doesn't set up a known fpu state on signal entry?
> > That seems like a bug to be fixed to me.
>
> I don't know when it changed and whether it works in all situations,
> but it seems at least on recent kernels the signal handler is always
> run with FE_TONEAREST. On x86-64.
Yeah, it seems for async signals (or sync signals too?) the FPU state is
reinitialized at least on x86_64 and i686, so we should be fine doing
this in libm.
#define _GNU_SOURCE
#include <fenv.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
pthread_barrier_t b;
void
print_fenv (int i)
{
fenv_t env;
fegetenv (&env);
#ifdef __x86_64__
printf ("%d %08x %08x %08x\n", i, env.__control_word, env.__status_word, env.__mxcsr);
#elif defined __i386__
printf ("%d %08x %08x\n", i, env.__control_word, env.__status_word);
#endif
}
volatile double d1 = 0x1p100;
volatile double d2 = 0x1p-100;
volatile double d3;
volatile long double l1 = 0x1p100L;
volatile long double l2 = 0x1p-100L;
volatile long double l3;
void
sig (int signum, siginfo_t *info, void *context)
{
print_fenv (0);
}
void *
tf (void *arg)
{
fenv_t env;
print_fenv (1);
d3 = d1 + d2;
print_fenv (2);
l3 = l1 + l2;
print_fenv (3);
feholdexcept (&env);
fesetround (FE_TOWARDZERO);
d3 = d1 + d2;
l3 = l1 + l2;
print_fenv (4);
pthread_barrier_wait (&b);
pthread_barrier_wait (&b);
print_fenv (5);
feenableexcept (FE_DIVBYZERO | FE_INVALID);
print_fenv (6);
pthread_barrier_wait (&b);
pthread_barrier_wait (&b);
print_fenv (7);
return NULL;
}
int
main (void)
{
struct sigaction sa;
sigemptyset (&sa.sa_mask);
sa.sa_sigaction = sig;
sa.sa_flags = SA_SIGINFO;
sigaction (SIGUSR1, &sa, NULL);
pthread_barrier_init (&b, NULL, 2);
pthread_t th;
pthread_create (&th, NULL, tf, NULL);
pthread_barrier_wait (&b);
pthread_kill (th, SIGUSR1);
pthread_barrier_wait (&b);
pthread_barrier_wait (&b);
pthread_kill (th, SIGUSR1);
pthread_barrier_wait (&b);
pthread_join (th, NULL);
return 0;
}
Jakub