Make powerpc-nofpu floating-point state thread-local (bug 15483).
This commit is contained in:
parent
b5449b1296
commit
73c1ce4fdb
67
ChangeLog
67
ChangeLog
|
@ -1,3 +1,70 @@
|
|||
2013-11-19 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #15483]
|
||||
* sysdeps/powerpc/nofpu/sim-full.c (__sim_exceptions): Change to
|
||||
thread-local __sim_exceptions_thread and global
|
||||
__sim_exceptions_global.
|
||||
(__sim_disabled_exceptions): Change to thread-local
|
||||
__sim_disabled_exceptions_thread and global
|
||||
__sim_disabled_exceptions_global.
|
||||
(__sim_round_mode): Change to thread-local __sim_round_mode_thread
|
||||
and global __sim_round_mode_global.
|
||||
(__simulate_exceptions): Use thread-local floating-point state and
|
||||
set global state from it as needed.
|
||||
* sysdeps/powerpc/nofpu/Versions (GLIBC_PRIVATE): Add
|
||||
__sim_exceptions_thread, __sim_disabled_exceptions_thread and
|
||||
__sim_round_mode_thread.
|
||||
* sysdeps/powerpc/nofpu/soft-supp.h: Include <shlib-compat.h>.
|
||||
(__sim_exceptions): Change to thread-local __sim_exceptions_thread
|
||||
and global __sim_exceptions_global.
|
||||
(__sim_disabled_exceptions): Change to thread-local
|
||||
__sim_disabled_exceptions_thread and global
|
||||
__sim_disabled_exceptions_global.
|
||||
(__sim_round_mode): Change to thread-local __sim_round_mode_thread
|
||||
and global __sim_round_mode_global.
|
||||
[SIM_GLOBAL_COMPAT] (SIM_COMPAT_SYMBOL): New macro.
|
||||
(SIM_SET_GLOBAL): Likewise.
|
||||
* sysdeps/powerpc/soft-fp/sfp-machine.h
|
||||
[!(__NO_FPRS__ && !_SOFT_FLOAT)] (FP_ROUNDMODE): Use
|
||||
__sim_round_mode_thread.
|
||||
[!(__NO_FPRS__ && !_SOFT_FLOAT)] (FP_TRAPPING_EXCEPTIONS): Use
|
||||
__sim_disabled_exceptions_thread.
|
||||
(__sim_exceptions): Change to __sim_exceptions_thread.
|
||||
(__sim_disabled_exceptions): Change to
|
||||
__sim_disabled_exceptions_thread.
|
||||
(__sim_round_mode): Change to __sim_round_mode_thread.
|
||||
* sysdeps/powerpc/nofpu/fclrexcpt.c (__feclearexcept): Use
|
||||
thread-local floating-point state and set global state from it as
|
||||
needed.
|
||||
* sysdeps/powerpc/nofpu/fedisblxcpt.c (fedisableexcept): Likewise.
|
||||
* sysdeps/powerpc/nofpu/feenablxcpt.c: Include "soft-supp.h".
|
||||
(__sim_disabled_exceptions): Remove extern declaration.
|
||||
(feenableexcept): Use thread-local floating-point state and set
|
||||
global state from it as needed.
|
||||
* sysdeps/powerpc/nofpu/fegetenv.c (__sim_exceptions): Remove
|
||||
extern declaration.
|
||||
(__sim_disabled_exceptions): Likewise.
|
||||
(__sim_round_mode): Likewise.
|
||||
(__fegetenv): Use thread-local floating-point state.
|
||||
* sysdeps/powerpc/nofpu/fegetexcept.c (fegetexcept): Likewise.
|
||||
* sysdeps/powerpc/nofpu/fegetround.c (fegetround): Likewise.
|
||||
* sysdeps/powerpc/nofpu/fesetenv.c (__fesetenv): Use thread-local
|
||||
floating-point state and set global state from it as needed.
|
||||
* sysdeps/powerpc/nofpu/fesetround.c (fesetround): Likewise.
|
||||
* sysdeps/powerpc/nofpu/feupdateenv.c (__feupdateenv): Likewise.
|
||||
* sysdeps/powerpc/nofpu/fgetexcptflg.c (__fegetexceptflag):
|
||||
Likewise.
|
||||
* sysdeps/powerpc/nofpu/fraiseexcpt.c (__feraiseexcept): Likewise.
|
||||
* sysdeps/powerpc/nofpu/fsetexcptflg.c (__fesetexceptflag):
|
||||
Likewise.
|
||||
sysdeps/powerpc/nofpu/ftestexcept.c (fetestexcept): Likewise.
|
||||
* sysdeps/powerpc/nofpu/get-rounding-mode.h (get_rounding_mode):
|
||||
Use __sim_round_mode_thread.
|
||||
* math/test-fenv-tls.c: New file.
|
||||
* math/Makefile (tests): Add test-fenv-tls.
|
||||
($(objpfx)test-fenv-tls): Depend on
|
||||
$(common-objpfx)nptl/libpthread.so.
|
||||
|
||||
2013-11-19 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
* locale/programs/locale.c (show_info): Decode wordarray elements.
|
||||
|
|
17
NEWS
17
NEWS
|
@ -11,14 +11,15 @@ Version 2.19
|
|||
|
||||
156, 387, 431, 832, 2801, 7003, 9954, 10253, 10278, 11087, 13028, 13982,
|
||||
13985, 14029, 14143, 14155, 14547, 14699, 14752, 14876, 14910, 15048,
|
||||
15218, 15277, 15308, 15362, 15374, 15400, 15427, 15522, 15531, 15532,
|
||||
15608, 15609, 15610, 15632, 15640, 15670, 15672, 15680, 15681, 15723,
|
||||
15734, 15735, 15736, 15748, 15749, 15754, 15760, 15763, 15764, 15797,
|
||||
15799, 15825, 15844, 15847, 15849, 15855, 15856, 15857, 15859, 15867,
|
||||
15886, 15887, 15890, 15892, 15893, 15895, 15897, 15905, 15909, 15917,
|
||||
15919, 15921, 15923, 15939, 15948, 15963, 15966, 15985, 15988, 15997,
|
||||
16032, 16034, 16036, 16037, 16041, 16055, 16071, 16072, 16074, 16078,
|
||||
16103, 16112, 16143, 16144, 16146, 16150, 16151, 16153, 16167, 16172.
|
||||
15218, 15277, 15308, 15362, 15374, 15400, 15427, 15483, 15522, 15531,
|
||||
15532, 15608, 15609, 15610, 15632, 15640, 15670, 15672, 15680, 15681,
|
||||
15723, 15734, 15735, 15736, 15748, 15749, 15754, 15760, 15763, 15764,
|
||||
15797, 15799, 15825, 15844, 15847, 15849, 15855, 15856, 15857, 15859,
|
||||
15867, 15886, 15887, 15890, 15892, 15893, 15895, 15897, 15905, 15909,
|
||||
15917, 15919, 15921, 15923, 15939, 15948, 15963, 15966, 15985, 15988,
|
||||
15997, 16032, 16034, 16036, 16037, 16041, 16055, 16071, 16072, 16074,
|
||||
16078, 16103, 16112, 16143, 16144, 16146, 16150, 16151, 16153, 16167,
|
||||
16172.
|
||||
|
||||
* CVE-2012-4412 The strcoll implementation caches indices and rules for
|
||||
large collation sequences to optimize multiple passes. This cache
|
||||
|
|
|
@ -90,7 +90,7 @@ tests = test-matherr test-fenv atest-exp atest-sincos atest-exp2 basic-test \
|
|||
test-misc test-fpucw test-fpucw-ieee tst-definitions test-tgmath \
|
||||
test-tgmath-ret bug-nextafter bug-nexttoward bug-tgmath1 \
|
||||
test-tgmath-int test-tgmath2 test-powl tst-CMPLX tst-CMPLX2 test-snan \
|
||||
$(tests-static)
|
||||
test-fenv-tls $(tests-static)
|
||||
tests-static = test-fpucw-static test-fpucw-ieee-static
|
||||
# We do the `long double' tests only if this data type is available and
|
||||
# distinct from `double'.
|
||||
|
@ -232,3 +232,4 @@ gmp-objs = $(patsubst %,$(common-objpfx)stdlib/%.o,\
|
|||
$(objpfx)atest-exp: $(gmp-objs)
|
||||
$(objpfx)atest-sincos: $(gmp-objs)
|
||||
$(objpfx)atest-exp2: $(gmp-objs)
|
||||
$(objpfx)test-fenv-tls: $(common-objpfx)nptl/libpthread.so
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
/* Test floating-point environment is thread-local.
|
||||
Copyright (C) 2013 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <fenv.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define TEST_ONE_RM(RM) \
|
||||
do \
|
||||
{ \
|
||||
if (fesetround (RM) == 0) \
|
||||
{ \
|
||||
rm = fegetround (); \
|
||||
if (rm != RM) \
|
||||
{ \
|
||||
printf ("expected " #RM ", got %d\n", rm); \
|
||||
ret = 1; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static void *
|
||||
test_round (void *arg)
|
||||
{
|
||||
intptr_t ret = 0;
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
int rm;
|
||||
#ifdef FE_DOWNWARD
|
||||
TEST_ONE_RM (FE_DOWNWARD);
|
||||
#endif
|
||||
#ifdef FE_TONEAREST
|
||||
TEST_ONE_RM (FE_TONEAREST);
|
||||
#endif
|
||||
#ifdef FE_TOWARDZERO
|
||||
TEST_ONE_RM (FE_TOWARDZERO);
|
||||
#endif
|
||||
#ifdef FE_UPWARD
|
||||
TEST_ONE_RM (FE_UPWARD);
|
||||
#endif
|
||||
}
|
||||
return (void *) ret;
|
||||
}
|
||||
|
||||
#define TEST_ONE_RAISE(EX) \
|
||||
do \
|
||||
{ \
|
||||
if (feraiseexcept (EX) == 0) \
|
||||
if (fetestexcept (EX) != EX) \
|
||||
{ \
|
||||
printf (#EX " not raised\n"); \
|
||||
ret = 1; \
|
||||
} \
|
||||
if (feclearexcept (FE_ALL_EXCEPT) == 0) \
|
||||
if (fetestexcept (FE_ALL_EXCEPT) != 0) \
|
||||
{ \
|
||||
printf ("exceptions not all cleared\n"); \
|
||||
ret = 1; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static void *
|
||||
test_raise (void *arg)
|
||||
{
|
||||
intptr_t ret = 0;
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
#ifdef FE_DIVBYZERO
|
||||
TEST_ONE_RAISE (FE_DIVBYZERO);
|
||||
#endif
|
||||
#ifdef FE_INEXACT
|
||||
TEST_ONE_RAISE (FE_INEXACT);
|
||||
#endif
|
||||
#ifdef FE_INVALID
|
||||
TEST_ONE_RAISE (FE_INVALID);
|
||||
#endif
|
||||
#ifdef FE_OVERFLOW
|
||||
TEST_ONE_RAISE (FE_OVERFLOW);
|
||||
#endif
|
||||
#ifdef UNDERFLOW
|
||||
TEST_ONE_RAISE (FE_UNDERFLOW);
|
||||
#endif
|
||||
}
|
||||
return (void *) ret;
|
||||
}
|
||||
|
||||
#define TEST_ONE_ENABLE(EX) \
|
||||
do \
|
||||
{ \
|
||||
if (feenableexcept (EX) != -1) \
|
||||
if (fegetexcept () != EX) \
|
||||
{ \
|
||||
printf (#EX " not enabled\n"); \
|
||||
ret = 1; \
|
||||
} \
|
||||
if (fedisableexcept (EX) != -1) \
|
||||
if (fegetexcept () != 0) \
|
||||
{ \
|
||||
printf ("exceptions not all disabled\n"); \
|
||||
ret = 1; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static void *
|
||||
test_enable (void *arg)
|
||||
{
|
||||
intptr_t ret = 0;
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
#ifdef FE_DIVBYZERO
|
||||
TEST_ONE_ENABLE (FE_DIVBYZERO);
|
||||
#endif
|
||||
#ifdef FE_INEXACT
|
||||
TEST_ONE_ENABLE (FE_INEXACT);
|
||||
#endif
|
||||
#ifdef FE_INVALID
|
||||
TEST_ONE_ENABLE (FE_INVALID);
|
||||
#endif
|
||||
#ifdef FE_OVERFLOW
|
||||
TEST_ONE_ENABLE (FE_OVERFLOW);
|
||||
#endif
|
||||
#ifdef UNDERFLOW
|
||||
TEST_ONE_ENABLE (FE_UNDERFLOW);
|
||||
#endif
|
||||
}
|
||||
return (void *) ret;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int ret = 0;
|
||||
void *vret;
|
||||
pthread_t thread_id;
|
||||
int pret;
|
||||
|
||||
pret = pthread_create (&thread_id, NULL, test_round, NULL);
|
||||
if (pret != 0)
|
||||
{
|
||||
printf ("pthread_create failed: %d\n", pret);
|
||||
return 1;
|
||||
}
|
||||
vret = test_round (NULL);
|
||||
ret |= (intptr_t) vret;
|
||||
pret = pthread_join (thread_id, &vret);
|
||||
if (pret != 0)
|
||||
{
|
||||
printf ("pthread_join failed: %d\n", pret);
|
||||
return 1;
|
||||
}
|
||||
ret |= (intptr_t) vret;
|
||||
|
||||
pret = pthread_create (&thread_id, NULL, test_raise, NULL);
|
||||
if (pret != 0)
|
||||
{
|
||||
printf ("pthread_create failed: %d\n", pret);
|
||||
return 1;
|
||||
}
|
||||
vret = test_raise (NULL);
|
||||
ret |= (intptr_t) vret;
|
||||
pret = pthread_join (thread_id, &vret);
|
||||
if (pret != 0)
|
||||
{
|
||||
printf ("pthread_join failed: %d\n", pret);
|
||||
return 1;
|
||||
}
|
||||
ret |= (intptr_t) vret;
|
||||
|
||||
pret = pthread_create (&thread_id, NULL, test_enable, NULL);
|
||||
if (pret != 0)
|
||||
{
|
||||
printf ("pthread_create failed: %d\n", pret);
|
||||
return 1;
|
||||
}
|
||||
vret = test_enable (NULL);
|
||||
ret |= (intptr_t) vret;
|
||||
pret = pthread_join (thread_id, &vret);
|
||||
if (pret != 0)
|
||||
{
|
||||
printf ("pthread_join failed: %d\n", pret);
|
||||
return 1;
|
||||
}
|
||||
ret |= (intptr_t) vret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
|
@ -17,4 +17,9 @@ libc {
|
|||
__gtdf2; __gtsf2;
|
||||
__ltdf2; __ltsf2;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
__sim_exceptions_thread;
|
||||
__sim_disabled_exceptions_thread;
|
||||
__sim_round_mode_thread;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
int
|
||||
__feclearexcept (int x)
|
||||
{
|
||||
__sim_exceptions &= ~x;
|
||||
__sim_exceptions_thread &= ~x;
|
||||
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
int
|
||||
fedisableexcept (int x)
|
||||
{
|
||||
int old_exceptions = ~__sim_disabled_exceptions & FE_ALL_EXCEPT;
|
||||
int old_exceptions = ~__sim_disabled_exceptions_thread & FE_ALL_EXCEPT;
|
||||
|
||||
__sim_disabled_exceptions |= x;
|
||||
__sim_disabled_exceptions_thread |= x;
|
||||
SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
|
||||
__sim_disabled_exceptions_thread);
|
||||
|
||||
return old_exceptions;
|
||||
}
|
||||
|
|
|
@ -17,16 +17,17 @@
|
|||
License along with the GNU C Library. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "soft-supp.h"
|
||||
#include <fenv.h>
|
||||
|
||||
extern int __sim_disabled_exceptions;
|
||||
|
||||
int
|
||||
feenableexcept (int exceptions)
|
||||
{
|
||||
int old_exceptions = ~__sim_disabled_exceptions & FE_ALL_EXCEPT;
|
||||
int old_exceptions = ~__sim_disabled_exceptions_thread & FE_ALL_EXCEPT;
|
||||
|
||||
__sim_disabled_exceptions &= ~exceptions;
|
||||
__sim_disabled_exceptions_thread &= ~exceptions;
|
||||
SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
|
||||
__sim_disabled_exceptions_thread);
|
||||
|
||||
return old_exceptions;
|
||||
}
|
||||
|
|
|
@ -20,18 +20,14 @@
|
|||
#include "soft-fp.h"
|
||||
#include "soft-supp.h"
|
||||
|
||||
extern int __sim_exceptions;
|
||||
extern int __sim_disabled_exceptions;
|
||||
extern int __sim_round_mode;
|
||||
|
||||
int
|
||||
__fegetenv (fenv_t *envp)
|
||||
{
|
||||
fenv_union_t u;
|
||||
|
||||
u.l[0] = __sim_exceptions;
|
||||
u.l[0] |= __sim_round_mode;
|
||||
u.l[1] = __sim_disabled_exceptions;
|
||||
u.l[0] = __sim_exceptions_thread;
|
||||
u.l[0] |= __sim_round_mode_thread;
|
||||
u.l[1] = __sim_disabled_exceptions_thread;
|
||||
|
||||
*envp = u.fenv;
|
||||
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
int
|
||||
fegetexcept (void)
|
||||
{
|
||||
return (__sim_disabled_exceptions ^ FE_ALL_EXCEPT) & FE_ALL_EXCEPT;
|
||||
return (__sim_disabled_exceptions_thread ^ FE_ALL_EXCEPT) & FE_ALL_EXCEPT;
|
||||
}
|
||||
|
|
|
@ -24,5 +24,5 @@
|
|||
int
|
||||
fegetround (void)
|
||||
{
|
||||
return __sim_round_mode;
|
||||
return __sim_round_mode_thread;
|
||||
}
|
||||
|
|
|
@ -26,9 +26,13 @@ __fesetenv (const fenv_t *envp)
|
|||
fenv_union_t u;
|
||||
|
||||
u.fenv = *envp;
|
||||
__sim_exceptions = u.l[0] & FE_ALL_EXCEPT;
|
||||
__sim_round_mode = u.l[0] & 0x3;
|
||||
__sim_disabled_exceptions = u.l[1];
|
||||
__sim_exceptions_thread = u.l[0] & FE_ALL_EXCEPT;
|
||||
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
|
||||
__sim_round_mode_thread = u.l[0] & 0x3;
|
||||
SIM_SET_GLOBAL (__sim_round_mode_global, __sim_round_mode_thread);
|
||||
__sim_disabled_exceptions_thread = u.l[1];
|
||||
SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
|
||||
__sim_disabled_exceptions_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ fesetround (int round)
|
|||
if ((unsigned int) round > FE_DOWNWARD)
|
||||
return 1;
|
||||
|
||||
__sim_round_mode = round;
|
||||
__sim_round_mode_thread = round;
|
||||
SIM_SET_GLOBAL (__sim_round_mode_global, __sim_round_mode_thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -28,14 +28,15 @@ __feupdateenv (const fenv_t *envp)
|
|||
int saved_exceptions;
|
||||
|
||||
/* Save currently set exceptions. */
|
||||
saved_exceptions = __sim_exceptions;
|
||||
saved_exceptions = __sim_exceptions_thread;
|
||||
|
||||
/* Set environment. */
|
||||
fesetenv (envp);
|
||||
|
||||
/* Raise old exceptions. */
|
||||
__sim_exceptions |= saved_exceptions;
|
||||
if (saved_exceptions & ~__sim_disabled_exceptions)
|
||||
__sim_exceptions_thread |= saved_exceptions;
|
||||
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
|
||||
if (saved_exceptions & ~__sim_disabled_exceptions_thread)
|
||||
raise (SIGFPE);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
int
|
||||
__fegetexceptflag (fexcept_t *flagp, int excepts)
|
||||
{
|
||||
*flagp = (fexcept_t) __sim_exceptions & excepts & FE_ALL_EXCEPT;
|
||||
*flagp = (fexcept_t) __sim_exceptions_thread & excepts & FE_ALL_EXCEPT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
int
|
||||
__feraiseexcept (int x)
|
||||
{
|
||||
__sim_exceptions |= x;
|
||||
if (x & ~__sim_disabled_exceptions)
|
||||
__sim_exceptions_thread |= x;
|
||||
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
|
||||
if (x & ~__sim_disabled_exceptions_thread)
|
||||
raise (SIGFPE);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@ int
|
|||
__fesetexceptflag(const fexcept_t *flagp, int excepts)
|
||||
{
|
||||
/* Ignore exceptions not listed in 'excepts'. */
|
||||
__sim_exceptions = (__sim_exceptions & ~excepts) | (*flagp & excepts);
|
||||
__sim_exceptions_thread
|
||||
= (__sim_exceptions_thread & ~excepts) | (*flagp & excepts);
|
||||
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,6 @@
|
|||
int
|
||||
fetestexcept (int x)
|
||||
{
|
||||
return __sim_exceptions & x;
|
||||
return __sim_exceptions_thread & x;
|
||||
}
|
||||
libm_hidden_def (fetestexcept)
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
static inline int
|
||||
get_rounding_mode (void)
|
||||
{
|
||||
return __sim_round_mode;
|
||||
return __sim_round_mode_thread;
|
||||
}
|
||||
|
||||
#endif /* get-rounding-mode.h */
|
||||
|
|
|
@ -21,26 +21,37 @@
|
|||
#include "soft-fp.h"
|
||||
#include "soft-supp.h"
|
||||
|
||||
/* FIXME: these variables should be thread specific (see bugzilla bug
|
||||
15483) and ideally preserved across signal handlers, like hardware
|
||||
FP status words, but the latter is quite difficult to accomplish in
|
||||
userland. */
|
||||
|
||||
/* Global to store sticky exceptions. */
|
||||
int __sim_exceptions __attribute__ ((nocommon));
|
||||
libc_hidden_data_def (__sim_exceptions);
|
||||
/* Thread-local to store sticky exceptions. */
|
||||
__thread int __sim_exceptions_thread __attribute__ ((nocommon));
|
||||
libc_hidden_data_def (__sim_exceptions_thread);
|
||||
|
||||
/* By default, no exceptions should trap. */
|
||||
int __sim_disabled_exceptions = 0xffffffff;
|
||||
libc_hidden_data_def (__sim_disabled_exceptions);
|
||||
__thread int __sim_disabled_exceptions_thread = 0xffffffff;
|
||||
libc_hidden_data_def (__sim_disabled_exceptions_thread);
|
||||
|
||||
int __sim_round_mode __attribute__ ((nocommon));
|
||||
libc_hidden_data_def (__sim_round_mode);
|
||||
__thread int __sim_round_mode_thread __attribute__ ((nocommon));
|
||||
libc_hidden_data_def (__sim_round_mode_thread);
|
||||
|
||||
#if SIM_GLOBAL_COMPAT
|
||||
int __sim_exceptions_global __attribute__ ((nocommon));
|
||||
libc_hidden_data_def (__sim_exceptions_global);
|
||||
SIM_COMPAT_SYMBOL (__sim_exceptions_global, __sim_exceptions);
|
||||
|
||||
int __sim_disabled_exceptions_global = 0xffffffff;
|
||||
libc_hidden_data_def (__sim_disabled_exceptions_global);
|
||||
SIM_COMPAT_SYMBOL (__sim_disabled_exceptions_global,
|
||||
__sim_disabled_exceptions);
|
||||
|
||||
int __sim_round_mode_global __attribute__ ((nocommon));
|
||||
libc_hidden_data_def (__sim_round_mode_global);
|
||||
SIM_COMPAT_SYMBOL (__sim_round_mode_global, __sim_round_mode);
|
||||
#endif
|
||||
|
||||
void
|
||||
__simulate_exceptions (int x)
|
||||
{
|
||||
__sim_exceptions |= x;
|
||||
if (x & ~__sim_disabled_exceptions)
|
||||
__sim_exceptions_thread |= x;
|
||||
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
|
||||
if (x & ~__sim_disabled_exceptions_thread)
|
||||
raise (SIGFPE);
|
||||
}
|
||||
|
|
|
@ -33,16 +33,31 @@ typedef union
|
|||
|
||||
#endif
|
||||
|
||||
/* FIXME: these variables should be thread specific (see bugzilla bug
|
||||
15483) and ideally preserved across signal handlers, like hardware
|
||||
FP status words, but the latter is quite difficult to accomplish in
|
||||
userland. */
|
||||
extern __thread int __sim_exceptions_thread attribute_tls_model_ie;
|
||||
libc_hidden_tls_proto (__sim_exceptions_thread, tls_model ("initial-exec"));
|
||||
extern __thread int __sim_disabled_exceptions_thread attribute_tls_model_ie;
|
||||
libc_hidden_tls_proto (__sim_disabled_exceptions_thread,
|
||||
tls_model ("initial-exec"));
|
||||
extern __thread int __sim_round_mode_thread attribute_tls_model_ie;
|
||||
libc_hidden_tls_proto (__sim_round_mode_thread, tls_model ("initial-exec"));
|
||||
|
||||
extern int __sim_exceptions;
|
||||
libc_hidden_proto (__sim_exceptions);
|
||||
extern int __sim_disabled_exceptions;
|
||||
libc_hidden_proto (__sim_disabled_exceptions);
|
||||
extern int __sim_round_mode;
|
||||
libc_hidden_proto (__sim_round_mode);
|
||||
/* These variables were formerly global, so there are compat symbols
|
||||
for global versions as well. */
|
||||
|
||||
#include <shlib-compat.h>
|
||||
#define SIM_GLOBAL_COMPAT SHLIB_COMPAT (libc, GLIBC_2_3_2, GLIBC_2_19)
|
||||
#if SIM_GLOBAL_COMPAT
|
||||
extern int __sim_exceptions_global;
|
||||
libc_hidden_proto (__sim_exceptions_global);
|
||||
extern int __sim_disabled_exceptions_global ;
|
||||
libc_hidden_proto (__sim_disabled_exceptions_global);
|
||||
extern int __sim_round_mode_global;
|
||||
libc_hidden_proto (__sim_round_mode_global);
|
||||
# define SIM_COMPAT_SYMBOL(GLOBAL_NAME, NAME) \
|
||||
compat_symbol (libc, GLOBAL_NAME, NAME, GLIBC_2_3_2)
|
||||
# define SIM_SET_GLOBAL(GLOBAL_VAR, THREAD_VAR) ((GLOBAL_VAR) = (THREAD_VAR))
|
||||
#else
|
||||
# define SIM_SET_GLOBAL(GLOBAL_VAR, THREAD_VAR) ((void) 0)
|
||||
#endif
|
||||
|
||||
extern void __simulate_exceptions (int x) attribute_hidden;
|
||||
|
|
|
@ -95,21 +95,18 @@ libc_hidden_proto (__feraiseexcept_soft)
|
|||
# define FP_EX_INEXACT (1 << (31 - 6))
|
||||
|
||||
# define FP_HANDLE_EXCEPTIONS __simulate_exceptions (_fex)
|
||||
# define FP_ROUNDMODE __sim_round_mode
|
||||
# define FP_TRAPPING_EXCEPTIONS (~__sim_disabled_exceptions & 0x3e000000)
|
||||
# define FP_ROUNDMODE __sim_round_mode_thread
|
||||
# define FP_TRAPPING_EXCEPTIONS \
|
||||
(~__sim_disabled_exceptions_thread & 0x3e000000)
|
||||
|
||||
#endif
|
||||
|
||||
/* FIXME: these variables should be thread specific (see bugzilla bug
|
||||
15483) and ideally preserved across signal handlers, like hardware
|
||||
FP status words, but the latter is quite difficult to accomplish in
|
||||
userland. */
|
||||
|
||||
extern int __sim_exceptions;
|
||||
libc_hidden_proto (__sim_exceptions);
|
||||
extern int __sim_disabled_exceptions;
|
||||
libc_hidden_proto (__sim_disabled_exceptions);
|
||||
extern int __sim_round_mode;
|
||||
libc_hidden_proto (__sim_round_mode);
|
||||
extern __thread int __sim_exceptions_thread attribute_tls_model_ie;
|
||||
libc_hidden_tls_proto (__sim_exceptions_thread, tls_model ("initial-exec"));
|
||||
extern __thread int __sim_disabled_exceptions_thread attribute_tls_model_ie;
|
||||
libc_hidden_tls_proto (__sim_disabled_exceptions_thread,
|
||||
tls_model ("initial-exec"));
|
||||
extern __thread int __sim_round_mode_thread attribute_tls_model_ie;
|
||||
libc_hidden_tls_proto (__sim_round_mode_thread, tls_model ("initial-exec"));
|
||||
|
||||
extern void __simulate_exceptions (int x) attribute_hidden;
|
||||
|
|
Loading…
Reference in New Issue