[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: fenv-rounding: Improve code for MSVC
|
From: |
Bruno Haible |
|
Subject: |
Re: fenv-rounding: Improve code for MSVC |
|
Date: |
Sat, 04 Nov 2023 14:17:15 +0100 |
This patch improves the fenv-rounding code for MSVC:
- It works around the fact that the values of FE_UPWARD and FE_DOWNWARD
have been swapped.
- Since MSVC uses only the SSE unit and delegates no arithmetic operations
to the 387 unit (with its excess precision flaws), it's sufficient to
set and look up the rounding mode only in the SSE unit. Relying on the
closed-source fegetenv() and fesetenv() implementations for this purpose
is more fragile than needed.
It thus fixes unit test failures on MSVC 14 or 14.30.
2023-11-04 Bruno Haible <bruno@clisp.org>
fenv-rounding: Improve code for MSVC.
* lib/fenv-round.c (fegetround) [MSVC]: Use the rounding direction from
the SSE unit. Don't assume stable values for FE_UPWARD and FE_DOWNWARD.
(fesetround) [MSVC]: Set the rounding direction only in the SSE unit.
Don't assume stable values for FE_UPWARD and FE_DOWNWARD.
diff --git a/lib/fenv-round.c b/lib/fenv-round.c
index 14048a5ca7..5489ac98a8 100644
--- a/lib/fenv-round.c
+++ b/lib/fenv-round.c
@@ -32,11 +32,10 @@ int
fegetround (void)
{
# ifdef _MSC_VER
- /* XXX Simplify: access the SSE unit. */
- fenv_t env;
- if (fegetenv (&env) != 0)
- return FE_TONEAREST;
- unsigned int fctrl = env._Fe_ctl;
+ /* Use the rounding direction from the SSE unit. */
+ unsigned int mxcsr;
+ _FPU_GETSSECW (mxcsr);
+ unsigned int fctrl = (mxcsr >> 3) & 0x0C00;
# else
/* Use the rounding direction from the control word of the 387 unit, the
so-called fctrl register.
@@ -47,12 +46,13 @@ fegetround (void)
# endif
# ifdef _MSC_VER
/* The MSVC header files have different values for the rounding directions
- than all the other platforms. Map
- 0x0000 -> 0x0000 = FE_TONEAREST
- 0x0400 -> 0x0200 = FE_DOWNWARD
- 0x0800 -> 0x0100 = FE_UPWARD
- 0x0C00 -> 0x0300 = FE_TOWARDZERO */
- return ((fctrl & 0x0400) >> 1) | ((fctrl & 0x0800) >> 3);
+ than all the other platforms, and the even changed between MSVC 14 and
+ MSVC 14.30 (!). Map
+ 0x0000 -> FE_TONEAREST = 0
+ 0x0400 -> FE_DOWNWARD
+ 0x0800 -> FE_UPWARD
+ 0x0C00 -> FE_TOWARDZERO = FE_DOWNWARD | FE_UPWARD */
+ return (fctrl & 0x0800 ? FE_UPWARD : 0) | (fctrl & 0x0400 ? FE_DOWNWARD : 0);
# else
return fctrl & 0x0C00;
# endif
@@ -66,39 +66,35 @@ fesetround (int rounding_direction)
than all the other platforms. */
if ((rounding_direction & ~0x0300) != 0)
return -1;
- /* Map
- FE_TONEAREST = 0x0000 -> 0x0000
- FE_DOWNWARD = 0x0200 -> 0x0400
- FE_UPWARD = 0x0100 -> 0x0800
- FE_TOWARDZERO = 0x0300 -> 0x0C00 */
+ /* The MSVC header files have different values for the rounding directions
+ than all the other platforms, and the even changed between MSVC 14 and
+ MSVC 14.30 (!). Map
+ FE_TONEAREST = 0 -> 0x0000
+ FE_DOWNWARD -> 0x0400
+ FE_UPWARD -> 0x0800
+ FE_TOWARDZERO = FE_DOWNWARD | FE_UPWARD -> 0x0C00 */
rounding_direction =
- ((rounding_direction & 0x0200) << 1) | ((rounding_direction & 0x0100) <<
3);
+ (rounding_direction & FE_UPWARD ? 0x0800 : 0)
+ | (rounding_direction & FE_DOWNWARD ? 0x0400 : 0);
# else
if ((rounding_direction & ~0x0C00) != 0)
return -1;
# endif
- /* Set it in the 387 unit. */
# ifdef _MSC_VER
- /* XXX Simplify: only access the SSE unit. */
- fenv_t env;
- unsigned long orig_ctl;
- if (fegetenv (&env) != 0)
- return -1;
- orig_ctl = env._Fe_ctl;
- env._Fe_ctl = (env._Fe_ctl & ~0x0C00) | rounding_direction;
- if (env._Fe_ctl != orig_ctl)
- {
- if (fesetenv (&env) != 0)
- return -1;
- }
+ /* Set it in the SSE unit. */
+ unsigned int mxcsr, orig_mxcsr;
+ _FPU_GETSSECW (orig_mxcsr);
+ mxcsr = (orig_mxcsr & ~(0x0C00 << 3)) | (rounding_direction << 3);
+ if (mxcsr != orig_mxcsr)
+ _FPU_SETSSECW (mxcsr);
# else
+ /* Set it in the 387 unit. */
unsigned short fctrl, orig_fctrl;
_FPU_GETCW (orig_fctrl);
fctrl = (orig_fctrl & ~0x0C00) | rounding_direction;
if (fctrl != orig_fctrl)
_FPU_SETCW (fctrl);
-# endif
if (CPU_HAS_SSE ())
{
@@ -109,6 +105,7 @@ fesetround (int rounding_direction)
if (mxcsr != orig_mxcsr)
_FPU_SETSSECW (mxcsr);
}
+# endif
return 0;
}
| [Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: fenv-rounding: Improve code for MSVC,
Bruno Haible <=