From fa54e895a784038e56a62ef7515429f6610dc2b6 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 21 May 2019 16:50:42 -0500 Subject: [PATCH] msvcrt: Implement fma and fmaf. Signed-off-by: Andrew Eikum Signed-off-by: Piotr Caban Signed-off-by: Alexandre Julliard --- configure | 3 +- configure.ac | 2 + .../api-ms-win-crt-math-l1-1-0.spec | 4 +- dlls/msvcr120/msvcr120.spec | 4 +- dlls/msvcr120_app/msvcr120_app.spec | 4 +- dlls/msvcrt/math.c | 32 ++++++++++ dlls/msvcrt/msvcrt.spec | 2 + dlls/ucrtbase/tests/misc.c | 60 +++++++++++++++++++ dlls/ucrtbase/ucrtbase.spec | 4 +- include/config.h.in | 6 ++ 10 files changed, 112 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 69d085cda7b..c206e8d6400 100755 --- a/configure +++ b/configure @@ -631,7 +631,6 @@ RT_LIBS POLL_LIBS DL_LIBS TOOLSEXT -UNWINDFLAGS MSVCRTFLAGS EXCESS_PRECISION_CFLAGS EXTRACFLAGS @@ -19147,6 +19146,8 @@ for ac_func in \ exp2f \ expm1 \ expm1f \ + fma \ + fmaf \ ilogb \ ilogbf \ j0 \ diff --git a/configure.ac b/configure.ac index 0490b53410a..83a8181f33c 100644 --- a/configure.ac +++ b/configure.ac @@ -2634,6 +2634,8 @@ AC_CHECK_FUNCS(\ exp2f \ expm1 \ expm1f \ + fma \ + fmaf \ ilogb \ ilogbf \ j0 \ diff --git a/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec b/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec index 75ecaf1effc..3a5991f1246 100644 --- a/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec +++ b/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec @@ -241,8 +241,8 @@ @ stub fdiml @ cdecl floor(double) ucrtbase.floor @ cdecl -arch=arm,x86_64,arm64 floorf(float) ucrtbase.floorf -@ stub fma -@ stub fmaf +@ cdecl fma(double double double) ucrtbase.fma +@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) ucrtbase.fmaf @ stub fmal @ cdecl fmax(double double) ucrtbase.fmax @ cdecl fmaxf(float float) ucrtbase.fmaxf diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec index 92ac3246e10..63dc44d32b3 100644 --- a/dlls/msvcr120/msvcr120.spec +++ b/dlls/msvcr120/msvcr120.spec @@ -2164,8 +2164,8 @@ @ cdecl fgetws(ptr long ptr) MSVCRT_fgetws @ cdecl floor(double) MSVCRT_floor @ cdecl -arch=arm,x86_64,arm64 floorf(float) MSVCRT_floorf -@ stub fma -@ stub fmaf +@ cdecl fma(double double double) MSVCRT_fma +@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) MSVCRT_fmaf @ stub fmal @ cdecl fmax(double double) MSVCR120_fmax @ cdecl fmaxf(float float) MSVCR120_fmaxf diff --git a/dlls/msvcr120_app/msvcr120_app.spec b/dlls/msvcr120_app/msvcr120_app.spec index af6b0fe369d..9b7727e233d 100644 --- a/dlls/msvcr120_app/msvcr120_app.spec +++ b/dlls/msvcr120_app/msvcr120_app.spec @@ -1830,8 +1830,8 @@ @ cdecl fgetws(ptr long ptr) msvcr120.fgetws @ cdecl floor(double) msvcr120.floor @ cdecl -arch=arm,x86_64,arm64 floorf(float) msvcr120.floorf -@ stub fma -@ stub fmaf +@ cdecl fma(double double double) msvcr120.fma +@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) msvcr120.fmaf @ stub fmal @ cdecl fmax(double double) msvcr120.fmax @ cdecl fmaxf(float float) msvcr120.fmaxf diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index 049c3407321..63744e33e33 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -387,6 +387,22 @@ float CDECL MSVCRT_floorf( float x ) return floorf(x); } +/********************************************************************* + * fmaf (MSVCRT.@) + */ +float CDECL MSVCRT_fmaf( float x, float y, float z ) +{ +#ifdef HAVE_FMAF + float w = fmaf(x, y, z); +#else + float w = x * y + z; +#endif + if ((isinf(x) && y == 0) || (x == 0 && isinf(y))) *MSVCRT__errno() = MSVCRT_EDOM; + else if (isinf(x) && isinf(z) && x != z) *MSVCRT__errno() = MSVCRT_EDOM; + else if (isinf(y) && isinf(z) && y != z) *MSVCRT__errno() = MSVCRT_EDOM; + return w; +} + /********************************************************************* * frexpf (MSVCRT.@) */ @@ -863,6 +879,22 @@ double CDECL MSVCRT_floor( double x ) return floor(x); } +/********************************************************************* + * fma (MSVCRT.@) + */ +double CDECL MSVCRT_fma( double x, double y, double z ) +{ +#ifdef HAVE_FMA + double w = fma(x, y, z); +#else + double w = x * y + z; +#endif + if ((isinf(x) && y == 0) || (x == 0 && isinf(y))) *MSVCRT__errno() = MSVCRT_EDOM; + else if (isinf(x) && isinf(z) && x != z) *MSVCRT__errno() = MSVCRT_EDOM; + else if (isinf(y) && isinf(z) && y != z) *MSVCRT__errno() = MSVCRT_EDOM; + return w; +} + /********************************************************************* * fabs (MSVCRT.@) */ diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 952de55b49a..f464db2f9cc 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -1288,6 +1288,8 @@ @ cdecl fgetws(ptr long ptr) MSVCRT_fgetws @ cdecl floor(double) MSVCRT_floor @ cdecl -arch=arm,x86_64,arm64 floorf(float) MSVCRT_floorf +@ cdecl fma(double double double) MSVCRT_fma +@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) MSVCRT_fmaf @ cdecl fmod(double double) MSVCRT_fmod @ cdecl -arch=arm,x86_64,arm64 fmodf(float float) MSVCRT_fmodf @ cdecl fopen(str str) MSVCRT_fopen diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c index ddb793851ab..7559edecc33 100644 --- a/dlls/ucrtbase/tests/misc.c +++ b/dlls/ucrtbase/tests/misc.c @@ -64,6 +64,25 @@ static inline float __port_infinity(void) } #define INFINITY __port_infinity() +static inline float __port_nan(void) +{ + static const unsigned __nan_bytes = 0x7fc00000; + return *(const float *)&__nan_bytes; +} +#define NAN __port_nan() + +static inline double __port_min_pos_double(void) +{ + static const UINT64 __min_pos_double = 0x10000000000000; + return *(const double *)&__min_pos_double; +} + +static inline double __port_max_double(void) +{ + static const UINT64 __max_double = 0x7FEFFFFFFFFFFFFF; + return *(const double *)&__max_double; +} + #define M_PI_2 1.57079632679489661923 #define FE_TONEAREST 0 @@ -747,6 +766,30 @@ static void test_math_errors(void) {"pow", INFINITY, 1, -1, -1}, {"pow", INFINITY, 2, -1, -1}, }; + const struct { + char func[16]; + double a; + double b; + double c; + int error; + int exception; + } tests3d[] = { + /* 0 * inf --> EDOM */ + {"fma", INFINITY, 0, 0, EDOM, -1}, + {"fma", 0, INFINITY, 0, EDOM, -1}, + /* inf - inf -> EDOM */ + {"fma", INFINITY, 1, -INFINITY, EDOM, -1}, + {"fma", -INFINITY, 1, INFINITY, EDOM, -1}, + {"fma", 1, INFINITY, -INFINITY, EDOM, -1}, + {"fma", 1, -INFINITY, INFINITY, EDOM, -1}, + /* NaN */ + {"fma", NAN, 0, 0, -1, -1}, + {"fma", 0, NAN, 0, -1, -1}, + {"fma", 0, 0, NAN, -1, -1}, + /* over/underflow */ + {"fma", __port_max_double(), __port_max_double(), __port_max_double(), -1, -1}, + {"fma", __port_min_pos_double(), __port_min_pos_double(), 1, -1, -1}, + }; const struct { char func[16]; double a; @@ -770,6 +813,7 @@ static void test_math_errors(void) }; double (CDECL *p_funcd)(double); double (CDECL *p_func2d)(double, double); + double (CDECL *p_func3d)(double, double, double); double (CDECL *p_funcdl)(double, long); int i; @@ -808,6 +852,22 @@ static void test_math_errors(void) "%s(%f, %f) got exception arg2 %f\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, exception.arg2); } + for(i = 0; i < ARRAY_SIZE(tests3d); i++) { + p_func3d = (void*)GetProcAddress(module, tests3d[i].func); + *p_errno() = -1; + exception.type = -1; + p_func3d(tests3d[i].a, tests3d[i].b, tests3d[i].c); + ok(*p_errno() == tests3d[i].error, + "%s(%f, %f, %f) got errno %d\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, *p_errno()); + ok(exception.type == tests3d[i].exception, + "%s(%f, %f, %f) got exception type %d\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.type); + if(exception.type == -1) continue; + ok(exception.arg1 == tests3d[i].a, + "%s(%f, %f, %f) got exception arg1 %f\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.arg1); + ok(exception.arg2 == tests3d[i].b, + "%s(%f, %f, %f) got exception arg2 %f\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.arg2); + } + for(i = 0; i < ARRAY_SIZE(testsdl); i++) { p_funcdl = (void*)GetProcAddress(module, testsdl[i].func); *p_errno() = -1; diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec index b7f814a4907..c64fee2b260 100644 --- a/dlls/ucrtbase/ucrtbase.spec +++ b/dlls/ucrtbase/ucrtbase.spec @@ -2305,8 +2305,8 @@ @ cdecl fgetws(ptr long ptr) MSVCRT_fgetws @ cdecl floor(double) MSVCRT_floor @ cdecl -arch=arm,x86_64,arm64 floorf(float) MSVCRT_floorf -@ stub fma -@ stub fmaf +@ cdecl fma(double double double) MSVCRT_fma +@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) MSVCRT_fmaf @ stub fmal @ cdecl fmax(double double) MSVCR120_fmax @ cdecl fmaxf(float float) MSVCR120_fmaxf diff --git a/include/config.h.in b/include/config.h.in index 7998764075c..774e9ee50e1 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -161,6 +161,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_FLOAT_H +/* Define to 1 if you have the `fma' function. */ +#undef HAVE_FMA + +/* Define to 1 if you have the `fmaf' function. */ +#undef HAVE_FMAF + /* Define to 1 if you have the `fnmatch' function. */ #undef HAVE_FNMATCH