Back to home page

Wine source

 
 

    


File indexing completed on 2023-09-01 22:05:37

1db20bfd3 Jon *0001 /*
                0002  * msvcrt.dll math functions
                0003  *
                0004  * Copyright 2000 Jon Griffiths
0799c1a78 Alex*0005  *
                0006  * This library is free software; you can redistribute it and/or
                0007  * modify it under the terms of the GNU Lesser General Public
                0008  * License as published by the Free Software Foundation; either
                0009  * version 2.1 of the License, or (at your option) any later version.
                0010  *
                0011  * This library is distributed in the hope that it will be useful,
                0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                0014  * Lesser General Public License for more details.
                0015  *
                0016  * You should have received a copy of the GNU Lesser General Public
                0017  * License along with this library; if not, write to the Free Software
360a3f914 Jona*0018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
bfc23bbd5 Piot*0019  *
                0020  *
9fa7b779f Alex*0021  * For functions copied from musl libc (http://musl.libc.org/):
bfc23bbd5 Piot*0022  * ====================================================
9fa7b779f Alex*0023  * Copyright 2005-2020 Rich Felker, et al.
bfc23bbd5 Piot*0024  *
9fa7b779f Alex*0025  * Permission is hereby granted, free of charge, to any person obtaining
                0026  * a copy of this software and associated documentation files (the
                0027  * "Software"), to deal in the Software without restriction, including
                0028  * without limitation the rights to use, copy, modify, merge, publish,
                0029  * distribute, sublicense, and/or sell copies of the Software, and to
                0030  * permit persons to whom the Software is furnished to do so, subject to
                0031  * the following conditions:
                0032  *
                0033  * The above copyright notice and this permission notice shall be
                0034  * included in all copies or substantial portions of the Software.
bfc23bbd5 Piot*0035  * ====================================================
1db20bfd3 Jon *0036  */
bfc23bbd5 Piot*0037 
62d269370 Piot*0038 #include <assert.h>
494a78940 Piot*0039 #include <complex.h>
961238367 Alex*0040 #include <stdio.h>
34422eb56 Alex*0041 #include <fenv.h>
1f11f41f6 Alex*0042 #include <fpieee.h>
758460faf Piot*0043 #include <limits.h>
70c06601e Piot*0044 #include <locale.h>
1db20bfd3 Jon *0045 #include <math.h>
                0046 
821f4775a Hans*0047 #include "msvcrt.h"
c72e1b096 Alex*0048 #include "winternl.h"
e7f75c5df Fran*0049 
d5a372abb Alex*0050 #include "wine/asm.h"
bd1689ec0 Alex*0051 #include "wine/debug.h"
                0052 
                0053 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
1db20bfd3 Jon *0054 
4f2f3545e Piot*0055 #undef div
                0056 #undef ldiv
                0057 
994c071a1 Alex*0058 #define _DOMAIN         1       /* domain error in argument */
                0059 #define _SING           2       /* singularity */
                0060 #define _OVERFLOW       3       /* range overflow */
                0061 #define _UNDERFLOW      4       /* range underflow */
                0062 
595ee43c4 Piot*0063 typedef int (CDECL *MSVCRT_matherr_func)(struct _exception *);
1db20bfd3 Jon *0064 
                0065 static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;
                0066 
38c490496 Piot*0067 BOOL sse2_supported;
a8d8e4a36 Alex*0068 static BOOL sse2_enabled;
                0069 
c72e1b096 Alex*0070 void msvcrt_init_math( void *module )
a8d8e4a36 Alex*0071 {
4ae82fd00 Piot*0072     sse2_supported = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE );
                0073 #if _MSVCR_VER <=71
                0074     sse2_enabled = FALSE;
                0075 #else
                0076     sse2_enabled = sse2_supported;
                0077 #endif
a8d8e4a36 Alex*0078 }
                0079 
75eb98776 Alex*0080 #if defined(__i386__) || defined(__x86_64__)
a6b1e97eb Fran*0081 static inline double ret_nan( BOOL update_sw )
0cd71776f Piot*0082 {
                0083     double x = 1.0;
                0084     if (!update_sw) return -NAN;
                0085     return (x - x) / (x - x);
                0086 }
75eb98776 Alex*0087 #endif
0cd71776f Piot*0088 
a6e3987e5 Piot*0089 #define SET_X87_CW(MASK) \
                0090     "subl $4, %esp\n\t" \
                0091     __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
                0092     "fnstcw (%esp)\n\t" \
                0093     "movw (%esp), %ax\n\t" \
                0094     "movw %ax, 2(%esp)\n\t" \
                0095     "testw $" #MASK ", %ax\n\t" \
                0096     "jz 1f\n\t" \
                0097     "andw $~" #MASK ", %ax\n\t" \
                0098     "movw %ax, 2(%esp)\n\t" \
                0099     "fldcw 2(%esp)\n\t" \
                0100     "1:\n\t"
                0101 
                0102 #define RESET_X87_CW \
                0103     "movw (%esp), %ax\n\t" \
                0104     "cmpw %ax, 2(%esp)\n\t" \
                0105     "je 1f\n\t" \
                0106     "fstpl 8(%esp)\n\t" \
                0107     "fldcw (%esp)\n\t" \
                0108     "fldl 8(%esp)\n\t" \
                0109     "fwait\n\t" \
                0110     "1:\n\t" \
                0111     "addl $4, %esp\n\t" \
                0112     __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
                0113 
994c071a1 Alex*0114 /*********************************************************************
9a364c1a6 Alex*0115  *      _matherr (CRTDLL.@)
994c071a1 Alex*0116  */
4f2f3545e Piot*0117 int CDECL _matherr(struct _exception *e)
994c071a1 Alex*0118 {
9a364c1a6 Alex*0119     return 0;
                0120 }
994c071a1 Alex*0121 
9a364c1a6 Alex*0122 
1cff65b69 Alex*0123 double math_error(int type, const char *name, double arg1, double arg2, double retval)
9a364c1a6 Alex*0124 {
595ee43c4 Piot*0125     struct _exception exception = {type, (char *)name, arg1, arg2, retval};
2833a10ba Piot*0126 
9a364c1a6 Alex*0127     TRACE("(%d, %s, %g, %g, %g)\n", type, debugstr_a(name), arg1, arg2, retval);
994c071a1 Alex*0128 
2833a10ba Piot*0129     if (MSVCRT_default_matherr_func && MSVCRT_default_matherr_func(&exception))
                0130         return exception.retval;
994c071a1 Alex*0131 
9a364c1a6 Alex*0132     switch (type)
994c071a1 Alex*0133     {
3911ac3f4 Piot*0134     case 0:
                0135         /* don't set errno */
                0136         break;
994c071a1 Alex*0137     case _DOMAIN:
eeada5682 Piot*0138         *_errno() = EDOM;
994c071a1 Alex*0139         break;
                0140     case _SING:
                0141     case _OVERFLOW:
eeada5682 Piot*0142         *_errno() = ERANGE;
994c071a1 Alex*0143         break;
                0144     case _UNDERFLOW:
                0145         /* don't set errno */
                0146         break;
                0147     default:
                0148         ERR("Unhandled math error!\n");
                0149     }
2833a10ba Piot*0150 
                0151     return exception.retval;
994c071a1 Alex*0152 }
                0153 
                0154 /*********************************************************************
                0155  *      __setusermatherr (MSVCRT.@)
                0156  */
4f2f3545e Piot*0157 void CDECL __setusermatherr(MSVCRT_matherr_func func)
994c071a1 Alex*0158 {
                0159     MSVCRT_default_matherr_func = func;
                0160     TRACE("new matherr handler %p\n", func);
                0161 }
                0162 
76058b14e Piot*0163 /*********************************************************************
                0164  *      _set_SSE2_enable (MSVCRT.@)
                0165  */
4f2f3545e Piot*0166 int CDECL _set_SSE2_enable(int flag)
76058b14e Piot*0167 {
a8d8e4a36 Alex*0168     sse2_enabled = flag && sse2_supported;
                0169     return sse2_enabled;
76058b14e Piot*0170 }
                0171 
87f42c3ae Piot*0172 #if defined(_WIN64)
                0173 # if _MSVCR_VER>=140
                0174 /*********************************************************************
                0175  *      _get_FMA3_enable (UCRTBASE.@)
                0176  */
4f2f3545e Piot*0177 int CDECL _get_FMA3_enable(void)
87f42c3ae Piot*0178 {
                0179     FIXME("() stub\n");
                0180     return 0;
                0181 }
                0182 # endif
                0183 
                0184 # if _MSVCR_VER>=120
68fedc126 Piot*0185 /*********************************************************************
                0186  *      _set_FMA3_enable (MSVCR120.@)
                0187  */
4f2f3545e Piot*0188 int CDECL _set_FMA3_enable(int flag)
68fedc126 Piot*0189 {
                0190     FIXME("(%x) stub\n", flag);
                0191     return 0;
                0192 }
87f42c3ae Piot*0193 # endif
68fedc126 Piot*0194 #endif
                0195 
2199be1c0 Alex*0196 #if !defined(__i386__) || _MSVCR_VER>=120
af9f9cb36 Maar*0197 
f80d443f5 Alex*0198 /*********************************************************************
                0199  *      _chgsignf (MSVCRT.@)
                0200  */
4f2f3545e Piot*0201 float CDECL _chgsignf( float num )
f80d443f5 Alex*0202 {
dbda71f74 Alex*0203     union { float f; UINT32 i; } u = { num };
                0204     u.i ^= 0x80000000;
                0205     return u.f;
f80d443f5 Alex*0206 }
                0207 
ccea6c605 Piot*0208 #endif
2199be1c0 Alex*0209 
4f2f3545e Piot*0210 #ifndef __i386__
                0211 
fd51f229f Alex*0212 /*********************************************************************
                0213  *      _fpclassf (MSVCRT.@)
                0214  */
4f2f3545e Piot*0215 int CDECL _fpclassf( float num )
fd51f229f Alex*0216 {
                0217     union { float f; UINT32 i; } u = { num };
                0218     int e = u.i >> 23 & 0xff;
                0219     int s = u.i >> 31;
                0220 
                0221     switch (e)
                0222     {
                0223     case 0:
480e25a5f Piot*0224         if (u.i << 1) return s ? _FPCLASS_ND : _FPCLASS_PD;
                0225         return s ? _FPCLASS_NZ : _FPCLASS_PZ;
fd51f229f Alex*0226     case 0xff:
480e25a5f Piot*0227         if (u.i << 9) return ((u.i >> 22) & 1) ? _FPCLASS_QNAN : _FPCLASS_SNAN;
                0228         return s ? _FPCLASS_NINF : _FPCLASS_PINF;
fd51f229f Alex*0229     default:
480e25a5f Piot*0230         return s ? _FPCLASS_NN : _FPCLASS_PN;
fd51f229f Alex*0231     }
                0232 }
                0233 
f80d443f5 Alex*0234 /*********************************************************************
                0235  *      _finitef (MSVCRT.@)
                0236  */
4f2f3545e Piot*0237 int CDECL _finitef( float num )
f80d443f5 Alex*0238 {
9f088d019 Alex*0239     union { float f; UINT32 i; } u = { num };
                0240     return (u.i & 0x7fffffff) < 0x7f800000;
f80d443f5 Alex*0241 }
                0242 
                0243 /*********************************************************************
                0244  *      _isnanf (MSVCRT.@)
                0245  */
4f2f3545e Piot*0246 int CDECL _isnanf( float num )
f80d443f5 Alex*0247 {
d6476e009 Alex*0248     union { float f; UINT32 i; } u = { num };
                0249     return (u.i & 0x7fffffff) > 0x7f800000;
f80d443f5 Alex*0250 }
                0251 
af9f9cb36 Maar*0252 /*********************************************************************
4f2f3545e Piot*0253  *      atanf (MSVCRT.@)
af9f9cb36 Maar*0254  */
e525730cc Alex*0255 #if _MSVCR_VER == 0  /* other versions call atanf() directly */
                0256 float CDECL MSVCRT_atanf( float x )
af9f9cb36 Maar*0257 {
b9002cc8c Alex*0258     if (isnan(x)) return math_error(_DOMAIN, "atanf", x, 0, x);
e525730cc Alex*0259     return atanf( x );
af9f9cb36 Maar*0260 }
e525730cc Alex*0261 #endif
af9f9cb36 Maar*0262 
20c53e72c Alex*0263 #ifdef __x86_64__
d70a652da Alex*0264 extern short CDECL _fdclass(float x);
                0265 
0cd71776f Piot*0266 static BOOL sqrtf_validate( float *x )
                0267 {
                0268     short c = _fdclass(*x);
                0269 
                0270     if (c == FP_ZERO) return FALSE;
                0271     if (c == FP_NAN) return FALSE;
                0272     if (signbit(*x))
                0273     {
                0274         *x = math_error(_DOMAIN, "sqrtf", *x, 0, ret_nan(TRUE));
                0275         return FALSE;
                0276     }
                0277     if (c == FP_INFINITE) return FALSE;
                0278     return TRUE;
                0279 }
                0280 
                0281 float CDECL sse2_sqrtf(float);
                0282 __ASM_GLOBAL_FUNC( sse2_sqrtf,
                0283         "sqrtss %xmm0, %xmm0\n\t"
                0284         "ret" )
                0285 #endif
                0286 
af9f9cb36 Maar*0287 /*********************************************************************
4f2f3545e Piot*0288  *      sqrtf (MSVCRT.@)
af9f9cb36 Maar*0289  */
20c53e72c Alex*0290 float CDECL MSVCRT_sqrtf( float x )
af9f9cb36 Maar*0291 {
0cd71776f Piot*0292 #ifdef __x86_64__
                0293     if (!sqrtf_validate(&x))
                0294         return x;
                0295 
                0296     return sse2_sqrtf(x);
                0297 #else
20c53e72c Alex*0298     return sqrtf( x );
0cd71776f Piot*0299 #endif
af9f9cb36 Maar*0300 }
                0301 
                0302 /*********************************************************************
4f2f3545e Piot*0303  *      tanhf (MSVCRT.@)
af9f9cb36 Maar*0304  */
5c00be28f Alex*0305 #if _MSVCR_VER < 140  /* other versions call tanhf() directly */
                0306 float CDECL MSVCRT_tanhf( float x )
af9f9cb36 Maar*0307 {
5c00be28f Alex*0308     if (isnan( x ))
                0309     {
                0310         *(UINT32*)&x |= 0x400000;
                0311         return math_error(_DOMAIN, "tanhf", x, 0, x);
bb9f97c4d Piot*0312     }
5c00be28f Alex*0313     return tanhf( x );
af9f9cb36 Maar*0314 }
5c00be28f Alex*0315 #endif
af9f9cb36 Maar*0316 
4f2f3545e Piot*0317 #endif
                0318 
78412005e Alex*0319 /*********************************************************************
4f2f3545e Piot*0320  *      asin (MSVCRT.@)
78412005e Alex*0321  */
a6e3987e5 Piot*0322 #ifdef __i386__
                0323 double CDECL x87_asin(double);
                0324 __ASM_GLOBAL_FUNC( x87_asin,
                0325         "fldl 4(%esp)\n\t"
                0326         SET_X87_CW(~0x37f)
                0327         "fld %st\n\t"
                0328         "fld1\n\t"
                0329         "fsubp\n\t"
                0330         "fld1\n\t"
                0331         "fadd %st(2)\n\t"
                0332         "fmulp\n\t"
                0333         "fsqrt\n\t"
                0334         "fpatan\n\t"
                0335         RESET_X87_CW
                0336         "ret" )
                0337 #endif
                0338 
82563ede7 Alex*0339 double CDECL MSVCRT_asin( double x )
78412005e Alex*0340 {
a6e3987e5 Piot*0341 #ifdef __i386__
                0342     unsigned int x87_cw, sse2_cw;
82563ede7 Alex*0343     unsigned int hx = *(ULONGLONG*)&x >> 32;
                0344     unsigned int ix = hx & 0x7fffffff;
2cb6a1780 Piot*0345 
82563ede7 Alex*0346     if (isnan(x)) return math_error(_DOMAIN, "asin", x, 0, x);
a6e3987e5 Piot*0347 
82563ede7 Alex*0348     /* |x| < 1 */
                0349     if (ix < 0x3ff00000)
                0350     {
                0351         __control87_2(0, 0, &x87_cw, &sse2_cw);
                0352         if (!sse2_enabled || (x87_cw & _MCW_EM) != _MCW_EM
a6e3987e5 Piot*0353             || (sse2_cw & (_MCW_EM | _MCW_RC)) != _MCW_EM)
82563ede7 Alex*0354             return x87_asin(x);
                0355     }
                0356 #else
                0357     if (isnan(x)) return x;
a6e3987e5 Piot*0358 #endif
                0359 
82563ede7 Alex*0360     return asin( x );
78412005e Alex*0361 }
                0362 
                0363 /*********************************************************************
4f2f3545e Piot*0364  *      atan (MSVCRT.@)
78412005e Alex*0365  */
ecfbd5971 Alex*0366 #if _MSVCR_VER == 0  /* other versions call atan() directly */
                0367 double CDECL MSVCRT_atan( double x )
78412005e Alex*0368 {
8cbbb4f39 Piot*0369     if (isnan(x)) return math_error(_DOMAIN, "atan", x, 0, x);
ecfbd5971 Alex*0370     return atan( x );
78412005e Alex*0371 }
ecfbd5971 Alex*0372 #endif
78412005e Alex*0373 
                0374 /*********************************************************************
4f2f3545e Piot*0375  *      exp (MSVCRT.@)
78412005e Alex*0376  */
5c3de7d79 Alex*0377 #if _MSVCR_VER == 0  /* other versions call exp() directly */
                0378 double CDECL MSVCRT_exp( double x )
78412005e Alex*0379 {
5c3de7d79 Alex*0380     if (isnan( x )) return math_error(_DOMAIN, "exp", x, 0, 1.0 + x);
                0381     return exp( x );
78412005e Alex*0382 }
5c3de7d79 Alex*0383 #endif
78412005e Alex*0384 
75eb98776 Alex*0385 #if defined(__x86_64__) || defined(__i386__)
d70a652da Alex*0386 extern short CDECL _dclass(double x);
                0387 
0cd71776f Piot*0388 static BOOL sqrt_validate( double *x, BOOL update_sw )
e53c4bd50 Piot*0389 {
                0390     short c = _dclass(*x);
                0391 
                0392     if (c == FP_ZERO) return FALSE;
                0393     if (c == FP_NAN)
                0394     {
                0395 #ifdef __i386__
e3772c917 Piot*0396         if (update_sw)
                0397             *x = math_error(_DOMAIN, "sqrt", *x, 0, *x);
e53c4bd50 Piot*0398 #else
                0399         /* set signaling bit */
                0400         *(ULONGLONG*)x |= 0x8000000000000ULL;
                0401 #endif
                0402         return FALSE;
                0403     }
                0404     if (signbit(*x))
                0405     {
e3772c917 Piot*0406         *x = math_error(_DOMAIN, "sqrt", *x, 0, ret_nan(update_sw));
e53c4bd50 Piot*0407         return FALSE;
                0408     }
                0409     if (c == FP_INFINITE) return FALSE;
                0410     return TRUE;
                0411 }
                0412 
                0413 double CDECL sse2_sqrt(double);
                0414 __ASM_GLOBAL_FUNC( sse2_sqrt,
                0415         "sqrtsd %xmm0, %xmm0\n\t"
                0416         "ret" )
                0417 #endif
                0418 
ba3cc1274 Piot*0419 #ifdef __i386__
                0420 double CDECL x87_sqrt(double);
                0421 __ASM_GLOBAL_FUNC( x87_sqrt,
                0422         "fldl 4(%esp)\n\t"
a6e3987e5 Piot*0423         SET_X87_CW(0xc00)
ba3cc1274 Piot*0424         "fsqrt\n\t"
                0425         RESET_X87_CW
                0426         "ret" )
                0427 #endif
                0428 
78412005e Alex*0429 /*********************************************************************
4f2f3545e Piot*0430  *      sqrt (MSVCRT.@)
78412005e Alex*0431  */
75eb98776 Alex*0432 double CDECL MSVCRT_sqrt( double x )
78412005e Alex*0433 {
e53c4bd50 Piot*0434 #ifdef __x86_64__
e3772c917 Piot*0435     if (!sqrt_validate(&x, TRUE))
e53c4bd50 Piot*0436         return x;
                0437 
                0438     return sse2_sqrt(x);
ba3cc1274 Piot*0439 #elif defined( __i386__ )
e3772c917 Piot*0440     if (!sqrt_validate(&x, TRUE))
ba3cc1274 Piot*0441         return x;
                0442 
                0443     return x87_sqrt(x);
e53c4bd50 Piot*0444 #else
75eb98776 Alex*0445     return sqrt( x );
e53c4bd50 Piot*0446 #endif
78412005e Alex*0447 }
                0448 
                0449 /*********************************************************************
4f2f3545e Piot*0450  *      tanh (MSVCRT.@)
78412005e Alex*0451  */
5c00be28f Alex*0452 #if _MSVCR_VER < 140  /* other versions call tanh() directly */
                0453 double CDECL MSVCRT_tanh( double x )
78412005e Alex*0454 {
5c00be28f Alex*0455     if (isnan( x ))
                0456     {
                0457         *(UINT64*)&x |= 0x0008000000000000ULL;
                0458         return math_error(_DOMAIN, "tanh", x, 0, x);
3171dccbe Piot*0459     }
5c00be28f Alex*0460     return tanh( x );
78412005e Alex*0461 }
5c00be28f Alex*0462 #endif
78412005e Alex*0463 
05806e0ed Jace*0464 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
1db20bfd3 Jon *0465 
ee33d38c5 Piot*0466 #define CREATE_FPU_FUNC1(name, call) \
                0467     __ASM_GLOBAL_FUNC(name, \
                0468             "pushl   %ebp\n\t" \
                0469             __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
                0470             __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
                0471             "movl    %esp, %ebp\n\t" \
                0472             __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
                0473             "subl    $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
                0474             "fstpl   (%esp)\n\t"    /* store function argument */ \
                0475             "fwait\n\t" \
                0476             "movl    $1, %ecx\n\t"  /* empty FPU stack */ \
                0477             "1:\n\t" \
                0478             "fxam\n\t" \
                0479             "fstsw   %ax\n\t" \
                0480             "and     $0x4500, %ax\n\t" \
                0481             "cmp     $0x4100, %ax\n\t" \
                0482             "je      2f\n\t" \
                0483             "fstpl    (%esp,%ecx,8)\n\t" \
                0484             "fwait\n\t" \
                0485             "incl    %ecx\n\t" \
                0486             "jmp     1b\n\t" \
                0487             "2:\n\t" \
                0488             "movl    %ecx, -4(%ebp)\n\t" \
                0489             "call    " __ASM_NAME( #call ) "\n\t" \
                0490             "movl    -4(%ebp), %ecx\n\t" \
                0491             "fstpl   (%esp)\n\t"    /* save result */ \
                0492             "3:\n\t"                /* restore FPU stack */ \
                0493             "decl    %ecx\n\t" \
                0494             "fldl    (%esp,%ecx,8)\n\t" \
                0495             "cmpl    $0, %ecx\n\t" \
                0496             "jne     3b\n\t" \
                0497             "leave\n\t" \
                0498             __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
                0499             __ASM_CFI(".cfi_same_value %ebp\n\t") \
                0500             "ret")
                0501 
                0502 #define CREATE_FPU_FUNC2(name, call) \
                0503     __ASM_GLOBAL_FUNC(name, \
                0504             "pushl   %ebp\n\t" \
                0505             __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
                0506             __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
                0507             "movl    %esp, %ebp\n\t" \
                0508             __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
                0509             "subl    $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
                0510             "fstpl   8(%esp)\n\t"   /* store function argument */ \
                0511             "fwait\n\t" \
                0512             "fstpl   (%esp)\n\t" \
                0513             "fwait\n\t" \
                0514             "movl    $2, %ecx\n\t"  /* empty FPU stack */ \
                0515             "1:\n\t" \
                0516             "fxam\n\t" \
                0517             "fstsw   %ax\n\t" \
                0518             "and     $0x4500, %ax\n\t" \
                0519             "cmp     $0x4100, %ax\n\t" \
                0520             "je      2f\n\t" \
                0521             "fstpl    (%esp,%ecx,8)\n\t" \
                0522             "fwait\n\t" \
                0523             "incl    %ecx\n\t" \
                0524             "jmp     1b\n\t" \
                0525             "2:\n\t" \
                0526             "movl    %ecx, -4(%ebp)\n\t" \
                0527             "call    " __ASM_NAME( #call ) "\n\t" \
                0528             "movl    -4(%ebp), %ecx\n\t" \
                0529             "fstpl   8(%esp)\n\t"   /* save result */ \
                0530             "3:\n\t"                /* restore FPU stack */ \
                0531             "decl    %ecx\n\t" \
                0532             "fldl    (%esp,%ecx,8)\n\t" \
                0533             "cmpl    $1, %ecx\n\t" \
                0534             "jne     3b\n\t" \
                0535             "leave\n\t" \
                0536             __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
                0537             __ASM_CFI(".cfi_same_value %ebp\n\t") \
                0538             "ret")
                0539 
4f2f3545e Piot*0540 CREATE_FPU_FUNC1(_CIacos, acos)
                0541 CREATE_FPU_FUNC1(_CIasin, asin)
                0542 CREATE_FPU_FUNC1(_CIatan, atan)
                0543 CREATE_FPU_FUNC2(_CIatan2, atan2)
                0544 CREATE_FPU_FUNC1(_CIcos, cos)
                0545 CREATE_FPU_FUNC1(_CIcosh, cosh)
                0546 CREATE_FPU_FUNC1(_CIexp, exp)
                0547 CREATE_FPU_FUNC2(_CIfmod, fmod)
                0548 CREATE_FPU_FUNC1(_CIlog, log)
                0549 CREATE_FPU_FUNC1(_CIlog10, log10)
                0550 CREATE_FPU_FUNC2(_CIpow, pow)
                0551 CREATE_FPU_FUNC1(_CIsin, sin)
                0552 CREATE_FPU_FUNC1(_CIsinh, sinh)
                0553 CREATE_FPU_FUNC1(_CIsqrt, sqrt)
                0554 CREATE_FPU_FUNC1(_CItan, tan)
                0555 CREATE_FPU_FUNC1(_CItanh, tanh)
                0556 
                0557 __ASM_GLOBAL_FUNC(_ftol,
ee33d38c5 Piot*0558         "pushl   %ebp\n\t"
                0559         __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
                0560         __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
                0561         "movl    %esp, %ebp\n\t"
                0562         __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
                0563         "subl    $12, %esp\n\t"     /* sizeof(LONGLONG) + 2*sizeof(WORD) */
                0564         "fnstcw  (%esp)\n\t"
                0565         "mov     (%esp), %ax\n\t"
22edbd849 Piot*0566         "or      $0xc00, %ax\n\t"
ee33d38c5 Piot*0567         "mov     %ax, 2(%esp)\n\t"
                0568         "fldcw   2(%esp)\n\t"
                0569         "fistpq  4(%esp)\n\t"
                0570         "fldcw   (%esp)\n\t"
                0571         "movl    4(%esp), %eax\n\t"
                0572         "movl    8(%esp), %edx\n\t"
                0573         "leave\n\t"
                0574         __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
                0575         __ASM_CFI(".cfi_same_value %ebp\n\t")
                0576         "ret")
a79de8aa2 Aust*0577 
05806e0ed Jace*0578 #endif /* (defined(__GNUC__) || defined(__clang__)) && defined(__i386__) */
1db20bfd3 Jon *0579 
                0580 /*********************************************************************
                0581  *      _fpclass (MSVCRT.@)
                0582  */
4f2f3545e Piot*0583 int CDECL _fpclass(double num)
1db20bfd3 Jon *0584 {
fd51f229f Alex*0585     union { double f; UINT64 i; } u = { num };
                0586     int e = u.i >> 52 & 0x7ff;
                0587     int s = u.i >> 63;
                0588 
                0589     switch (e)
                0590     {
                0591     case 0:
480e25a5f Piot*0592         if (u.i << 1) return s ? _FPCLASS_ND : _FPCLASS_PD;
                0593         return s ? _FPCLASS_NZ : _FPCLASS_PZ;
fd51f229f Alex*0594     case 0x7ff:
480e25a5f Piot*0595         if (u.i << 12) return ((u.i >> 51) & 1) ? _FPCLASS_QNAN : _FPCLASS_SNAN;
                0596         return s ? _FPCLASS_NINF : _FPCLASS_PINF;
fd51f229f Alex*0597     default:
480e25a5f Piot*0598         return s ? _FPCLASS_NN : _FPCLASS_PN;
fd51f229f Alex*0599     }
1db20bfd3 Jon *0600 }
                0601 
                0602 /*********************************************************************
                0603  *      _rotl (MSVCRT.@)
                0604  */
e8936e79c Jace*0605 unsigned int CDECL MSVCRT__rotl(unsigned int num, int shift)
1db20bfd3 Jon *0606 {
                0607   shift &= 31;
                0608   return (num << shift) | (num >> (32-shift));
                0609 }
                0610 
                0611 /*********************************************************************
                0612  *      _lrotl (MSVCRT.@)
                0613  */
e8936e79c Jace*0614 __msvcrt_ulong CDECL MSVCRT__lrotl(__msvcrt_ulong num, int shift)
1db20bfd3 Jon *0615 {
                0616   shift &= 0x1f;
                0617   return (num << shift) | (num >> (32-shift));
                0618 }
                0619 
                0620 /*********************************************************************
                0621  *      _lrotr (MSVCRT.@)
                0622  */
e8936e79c Jace*0623 __msvcrt_ulong CDECL MSVCRT__lrotr(__msvcrt_ulong num, int shift)
1db20bfd3 Jon *0624 {
                0625   shift &= 0x1f;
                0626   return (num >> shift) | (num << (32-shift));
                0627 }
                0628 
                0629 /*********************************************************************
                0630  *      _rotr (MSVCRT.@)
                0631  */
e8936e79c Jace*0632 unsigned int CDECL MSVCRT__rotr(unsigned int num, int shift)
1db20bfd3 Jon *0633 {
                0634     shift &= 0x1f;
                0635     return (num >> shift) | (num << (32-shift));
                0636 }
                0637 
abe0823b7 Alex*0638 /*********************************************************************
                0639  *      _rotl64 (MSVCRT.@)
                0640  */
e8936e79c Jace*0641 unsigned __int64 CDECL MSVCRT__rotl64(unsigned __int64 num, int shift)
abe0823b7 Alex*0642 {
                0643   shift &= 63;
                0644   return (num << shift) | (num >> (64-shift));
                0645 }
                0646 
                0647 /*********************************************************************
                0648  *      _rotr64 (MSVCRT.@)
                0649  */
e8936e79c Jace*0650 unsigned __int64 CDECL MSVCRT__rotr64(unsigned __int64 num, int shift)
abe0823b7 Alex*0651 {
                0652     shift &= 63;
                0653     return (num >> shift) | (num << (64-shift));
                0654 }
                0655 
                0656 /*********************************************************************
                0657  *      abs (MSVCRT.@)
                0658  */
4f2f3545e Piot*0659 int CDECL abs( int n )
abe0823b7 Alex*0660 {
                0661     return n >= 0 ? n : -n;
                0662 }
                0663 
                0664 /*********************************************************************
                0665  *      labs (MSVCRT.@)
                0666  */
4f2f3545e Piot*0667 __msvcrt_long CDECL labs( __msvcrt_long n )
abe0823b7 Alex*0668 {
                0669     return n >= 0 ? n : -n;
                0670 }
                0671 
86597db83 Alex*0672 #if _MSVCR_VER>=100
60de49770 Niko*0673 /*********************************************************************
86597db83 Alex*0674  *      llabs (MSVCR100.@)
60de49770 Niko*0675  */
4f2f3545e Piot*0676 __int64 CDECL llabs( __int64 n )
60de49770 Niko*0677 {
                0678     return n >= 0 ? n : -n;
                0679 }
86597db83 Alex*0680 #endif
60de49770 Niko*0681 
1bb193238 Myah*0682 #if _MSVCR_VER>=120
                0683 /*********************************************************************
                0684  *      imaxabs (MSVCR120.@)
                0685  */
4f2f3545e Piot*0686 intmax_t CDECL imaxabs( intmax_t n )
1bb193238 Myah*0687 {
                0688     return n >= 0 ? n : -n;
                0689 }
                0690 #endif
                0691 
abe0823b7 Alex*0692 /*********************************************************************
                0693  *      _abs64 (MSVCRT.@)
                0694  */
                0695 __int64 CDECL _abs64( __int64 n )
                0696 {
                0697     return n >= 0 ? n : -n;
                0698 }
                0699 
24fb503e2 Piot*0700 #if defined(__i386__) || defined(__x86_64__)
c521ec04c Piot*0701 static void _setfp_sse( unsigned int *cw, unsigned int cw_mask,
24fb503e2 Piot*0702         unsigned int *sw, unsigned int sw_mask )
                0703 {
                0704 #if defined(__GNUC__) || defined(__clang__)
                0705     unsigned long old_fpword, fpword;
                0706     unsigned int flags;
                0707 
                0708     __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
                0709     old_fpword = fpword;
                0710 
                0711     cw_mask &= _MCW_EM | _MCW_RC | _MCW_DN;
                0712     sw_mask &= _MCW_EM;
                0713 
                0714     if (sw)
                0715     {
                0716         flags = 0;
                0717         if (fpword & 0x1) flags |= _SW_INVALID;
                0718         if (fpword & 0x2) flags |= _SW_DENORMAL;
                0719         if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
                0720         if (fpword & 0x8) flags |= _SW_OVERFLOW;
                0721         if (fpword & 0x10) flags |= _SW_UNDERFLOW;
                0722         if (fpword & 0x20) flags |= _SW_INEXACT;
                0723 
                0724         *sw = (flags & ~sw_mask) | (*sw & sw_mask);
                0725         TRACE("sse2 update sw %08x to %08x\n", flags, *sw);
                0726         fpword &= ~0x3f;
                0727         if (*sw & _SW_INVALID) fpword |= 0x1;
                0728         if (*sw & _SW_DENORMAL) fpword |= 0x2;
                0729         if (*sw & _SW_ZERODIVIDE) fpword |= 0x4;
                0730         if (*sw & _SW_OVERFLOW) fpword |= 0x8;
                0731         if (*sw & _SW_UNDERFLOW) fpword |= 0x10;
                0732         if (*sw & _SW_INEXACT) fpword |= 0x20;
                0733         *sw = flags;
                0734     }
                0735 
                0736     if (cw)
                0737     {
                0738         flags = 0;
                0739         if (fpword & 0x80) flags |= _EM_INVALID;
                0740         if (fpword & 0x100) flags |= _EM_DENORMAL;
                0741         if (fpword & 0x200) flags |= _EM_ZERODIVIDE;
                0742         if (fpword & 0x400) flags |= _EM_OVERFLOW;
                0743         if (fpword & 0x800) flags |= _EM_UNDERFLOW;
                0744         if (fpword & 0x1000) flags |= _EM_INEXACT;
                0745         switch (fpword & 0x6000)
                0746         {
                0747         case 0x6000: flags |= _RC_UP|_RC_DOWN; break;
                0748         case 0x4000: flags |= _RC_UP; break;
                0749         case 0x2000: flags |= _RC_DOWN; break;
                0750         }
                0751         switch (fpword & 0x8040)
                0752         {
                0753         case 0x0040: flags |= _DN_FLUSH_OPERANDS_SAVE_RESULTS; break;
                0754         case 0x8000: flags |= _DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
                0755         case 0x8040: flags |= _DN_FLUSH; break;
                0756         }
                0757 
                0758         *cw = (flags & ~cw_mask) | (*cw & cw_mask);
                0759         TRACE("sse2 update cw %08x to %08x\n", flags, *cw);
                0760         fpword &= ~0xffc0;
                0761         if (*cw & _EM_INVALID) fpword |= 0x80;
                0762         if (*cw & _EM_DENORMAL) fpword |= 0x100;
                0763         if (*cw & _EM_ZERODIVIDE) fpword |= 0x200;
                0764         if (*cw & _EM_OVERFLOW) fpword |= 0x400;
                0765         if (*cw & _EM_UNDERFLOW) fpword |= 0x800;
                0766         if (*cw & _EM_INEXACT) fpword |= 0x1000;
                0767         switch (*cw & _MCW_RC)
                0768         {
                0769         case _RC_UP|_RC_DOWN: fpword |= 0x6000; break;
                0770         case _RC_UP: fpword |= 0x4000; break;
                0771         case _RC_DOWN: fpword |= 0x2000; break;
                0772         }
                0773         switch (*cw & _MCW_DN)
                0774         {
                0775         case _DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
                0776         case _DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
                0777         case _DN_FLUSH: fpword |= 0x8040; break;
                0778         }
                0779 
                0780         /* clear status word if anything changes */
                0781         if (fpword != old_fpword && !sw)
                0782         {
                0783             TRACE("sse2 clear status word\n");
                0784             fpword &= ~0x3f;
                0785         }
                0786     }
                0787 
                0788     if (fpword != old_fpword)
                0789         __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
                0790 #else
                0791     FIXME("not implemented\n");
                0792     if (cw) *cw = 0;
                0793     if (sw) *sw = 0;
                0794 #endif
                0795 }
                0796 #endif
                0797 
c521ec04c Piot*0798 static void _setfp( unsigned int *cw, unsigned int cw_mask,
f1ef14dc1 Piot*0799         unsigned int *sw, unsigned int sw_mask )
4b17ec740 Alex*0800 {
0c808ff4d Piot*0801 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
f1ef14dc1 Piot*0802     unsigned long oldcw = 0, newcw = 0;
                0803     unsigned long oldsw = 0, newsw = 0;
4b17ec740 Alex*0804     unsigned int flags;
                0805 
f1ef14dc1 Piot*0806     cw_mask &= _MCW_EM | _MCW_IC | _MCW_RC | _MCW_PC;
                0807     sw_mask &= _MCW_EM;
                0808 
                0809     if (sw)
4b17ec740 Alex*0810     {
f1ef14dc1 Piot*0811         __asm__ __volatile__( "fstsw %0" : "=m" (newsw) );
                0812         oldsw = newsw;
                0813 
4b17ec740 Alex*0814         flags = 0;
f1ef14dc1 Piot*0815         if (newsw & 0x1) flags |= _SW_INVALID;
                0816         if (newsw & 0x2) flags |= _SW_DENORMAL;
                0817         if (newsw & 0x4) flags |= _SW_ZERODIVIDE;
                0818         if (newsw & 0x8) flags |= _SW_OVERFLOW;
                0819         if (newsw & 0x10) flags |= _SW_UNDERFLOW;
                0820         if (newsw & 0x20) flags |= _SW_INEXACT;
                0821 
                0822         *sw = (flags & ~sw_mask) | (*sw & sw_mask);
                0823         TRACE("x86 update sw %08x to %08x\n", flags, *sw);
                0824         newsw &= ~0x3f;
                0825         if (*sw & _SW_INVALID) newsw |= 0x1;
                0826         if (*sw & _SW_DENORMAL) newsw |= 0x2;
                0827         if (*sw & _SW_ZERODIVIDE) newsw |= 0x4;
                0828         if (*sw & _SW_OVERFLOW) newsw |= 0x8;
                0829         if (*sw & _SW_UNDERFLOW) newsw |= 0x10;
                0830         if (*sw & _SW_INEXACT) newsw |= 0x20;
                0831         *sw = flags;
4b17ec740 Alex*0832     }
                0833 
f1ef14dc1 Piot*0834     if (cw)
                0835     {
                0836         __asm__ __volatile__( "fstcw %0" : "=m" (newcw) );
                0837         oldcw = newcw;
4b17ec740 Alex*0838 
f1ef14dc1 Piot*0839         flags = 0;
                0840         if (newcw & 0x1) flags |= _EM_INVALID;
                0841         if (newcw & 0x2) flags |= _EM_DENORMAL;
                0842         if (newcw & 0x4) flags |= _EM_ZERODIVIDE;
                0843         if (newcw & 0x8) flags |= _EM_OVERFLOW;
                0844         if (newcw & 0x10) flags |= _EM_UNDERFLOW;
                0845         if (newcw & 0x20) flags |= _EM_INEXACT;
                0846         switch (newcw & 0xc00)
                0847         {
                0848         case 0xc00: flags |= _RC_UP|_RC_DOWN; break;
                0849         case 0x800: flags |= _RC_UP; break;
                0850         case 0x400: flags |= _RC_DOWN; break;
                0851         }
                0852         switch (newcw & 0x300)
                0853         {
                0854         case 0x0: flags |= _PC_24; break;
                0855         case 0x200: flags |= _PC_53; break;
                0856         case 0x300: flags |= _PC_64; break;
                0857         }
                0858         if (newcw & 0x1000) flags |= _IC_AFFINE;
                0859 
                0860         *cw = (flags & ~cw_mask) | (*cw & cw_mask);
                0861         TRACE("x86 update cw %08x to %08x\n", flags, *cw);
7555573dc Piot*0862         newcw &= ~0x1f3f;
f1ef14dc1 Piot*0863         if (*cw & _EM_INVALID) newcw |= 0x1;
                0864         if (*cw & _EM_DENORMAL) newcw |= 0x2;
                0865         if (*cw & _EM_ZERODIVIDE) newcw |= 0x4;
                0866         if (*cw & _EM_OVERFLOW) newcw |= 0x8;
                0867         if (*cw & _EM_UNDERFLOW) newcw |= 0x10;
                0868         if (*cw & _EM_INEXACT) newcw |= 0x20;
                0869         switch (*cw & _MCW_RC)
                0870         {
                0871         case _RC_UP|_RC_DOWN: newcw |= 0xc00; break;
                0872         case _RC_UP: newcw |= 0x800; break;
                0873         case _RC_DOWN: newcw |= 0x400; break;
                0874         }
                0875         switch (*cw & _MCW_PC)
                0876         {
                0877         case _PC_64: newcw |= 0x300; break;
                0878         case _PC_53: newcw |= 0x200; break;
                0879         case _PC_24: newcw |= 0x0; break;
                0880         }
                0881         if (*cw & _IC_AFFINE) newcw |= 0x1000;
                0882     }
                0883 
62d269370 Piot*0884     if (oldsw != newsw && (newsw & 0x3f))
f1ef14dc1 Piot*0885     {
                0886         struct {
                0887             WORD control_word;
                0888             WORD unused1;
                0889             WORD status_word;
                0890             WORD unused2;
                0891             WORD tag_word;
                0892             WORD unused3;
                0893             DWORD instruction_pointer;
                0894             WORD code_segment;
                0895             WORD unused4;
                0896             DWORD operand_addr;
                0897             WORD data_segment;
                0898             WORD unused5;
                0899         } fenv;
                0900 
62d269370 Piot*0901         assert(cw);
                0902 
f1ef14dc1 Piot*0903         __asm__ __volatile__( "fnstenv %0" : "=m" (fenv) );
                0904         fenv.control_word = newcw;
                0905         fenv.status_word = newsw;
                0906         __asm__ __volatile__( "fldenv %0" : : "m" (fenv) : "st", "st(1)",
                0907                 "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" );
c521ec04c Piot*0908         return;
f1ef14dc1 Piot*0909     }
                0910 
                0911     if (oldsw != newsw)
                0912         __asm__ __volatile__( "fnclex" );
                0913     if (oldcw != newcw)
                0914         __asm__ __volatile__( "fldcw %0" : : "m" (newcw) );
                0915 #elif defined(__x86_64__)
c521ec04c Piot*0916     _setfp_sse(cw, cw_mask, sw, sw_mask);
63f3f4283 Piot*0917 #elif defined(__aarch64__)
                0918     ULONG_PTR old_fpsr = 0, fpsr = 0, old_fpcr = 0, fpcr = 0;
                0919     unsigned int flags;
                0920 
                0921     cw_mask &= _MCW_EM | _MCW_RC;
                0922     sw_mask &= _MCW_EM;
                0923 
                0924     if (sw)
                0925     {
                0926         __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) );
                0927         old_fpsr = fpsr;
                0928 
                0929         flags = 0;
                0930         if (fpsr & 0x1) flags |= _SW_INVALID;
                0931         if (fpsr & 0x2) flags |= _SW_ZERODIVIDE;
                0932         if (fpsr & 0x4) flags |= _SW_OVERFLOW;
                0933         if (fpsr & 0x8) flags |= _SW_UNDERFLOW;
                0934         if (fpsr & 0x10) flags |= _SW_INEXACT;
                0935         if (fpsr & 0x80) flags |= _SW_DENORMAL;
                0936 
                0937         *sw = (flags & ~sw_mask) | (*sw & sw_mask);
                0938         TRACE("aarch64 update sw %08x to %08x\n", flags, *sw);
                0939         fpsr &= ~0x9f;
                0940         if (*sw & _SW_INVALID) fpsr |= 0x1;
                0941         if (*sw & _SW_ZERODIVIDE) fpsr |= 0x2;
                0942         if (*sw & _SW_OVERFLOW) fpsr |= 0x4;
                0943         if (*sw & _SW_UNDERFLOW) fpsr |= 0x8;
                0944         if (*sw & _SW_INEXACT) fpsr |= 0x10;
                0945         if (*sw & _SW_DENORMAL) fpsr |= 0x80;
                0946         *sw = flags;
                0947     }
                0948 
                0949     if (cw)
                0950     {
                0951         __asm__ __volatile__( "mrs %0, fpcr" : "=r" (fpcr) );
                0952         old_fpcr = fpcr;
                0953 
                0954         flags = 0;
                0955         if (!(fpcr & 0x100)) flags |= _EM_INVALID;
                0956         if (!(fpcr & 0x200)) flags |= _EM_ZERODIVIDE;
                0957         if (!(fpcr & 0x400)) flags |= _EM_OVERFLOW;
                0958         if (!(fpcr & 0x800)) flags |= _EM_UNDERFLOW;
                0959         if (!(fpcr & 0x1000)) flags |= _EM_INEXACT;
                0960         if (!(fpcr & 0x8000)) flags |= _EM_DENORMAL;
                0961         switch (fpcr & 0xc00000)
                0962         {
                0963         case 0x400000: flags |= _RC_UP; break;
                0964         case 0x800000: flags |= _RC_DOWN; break;
                0965         case 0xc00000: flags |= _RC_CHOP; break;
                0966         }
                0967 
                0968         *cw = (flags & ~cw_mask) | (*cw & cw_mask);
                0969         TRACE("aarch64 update cw %08x to %08x\n", flags, *cw);
                0970         fpcr &= ~0xc09f00ul;
                0971         if (!(*cw & _EM_INVALID)) fpcr |= 0x100;
                0972         if (!(*cw & _EM_ZERODIVIDE)) fpcr |= 0x200;
                0973         if (!(*cw & _EM_OVERFLOW)) fpcr |= 0x400;
                0974         if (!(*cw & _EM_UNDERFLOW)) fpcr |= 0x800;
                0975         if (!(*cw & _EM_INEXACT)) fpcr |= 0x1000;
                0976         if (!(*cw & _EM_DENORMAL)) fpcr |= 0x8000;
                0977         switch (*cw & _MCW_RC)
                0978         {
                0979         case _RC_CHOP: fpcr |= 0xc00000; break;
                0980         case _RC_UP: fpcr |= 0x400000; break;
                0981         case _RC_DOWN: fpcr |= 0x800000; break;
                0982         }
                0983     }
                0984 
                0985     /* mask exceptions if needed */
                0986     if (old_fpcr != fpcr && ~(old_fpcr >> 8) & fpsr & 0x9f != fpsr & 0x9f)
                0987     {
                0988         ULONG_PTR mask = fpcr & ~0x9f00;
                0989         __asm__ __volatile__( "msr fpcr, %0" :: "r" (mask) );
                0990     }
                0991 
                0992     if (old_fpsr != fpsr)
                0993         __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) );
                0994     if (old_fpcr != fpcr)
                0995         __asm__ __volatile__( "msr fpcr, %0" :: "r" (fpcr) );
b28b409bb Piot*0996 #elif defined(__arm__) && !defined(__SOFTFP__)
                0997     DWORD old_fpscr, fpscr;
                0998     unsigned int flags;
                0999 
                1000     __asm__ __volatile__( "vmrs %0, fpscr" : "=r" (fpscr) );
                1001     old_fpscr = fpscr;
                1002 
                1003     cw_mask &= _MCW_EM | _MCW_RC;
                1004     sw_mask &= _MCW_EM;
                1005 
                1006     if (sw)
                1007     {
                1008         flags = 0;
                1009         if (fpscr & 0x1) flags |= _SW_INVALID;
                1010         if (fpscr & 0x2) flags |= _SW_ZERODIVIDE;
                1011         if (fpscr & 0x4) flags |= _SW_OVERFLOW;
                1012         if (fpscr & 0x8) flags |= _SW_UNDERFLOW;
                1013         if (fpscr & 0x10) flags |= _SW_INEXACT;
                1014         if (fpscr & 0x80) flags |= _SW_DENORMAL;
                1015 
                1016         *sw = (flags & ~sw_mask) | (*sw & sw_mask);
                1017         TRACE("arm update sw %08x to %08x\n", flags, *sw);
                1018         fpscr &= ~0x9f;
                1019         if (*sw & _SW_INVALID) fpscr |= 0x1;
                1020         if (*sw & _SW_ZERODIVIDE) fpscr |= 0x2;
                1021         if (*sw & _SW_OVERFLOW) fpscr |= 0x4;
                1022         if (*sw & _SW_UNDERFLOW) fpscr |= 0x8;
                1023         if (*sw & _SW_INEXACT) fpscr |= 0x10;
                1024         if (*sw & _SW_DENORMAL) fpscr |= 0x80;
                1025         *sw = flags;
                1026     }
                1027 
                1028     if (cw)
                1029     {
                1030         flags = 0;
                1031         if (!(fpscr & 0x100)) flags |= _EM_INVALID;
                1032         if (!(fpscr & 0x200)) flags |= _EM_ZERODIVIDE;
                1033         if (!(fpscr & 0x400)) flags |= _EM_OVERFLOW;
                1034         if (!(fpscr & 0x800)) flags |= _EM_UNDERFLOW;
                1035         if (!(fpscr & 0x1000)) flags |= _EM_INEXACT;
                1036         if (!(fpscr & 0x8000)) flags |= _EM_DENORMAL;
                1037         switch (fpscr & 0xc00000)
                1038         {
                1039         case 0x400000: flags |= _RC_UP; break;
                1040         case 0x800000: flags |= _RC_DOWN; break;
                1041         case 0xc00000: flags |= _RC_CHOP; break;
                1042         }
                1043 
                1044         *cw = (flags & ~cw_mask) | (*cw & cw_mask);
                1045         TRACE("arm update cw %08x to %08x\n", flags, *cw);
                1046         fpscr &= ~0xc09f00ul;
                1047         if (!(*cw & _EM_INVALID)) fpscr |= 0x100;
                1048         if (!(*cw & _EM_ZERODIVIDE)) fpscr |= 0x200;
                1049         if (!(*cw & _EM_OVERFLOW)) fpscr |= 0x400;
                1050         if (!(*cw & _EM_UNDERFLOW)) fpscr |= 0x800;
                1051         if (!(*cw & _EM_INEXACT)) fpscr |= 0x1000;
                1052         if (!(*cw & _EM_DENORMAL)) fpscr |= 0x8000;
                1053         switch (*cw & _MCW_RC)
                1054         {
                1055         case _RC_CHOP: fpscr |= 0xc00000; break;
                1056         case _RC_UP: fpscr |= 0x400000; break;
                1057         case _RC_DOWN: fpscr |= 0x800000; break;
                1058         }
                1059     }
                1060 
                1061     if (old_fpscr != fpscr)
                1062         __asm__ __volatile__( "vmsr fpscr, %0" :: "r" (fpscr) );
f1ef14dc1 Piot*1063 #else
                1064     FIXME("not implemented\n");
                1065     if (cw) *cw = 0;
                1066     if (sw) *sw = 0;
                1067 #endif
                1068 }
                1069 
                1070 /**********************************************************************
                1071  *      _statusfp2 (MSVCR80.@)
                1072  */
                1073 #if defined(__i386__)
                1074 void CDECL _statusfp2( unsigned int *x86_sw, unsigned int *sse2_sw )
                1075 {
                1076     if (x86_sw)
                1077         _setfp(NULL, 0, x86_sw, 0);
                1078     if (!sse2_sw) return;
4b17ec740 Alex*1079     if (sse2_supported)
24fb503e2 Piot*1080         _setfp_sse(NULL, 0, sse2_sw, 0);
4b17ec740 Alex*1081     else *sse2_sw = 0;
                1082 }
                1083 #endif
                1084 
1db20bfd3 Jon *1085 /**********************************************************************
                1086  *      _statusfp (MSVCRT.@)
                1087  */
24beabfd4 Alex*1088 unsigned int CDECL _statusfp(void)
1db20bfd3 Jon *1089 {
6f912787a Alex*1090     unsigned int flags = 0;
ab3afe834 Piot*1091 #if defined(__i386__)
4b17ec740 Alex*1092     unsigned int x86_sw, sse2_sw;
                1093 
                1094     _statusfp2( &x86_sw, &sse2_sw );
                1095     /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
6f912787a Alex*1096     flags = x86_sw | sse2_sw;
1db20bfd3 Jon *1097 #else
0c808ff4d Piot*1098     _setfp(NULL, 0, &flags, 0);
1db20bfd3 Jon *1099 #endif
6f912787a Alex*1100     return flags;
1db20bfd3 Jon *1101 }
                1102 
                1103 /*********************************************************************
                1104  *      _clearfp (MSVCRT.@)
                1105  */
24beabfd4 Alex*1106 unsigned int CDECL _clearfp(void)
1db20bfd3 Jon *1107 {
98d7a021d Alex*1108     unsigned int flags = 0;
f1ef14dc1 Piot*1109 #ifdef __i386__
                1110     _setfp(NULL, 0, &flags, _MCW_EM);
98d7a021d Alex*1111     if (sse2_supported)
                1112     {
24fb503e2 Piot*1113         unsigned int sse_sw = 0;
                1114 
                1115         _setfp_sse(NULL, 0, &sse_sw, _MCW_EM);
                1116         flags |= sse_sw;
98d7a021d Alex*1117     }
1db20bfd3 Jon *1118 #else
0c808ff4d Piot*1119     _setfp(NULL, 0, &flags, _MCW_EM);
1db20bfd3 Jon *1120 #endif
98d7a021d Alex*1121     return flags;
1db20bfd3 Jon *1122 }
                1123 
dec198afe Alex*1124 /*********************************************************************
                1125  *      __fpecode (MSVCRT.@)
                1126  */
24beabfd4 Alex*1127 int * CDECL __fpecode(void)
dec198afe Alex*1128 {
                1129     return &msvcrt_get_thread_data()->fpecode;
                1130 }
                1131 
1db20bfd3 Jon *1132 /*********************************************************************
                1133  *      ldexp (MSVCRT.@)
                1134  */
4f2f3545e Piot*1135 double CDECL ldexp(double num, int exp)
1db20bfd3 Jon *1136 {
52621691f Alex*1137   double z = scalbn(num, exp);
1db20bfd3 Jon *1138 
79c3b610c Alex*1139   if (isfinite(num) && !isfinite(z))
2833a10ba Piot*1140     return math_error(_OVERFLOW, "ldexp", num, exp, z);
                1141   if (num && isfinite(num) && !z)
                1142     return math_error(_UNDERFLOW, "ldexp", num, exp, z);
1db20bfd3 Jon *1143   return z;
                1144 }
                1145 
                1146 /*********************************************************************
                1147  *      _cabs (MSVCRT.@)
                1148  */
4f2f3545e Piot*1149 double CDECL _cabs(struct _complex num)
1db20bfd3 Jon *1150 {
4f2f3545e Piot*1151   return sqrt(num.x * num.x + num.y * num.y);
1db20bfd3 Jon *1152 }
                1153 
                1154 /*********************************************************************
                1155  *      _chgsign (MSVCRT.@)
                1156  */
4f2f3545e Piot*1157 double CDECL _chgsign(double num)
1db20bfd3 Jon *1158 {
dbda71f74 Alex*1159     union { double f; UINT64 i; } u = { num };
                1160     u.i ^= 1ull << 63;
                1161     return u.f;
1db20bfd3 Jon *1162 }
                1163 
a8d8e4a36 Alex*1164 /*********************************************************************
f0e74961e Alex*1165  *      __control87_2 (MSVCR80.@)
a8d8e4a36 Alex*1166  *
                1167  * Not exported by native msvcrt, added in msvcr80.
                1168  */
0e183cc3c Alex*1169 #ifdef __i386__
a8d8e4a36 Alex*1170 int CDECL __control87_2( unsigned int newval, unsigned int mask,
                1171                          unsigned int *x86_cw, unsigned int *sse2_cw )
                1172 {
                1173     if (x86_cw)
                1174     {
f1ef14dc1 Piot*1175         *x86_cw = newval;
c521ec04c Piot*1176         _setfp(x86_cw, mask, NULL, 0);
a8d8e4a36 Alex*1177     }
                1178 
                1179     if (!sse2_cw) return 1;
                1180 
                1181     if (sse2_supported)
                1182     {
24fb503e2 Piot*1183         *sse2_cw = newval;
c521ec04c Piot*1184         _setfp_sse(sse2_cw, mask, NULL, 0);
a8d8e4a36 Alex*1185     }
                1186     else *sse2_cw = 0;
                1187 
                1188     return 1;
                1189 }
                1190 #endif
                1191 
1db20bfd3 Jon *1192 /*********************************************************************
                1193  *      _control87 (MSVCRT.@)
                1194  */
24beabfd4 Alex*1195 unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
1db20bfd3 Jon *1196 {
6f912787a Alex*1197     unsigned int flags = 0;
254dd0a2b Piot*1198 #if defined(__i386__) && (_MSVCR_VER == 0 || _MSVCR_VER >= 80)
6f912787a Alex*1199     unsigned int sse2_cw;
                1200 
                1201     __control87_2( newval, mask, &flags, &sse2_cw );
                1202 
564ede5d3 Piot*1203     if (sse2_supported)
                1204     {
                1205         if ((flags ^ sse2_cw) & (_MCW_EM | _MCW_RC)) flags |= _EM_AMBIGUOUS;
                1206         flags |= sse2_cw;
                1207     }
0c808ff4d Piot*1208 #else
24fb503e2 Piot*1209     flags = newval;
f1ef14dc1 Piot*1210     _setfp(&flags, mask, NULL, 0);
1db20bfd3 Jon *1211 #endif
6f912787a Alex*1212     return flags;
1db20bfd3 Jon *1213 }
                1214 
                1215 /*********************************************************************
                1216  *      _controlfp (MSVCRT.@)
                1217  */
24beabfd4 Alex*1218 unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask)
1db20bfd3 Jon *1219 {
467486030 Piot*1220   return _control87( newval, mask & ~_EM_DENORMAL );
1db20bfd3 Jon *1221 }
                1222 
658eaeb3e Alex*1223 /*********************************************************************
                1224  *      _set_controlfp (MSVCRT.@)
                1225  */
                1226 void CDECL _set_controlfp( unsigned int newval, unsigned int mask )
                1227 {
                1228     _controlfp( newval, mask );
                1229 }
                1230 
bfd0866be Piot*1231 /*********************************************************************
                1232  *              _controlfp_s (MSVCRT.@)
                1233  */
                1234 int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask)
                1235 {
467486030 Piot*1236     static const unsigned int all_flags = (_MCW_EM | _MCW_IC | _MCW_RC |
                1237                                            _MCW_PC | _MCW_DN);
f53d82b4f Alex*1238     unsigned int val;
bfd0866be Piot*1239 
f53d82b4f Alex*1240     if (!MSVCRT_CHECK_PMT( !(newval & mask & ~all_flags) ))
4dba956ea Alex*1241     {
f53d82b4f Alex*1242         if (cur) *cur = _controlfp( 0, 0 );  /* retrieve it anyway */
1317b935e Piot*1243         return EINVAL;
4dba956ea Alex*1244     }
f53d82b4f Alex*1245     val = _controlfp( newval, mask );
                1246     if (cur) *cur = val;
bfd0866be Piot*1247     return 0;
                1248 }
                1249 
6391a9f89 Mart*1250 #if _MSVCR_VER >= 140 && (defined(__i386__) || defined(__x86_64__))
1b7e93c4c Piot*1251 enum fenv_masks
                1252 {
                1253     FENV_X_INVALID = 0x00100010,
                1254     FENV_X_DENORMAL = 0x00200020,
                1255     FENV_X_ZERODIVIDE = 0x00080008,
                1256     FENV_X_OVERFLOW = 0x00040004,
                1257     FENV_X_UNDERFLOW = 0x00020002,
                1258     FENV_X_INEXACT = 0x00010001,
                1259     FENV_X_AFFINE = 0x00004000,
                1260     FENV_X_UP = 0x00800200,
                1261     FENV_X_DOWN = 0x00400100,
                1262     FENV_X_24 = 0x00002000,
                1263     FENV_X_53 = 0x00001000,
                1264     FENV_Y_INVALID = 0x10000010,
                1265     FENV_Y_DENORMAL = 0x20000020,
                1266     FENV_Y_ZERODIVIDE = 0x08000008,
                1267     FENV_Y_OVERFLOW = 0x04000004,
                1268     FENV_Y_UNDERFLOW = 0x02000002,
                1269     FENV_Y_INEXACT = 0x01000001,
                1270     FENV_Y_UP = 0x80000200,
                1271     FENV_Y_DOWN = 0x40000100,
                1272     FENV_Y_FLUSH = 0x00000400,
                1273     FENV_Y_FLUSH_SAVE = 0x00000800
                1274 };
                1275 
                1276 /* encodes x87/sse control/status word in ulong */
                1277 static __msvcrt_ulong fenv_encode(unsigned int x, unsigned int y)
                1278 {
                1279     __msvcrt_ulong ret = 0;
                1280 
2f9312fe5 Piot*1281 #ifdef __i386__
1b7e93c4c Piot*1282     if (x & _EM_INVALID) ret |= FENV_X_INVALID;
                1283     if (x & _EM_DENORMAL) ret |= FENV_X_DENORMAL;
                1284     if (x & _EM_ZERODIVIDE) ret |= FENV_X_ZERODIVIDE;
                1285     if (x & _EM_OVERFLOW) ret |= FENV_X_OVERFLOW;
                1286     if (x & _EM_UNDERFLOW) ret |= FENV_X_UNDERFLOW;
                1287     if (x & _EM_INEXACT) ret |= FENV_X_INEXACT;
                1288     if (x & _IC_AFFINE) ret |= FENV_X_AFFINE;
                1289     if (x & _RC_UP) ret |= FENV_X_UP;
                1290     if (x & _RC_DOWN) ret |= FENV_X_DOWN;
                1291     if (x & _PC_24) ret |= FENV_X_24;
                1292     if (x & _PC_53) ret |= FENV_X_53;
2f9312fe5 Piot*1293 #endif
1b7e93c4c Piot*1294     x &= ~(_MCW_EM | _MCW_IC | _MCW_RC | _MCW_PC);
                1295 
                1296     if (y & _EM_INVALID) ret |= FENV_Y_INVALID;
                1297     if (y & _EM_DENORMAL) ret |= FENV_Y_DENORMAL;
                1298     if (y & _EM_ZERODIVIDE) ret |= FENV_Y_ZERODIVIDE;
                1299     if (y & _EM_OVERFLOW) ret |= FENV_Y_OVERFLOW;
                1300     if (y & _EM_UNDERFLOW) ret |= FENV_Y_UNDERFLOW;
                1301     if (y & _EM_INEXACT) ret |= FENV_Y_INEXACT;
                1302     if (y & _RC_UP) ret |= FENV_Y_UP;
                1303     if (y & _RC_DOWN) ret |= FENV_Y_DOWN;
                1304     if (y & _DN_FLUSH) ret |= FENV_Y_FLUSH;
                1305     if (y & _DN_FLUSH_OPERANDS_SAVE_RESULTS) ret |= FENV_Y_FLUSH_SAVE;
                1306     y &= ~(_MCW_EM | _MCW_IC | _MCW_RC | _MCW_DN);
                1307 
                1308     if(x || y) FIXME("unsupported flags: %x, %x\n", x, y);
                1309     return ret;
                1310 }
                1311 
                1312 /* decodes x87/sse control/status word, returns FALSE on error */
                1313 static BOOL fenv_decode(__msvcrt_ulong enc, unsigned int *x, unsigned int *y)
                1314 {
                1315     *x = *y = 0;
                1316     if ((enc & FENV_X_INVALID) == FENV_X_INVALID) *x |= _EM_INVALID;
                1317     if ((enc & FENV_X_DENORMAL) == FENV_X_DENORMAL) *x |= _EM_DENORMAL;
                1318     if ((enc & FENV_X_ZERODIVIDE) == FENV_X_ZERODIVIDE) *x |= _EM_ZERODIVIDE;
                1319     if ((enc & FENV_X_OVERFLOW) == FENV_X_OVERFLOW) *x |= _EM_OVERFLOW;
                1320     if ((enc & FENV_X_UNDERFLOW) == FENV_X_UNDERFLOW) *x |= _EM_UNDERFLOW;
                1321     if ((enc & FENV_X_INEXACT) == FENV_X_INEXACT) *x |= _EM_INEXACT;
                1322     if ((enc & FENV_X_AFFINE) == FENV_X_AFFINE) *x |= _IC_AFFINE;
                1323     if ((enc & FENV_X_UP) == FENV_X_UP) *x |= _RC_UP;
                1324     if ((enc & FENV_X_DOWN) == FENV_X_DOWN) *x |= _RC_DOWN;
                1325     if ((enc & FENV_X_24) == FENV_X_24) *x |= _PC_24;
                1326     if ((enc & FENV_X_53) == FENV_X_53) *x |= _PC_53;
                1327 
                1328     if ((enc & FENV_Y_INVALID) == FENV_Y_INVALID) *y |= _EM_INVALID;
                1329     if ((enc & FENV_Y_DENORMAL) == FENV_Y_DENORMAL) *y |= _EM_DENORMAL;
                1330     if ((enc & FENV_Y_ZERODIVIDE) == FENV_Y_ZERODIVIDE) *y |= _EM_ZERODIVIDE;
                1331     if ((enc & FENV_Y_OVERFLOW) == FENV_Y_OVERFLOW) *y |= _EM_OVERFLOW;
                1332     if ((enc & FENV_Y_UNDERFLOW) == FENV_Y_UNDERFLOW) *y |= _EM_UNDERFLOW;
                1333     if ((enc & FENV_Y_INEXACT) == FENV_Y_INEXACT) *y |= _EM_INEXACT;
                1334     if ((enc & FENV_Y_UP) == FENV_Y_UP) *y |= _RC_UP;
                1335     if ((enc & FENV_Y_DOWN) == FENV_Y_DOWN) *y |= _RC_DOWN;
                1336     if ((enc & FENV_Y_FLUSH) == FENV_Y_FLUSH) *y |= _DN_FLUSH;
                1337     if ((enc & FENV_Y_FLUSH_SAVE) == FENV_Y_FLUSH_SAVE) *y |= _DN_FLUSH_OPERANDS_SAVE_RESULTS;
                1338 
                1339     if (fenv_encode(*x, *y) != enc)
                1340     {
                1341         WARN("can't decode: %lx\n", enc);
                1342         return FALSE;
                1343     }
                1344     return TRUE;
                1345 }
5189d73b5 Piot*1346 #elif _MSVCR_VER >= 120
2f9312fe5 Piot*1347 static __msvcrt_ulong fenv_encode(unsigned int x, unsigned int y)
                1348 {
6391a9f89 Mart*1349     if (y & _EM_DENORMAL)
                1350         y = (y & ~_EM_DENORMAL) | 0x20;
                1351 
2f9312fe5 Piot*1352     return x | y;
                1353 }
                1354 
5189d73b5 Piot*1355 static BOOL fenv_decode(__msvcrt_ulong enc, unsigned int *x, unsigned int *y)
                1356 {
6391a9f89 Mart*1357     if (enc & 0x20)
                1358         enc = (enc & ~0x20) | _EM_DENORMAL;
                1359 
5189d73b5 Piot*1360     *x = *y = enc;
                1361     return TRUE;
                1362 }
                1363 #endif
1b7e93c4c Piot*1364 
86597db83 Alex*1365 #if _MSVCR_VER>=120
1150c0454 Piot*1366 /*********************************************************************
                1367  *      fegetenv (MSVCR120.@)
                1368  */
4f2f3545e Piot*1369 int CDECL fegetenv(fenv_t *env)
1150c0454 Piot*1370 {
1b7e93c4c Piot*1371 #if _MSVCR_VER>=140 && defined(__i386__)
                1372     unsigned int x87, sse;
                1373     __control87_2(0, 0, &x87, &sse);
                1374     env->_Fe_ctl = fenv_encode(x87, sse);
                1375     _statusfp2(&x87, &sse);
                1376     env->_Fe_stat = fenv_encode(x87, sse);
                1377 #elif _MSVCR_VER>=140
                1378     env->_Fe_ctl = fenv_encode(0, _control87(0, 0));
                1379     env->_Fe_stat = fenv_encode(0, _statusfp());
                1380 #else
467486030 Piot*1381     env->_Fe_ctl = _controlfp(0, 0) & (_EM_INEXACT | _EM_UNDERFLOW |
f1ef14dc1 Piot*1382             _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID | _MCW_RC);
34422eb56 Alex*1383     env->_Fe_stat = _statusfp();
1b7e93c4c Piot*1384 #endif
1150c0454 Piot*1385     return 0;
                1386 }
7981ab4fd Dani*1387 
06f205d07 Piot*1388 /*********************************************************************
                1389  *      feupdateenv (MSVCR120.@)
                1390  */
                1391 int CDECL feupdateenv(const fenv_t *env)
                1392 {
1b7e93c4c Piot*1393     fenv_t set;
                1394     fegetenv(&set);
                1395     set._Fe_ctl = env->_Fe_ctl;
                1396     set._Fe_stat |= env->_Fe_stat;
06f205d07 Piot*1397     return fesetenv(&set);
                1398 }
                1399 
7981ab4fd Dani*1400 /*********************************************************************
                1401  *      fetestexcept (MSVCR120.@)
                1402  */
                1403 int CDECL fetestexcept(int flags)
                1404 {
                1405     return _statusfp() & flags;
                1406 }
5fd512504 Dani*1407 
                1408 /*********************************************************************
                1409  *      fesetexceptflag (MSVCR120.@)
                1410  */
                1411 int CDECL fesetexceptflag(const fexcept_t *status, int excepts)
                1412 {
                1413     fenv_t env;
                1414 
1b7e93c4c Piot*1415     excepts &= FE_ALL_EXCEPT;
5fd512504 Dani*1416     if(!excepts)
                1417         return 0;
                1418 
                1419     fegetenv(&env);
1b7e93c4c Piot*1420     env._Fe_stat &= ~fenv_encode(excepts, excepts);
90fd548d0 Piot*1421     env._Fe_stat |= *status & fenv_encode(excepts, excepts);
5fd512504 Dani*1422     return fesetenv(&env);
                1423 }
fd0c03c64 Dani*1424 
0f721c2f0 Piot*1425 /*********************************************************************
                1426  *      feraiseexcept (MSVCR120.@)
                1427  */
                1428 int CDECL feraiseexcept(int flags)
                1429 {
                1430     fenv_t env;
                1431 
1b7e93c4c Piot*1432     flags &= FE_ALL_EXCEPT;
0f721c2f0 Piot*1433     fegetenv(&env);
1b7e93c4c Piot*1434     env._Fe_stat |= fenv_encode(flags, flags);
0f721c2f0 Piot*1435     return fesetenv(&env);
                1436 }
                1437 
fd0c03c64 Dani*1438 /*********************************************************************
                1439  *      feclearexcept (MSVCR120.@)
                1440  */
                1441 int CDECL feclearexcept(int flags)
                1442 {
                1443     fenv_t env;
                1444 
                1445     fegetenv(&env);
1b7e93c4c Piot*1446     flags &= FE_ALL_EXCEPT;
                1447     env._Fe_stat &= ~fenv_encode(flags, flags);
fd0c03c64 Dani*1448     return fesetenv(&env);
                1449 }
9fa81aab5 Dani*1450 
                1451 /*********************************************************************
                1452  *      fegetexceptflag (MSVCR120.@)
                1453  */
                1454 int CDECL fegetexceptflag(fexcept_t *status, int excepts)
                1455 {
90fd548d0 Piot*1456 #if _MSVCR_VER>=140 && defined(__i386__)
                1457     unsigned int x87, sse;
                1458     _statusfp2(&x87, &sse);
                1459     *status = fenv_encode(x87 & excepts, sse & excepts);
                1460 #else
2f9312fe5 Piot*1461     *status = fenv_encode(0, _statusfp() & excepts);
90fd548d0 Piot*1462 #endif
9fa81aab5 Dani*1463     return 0;
                1464 }
86597db83 Alex*1465 #endif
1150c0454 Piot*1466 
86597db83 Alex*1467 #if _MSVCR_VER>=140
6b6f3406f Piot*1468 /*********************************************************************
                1469  *      __fpe_flt_rounds (UCRTBASE.@)
                1470  */
                1471 int CDECL __fpe_flt_rounds(void)
                1472 {
467486030 Piot*1473     unsigned int fpc = _controlfp(0, 0) & _RC_CHOP;
6b6f3406f Piot*1474 
                1475     TRACE("()\n");
                1476 
                1477     switch(fpc) {
467486030 Piot*1478         case _RC_CHOP: return 0;
                1479         case _RC_NEAR: return 1;
                1480         case _RC_UP: return 2;
6b6f3406f Piot*1481         default: return 3;
                1482     }
                1483 }
86597db83 Alex*1484 #endif
                1485 
                1486 #if _MSVCR_VER>=120
6b6f3406f Piot*1487 
92651b985 Piot*1488 /*********************************************************************
                1489  *      fegetround (MSVCR120.@)
                1490  */
4f2f3545e Piot*1491 int CDECL fegetround(void)
92651b985 Piot*1492 {
bf859348a Piot*1493     return _controlfp(0, 0) & _MCW_RC;
92651b985 Piot*1494 }
                1495 
                1496 /*********************************************************************
                1497  *      fesetround (MSVCR120.@)
                1498  */
4f2f3545e Piot*1499 int CDECL fesetround(int round_mode)
92651b985 Piot*1500 {
bf859348a Piot*1501     if (round_mode & (~_MCW_RC))
92651b985 Piot*1502         return 1;
bf859348a Piot*1503     _controlfp(round_mode, _MCW_RC);
92651b985 Piot*1504     return 0;
                1505 }
                1506 
86597db83 Alex*1507 #endif /* _MSVCR_VER>=120 */
                1508 
1db20bfd3 Jon *1509 /*********************************************************************
                1510  *      _finite (MSVCRT.@)
                1511  */
4f2f3545e Piot*1512 int CDECL _finite(double num)
1db20bfd3 Jon *1513 {
9f088d019 Alex*1514     union { double f; UINT64 i; } u = { num };
                1515     return (u.i & ~0ull >> 1) < 0x7ffull << 52;
1db20bfd3 Jon *1516 }
                1517 
                1518 /*********************************************************************
                1519  *      _fpreset (MSVCRT.@)
                1520  */
24beabfd4 Alex*1521 void CDECL _fpreset(void)
1db20bfd3 Jon *1522 {
f53b2095f Piot*1523 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
c74f6ca57 Alex*1524     const unsigned int x86_cw = 0x27f;
                1525     __asm__ __volatile__( "fninit; fldcw %0" : : "m" (x86_cw) );
                1526     if (sse2_supported)
                1527     {
24fb503e2 Piot*1528         unsigned int cw = _MCW_EM, sw = 0;
                1529         _setfp_sse(&cw, ~0, &sw, ~0);
c74f6ca57 Alex*1530     }
a440e8aa8 Piot*1531 #else
f53b2095f Piot*1532     unsigned int cw = _MCW_EM, sw = 0;
f1ef14dc1 Piot*1533     _setfp(&cw, ~0, &sw, ~0);
1db20bfd3 Jon *1534 #endif
                1535 }
                1536 
86597db83 Alex*1537 #if _MSVCR_VER>=120
986a67ab3 Fabi*1538 /*********************************************************************
                1539  *              fesetenv (MSVCR120.@)
                1540  */
4f2f3545e Piot*1541 int CDECL fesetenv(const fenv_t *env)
986a67ab3 Fabi*1542 {
f1ef14dc1 Piot*1543     unsigned int x87_cw, cw, x87_stat, stat;
                1544     unsigned int mask;
98a0c3df2 Piot*1545 
                1546     TRACE( "(%p)\n", env );
                1547 
34422eb56 Alex*1548     if (!env->_Fe_ctl && !env->_Fe_stat) {
98a0c3df2 Piot*1549         _fpreset();
                1550         return 0;
                1551     }
                1552 
f1ef14dc1 Piot*1553     if (!fenv_decode(env->_Fe_ctl, &x87_cw, &cw))
1b7e93c4c Piot*1554         return 1;
f1ef14dc1 Piot*1555     if (!fenv_decode(env->_Fe_stat, &x87_stat, &stat))
1b7e93c4c Piot*1556         return 1;
                1557 
f1ef14dc1 Piot*1558 #if _MSVCR_VER >= 140
                1559     mask = ~0;
                1560 #else
                1561     mask = _EM_INEXACT | _EM_UNDERFLOW | _EM_OVERFLOW
                1562         | _EM_ZERODIVIDE | _EM_INVALID | _MCW_RC;
67c7c4035 Piot*1563 #endif
98a0c3df2 Piot*1564 
f1ef14dc1 Piot*1565 #ifdef __i386__
c521ec04c Piot*1566     _setfp(&x87_cw, mask, &x87_stat, ~0);
98a0c3df2 Piot*1567     if (sse2_supported)
c521ec04c Piot*1568         _setfp_sse(&cw, mask, &stat, ~0);
6391a9f89 Mart*1569     return 0;
f1ef14dc1 Piot*1570 #else
c521ec04c Piot*1571     _setfp(&cw, mask, &stat, ~0);
f1ef14dc1 Piot*1572     return 0;
                1573 #endif
986a67ab3 Fabi*1574 }
86597db83 Alex*1575 #endif
986a67ab3 Fabi*1576 
1db20bfd3 Jon *1577 /*********************************************************************
                1578  *      _isnan (MSVCRT.@)
                1579  */
4f2f3545e Piot*1580 int CDECL _isnan(double num)
1db20bfd3 Jon *1581 {
d6476e009 Alex*1582     union { double f; UINT64 i; } u = { num };
                1583     return (u.i & ~0ull >> 1) > 0x7ffull << 52;
1db20bfd3 Jon *1584 }
                1585 
86597db83 Alex*1586 #if _MSVCR_VER>=120
                1587 
554e7aee7 Alex*1588 /*********************************************************************
                1589  *      rint (MSVCR120.@)
                1590  */
                1591 double CDECL MSVCRT_rint(double x)
                1592 {
                1593     unsigned cw;
                1594     double y;
                1595 
                1596     cw = _controlfp(0, 0);
                1597     if ((cw & _MCW_PC) != _PC_53)
                1598         _controlfp(_PC_53, _MCW_PC);
                1599     y = rint(x);
                1600     if ((cw & _MCW_PC) != _PC_53)
                1601         _controlfp(cw, _MCW_PC);
                1602     return y;
                1603 }
                1604 
4d37b8721 Stef*1605 /*********************************************************************
86597db83 Alex*1606  *      _nearbyint (MSVCR120.@)
854a3cab4 Piot*1607  *
                1608  * Based on musl: src/math/nearbyteint.c
4d37b8721 Stef*1609  */
854a3cab4 Piot*1610 double CDECL nearbyint(double x)
4d37b8721 Stef*1611 {
5d9d195f4 Piot*1612     BOOL update_cw, update_sw;
                1613     unsigned int cw, sw;
854a3cab4 Piot*1614 
5d9d195f4 Piot*1615     _setfp(&cw, 0, &sw, 0);
                1616     update_cw = !(cw & _EM_INEXACT);
                1617     update_sw = !(sw & _SW_INEXACT);
                1618     if (update_cw)
                1619     {
                1620         cw |= _EM_INEXACT;
                1621         _setfp(&cw, _EM_INEXACT, NULL, 0);
                1622     }
554e7aee7 Alex*1623     x = MSVCRT_rint(x);
5d9d195f4 Piot*1624     if (update_cw || update_sw)
                1625     {
                1626         sw = 0;
                1627         cw &= ~_EM_INEXACT;
                1628         _setfp(update_cw ? &cw : NULL, _EM_INEXACT,
                1629                 update_sw ? &sw : NULL, _SW_INEXACT);
                1630     }
854a3cab4 Piot*1631     return x;
4d37b8721 Stef*1632 }
                1633 
                1634 /*********************************************************************
86597db83 Alex*1635  *      _nearbyintf (MSVCR120.@)
2caca4373 Piot*1636  *
                1637  * Based on musl: src/math/nearbyteintf.c
4d37b8721 Stef*1638  */
2caca4373 Piot*1639 float CDECL nearbyintf(float x)
4d37b8721 Stef*1640 {
201266769 Piot*1641     BOOL update_cw, update_sw;
                1642     unsigned int cw, sw;
2caca4373 Piot*1643 
201266769 Piot*1644     _setfp(&cw, 0, &sw, 0);
                1645     update_cw = !(cw & _EM_INEXACT);
                1646     update_sw = !(sw & _SW_INEXACT);
                1647     if (update_cw)
                1648     {
                1649         cw |= _EM_INEXACT;
                1650         _setfp(&cw, _EM_INEXACT, NULL, 0);
                1651     }
2caca4373 Piot*1652     x = rintf(x);
201266769 Piot*1653     if (update_cw || update_sw)
                1654     {
                1655         sw = 0;
                1656         cw &= ~_EM_INEXACT;
                1657         _setfp(update_cw ? &cw : NULL, _EM_INEXACT,
                1658                 update_sw ? &sw : NULL, _SW_INEXACT);
                1659     }
2caca4373 Piot*1660     return x;
4d37b8721 Stef*1661 }
                1662 
86597db83 Alex*1663 #endif /* _MSVCR_VER>=120 */
                1664 
961238367 Alex*1665 /*********************************************************************
                1666  *      _ecvt (MSVCRT.@)
                1667  */
4f2f3545e Piot*1668 char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
961238367 Alex*1669 {
fbe6b57b7 Andr*1670     int prec, len;
037746246 Dimi*1671     thread_data_t *data = msvcrt_get_thread_data();
7e309601f Fréd*1672     /* FIXME: check better for overflow (native supports over 300 chars) */
97b420224 Laur*1673     ndigits = min( ndigits, 80 - 8); /* 8 : space for sign, dec point, "e",
1ab5f4191 Rein*1674                                       * 4 for exponent and one for
                1675                                       * terminating '\0' */
961238367 Alex*1676     if (!data->efcvt_buffer)
d784dbb89 Piot*1677         data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
961238367 Alex*1678 
1ab5f4191 Rein*1679     /* handle cases with zero ndigits or less */
                1680     prec = ndigits;
                1681     if( prec < 1) prec = 2;
6ad42ee7f Piot*1682     len = _snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
97b420224 Laur*1683 
                1684     if (data->efcvt_buffer[0] == '-') {
                1685         memmove( data->efcvt_buffer, data->efcvt_buffer + 1, len-- );
                1686         *sign = 1;
                1687     } else *sign = 0;
                1688 
1ab5f4191 Rein*1689     /* take the decimal "point away */
                1690     if( prec != 1)
fbe6b57b7 Andr*1691         memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
1ab5f4191 Rein*1692     /* take the exponential "e" out */
                1693     data->efcvt_buffer[ prec] = '\0';
                1694     /* read the exponent */
a1662e3f7 Piot*1695     sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
1ab5f4191 Rein*1696     (*decpt)++;
                1697     /* adjust for some border cases */
                1698     if( data->efcvt_buffer[0] == '0')/* value is zero */
                1699         *decpt = 0;
                1700     /* handle cases with zero ndigits or less */
                1701     if( ndigits < 1){
                1702         if( data->efcvt_buffer[ 0] >= '5')
                1703             (*decpt)++;
                1704         data->efcvt_buffer[ 0] = '\0';
                1705     }
                1706     TRACE("out=\"%s\"\n",data->efcvt_buffer);
961238367 Alex*1707     return data->efcvt_buffer;
                1708 }
                1709 
1ade6c2bc Eryk*1710 /*********************************************************************
                1711  *      _ecvt_s (MSVCRT.@)
                1712  */
4f2f3545e Piot*1713 int CDECL _ecvt_s( char *buffer, size_t length, double number, int ndigits, int *decpt, int *sign )
1ade6c2bc Eryk*1714 {
                1715     int prec, len;
                1716     char *result;
                1717 
1317b935e Piot*1718     if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
                1719     if (!MSVCRT_CHECK_PMT(decpt != NULL)) return EINVAL;
                1720     if (!MSVCRT_CHECK_PMT(sign != NULL)) return EINVAL;
                1721     if (!MSVCRT_CHECK_PMT_ERR( length > 2, ERANGE )) return ERANGE;
                1722     if (!MSVCRT_CHECK_PMT_ERR(ndigits < (int)length - 1, ERANGE )) return ERANGE;
1ade6c2bc Eryk*1723 
f48cfa2be Piot*1724     /* handle cases with zero ndigits or less */
                1725     prec = ndigits;
                1726     if( prec < 1) prec = 2;
97b420224 Laur*1727     result = malloc(prec + 8);
                1728 
                1729     len = _snprintf(result, prec + 8, "%.*le", prec - 1, number);
                1730     if (result[0] == '-') {
                1731         memmove( result, result + 1, len-- );
                1732         *sign = 1;
                1733     } else *sign = 0;
                1734 
1ade6c2bc Eryk*1735     /* take the decimal "point away */
                1736     if( prec != 1)
                1737         memmove( result + 1, result + 2, len - 1 );
                1738     /* take the exponential "e" out */
                1739     result[ prec] = '\0';
                1740     /* read the exponent */
a1662e3f7 Piot*1741     sscanf( result + prec + 1, "%d", decpt);
1ade6c2bc Eryk*1742     (*decpt)++;
                1743     /* adjust for some border cases */
                1744     if( result[0] == '0')/* value is zero */
                1745         *decpt = 0;
                1746     /* handle cases with zero ndigits or less */
                1747     if( ndigits < 1){
                1748         if( result[ 0] >= '5')
                1749             (*decpt)++;
                1750         result[ 0] = '\0';
                1751     }
                1752     memcpy( buffer, result, max(ndigits + 1, 1) );
d784dbb89 Piot*1753     free( result );
1ade6c2bc Eryk*1754     return 0;
                1755 }
                1756 
961238367 Alex*1757 /***********************************************************************
                1758  *      _fcvt  (MSVCRT.@)
                1759  */
4f2f3545e Piot*1760 char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
961238367 Alex*1761 {
037746246 Dimi*1762     thread_data_t *data = msvcrt_get_thread_data();
260fd8a4a Karl*1763     int stop, dec1, dec2;
                1764     char *ptr1, *ptr2, *first;
                1765     char buf[80]; /* ought to be enough */
9a9319b05 Fabi*1766     char decimal_separator = get_locinfo()->lconv->decimal_point[0];
961238367 Alex*1767 
                1768     if (!data->efcvt_buffer)
d784dbb89 Piot*1769         data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
961238367 Alex*1770 
6ad42ee7f Piot*1771     stop = _snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
260fd8a4a Karl*1772     ptr1 = buf;
                1773     ptr2 = data->efcvt_buffer;
                1774     first = NULL;
                1775     dec1 = 0;
                1776     dec2 = 0;
                1777 
97b420224 Laur*1778     if (*ptr1 == '-') {
                1779         *sign = 1;
                1780         ptr1++;
                1781     } else *sign = 0;
                1782 
260fd8a4a Karl*1783     /* For numbers below the requested resolution, work out where
                1784        the decimal point will be rather than finding it in the string */
                1785     if (number < 1.0 && number > 0.0) {
4f2f3545e Piot*1786     dec2 = log10(number + 1e-10);
260fd8a4a Karl*1787     if (-dec2 <= ndigits) dec2 = 0;
                1788     }
                1789 
                1790     /* If requested digits is zero or less, we will need to truncate
                1791      * the returned string */
                1792     if (ndigits < 1) {
5f2b9d596 Carl*1793     stop += ndigits;
260fd8a4a Karl*1794     }
                1795 
                1796     while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
9a9319b05 Fabi*1797     while (*ptr1 != '\0' && *ptr1 != decimal_separator) {
260fd8a4a Karl*1798     if (!first) first = ptr2;
                1799     if ((ptr1 - buf) < stop) {
                1800         *ptr2++ = *ptr1++;
                1801     } else {
                1802         ptr1++;
                1803     }
                1804     dec1++;
                1805     }
                1806 
                1807     if (ndigits > 0) {
                1808     ptr1++;
                1809     if (!first) {
                1810         while (*ptr1 == '0') { /* Process leading zeroes */
                1811         *ptr2++ = *ptr1++;
                1812         dec1--;
                1813         }
                1814     }
                1815     while (*ptr1 != '\0') {
                1816         if (!first) first = ptr2;
                1817         *ptr2++ = *ptr1++;
                1818     }
                1819     }
                1820 
                1821     *ptr2 = '\0';
                1822 
                1823     /* We never found a non-zero digit, then our number is either
                1824      * smaller than the requested precision, or 0.0 */
                1825     if (!first) {
                1826     if (number > 0.0) {
                1827         first = ptr2;
                1828     } else {
                1829         first = data->efcvt_buffer;
                1830         dec1 = 0;
                1831     }
                1832     }
                1833 
                1834     *decpt = dec2 ? dec2 : dec1;
                1835     return first;
961238367 Alex*1836 }
                1837 
7a57f02b8 Niko*1838 /***********************************************************************
                1839  *      _fcvt_s  (MSVCRT.@)
                1840  */
4f2f3545e Piot*1841 int CDECL _fcvt_s(char* outbuffer, size_t size, double number, int ndigits, int *decpt, int *sign)
7a57f02b8 Niko*1842 {
                1843     int stop, dec1, dec2;
                1844     char *ptr1, *ptr2, *first;
                1845     char buf[80]; /* ought to be enough */
9a9319b05 Fabi*1846     char decimal_separator = get_locinfo()->lconv->decimal_point[0];
7a57f02b8 Niko*1847 
                1848     if (!outbuffer || !decpt || !sign || size == 0)
                1849     {
eeada5682 Piot*1850         *_errno() = EINVAL;
1317b935e Piot*1851         return EINVAL;
7a57f02b8 Niko*1852     }
                1853 
6ad42ee7f Piot*1854     stop = _snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
7a57f02b8 Niko*1855     ptr1 = buf;
                1856     ptr2 = outbuffer;
                1857     first = NULL;
                1858     dec1 = 0;
                1859     dec2 = 0;
                1860 
97b420224 Laur*1861     if (*ptr1 == '-') {
                1862         *sign = 1;
                1863         ptr1++;
                1864     } else *sign = 0;
                1865 
7a57f02b8 Niko*1866     /* For numbers below the requested resolution, work out where
                1867        the decimal point will be rather than finding it in the string */
                1868     if (number < 1.0 && number > 0.0) {
4f2f3545e Piot*1869     dec2 = log10(number + 1e-10);
7a57f02b8 Niko*1870     if (-dec2 <= ndigits) dec2 = 0;
                1871     }
                1872 
                1873     /* If requested digits is zero or less, we will need to truncate
                1874      * the returned string */
                1875     if (ndigits < 1) {
5f2b9d596 Carl*1876     stop += ndigits;
7a57f02b8 Niko*1877     }
                1878 
                1879     while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
9a9319b05 Fabi*1880     while (*ptr1 != '\0' && *ptr1 != decimal_separator) {
7a57f02b8 Niko*1881     if (!first) first = ptr2;
                1882     if ((ptr1 - buf) < stop) {
                1883         if (size > 1) {
                1884                 *ptr2++ = *ptr1++;
                1885                 size--;
                1886             }
                1887     } else {
                1888         ptr1++;
                1889     }
                1890     dec1++;
                1891     }
                1892 
                1893     if (ndigits > 0) {
                1894     ptr1++;
                1895     if (!first) {
                1896         while (*ptr1 == '0') { /* Process leading zeroes */
                1897                 if (number == 0.0 && size > 1) {
                1898                     *ptr2++ = '0';
                1899                     size--;
                1900                 }
                1901                 ptr1++;
                1902         dec1--;
                1903         }
                1904     }
                1905     while (*ptr1 != '\0') {
                1906         if (!first) first = ptr2;
                1907         if (size > 1) {
                1908                 *ptr2++ = *ptr1++;
                1909                 size--;
                1910             }
                1911     }
                1912     }
                1913 
                1914     *ptr2 = '\0';
                1915 
                1916     /* We never found a non-zero digit, then our number is either
                1917      * smaller than the requested precision, or 0.0 */
                1918     if (!first && (number <= 0.0))
                1919         dec1 = 0;
                1920 
                1921     *decpt = dec2 ? dec2 : dec1;
                1922     return 0;
                1923 }
                1924 
961238367 Alex*1925 /***********************************************************************
                1926  *      _gcvt  (MSVCRT.@)
                1927  */
4f2f3545e Piot*1928 char * CDECL _gcvt( double number, int ndigit, char *buff )
961238367 Alex*1929 {
3a25d7d9a Piot*1930     if(!buff) {
eeada5682 Piot*1931         *_errno() = EINVAL;
3a25d7d9a Piot*1932         return NULL;
                1933     }
                1934 
                1935     if(ndigit < 0) {
eeada5682 Piot*1936         *_errno() = ERANGE;
3a25d7d9a Piot*1937         return NULL;
                1938     }
                1939 
6ad42ee7f Piot*1940     sprintf(buff, "%.*g", ndigit, number);
961238367 Alex*1941     return buff;
                1942 }
                1943 
3a25d7d9a Piot*1944 /***********************************************************************
                1945  *              _gcvt_s  (MSVCRT.@)
                1946  */
4f2f3545e Piot*1947 int CDECL _gcvt_s(char *buff, size_t size, double number, int digits)
3a25d7d9a Piot*1948 {
                1949     int len;
                1950 
                1951     if(!buff) {
eeada5682 Piot*1952         *_errno() = EINVAL;
1317b935e Piot*1953         return EINVAL;
3a25d7d9a Piot*1954     }
                1955 
                1956     if( digits<0 || digits>=size) {
                1957         if(size)
                1958             buff[0] = '\0';
                1959 
eeada5682 Piot*1960         *_errno() = ERANGE;
1317b935e Piot*1961         return ERANGE;
3a25d7d9a Piot*1962     }
                1963 
6ad42ee7f Piot*1964     len = _scprintf("%.*g", digits, number);
3a25d7d9a Piot*1965     if(len > size) {
                1966         buff[0] = '\0';
eeada5682 Piot*1967         *_errno() = ERANGE;
1317b935e Piot*1968         return ERANGE;
3a25d7d9a Piot*1969     }
                1970 
6ad42ee7f Piot*1971     sprintf(buff, "%.*g", digits, number);
3a25d7d9a Piot*1972     return 0;
                1973 }
                1974 
1db20bfd3 Jon *1975 #include <stdlib.h> /* div_t, ldiv_t */
                1976 
                1977 /*********************************************************************
                1978  *      div (MSVCRT.@)
                1979  * VERSION
                1980  *  [i386] Windows binary compatible - returns the struct in eax/edx.
                1981  */
                1982 #ifdef __i386__
4f2f3545e Piot*1983 unsigned __int64 CDECL div(int num, int denom)
1db20bfd3 Jon *1984 {
75cdc3b60 Piot*1985     union {
0edef50df Alex*1986         div_t div;
75cdc3b60 Piot*1987         unsigned __int64 uint64;
                1988     } ret;
                1989 
                1990     ret.div.quot = num / denom;
                1991     ret.div.rem = num % denom;
                1992     return ret.uint64;
1db20bfd3 Jon *1993 }
                1994 #else
                1995 /*********************************************************************
                1996  *      div (MSVCRT.@)
                1997  * VERSION
                1998  *  [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
                1999  */
4f2f3545e Piot*2000 div_t CDECL div(int num, int denom)
1db20bfd3 Jon *2001 {
0edef50df Alex*2002     div_t ret;
c43b5c8f1 Warr*2003 
75cdc3b60 Piot*2004     ret.quot = num / denom;
                2005     ret.rem = num % denom;
                2006     return ret;
1db20bfd3 Jon *2007 }
                2008 #endif /* ifdef __i386__ */
                2009 
                2010 
                2011 /*********************************************************************
                2012  *      ldiv (MSVCRT.@)
                2013  * VERSION
                2014  *  [i386] Windows binary compatible - returns the struct in eax/edx.
                2015  */
                2016 #ifdef __i386__
4f2f3545e Piot*2017 unsigned __int64 CDECL ldiv(__msvcrt_long num, __msvcrt_long denom)
1db20bfd3 Jon *2018 {
75cdc3b60 Piot*2019     union {
0edef50df Alex*2020         ldiv_t ldiv;
75cdc3b60 Piot*2021         unsigned __int64 uint64;
                2022     } ret;
                2023 
                2024     ret.ldiv.quot = num / denom;
                2025     ret.ldiv.rem = num % denom;
                2026     return ret.uint64;
1db20bfd3 Jon *2027 }
                2028 #else
                2029 /*********************************************************************
                2030  *      ldiv (MSVCRT.@)
                2031  * VERSION
                2032  *  [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
                2033  */
4f2f3545e Piot*2034 ldiv_t CDECL ldiv(__msvcrt_long num, __msvcrt_long denom)
1db20bfd3 Jon *2035 {
0edef50df Alex*2036     ldiv_t ret;
c43b5c8f1 Warr*2037 
75cdc3b60 Piot*2038     ret.quot = num / denom;
                2039     ret.rem = num % denom;
                2040     return ret;
1db20bfd3 Jon *2041 }
                2042 #endif /* ifdef __i386__ */
                2043 
86597db83 Alex*2044 #if _MSVCR_VER>=100
60c98caa9 Jace*2045 /*********************************************************************
86597db83 Alex*2046  *      lldiv (MSVCR100.@)
60c98caa9 Jace*2047  */
4f2f3545e Piot*2048 lldiv_t CDECL lldiv(__int64 num, __int64 denom)
60c98caa9 Jace*2049 {
0edef50df Alex*2050   lldiv_t ret;
0a835c8da Serg*2051 
                2052   ret.quot = num / denom;
                2053   ret.rem = num % denom;
60c98caa9 Jace*2054 
                2055   return ret;
                2056 }
86597db83 Alex*2057 #endif
60c98caa9 Jace*2058 
f2b3df637 Alex*2059 #ifdef __i386__
                2060 
                2061 /*********************************************************************
                2062  *      _adjust_fdiv (MSVCRT.@)
                2063  * Used by the MSVC compiler to work around the Pentium FDIV bug.
                2064  */
                2065 int MSVCRT__adjust_fdiv = 0;
                2066 
4fb3aa5fc Patr*2067 /***********************************************************************
                2068  *      _adj_fdiv_m16i (MSVCRT.@)
                2069  *
                2070  * NOTE
                2071  *    I _think_ this function is intended to work around the Pentium
                2072  *    fdiv bug.
                2073  */
8f7c2bc6a Alex*2074 void __stdcall _adj_fdiv_m16i( short arg )
4fb3aa5fc Patr*2075 {
e76218dd6 Fran*2076   TRACE("(): stub\n");
4fb3aa5fc Patr*2077 }
                2078 
                2079 /***********************************************************************
                2080  *      _adj_fdiv_m32 (MSVCRT.@)
                2081  *
                2082  * NOTE
                2083  *    I _think_ this function is intended to work around the Pentium
                2084  *    fdiv bug.
                2085  */
8f7c2bc6a Alex*2086 void __stdcall _adj_fdiv_m32( unsigned int arg )
4fb3aa5fc Patr*2087 {
e76218dd6 Fran*2088   TRACE("(): stub\n");
4fb3aa5fc Patr*2089 }
                2090 
                2091 /***********************************************************************
                2092  *      _adj_fdiv_m32i (MSVCRT.@)
                2093  *
                2094  * NOTE
                2095  *    I _think_ this function is intended to work around the Pentium
                2096  *    fdiv bug.
                2097  */
8f7c2bc6a Alex*2098 void __stdcall _adj_fdiv_m32i( int arg )
4fb3aa5fc Patr*2099 {
e76218dd6 Fran*2100   TRACE("(): stub\n");
4fb3aa5fc Patr*2101 }
                2102 
                2103 /***********************************************************************
                2104  *      _adj_fdiv_m64 (MSVCRT.@)
                2105  *
                2106  * NOTE
                2107  *    I _think_ this function is intended to work around the Pentium
                2108  *    fdiv bug.
                2109  */
8f7c2bc6a Alex*2110 void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
4fb3aa5fc Patr*2111 {
e76218dd6 Fran*2112   TRACE("(): stub\n");
4fb3aa5fc Patr*2113 }
                2114 
                2115 /***********************************************************************
                2116  *      _adj_fdiv_r (MSVCRT.@)
                2117  * FIXME
                2118  *    This function is likely to have the wrong number of arguments.
                2119  *
                2120  * NOTE
                2121  *    I _think_ this function is intended to work around the Pentium
                2122  *    fdiv bug.
                2123  */
203a8f829 Fran*2124 void _adj_fdiv_r(void)
4fb3aa5fc Patr*2125 {
e76218dd6 Fran*2126   TRACE("(): stub\n");
4fb3aa5fc Patr*2127 }
                2128 
                2129 /***********************************************************************
                2130  *      _adj_fdivr_m16i (MSVCRT.@)
                2131  *
                2132  * NOTE
                2133  *    I _think_ this function is intended to work around the Pentium
                2134  *    fdiv bug.
                2135  */
8f7c2bc6a Alex*2136 void __stdcall _adj_fdivr_m16i( short arg )
4fb3aa5fc Patr*2137 {
e76218dd6 Fran*2138   TRACE("(): stub\n");
4fb3aa5fc Patr*2139 }
                2140 
                2141 /***********************************************************************
                2142  *      _adj_fdivr_m32 (MSVCRT.@)
                2143  *
                2144  * NOTE
                2145  *    I _think_ this function is intended to work around the Pentium
                2146  *    fdiv bug.
                2147  */
8f7c2bc6a Alex*2148 void __stdcall _adj_fdivr_m32( unsigned int arg )
4fb3aa5fc Patr*2149 {
e76218dd6 Fran*2150   TRACE("(): stub\n");
4fb3aa5fc Patr*2151 }
                2152 
                2153 /***********************************************************************
                2154  *      _adj_fdivr_m32i (MSVCRT.@)
                2155  *
                2156  * NOTE
                2157  *    I _think_ this function is intended to work around the Pentium
                2158  *    fdiv bug.
                2159  */
8f7c2bc6a Alex*2160 void __stdcall _adj_fdivr_m32i( int arg )
4fb3aa5fc Patr*2161 {
e76218dd6 Fran*2162   TRACE("(): stub\n");
4fb3aa5fc Patr*2163 }
                2164 
                2165 /***********************************************************************
                2166  *      _adj_fdivr_m64 (MSVCRT.@)
                2167  *
                2168  * NOTE
                2169  *    I _think_ this function is intended to work around the Pentium
                2170  *    fdiv bug.
                2171  */
8f7c2bc6a Alex*2172 void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
4fb3aa5fc Patr*2173 {
e76218dd6 Fran*2174   TRACE("(): stub\n");
4fb3aa5fc Patr*2175 }
                2176 
                2177 /***********************************************************************
                2178  *      _adj_fpatan (MSVCRT.@)
                2179  * FIXME
                2180  *    This function is likely to have the wrong number of arguments.
                2181  *
                2182  * NOTE
                2183  *    I _think_ this function is intended to work around the Pentium
                2184  *    fdiv bug.
                2185  */
203a8f829 Fran*2186 void _adj_fpatan(void)
4fb3aa5fc Patr*2187 {
e76218dd6 Fran*2188   TRACE("(): stub\n");
4fb3aa5fc Patr*2189 }
                2190 
                2191 /***********************************************************************
                2192  *      _adj_fprem (MSVCRT.@)
                2193  * FIXME
                2194  *    This function is likely to have the wrong number of arguments.
                2195  *
                2196  * NOTE
                2197  *    I _think_ this function is intended to work around the Pentium
                2198  *    fdiv bug.
                2199  */
203a8f829 Fran*2200 void _adj_fprem(void)
4fb3aa5fc Patr*2201 {
e76218dd6 Fran*2202   TRACE("(): stub\n");
4fb3aa5fc Patr*2203 }
                2204 
                2205 /***********************************************************************
                2206  *      _adj_fprem1 (MSVCRT.@)
                2207  * FIXME
                2208  *    This function is likely to have the wrong number of arguments.
                2209  *
                2210  * NOTE
                2211  *    I _think_ this function is intended to work around the Pentium
                2212  *    fdiv bug.
                2213  */
203a8f829 Fran*2214 void _adj_fprem1(void)
4fb3aa5fc Patr*2215 {
e76218dd6 Fran*2216   TRACE("(): stub\n");
4fb3aa5fc Patr*2217 }
                2218 
                2219 /***********************************************************************
                2220  *      _adj_fptan (MSVCRT.@)
                2221  * FIXME
                2222  *    This function is likely to have the wrong number of arguments.
                2223  *
                2224  * NOTE
                2225  *    I _think_ this function is intended to work around the Pentium
                2226  *    fdiv bug.
                2227  */
203a8f829 Fran*2228 void _adj_fptan(void)
4fb3aa5fc Patr*2229 {
e76218dd6 Fran*2230   TRACE("(): stub\n");
4fb3aa5fc Patr*2231 }
                2232 
                2233 /***********************************************************************
                2234  *      _safe_fdiv (MSVCRT.@)
                2235  * FIXME
                2236  *    This function is likely to have the wrong number of arguments.
                2237  *
                2238  * NOTE
                2239  *    I _think_ this function is intended to work around the Pentium
                2240  *    fdiv bug.
                2241  */
203a8f829 Fran*2242 void _safe_fdiv(void)
4fb3aa5fc Patr*2243 {
e76218dd6 Fran*2244   TRACE("(): stub\n");
4fb3aa5fc Patr*2245 }
                2246 
                2247 /***********************************************************************
                2248  *      _safe_fdivr (MSVCRT.@)
                2249  * FIXME
                2250  *    This function is likely to have the wrong number of arguments.
                2251  *
                2252  * NOTE
                2253  *    I _think_ this function is intended to work around the Pentium
                2254  *    fdiv bug.
                2255  */
203a8f829 Fran*2256 void _safe_fdivr(void)
4fb3aa5fc Patr*2257 {
e76218dd6 Fran*2258   TRACE("(): stub\n");
4fb3aa5fc Patr*2259 }
                2260 
                2261 /***********************************************************************
                2262  *      _safe_fprem (MSVCRT.@)
                2263  * FIXME
                2264  *    This function is likely to have the wrong number of arguments.
                2265  *
                2266  * NOTE
                2267  *    I _think_ this function is intended to work around the Pentium
                2268  *    fdiv bug.
                2269  */
203a8f829 Fran*2270 void _safe_fprem(void)
4fb3aa5fc Patr*2271 {
e76218dd6 Fran*2272   TRACE("(): stub\n");
4fb3aa5fc Patr*2273 }
                2274 
                2275 /***********************************************************************
                2276  *      _safe_fprem1 (MSVCRT.@)
                2277  *
                2278  * FIXME
                2279  *    This function is likely to have the wrong number of arguments.
                2280  *
                2281  * NOTE
                2282  *    I _think_ this function is intended to work around the Pentium
                2283  *    fdiv bug.
                2284  */
203a8f829 Fran*2285 void _safe_fprem1(void)
4fb3aa5fc Patr*2286 {
e76218dd6 Fran*2287   TRACE("(): stub\n");
4fb3aa5fc Patr*2288 }
f2b3df637 Alex*2289 
7c95b251e Alex*2290 /***********************************************************************
                2291  *      __libm_sse2_acos   (MSVCRT.@)
                2292  */
4f2f3545e Piot*2293 void __cdecl __libm_sse2_acos(void)
7c95b251e Alex*2294 {
                2295     double d;
                2296     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2297     d = acos( d );
7c95b251e Alex*2298     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2299 }
                2300 
                2301 /***********************************************************************
                2302  *      __libm_sse2_acosf   (MSVCRT.@)
                2303  */
4f2f3545e Piot*2304 void __cdecl __libm_sse2_acosf(void)
7c95b251e Alex*2305 {
                2306     float f;
                2307     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2308     f = acosf( f );
7c95b251e Alex*2309     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2310 }
                2311 
                2312 /***********************************************************************
                2313  *      __libm_sse2_asin   (MSVCRT.@)
                2314  */
4f2f3545e Piot*2315 void __cdecl __libm_sse2_asin(void)
7c95b251e Alex*2316 {
                2317     double d;
                2318     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2319     d = asin( d );
7c95b251e Alex*2320     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2321 }
                2322 
                2323 /***********************************************************************
                2324  *      __libm_sse2_asinf   (MSVCRT.@)
                2325  */
4f2f3545e Piot*2326 void __cdecl __libm_sse2_asinf(void)
7c95b251e Alex*2327 {
                2328     float f;
                2329     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2330     f = asinf( f );
7c95b251e Alex*2331     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2332 }
                2333 
                2334 /***********************************************************************
                2335  *      __libm_sse2_atan   (MSVCRT.@)
                2336  */
4f2f3545e Piot*2337 void __cdecl __libm_sse2_atan(void)
7c95b251e Alex*2338 {
                2339     double d;
                2340     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2341     d = atan( d );
7c95b251e Alex*2342     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2343 }
                2344 
                2345 /***********************************************************************
                2346  *      __libm_sse2_atan2   (MSVCRT.@)
                2347  */
4f2f3545e Piot*2348 void __cdecl __libm_sse2_atan2(void)
7c95b251e Alex*2349 {
                2350     double d1, d2;
                2351     __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
4f2f3545e Piot*2352     d1 = atan2( d1, d2 );
7c95b251e Alex*2353     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
                2354 }
                2355 
                2356 /***********************************************************************
                2357  *      __libm_sse2_atanf   (MSVCRT.@)
                2358  */
4f2f3545e Piot*2359 void __cdecl __libm_sse2_atanf(void)
7c95b251e Alex*2360 {
                2361     float f;
                2362     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2363     f = atanf( f );
7c95b251e Alex*2364     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2365 }
                2366 
                2367 /***********************************************************************
                2368  *      __libm_sse2_cos   (MSVCRT.@)
                2369  */
4f2f3545e Piot*2370 void __cdecl __libm_sse2_cos(void)
7c95b251e Alex*2371 {
                2372     double d;
                2373     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2374     d = cos( d );
7c95b251e Alex*2375     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2376 }
                2377 
                2378 /***********************************************************************
                2379  *      __libm_sse2_cosf   (MSVCRT.@)
                2380  */
4f2f3545e Piot*2381 void __cdecl __libm_sse2_cosf(void)
7c95b251e Alex*2382 {
                2383     float f;
                2384     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2385     f = cosf( f );
7c95b251e Alex*2386     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2387 }
                2388 
                2389 /***********************************************************************
                2390  *      __libm_sse2_exp   (MSVCRT.@)
                2391  */
4f2f3545e Piot*2392 void __cdecl __libm_sse2_exp(void)
7c95b251e Alex*2393 {
                2394     double d;
                2395     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2396     d = exp( d );
7c95b251e Alex*2397     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2398 }
                2399 
                2400 /***********************************************************************
                2401  *      __libm_sse2_expf   (MSVCRT.@)
                2402  */
4f2f3545e Piot*2403 void __cdecl __libm_sse2_expf(void)
7c95b251e Alex*2404 {
                2405     float f;
                2406     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2407     f = expf( f );
7c95b251e Alex*2408     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2409 }
                2410 
                2411 /***********************************************************************
                2412  *      __libm_sse2_log   (MSVCRT.@)
                2413  */
4f2f3545e Piot*2414 void __cdecl __libm_sse2_log(void)
7c95b251e Alex*2415 {
                2416     double d;
                2417     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2418     d = log( d );
7c95b251e Alex*2419     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2420 }
                2421 
                2422 /***********************************************************************
                2423  *      __libm_sse2_log10   (MSVCRT.@)
                2424  */
4f2f3545e Piot*2425 void __cdecl __libm_sse2_log10(void)
7c95b251e Alex*2426 {
                2427     double d;
                2428     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2429     d = log10( d );
7c95b251e Alex*2430     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2431 }
                2432 
                2433 /***********************************************************************
                2434  *      __libm_sse2_log10f   (MSVCRT.@)
                2435  */
4f2f3545e Piot*2436 void __cdecl __libm_sse2_log10f(void)
7c95b251e Alex*2437 {
                2438     float f;
                2439     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2440     f = log10f( f );
7c95b251e Alex*2441     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2442 }
                2443 
                2444 /***********************************************************************
                2445  *      __libm_sse2_logf   (MSVCRT.@)
                2446  */
4f2f3545e Piot*2447 void __cdecl __libm_sse2_logf(void)
7c95b251e Alex*2448 {
                2449     float f;
                2450     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2451     f = logf( f );
7c95b251e Alex*2452     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2453 }
                2454 
                2455 /***********************************************************************
                2456  *      __libm_sse2_pow   (MSVCRT.@)
                2457  */
4f2f3545e Piot*2458 void __cdecl __libm_sse2_pow(void)
7c95b251e Alex*2459 {
                2460     double d1, d2;
                2461     __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
4f2f3545e Piot*2462     d1 = pow( d1, d2 );
7c95b251e Alex*2463     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
                2464 }
                2465 
                2466 /***********************************************************************
                2467  *      __libm_sse2_powf   (MSVCRT.@)
                2468  */
4f2f3545e Piot*2469 void __cdecl __libm_sse2_powf(void)
7c95b251e Alex*2470 {
                2471     float f1, f2;
                2472     __asm__ __volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1), "=g" (f2) );
4f2f3545e Piot*2473     f1 = powf( f1, f2 );
7c95b251e Alex*2474     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f1) );
                2475 }
                2476 
                2477 /***********************************************************************
                2478  *      __libm_sse2_sin   (MSVCRT.@)
                2479  */
4f2f3545e Piot*2480 void __cdecl __libm_sse2_sin(void)
7c95b251e Alex*2481 {
                2482     double d;
                2483     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2484     d = sin( d );
7c95b251e Alex*2485     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2486 }
                2487 
                2488 /***********************************************************************
                2489  *      __libm_sse2_sinf   (MSVCRT.@)
                2490  */
4f2f3545e Piot*2491 void __cdecl __libm_sse2_sinf(void)
7c95b251e Alex*2492 {
                2493     float f;
                2494     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2495     f = sinf( f );
7c95b251e Alex*2496     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2497 }
                2498 
                2499 /***********************************************************************
                2500  *      __libm_sse2_tan   (MSVCRT.@)
                2501  */
4f2f3545e Piot*2502 void __cdecl __libm_sse2_tan(void)
7c95b251e Alex*2503 {
                2504     double d;
                2505     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
4f2f3545e Piot*2506     d = tan( d );
7c95b251e Alex*2507     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2508 }
                2509 
                2510 /***********************************************************************
                2511  *      __libm_sse2_tanf   (MSVCRT.@)
                2512  */
4f2f3545e Piot*2513 void __cdecl __libm_sse2_tanf(void)
7c95b251e Alex*2514 {
                2515     float f;
                2516     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
4f2f3545e Piot*2517     f = tanf( f );
7c95b251e Alex*2518     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
                2519 }
                2520 
0c496f028 Alex*2521 /***********************************************************************
                2522  *      __libm_sse2_sqrt_precise   (MSVCR110.@)
                2523  */
4f2f3545e Piot*2524 void __cdecl __libm_sse2_sqrt_precise(void)
07566faac Piot*2525 {
e3772c917 Piot*2526     unsigned int cw;
07566faac Piot*2527     double d;
e3772c917 Piot*2528 
153965b62 Piot*2529     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
e3772c917 Piot*2530     __control87_2(0, 0, NULL, &cw);
                2531     if (cw & _MCW_RC)
                2532     {
                2533         d = sqrt(d);
                2534         __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2535         return;
                2536     }
07566faac Piot*2537 
e3772c917 Piot*2538     if (!sqrt_validate(&d, FALSE))
                2539     {
                2540         __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
                2541         return;
                2542     }
                2543     __asm__ __volatile__( "call " __ASM_NAME( "sse2_sqrt" ) );
                2544 }
f2b3df637 Alex*2545 #endif  /* __i386__ */
547ba7a10 Mart*2546 
d5fb71553 Piot*2547 #if _MSVCR_VER>=120
                2548 
547ba7a10 Mart*2549 /*********************************************************************
                2550  *      lrint (MSVCR120.@)
                2551  */
4f2f3545e Piot*2552 __msvcrt_long CDECL lrint(double x)
547ba7a10 Mart*2553 {
0838c995e Piot*2554     double d;
                2555 
554e7aee7 Alex*2556     d = MSVCRT_rint(x);
0838c995e Piot*2557     if ((d < 0 && d != (double)(__msvcrt_long)d)
                2558             || (d >= 0 && d != (double)(__msvcrt_ulong)d)) {
                2559         *_errno() = EDOM;
                2560         return 0;
                2561     }
                2562     return d;
547ba7a10 Mart*2563 }
                2564 
                2565 /*********************************************************************
                2566  *      lrintf (MSVCR120.@)
                2567  */
4f2f3545e Piot*2568 __msvcrt_long CDECL lrintf(float x)
547ba7a10 Mart*2569 {
aa2248164 Piot*2570     float f;
                2571 
                2572     f = rintf(x);
                2573     if ((f < 0 && f != (float)(__msvcrt_long)f)
                2574             || (f >= 0 && f != (float)(__msvcrt_ulong)f)) {
                2575         *_errno() = EDOM;
                2576         return 0;
                2577     }
                2578     return f;
547ba7a10 Mart*2579 }
                2580 
                2581 /*********************************************************************
                2582  *      llrint (MSVCR120.@)
                2583  */
4f2f3545e Piot*2584 __int64 CDECL llrint(double x)
547ba7a10 Mart*2585 {
45586c570 Piot*2586     double d;
                2587 
554e7aee7 Alex*2588     d = MSVCRT_rint(x);
45586c570 Piot*2589     if ((d < 0 && d != (double)(__int64)d)
                2590             || (d >= 0 && d != (double)(unsigned __int64)d)) {
                2591         *_errno() = EDOM;
                2592         return 0;
                2593     }
                2594     return d;
547ba7a10 Mart*2595 }
                2596 
                2597 /*********************************************************************
                2598  *      llrintf (MSVCR120.@)
                2599  */
4f2f3545e Piot*2600 __int64 CDECL llrintf(float x)
547ba7a10 Mart*2601 {
0cdc52c65 Piot*2602     float f;
                2603 
                2604     f = rintf(x);
                2605     if ((f < 0 && f != (float)(__int64)f)
                2606             || (f >= 0 && f != (float)(unsigned __int64)f)) {
                2607         *_errno() = EDOM;
                2608         return 0;
                2609     }
                2610     return f;
547ba7a10 Mart*2611 }
                2612 
                2613 /*********************************************************************
                2614  *      lround (MSVCR120.@)
69ad3c11c Piot*2615  *
                2616  * Copied from musl: src/math/lround.c
547ba7a10 Mart*2617  */
4f2f3545e Piot*2618 __msvcrt_long CDECL lround(double x)
547ba7a10 Mart*2619 {
69ad3c11c Piot*2620     double d = round(x);
                2621     if (d != (double)(__msvcrt_long)d) {
                2622         *_errno() = EDOM;
                2623         return 0;
                2624     }
                2625     return d;
547ba7a10 Mart*2626 }
                2627 
                2628 /*********************************************************************
                2629  *      lroundf (MSVCR120.@)
7fa8b03cd Piot*2630  *
                2631  * Copied from musl: src/math/lroundf.c
547ba7a10 Mart*2632  */
4f2f3545e Piot*2633 __msvcrt_long CDECL lroundf(float x)
547ba7a10 Mart*2634 {
7fa8b03cd Piot*2635     float f = roundf(x);
                2636     if (f != (float)(__msvcrt_long)f) {
                2637         *_errno() = EDOM;
                2638         return 0;
                2639     }
                2640     return f;
547ba7a10 Mart*2641 }
                2642 
                2643 /*********************************************************************
                2644  *      llround (MSVCR120.@)
389e0532f Piot*2645  *
                2646  * Copied from musl: src/math/llround.c
547ba7a10 Mart*2647  */
4f2f3545e Piot*2648 __int64 CDECL llround(double x)
547ba7a10 Mart*2649 {
389e0532f Piot*2650     double d = round(x);
                2651     if (d != (double)(__int64)d) {
                2652         *_errno() = EDOM;
                2653         return 0;
                2654     }
                2655     return d;
547ba7a10 Mart*2656 }
                2657 
                2658 /*********************************************************************
                2659  *      llroundf (MSVCR120.@)
668cf2e66 Piot*2660  *
                2661  * Copied from musl: src/math/llroundf.c
547ba7a10 Mart*2662  */
4f2f3545e Piot*2663 __int64 CDECL llroundf(float x)
547ba7a10 Mart*2664 {
668cf2e66 Piot*2665     float f = roundf(x);
                2666     if (f != (float)(__int64)f) {
                2667         *_errno() = EDOM;
                2668         return 0;
                2669     }
                2670     return f;
547ba7a10 Mart*2671 }
                2672 
1109672f1 Piot*2673 /*********************************************************************
                2674  *      _dtest (MSVCR120.@)
                2675  */
4f2f3545e Piot*2676 short CDECL _dtest(double *x)
1109672f1 Piot*2677 {
4f2f3545e Piot*2678     return _dclass(*x);
1109672f1 Piot*2679 }
                2680 
                2681 /*********************************************************************
                2682  *      _fdtest (MSVCR120.@)
                2683  */
4f2f3545e Piot*2684 short CDECL _fdtest(float *x)
1109672f1 Piot*2685 {
4f2f3545e Piot*2686     return _fdclass(*x);
1109672f1 Piot*2687 }
                2688 
530d269e0 Piot*2689 /*********************************************************************
                2690  *      _fdsign (MSVCR120.@)
                2691  */
4f2f3545e Piot*2692 int CDECL _fdsign(float x)
530d269e0 Piot*2693 {
4619140b1 Alex*2694     union { float f; UINT32 i; } u = { x };
                2695     return (u.i >> 16) & 0x8000;
530d269e0 Piot*2696 }
                2697 
                2698 /*********************************************************************
                2699  *      _dsign (MSVCR120.@)
                2700  */
4f2f3545e Piot*2701 int CDECL _dsign(double x)
530d269e0 Piot*2702 {
4619140b1 Alex*2703     union { double f; UINT64 i; } u = { x };
                2704     return (u.i >> 48) & 0x8000;
530d269e0 Piot*2705 }
09a727c33 Piot*2706 
4083af404 Piot*2707 /*********************************************************************
                2708  *      _dpcomp (MSVCR120.@)
                2709  */
4f2f3545e Piot*2710 int CDECL _dpcomp(double x, double y)
4083af404 Piot*2711 {
                2712     if(isnan(x) || isnan(y))
                2713         return 0;
                2714 
                2715     if(x == y) return 2;
                2716     return x < y ? 1 : 4;
                2717 }
                2718 
                2719 /*********************************************************************
                2720  *      _fdpcomp (MSVCR120.@)
                2721  */
4f2f3545e Piot*2722 int CDECL _fdpcomp(float x, float y)
4083af404 Piot*2723 {
4f2f3545e Piot*2724     return _dpcomp(x, y);
4083af404 Piot*2725 }
                2726 
f1dad1480 Alex*2727 /*********************************************************************
                2728  *      acosh (MSVCR120.@)
                2729  */
e2924fafd Alex*2730 double CDECL MSVCRT_acosh(double x)
f1dad1480 Alex*2731 {
c72e1b096 Alex*2732     if (x < 1)
                2733     {
eeada5682 Piot*2734         *_errno() = EDOM;
593ddf0b6 Piot*2735         feraiseexcept(FE_INVALID);
f1dad1480 Alex*2736         return NAN;
                2737     }
e2924fafd Alex*2738     return acosh( x );
f1dad1480 Alex*2739 }
                2740 
                2741 /*********************************************************************
                2742  *      acoshf (MSVCR120.@)
                2743  */
e2924fafd Alex*2744 float CDECL MSVCRT_acoshf(float x)
f1dad1480 Alex*2745 {
c72e1b096 Alex*2746     if (x < 1)
                2747     {
eeada5682 Piot*2748         *_errno() = EDOM;
593ddf0b6 Piot*2749         feraiseexcept(FE_INVALID);
c72e1b096 Alex*2750         return NAN;
                2751     }
e2924fafd Alex*2752     return acoshf( x );
f1dad1480 Alex*2753 }
                2754 
860c1578e Alex*2755 /*********************************************************************
                2756  *      atanh (MSVCR120.@)
                2757  */
4ffb1199e Alex*2758 double CDECL MSVCRT_atanh(double x)
860c1578e Alex*2759 {
4ffb1199e Alex*2760     if (fabs(x) > 1)
                2761     {
eeada5682 Piot*2762         *_errno() = EDOM;
593ddf0b6 Piot*2763         feraiseexcept(FE_INVALID);
860c1578e Alex*2764         return NAN;
                2765     }
4ffb1199e Alex*2766     return atanh( x );
860c1578e Alex*2767 }
                2768 
                2769 /*********************************************************************
                2770  *      atanhf (MSVCR120.@)
                2771  */
4ffb1199e Alex*2772 float CDECL MSVCRT_atanhf(float x)
860c1578e Alex*2773 {
4ffb1199e Alex*2774     if (fabs(x) > 1)
                2775     {
eeada5682 Piot*2776         *_errno() = EDOM;
593ddf0b6 Piot*2777         feraiseexcept(FE_INVALID);
860c1578e Alex*2778         return NAN;
                2779     }
4ffb1199e Alex*2780     return atanhf( x );
860c1578e Alex*2781 }
                2782 
86597db83 Alex*2783 #endif /* _MSVCR_VER>=120 */
                2784 
9acfcb0eb Dani*2785 /*********************************************************************
                2786  *      _scalb  (MSVCRT.@)
                2787  *      scalbn  (MSVCR120.@)
                2788  *      scalbln (MSVCR120.@)
                2789  */
4f2f3545e Piot*2790 double CDECL _scalb(double num, __msvcrt_long power)
9acfcb0eb Dani*2791 {
4f2f3545e Piot*2792   return ldexp(num, power);
9acfcb0eb Dani*2793 }
                2794 
                2795 /*********************************************************************
                2796  *      _scalbf  (MSVCRT.@)
                2797  *      scalbnf  (MSVCR120.@)
                2798  *      scalblnf (MSVCR120.@)
                2799  */
4f2f3545e Piot*2800 float CDECL _scalbf(float num, __msvcrt_long power)
9acfcb0eb Dani*2801 {
4f2f3545e Piot*2802   return ldexp(num, power);
9acfcb0eb Dani*2803 }
                2804 
3b1e2a7bf Alex*2805 #if _MSVCR_VER == 120 /* other versions call remainder() directly */
86597db83 Alex*2806 
d9a0c55e7 Dani*2807 /*********************************************************************
                2808  *      remainder (MSVCR120.@)
                2809  */
3b1e2a7bf Alex*2810 double CDECL MSVCRT_remainder(double x, double y)
d9a0c55e7 Dani*2811 {
3b1e2a7bf Alex*2812 #ifdef __x86_64__
fd22e3b61 Piot*2813     if (isnan(x) || isnan(y)) *_errno() = EDOM;
                2814 #endif
3b1e2a7bf Alex*2815     return remainder(x, y);
d9a0c55e7 Dani*2816 }
                2817 
                2818 /*********************************************************************
                2819  *      remainderf (MSVCR120.@)
                2820  */
3b1e2a7bf Alex*2821 float CDECL MSVCRT_remainderf(float x, float y)
d9a0c55e7 Dani*2822 {
3b1e2a7bf Alex*2823 #ifdef __x86_64__
b48e80a52 Piot*2824     if (isnan(x) || isnan(y)) *_errno() = EDOM;
                2825 #endif
3b1e2a7bf Alex*2826     return remainderf(x, y);
d9a0c55e7 Dani*2827 }
                2828 
3b1e2a7bf Alex*2829 #endif /* _MSVCR_VER == 120 */
                2830 
                2831 #if _MSVCR_VER>=120
                2832 
10200af74 Piot*2833 /*********************************************************************
                2834  *      _except1 (MSVCR120.@)
                2835  *  TODO:
                2836  *   - find meaning of ignored cw and operation bits
                2837  *   - unk parameter
                2838  */
                2839 double CDECL _except1(DWORD fpe, _FP_OPERATION_CODE op, double arg, double res, DWORD cw, void *unk)
                2840 {
                2841     ULONG_PTR exception_arg;
                2842     DWORD exception = 0;
948f465da Eric*2843     unsigned int fpword = 0;
10200af74 Piot*2844     WORD operation;
29cbb60f6 Piot*2845     int raise = 0;
10200af74 Piot*2846 
9b802a3d5 Eric*2847     TRACE("(%lx %x %lf %lf %lx %p)\n", fpe, op, arg, res, cw, unk);
10200af74 Piot*2848 
                2849 #ifdef _WIN64
                2850     cw = ((cw >> 7) & 0x3f) | ((cw >> 3) & 0xc00);
                2851 #endif
                2852     operation = op << 5;
                2853     exception_arg = (ULONG_PTR)&operation;
                2854 
                2855     if (fpe & 0x1) { /* overflow */
                2856         if ((fpe == 0x1 && (cw & 0x8)) || (fpe==0x11 && (cw & 0x28))) {
                2857             /* 32-bit version also sets SW_INEXACT here */
29cbb60f6 Piot*2858             raise |= FE_OVERFLOW;
                2859             if (fpe & 0x10) raise |= FE_INEXACT;
10200af74 Piot*2860             res = signbit(res) ? -INFINITY : INFINITY;
                2861         } else {
                2862             exception = EXCEPTION_FLT_OVERFLOW;
                2863         }
                2864     } else if (fpe & 0x2) { /* underflow */
                2865         if ((fpe == 0x2 && (cw & 0x10)) || (fpe==0x12 && (cw & 0x30))) {
29cbb60f6 Piot*2866             raise |= FE_UNDERFLOW;
                2867             if (fpe & 0x10) raise |= FE_INEXACT;
10200af74 Piot*2868             res = signbit(res) ? -0.0 : 0.0;
                2869         } else {
                2870             exception = EXCEPTION_FLT_UNDERFLOW;
                2871         }
                2872     } else if (fpe & 0x4) { /* zerodivide */
                2873         if ((fpe == 0x4 && (cw & 0x4)) || (fpe==0x14 && (cw & 0x24))) {
29cbb60f6 Piot*2874             raise |= FE_DIVBYZERO;
                2875             if (fpe & 0x10) raise |= FE_INEXACT;
10200af74 Piot*2876         } else {
                2877             exception = EXCEPTION_FLT_DIVIDE_BY_ZERO;
                2878         }
                2879     } else if (fpe & 0x8) { /* invalid */
                2880         if (fpe == 0x8 && (cw & 0x1)) {
29cbb60f6 Piot*2881             raise |= FE_INVALID;
10200af74 Piot*2882         } else {
                2883             exception = EXCEPTION_FLT_INVALID_OPERATION;
                2884         }
                2885     } else if (fpe & 0x10) { /* inexact */
                2886         if (fpe == 0x10 && (cw & 0x20)) {
29cbb60f6 Piot*2887             raise |= FE_INEXACT;
10200af74 Piot*2888         } else {
                2889             exception = EXCEPTION_FLT_INEXACT_RESULT;
                2890         }
                2891     }
                2892 
                2893     if (exception)
29cbb60f6 Piot*2894         raise = 0;
                2895     feraiseexcept(raise);
10200af74 Piot*2896     if (exception)
                2897         RaiseException(exception, 0, 1, &exception_arg);
                2898 
467486030 Piot*2899     if (cw & 0x1) fpword |= _EM_INVALID;
                2900     if (cw & 0x2) fpword |= _EM_DENORMAL;
                2901     if (cw & 0x4) fpword |= _EM_ZERODIVIDE;
                2902     if (cw & 0x8) fpword |= _EM_OVERFLOW;
                2903     if (cw & 0x10) fpword |= _EM_UNDERFLOW;
                2904     if (cw & 0x20) fpword |= _EM_INEXACT;
10200af74 Piot*2905     switch (cw & 0xc00)
                2906     {
467486030 Piot*2907         case 0xc00: fpword |= _RC_UP|_RC_DOWN; break;
                2908         case 0x800: fpword |= _RC_UP; break;
                2909         case 0x400: fpword |= _RC_DOWN; break;
10200af74 Piot*2910     }
                2911     switch (cw & 0x300)
                2912     {
467486030 Piot*2913         case 0x0:   fpword |= _PC_24; break;
                2914         case 0x200: fpword |= _PC_53; break;
                2915         case 0x300: fpword |= _PC_64; break;
10200af74 Piot*2916     }
467486030 Piot*2917     if (cw & 0x1000) fpword |= _IC_AFFINE;
e617fe0bd Piot*2918     _setfp(&fpword, _MCW_EM | _MCW_RC | _MCW_PC | _MCW_IC, NULL, 0);
10200af74 Piot*2919 
                2920     return res;
                2921 }
86597db83 Alex*2922 
4f2f3545e Piot*2923 _Dcomplex* CDECL _Cbuild(_Dcomplex *ret, double r, double i)
84f5d8a61 Piot*2924 {
494a78940 Piot*2925     ret->_Val[0] = r;
                2926     ret->_Val[1] = i;
84f5d8a61 Piot*2927     return ret;
                2928 }
                2929 
83a0c2085 Piot*2930 double CDECL MSVCR120_creal(_Dcomplex z)
                2931 {
494a78940 Piot*2932     return z._Val[0];
83a0c2085 Piot*2933 }
                2934 
86597db83 Alex*2935 #endif /* _MSVCR_VER>=120 */