From 787282dede7f134fdb22155cee0c35172e3e28f3 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 24 Oct 2023 08:37:16 -0300 Subject: x86: Do not raises floating-point exception traps on fesetexceptflag (BZ 30990) According to ISO C23 (7.6.4.4), fesetexcept is supposed to set floating-point exception flags without raising a trap (unlike feraiseexcept, which is supposed to raise a trap if feenableexcept was called with the appropriate argument). The flags can be set in the 387 unit or in the SSE unit. When we need to clear a flag, we need to do so in both units, due to the way fetestexcept is implemented. When we need to set a flag, it is sufficient to do it in the SSE unit, because that is guaranteed to not trap. However, on i386 CPUs that have only a 387 unit, set the flags in the 387, as long as this cannot trap. Co-authored-by: Adhemerval Zanella Reviewed-by: Carlos O'Donell --- math/test-fexcept-traps.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'math') diff --git a/math/test-fexcept-traps.c b/math/test-fexcept-traps.c index 998c241058..ac63fbca2f 100644 --- a/math/test-fexcept-traps.c +++ b/math/test-fexcept-traps.c @@ -19,6 +19,7 @@ #include #include #include +#include static int do_test (void) @@ -65,12 +66,32 @@ do_test (void) /* The test is that this does not cause exception traps. For architectures where setting the exception might result in traps the function should - return a nonzero value. */ + return a nonzero value. + Also check if the function does not alter the exception mask. */ ret = fesetexceptflag (&saved, FE_ALL_EXCEPT); _Static_assert (!(EXCEPTION_SET_FORCES_TRAP && !EXCEPTION_TESTS(float)), "EXCEPTION_SET_FORCES_TRAP only makes sense if the " "architecture suports exceptions"); + { + int exc_before = fegetexcept (); + ret = fesetexceptflag (&saved, FE_ALL_EXCEPT); + int exc_after = fegetexcept (); + if (exc_before != exc_after) + { + puts ("fesetexceptflag (FE_ALL_EXCEPT) changed the exceptions mask"); + return 1; + } + } + + /* Execute some floating-point operations, since on some CPUs exceptions + triggers a trap only at the next floating-point instruction. */ + volatile double a = 1.0; + volatile double b = a + a; + math_force_eval (b); + volatile long double al = 1.0L; + volatile long double bl = al + al; + math_force_eval (bl); if (ret != 0 && !EXCEPTION_SET_FORCES_TRAP) { -- cgit 1.4.1