在 2025-12-28 02:32, Pali Rohár 写道:
At a first glance this doesn't look quite correct: When `sw` is null, `cw` is non-null and `cw_mask` is non-zero, this takes the slow path, and leaves `newsw` as zero, and eventually zeroes the status word.x87 fldcw instruction triggers pending x87 exception. So if there is a pending x87 exception and __mingw_setfp() is trying to disable some other x87 type then it will trigger pending exception.There is no non-waiting variant of x87 fldcw instruction. So for setting new control word use x87 fldenv instruction like for setting new status word. For using x87 fldenv instruction it is first need to load whole x87 env via x87 fnstenv instruction. Optimize code to not use x87 fnstenv when it is known that x87 fldenv would not be used - when cw_mask or sw_mask is empty (used just for quering cw/sw). --- mingw-w64-crt/misc/mingw_setfp.c | 63 +++++++++++++++++++------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/mingw-w64-crt/misc/mingw_setfp.c b/mingw-w64-crt/misc/mingw_setfp.c index fb03781292ce..2298515128b5 100644 --- a/mingw-w64-crt/misc/mingw_setfp.c +++ b/mingw-w64-crt/misc/mingw_setfp.c ... + if ((!sw || sw_mask == 0) && (!cw || cw_mask == 0)) + { + /* Fast path: when we are not going to change sw/cw which is indicated + * by zero mask then load sw/cw via fast fnstsw/fnstcw instruction. + */ + if (sw && sw_mask == 0) + __asm__ __volatile__( "fnstsw %0" : "=m" (newsw) ); + if (cw && cw_mask == 0) + __asm__ __volatile__( "fnstcw %0" : "=m" (newcw) ); + } + else + { + /* Slow path: when we are going to change sw/cw or we do not know yet then + * load whole x87 env via slow fnstenv as it is needed for changing sw/cw. + */ + __asm__ __volatile__( "fnstenv %0" : "=m" (fenv) ); + newsw = fenv.status_word; + newcw = fenv.control_word; + } + if (sw) { - __asm__ __volatile__( "fnstsw %0" : "=m" (newsw) ); oldsw = newsw;
Since the use of FLDENV is subject to a change in either word, it's necessary to initialize {old,new}{cw,sw} unconditionally.
I'm testing this series of patches with this change for now:
diff --git a/mingw-w64-crt/misc/mingw_setfp.c b/mingw-w64-crt/misc/mingw_setfp.c
index 229851512..dcd767d9a 100644
--- a/mingw-w64-crt/misc/mingw_setfp.c
+++ b/mingw-w64-crt/misc/mingw_setfp.c
@@ -144,10 +144,8 @@ void __mingw_setfp( unsigned int *cw, unsigned int cw_mask,
/* Fast path: when we are not going to change sw/cw which is indicated
* by zero mask then load sw/cw via fast fnstsw/fnstcw instruction.
*/
- if (sw && sw_mask == 0)
- __asm__ __volatile__( "fnstsw %0" : "=m" (newsw) );
- if (cw && cw_mask == 0)
- __asm__ __volatile__( "fnstcw %0" : "=m" (newcw) );
+ __asm__ __volatile__( "fnstsw %0" : "=m" (newsw) );
+ __asm__ __volatile__( "fnstcw %0" : "=m" (newcw) );
}
else
{
@@ -159,10 +157,11 @@ void __mingw_setfp( unsigned int *cw, unsigned int
cw_mask,
newcw = fenv.control_word;
}
+ oldsw = newsw;
+ oldcw = newcw;
+
if (sw)
{
- oldsw = newsw;
-
flags = 0;
if (newsw & 0x1) flags |= _SW_INVALID;
if (newsw & 0x2) flags |= _SW_DENORMAL;
@@ -184,8 +183,6 @@ void __mingw_setfp( unsigned int *cw, unsigned int cw_mask,
if (cw)
{
- oldcw = newcw;
-
flags = 0;
if (newcw & 0x1) flags |= _EM_INVALID;
if (newcw & 0x2) flags |= _EM_DENORMAL;
--
Best regards,
LIU Hao
OpenPGP_signature.asc
Description: OpenPGP digital signature
_______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
