File indexing completed on 2023-09-01 22:05:37
1db20bfd3… Jon *0001
0002
0003
0004
0799c1a78… Alex*0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
360a3f914… Jona*0018
bfc23bbd5… Piot*0019
0020
9fa7b779f… Alex*0021
bfc23bbd5… Piot*0022
9fa7b779f… Alex*0023
bfc23bbd5… Piot*0024
9fa7b779f… Alex*0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
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
0059 #define _SING 2
0060 #define _OVERFLOW 3
0061 #define _UNDERFLOW 4
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
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
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
0146 break;
0147 default:
0148 ERR("Unhandled math error!\n");
0149 }
2833a10ba… Piot*0150
0151 return exception.retval;
994c071a1… Alex*0152 }
0153
0154
0155
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
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
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
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
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
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
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
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
af9f9cb36… Maar*0254
e525730cc… Alex*0255 #if _MSVCR_VER == 0
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
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
af9f9cb36… Maar*0304
5c00be28f… Alex*0305 #if _MSVCR_VER < 140
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
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
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
78412005e… Alex*0365
ecfbd5971… Alex*0366 #if _MSVCR_VER == 0
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
78412005e… Alex*0376
5c3de7d79… Alex*0377 #if _MSVCR_VER == 0
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
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
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
78412005e… Alex*0451
5c00be28f… Alex*0452 #if _MSVCR_VER < 140
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" \
0474 "fstpl (%esp)\n\t" \
0475 "fwait\n\t" \
0476 "movl $1, %ecx\n\t" \
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" \
0492 "3:\n\t" \
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" \
0510 "fstpl 8(%esp)\n\t" \
0511 "fwait\n\t" \
0512 "fstpl (%esp)\n\t" \
0513 "fwait\n\t" \
0514 "movl $2, %ecx\n\t" \
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" \
0530 "3:\n\t" \
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"
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
1db20bfd3… Jon *0579
0580
0581
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
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
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
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
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
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
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
0658
4f2f3545e… Piot*0659 int CDECL abs( int n )
abe0823b7… Alex*0660 {
0661 return n >= 0 ? n : -n;
0662 }
0663
0664
0665
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
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
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
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
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
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
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
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
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
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
1126
24beabfd4… Alex*1127 int * CDECL __fpecode(void)
dec198afe… Alex*1128 {
1129 return &msvcrt_get_thread_data()->fpecode;
1130 }
1131
1db20bfd3… Jon *1132
1133
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
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
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
a8d8e4a36… Alex*1166
1167
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
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
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
1225
1226 void CDECL _set_controlfp( unsigned int newval, unsigned int mask )
1227 {
1228 _controlfp( newval, mask );
1229 }
1230
bfd0866be… Piot*1231
1232
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 );
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
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
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
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
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
1402
1403 int CDECL fetestexcept(int flags)
1404 {
1405 return _statusfp() & flags;
1406 }
5fd512504… Dani*1407
1408
1409
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
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
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
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
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
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
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
1508
1db20bfd3… Jon *1509
1510
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
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
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
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
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
854a3cab4… Piot*1607
1608
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
2caca4373… Piot*1636
1637
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
1664
961238367… Alex*1665
1666
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
97b420224… Laur*1673 ndigits = min( ndigits, 80 - 8);
1ab5f4191… Rein*1674
1675
961238367… Alex*1676 if (!data->efcvt_buffer)
d784dbb89… Piot*1677 data->efcvt_buffer = malloc( 80 );
961238367… Alex*1678
1ab5f4191… Rein*1679
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
1690 if( prec != 1)
fbe6b57b7… Andr*1691 memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
1ab5f4191… Rein*1692
1693 data->efcvt_buffer[ prec] = '\0';
1694
a1662e3f7… Piot*1695 sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
1ab5f4191… Rein*1696 (*decpt)++;
1697
1698 if( data->efcvt_buffer[0] == '0')
1699 *decpt = 0;
1700
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
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
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
1736 if( prec != 1)
1737 memmove( result + 1, result + 2, len - 1 );
1738
1739 result[ prec] = '\0';
1740
a1662e3f7… Piot*1741 sscanf( result + prec + 1, "%d", decpt);
1ade6c2bc… Eryk*1742 (*decpt)++;
1743
1744 if( result[0] == '0')
1745 *decpt = 0;
1746
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
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];
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 );
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
1784
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
1791
1792 if (ndigits < 1) {
5f2b9d596… Carl*1793 stop += ndigits;
260fd8a4a… Karl*1794 }
1795
1796 while (*ptr1 == '0') ptr1++;
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') {
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
1824
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
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];
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
1867
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
1874
1875 if (ndigits < 1) {
5f2b9d596… Carl*1876 stop += ndigits;
7a57f02b8… Niko*1877 }
1878
1879 while (*ptr1 == '0') ptr1++;
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') {
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
1917
1918 if (!first && (number <= 0.0))
1919 dec1 = 0;
1920
1921 *decpt = dec2 ? dec2 : dec1;
1922 return 0;
1923 }
1924
961238367… Alex*1925
1926
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
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
1979
1980
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
1997
1998
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
2009
2010
2011
2012
2013
2014
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
2031
2032
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
2043
86597db83… Alex*2044 #if _MSVCR_VER>=100
60c98caa9… Jace*2045
86597db83… Alex*2046
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
2063
2064
2065 int MSVCRT__adjust_fdiv = 0;
2066
4fb3aa5fc… Patr*2067
2068
2069
2070
2071
2072
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
2081
2082
2083
2084
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
2093
2094
2095
2096
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
2105
2106
2107
2108
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
2117
2118
2119
2120
2121
2122
2123
203a8f829… Fran*2124 void _adj_fdiv_r(void)
4fb3aa5fc… Patr*2125 {
e76218dd6… Fran*2126 TRACE("(): stub\n");
4fb3aa5fc… Patr*2127 }
2128
2129
2130
2131
2132
2133
2134
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
2143
2144
2145
2146
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
2155
2156
2157
2158
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
2167
2168
2169
2170
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
2179
2180
2181
2182
2183
2184
2185
203a8f829… Fran*2186 void _adj_fpatan(void)
4fb3aa5fc… Patr*2187 {
e76218dd6… Fran*2188 TRACE("(): stub\n");
4fb3aa5fc… Patr*2189 }
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
203a8f829… Fran*2200 void _adj_fprem(void)
4fb3aa5fc… Patr*2201 {
e76218dd6… Fran*2202 TRACE("(): stub\n");
4fb3aa5fc… Patr*2203 }
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
203a8f829… Fran*2214 void _adj_fprem1(void)
4fb3aa5fc… Patr*2215 {
e76218dd6… Fran*2216 TRACE("(): stub\n");
4fb3aa5fc… Patr*2217 }
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
203a8f829… Fran*2228 void _adj_fptan(void)
4fb3aa5fc… Patr*2229 {
e76218dd6… Fran*2230 TRACE("(): stub\n");
4fb3aa5fc… Patr*2231 }
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
203a8f829… Fran*2242 void _safe_fdiv(void)
4fb3aa5fc… Patr*2243 {
e76218dd6… Fran*2244 TRACE("(): stub\n");
4fb3aa5fc… Patr*2245 }
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
203a8f829… Fran*2256 void _safe_fdivr(void)
4fb3aa5fc… Patr*2257 {
e76218dd6… Fran*2258 TRACE("(): stub\n");
4fb3aa5fc… Patr*2259 }
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
203a8f829… Fran*2270 void _safe_fprem(void)
4fb3aa5fc… Patr*2271 {
e76218dd6… Fran*2272 TRACE("(): stub\n");
4fb3aa5fc… Patr*2273 }
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
547ba7a10… Mart*2546
d5fb71553… Piot*2547 #if _MSVCR_VER>=120
2548
547ba7a10… Mart*2549
2550
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
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
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
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
69ad3c11c… Piot*2615
2616
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
7fa8b03cd… Piot*2630
2631
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
389e0532f… Piot*2645
2646
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
668cf2e66… Piot*2660
2661
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
2675
4f2f3545e… Piot*2676 short CDECL _dtest(double *x)
1109672f1… Piot*2677 {
4f2f3545e… Piot*2678 return _dclass(*x);
1109672f1… Piot*2679 }
2680
2681
2682
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
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
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
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
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
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
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
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
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
2784
9acfcb0eb… Dani*2785
2786
2787
2788
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
2797
2798
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
86597db83… Alex*2806
d9a0c55e7… Dani*2807
2808
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
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
2830
2831 #if _MSVCR_VER>=120
2832
10200af74… Piot*2833
2834
2835
2836
2837
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) {
2856 if ((fpe == 0x1 && (cw & 0x8)) || (fpe==0x11 && (cw & 0x28))) {
2857
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) {
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) {
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) {
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) {
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