This one needs the same fix for x86_64 and i386 as the fsetenv() function.

2023-10-30  Bruno Haible  <br...@clisp.org>

        fenv-exceptions-state-c99: Fix the x86_64 and i386 case.
        * lib/fenv-except-state-set.c (fesetexceptflag): Make sure to restore
        the exception trap bits in all cases.

From 9c82dee623c1dca092d050d6e2289e9e7e07a687 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Mon, 30 Oct 2023 16:26:46 +0100
Subject: [PATCH 1/8] fenv-exceptions-state-c99: Fix the x86_64 and i386 case.

* lib/fenv-except-state-set.c (fesetexceptflag): Make sure to restore
the exception trap bits in all cases.
---
 ChangeLog                   |  6 ++++++
 lib/fenv-except-state-set.c | 27 ++++++++++++---------------
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e0bf89a9e2..0476828c50 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2023-10-30  Bruno Haible  <br...@clisp.org>
+
+	fenv-exceptions-state-c99: Fix the x86_64 and i386 case.
+	* lib/fenv-except-state-set.c (fesetexceptflag): Make sure to restore
+	the exception trap bits in all cases.
+
 2023-10-30  Bruno Haible  <br...@clisp.org>
 
 	fenv-exceptions-state-c23: Add tests.
diff --git a/lib/fenv-except-state-set.c b/lib/fenv-except-state-set.c
index 6ba4d63a7d..2035f61e27 100644
--- a/lib/fenv-except-state-set.c
+++ b/lib/fenv-except-state-set.c
@@ -72,33 +72,30 @@ fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
       /* Modify the flags in the 387 unit, but only by clearing bits, not by
          setting bits.  */
       x86_387_fenv_t env;
-      unsigned short orig_status_word;
       __asm__ __volatile__ ("fnstenv %0" : "=m" (*&env));
-      orig_status_word = env.__status_word;
+      /* Note: fnstenv masks all floating-point exceptions until the fldenv
+         below.  */
       env.__status_word &= ~ (exceptions & ~desired_flags);
-      if (env.__status_word != orig_status_word)
-        __asm__ __volatile__ ("fldenv %0" : : "m" (*&env));
+      __asm__ __volatile__ ("fldenv %0" : : "m" (*&env));
     }
 #   if !(defined __x86_64__ || defined _M_X64)
   else
     {
       /* Modify the flags in the 387 unit.  */
       x86_387_fenv_t env;
-      unsigned short orig_status_word;
       __asm__ __volatile__ ("fnstenv %0" : "=m" (*&env));
-      orig_status_word = env.__status_word;
+      /* Note: fnstenv masks all floating-point exceptions until the fldenv
+         or fldcw below.  */
       env.__status_word ^= ((env.__status_word ^ desired_flags) & exceptions);
-      if (env.__status_word != orig_status_word)
+      if ((~env.__control_word) & env.__status_word & exceptions)
         {
-          if ((~env.__control_word) & env.__status_word & exceptions)
-            {
-              /* Setting the exception flags may trigger a trap (at the next
-                 floating-point instruction, but that does not matter).
-                 ISO C 23 § 7.6.4.5 does not allow it.  */
-              return -1;
-            }
-          __asm__ __volatile__ ("fldenv %0" : : "m" (*&env));
+          /* Setting the exception flags may trigger a trap (at the next
+             floating-point instruction, but that does not matter).
+             ISO C 23 § 7.6.4.5 does not allow it.  */
+          __asm__ __volatile__ ("fldcw %0" : : "m" (*&env.__control_word));
+          return -1;
         }
+      __asm__ __volatile__ ("fldenv %0" : : "m" (*&env));
     }
 #   endif
 #  endif
-- 
2.34.1

Reply via email to