[PATCH v2] msvcrt: Implement fma and fmaf
Andrew Eikum
aeikum at codeweavers.com
Tue May 21 16:50:42 CDT 2019
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
v2: Add check for fma functions; add tests; add errno assigning.
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 +-
8 files changed, 104 insertions(+), 8 deletions(-)
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
--
2.21.0
More information about the wine-devel
mailing list