This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [RFC] How to add vector math functions to Glibc
- From: Andrew Senkevich <andrew dot n dot senkevich at gmail dot com>
- To: "Joseph S. Myers" <joseph at codesourcery dot com>
- Cc: libc-alpha <libc-alpha at sourceware dot org>
- Date: Thu, 16 Oct 2014 20:37:05 +0400
- Subject: Re: [RFC] How to add vector math functions to Glibc
- Authentication-results: sourceware.org; auth=none
- References: <CAMXFM3tjquzniXP1weqxSVFJyhXqsf2PHuyrrrmqp7K0ZzORqA at mail dot gmail dot com> <CAMXFM3tqiqUNuSU2KXvAFM-QescX3+6xUO9=z5X0Ac6C9qJ7zg at mail dot gmail dot com> <CAMe9rOq7bZHb8R=opUzSmAMGWjLpX21mR=Sx96cuBph=TTtDXA at mail dot gmail dot com> <54246CB5 dot 7020908 at redhat dot com> <CAMe9rOoLmJ2jHWmERoB0M83WNKovJOgh0--Kquw9O86A1tPU0g at mail dot gmail dot com> <5424733D dot 6010305 at redhat dot com> <CAMe9rOpacze055qyBFzz3M-b-GNtXCqZzMmkScBL9a94zVj28g at mail dot gmail dot com> <54247FAB dot 6050002 at redhat dot com> <CAMXFM3v8narOLMHC5U=fvyTFWV6s4ZACN-UrAC4fAcUs9SOFfA at mail dot gmail dot com> <54257507 dot 9070508 at redhat dot com> <CAMXFM3vOLspQtHxgJfD_Emht480w2RMbiwnEH6A_LhoS-JZFag at mail dot gmail dot com> <Pine dot LNX dot 4 dot 64 dot 1409301620020 dot 15186 at digraph dot polyomino dot org dot uk> <542AF92E dot 8090708 at lip6 dot fr> <Pine dot LNX dot 4 dot 64 dot 1409302003410 dot 12188 at digraph dot polyomino dot org dot uk> <CAMXFM3tuM_p6Acp4hzoQ2xzR=4BZqtw8NbezqY6h8V4Xx=5hUA at mail dot gmail dot com> <Pine dot LNX dot 4 dot 64 dot 1410021411420 dot 24886 at digraph dot polyomino dot org dot uk> <CAMXFM3uPiuJvSpgmt+8d0B1qh3QSA=TVx0ZExfojDVHzrscL8A at mail dot gmail dot com> <Pine dot LNX dot 4 dot 64 dot 1410091724031 dot 23641 at digraph dot polyomino dot org dot uk>
Hi, Joseph,
here is the patch with test suite changes with fixes based on your
previous comments.
>> @@ -6258,7 +6274,11 @@ static const struct test_f_f_data cos_test_data[] =
>> static void
>> cos_test (void)
>> {
>> +#ifndef TEST_MATHVEC
>> ALL_RM_TEST (cos, 0, cos_test_data, RUN_TEST_LOOP_f_f, END);
>> +#else
>> + TN_RM_TEST (vector_cos, 0, cos_test_data, RUN_TEST_LOOP_f_f, END);
>> +#endif
>> }
>
> And I don't think we want conditionals like this for every function -
> indeed, the tests shouldn't need to know which functions have vector
> versions at all.
Do you mean to use the same *_test function for testing vector
(through wrapper)?
I have such scheme now but it requires to add macros named as standard
function and it also caused changes in START macros.
>> +CFLAGS-test-vec-double.c = -fno-inline -ffloat-store -fno-builtin
>> -frounding-math -mavx2 -Wno-unused-function
>
> And since you can't determine at configure
> time what host the tests might run on, instruction set features such as
> AVX need testing for at runtime (this means building separate source files
> for the test with separate options so that you know the compiler won't
> generate AVX code before you've tested for AVX availability).
Because of vector tests grouped by ISA we have different test driver
names containing vector length (test-double-vlen4.c for AVX2).
Scalar wrappers (called from test driver) will be in separate files
(test-double-vlen4-wrapper.c) and will be built with
architecture-specific options specified in sysdeps Makefile.
For runtime check we need to insert condition before wrapper start so
with help of new macros added in *_test function that condition could
be defined in test driver.
Now I have built test-double-vlen4 manually and if this way is ok I
will prepare that sysdeps Makefile.
diff --git a/math/libm-test.inc b/math/libm-test.inc
index f86a4fa..9ddb77e 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -684,7 +684,7 @@ static void
test_single_errno (const char *test_name, int errno_value,
int expected_value, const char *expected_name)
{
-#ifndef TEST_INLINE
+#if !defined TEST_INLINE && !defined TEST_MATHVEC
if (errno_value == expected_value)
{
if (print_screen (1))
@@ -1691,8 +1691,9 @@ struct test_fFF_11_data
ROUND_RESTORE_ ## ROUNDING_MODE
/* Start and end the tests for a given function. */
-#define START(FUNC, EXACT) \
- const char *this_func = #FUNC; \
+#define STR_CON(x,y) __STRING(x##y)
+#define START(FUNC, SUFF, EXACT) \
+ const char *this_func = STR_CON (FUNC, SUFF); \
init_max_error (this_func, EXACT)
#define END \
print_max_error (this_func)
@@ -1705,28 +1706,28 @@ struct test_fFF_11_data
{ \
do \
{ \
- START (FUNC, EXACT); \
+ START (FUNC, , EXACT); \
LOOP_MACRO (FUNC, ARRAY, , ## __VA_ARGS__); \
END_MACRO; \
} \
while (0); \
do \
{ \
- START (FUNC ## _downward, EXACT); \
+ START (FUNC, _downward, EXACT); \
LOOP_MACRO (FUNC, ARRAY, FE_DOWNWARD, ## __VA_ARGS__); \
END_MACRO; \
} \
while (0); \
do \
{ \
- START (FUNC ## _towardzero, EXACT); \
+ START (FUNC, _towardzero, EXACT); \
LOOP_MACRO (FUNC, ARRAY, FE_TOWARDZERO, ## __VA_ARGS__); \
END_MACRO; \
} \
while (0); \
do \
{ \
- START (FUNC ## _upward, EXACT); \
+ START (FUNC, _upward, EXACT); \
LOOP_MACRO (FUNC, ARRAY, FE_UPWARD, ## __VA_ARGS__); \
END_MACRO; \
} \
@@ -6034,7 +6035,7 @@ static const struct test_c_c_data cexp_test_data[] =
static void
cexp_test (void)
{
- START (cexp, 0);
+ START (cexp, , 0);
RUN_TEST_LOOP_c_c (cexp, cexp_test_data, );
END_COMPLEX;
}
@@ -6247,7 +6248,7 @@ copysign_test (void)
static const struct test_f_f_data cos_test_data[] =
- {
+ {
TEST_f_f (cos, plus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM),
TEST_f_f (cos, minus_infty, qnan_value, INVALID_EXCEPTION|ERRNO_EDOM),
TEST_f_f (cos, qnan_value, qnan_value,
NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
@@ -6255,9 +6256,14 @@ static const struct test_f_f_data cos_test_data[] =
AUTO_TESTS_f_f (cos),
};
+#ifndef CHECKARCH
+# define CHECKARCH
+#endif
+
static void
cos_test (void)
{
+ CHECKARCH
ALL_RM_TEST (cos, 0, cos_test_data, RUN_TEST_LOOP_f_f, END);
}
@@ -7548,7 +7554,7 @@ static const struct test_if_f_data jn_test_data[] =
static void
jn_test (void)
{
- START (jn, 0);
+ START (jn, , 0);
RUN_TEST_LOOP_if_f (jn, jn_test_data, );
END;
}
@@ -9374,7 +9380,7 @@ static const struct test_f_f_data tgamma_test_data[] =
static void
tgamma_test (void)
{
- START (tgamma, 0);
+ START (tgamma, , 0);
RUN_TEST_LOOP_f_f (tgamma, tgamma_test_data, );
END;
}
@@ -9824,6 +9830,12 @@ main (int argc, char **argv)
initialize ();
printf (TEST_MSG);
+ /* Vector trigonometric functions: */
+#ifdef TEST_MATHVEC
+
+ cos_test ();
+
+#else
check_ulp ();
/* Keep the tests a wee bit ordered (according to ISO C99). */
@@ -9960,6 +9972,7 @@ main (int argc, char **argv)
y0_test ();
y1_test ();
yn_test ();
+#endif
if (output_ulps)
fclose (ulps_file);
diff --git a/sysdeps/x86_64/fpu/libm-test-ulps
b/sysdeps/x86_64/fpu/libm-test-ulps
index 36e1b76..0e11cd5 100644
--- a/sysdeps/x86_64/fpu/libm-test-ulps
+++ b/sysdeps/x86_64/fpu/libm-test-ulps
@@ -905,6 +905,12 @@ idouble: 1
ildouble: 2
ldouble: 2
+
+Function: "vlen4_cos":
+double: 1
+
Function: "cosh":
double: 1
float: 1
diff --git a/sysdeps/x86_64/fpu/test-double-vlen4-wrapper.c
b/sysdeps/x86_64/fpu/test-double-vlen4-wrapper.c
new file mode 100644
index 0000000..35e130e
--- /dev/null
+++ b/sysdeps/x86_64/fpu/test-double-vlen4-wrapper.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define FLOAT double
+
+// Wrapper from scalar to vector function implemented in AVX2.
+#define VECTOR_WRAPPER(scalar_func,vector_func) \
+extern __m256d vector_func(__m256d); \
+FLOAT scalar_func(FLOAT x)\
+{\
+ int i;\
+ __m256d mx = _mm256_set1_pd(x);\
+ __m256d mr = vector_func(mx);\
+ for(i=1;i<4;i++)\
+ {\
+ if (((FLOAT*)&mr)[0]!=((FLOAT*)&mr)[i])\
+ {\
+ return ((FLOAT*)&mr)[0]+0.1;\
+ }\
+ }\
+ return ((FLOAT*)&mr)[0];\
+}
+
+#include <immintrin.h>
+
+VECTOR_WRAPPER(vlen4_cos,_ZGVdN4v_cos)
diff --git a/sysdeps/x86_64/fpu/test-double-vlen4.c
b/sysdeps/x86_64/fpu/test-double-vlen4.c
new file mode 100644
index 0000000..ce40c04
--- /dev/null
+++ b/sysdeps/x86_64/fpu/test-double-vlen4.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define FUNC(function) function
+#define FLOAT double
+#define TEST_MSG "testing double vector math (without inline functions)\n"
+#define MATHCONST(x) x
+#define CHOOSE(Clongdouble,Cdouble,Cfloat,Cinlinelongdouble,Cinlinedouble,Cinlinefloat)
Cdouble
+#define PRINTF_EXPR "e"
+#define PRINTF_XEXPR "a"
+#define PRINTF_NEXPR "f"
+#define TEST_DOUBLE 1
+
+#ifndef __NO_MATH_INLINES
+# define __NO_MATH_INLINES
+#endif
+
+#define TEST_MATHVEC
+#define EXCEPTION_TESTS_double 0
+#define ROUNDING_TESTS_double(MODE) ((MODE) == FE_TONEAREST)
+
+#define cos vlen4_cos
+
+#include <init-arch.h>
+
+#define CHECKARCH \
+__init_cpu_features();\
+if (__cpu_features.feature[index_AVX2_Usable] & bit_AVX2_Usable)
+
+#include "libm-test.c"
--
WBR,
Andrew