From 88eefd344b3cf4a41284a1dfdaca61667e3a1b4b Mon Sep 17 00:00:00 2001 From: Stefan Liebler Date: Wed, 26 Aug 2015 10:26:24 +0200 Subject: S390: Optimize memchr, rawmemchr and wmemchr. This patch provides optimized versions of memchr, rawmemchr and wmemchr with the z13 vector instructions. ChangeLog: * sysdeps/s390/multiarch/memchr-vx.S: New File. * sysdeps/s390/multiarch/memchr.c: Likewise. * sysdeps/s390/multiarch/rawmemchr-c.c: Likewise. * sysdeps/s390/multiarch/rawmemchr-vx.S: Likewise. * sysdeps/s390/multiarch/rawmemchr.c: Likewise. * sysdeps/s390/multiarch/wmemchr-c.c: Likewise. * sysdeps/s390/multiarch/wmemchr-vx.S: Likewise. * sysdeps/s390/multiarch/wmemchr.c: Likewise. * sysdeps/s390/s390-32/multiarch/memchr.c: Likewise. * sysdeps/s390/s390-64/multiarch/memchr.c: Likewise. * sysdeps/s390/multiarch/Makefile (sysdep_routines): Add memchr, wmemchr and rawmemchr functions. * sysdeps/s390/multiarch/ifunc-impl-list-common.c (__libc_ifunc_impl_list_common): Add ifunc test for memchr, rawmemchr and wmemchr. * wcsmbs/wmemchr.c: Use WMEMCHR if defined. * string/test-memchr.c: Add wmemchr support. * wcsmbs/test-wmemchr.c: New File. * wcsmbs/Makefile (strop-tests): Add wmemchr. * benchtests/bench-memchr.c: Add wmemchr support. * benchtests/bench-wmemchr.c: New File. * benchtests/Makefile (wcsmbs-bench): wmemchr. --- ChangeLog | 25 +++++ benchtests/Makefile | 3 +- benchtests/bench-memchr.c | 69 ++++++++----- benchtests/bench-wmemchr.c | 20 ++++ string/test-memchr.c | 91 ++++++++++------- sysdeps/s390/multiarch/Makefile | 7 +- sysdeps/s390/multiarch/ifunc-impl-list.c | 4 + sysdeps/s390/multiarch/memchr-vx.S | 159 +++++++++++++++++++++++++++++ sysdeps/s390/multiarch/memchr.c | 24 +++++ sysdeps/s390/multiarch/rawmemchr-c.c | 34 +++++++ sysdeps/s390/multiarch/rawmemchr-vx.S | 92 +++++++++++++++++ sysdeps/s390/multiarch/rawmemchr.c | 28 ++++++ sysdeps/s390/multiarch/wmemchr-c.c | 37 +++++++ sysdeps/s390/multiarch/wmemchr-vx.S | 166 +++++++++++++++++++++++++++++++ sysdeps/s390/multiarch/wmemchr.c | 29 ++++++ sysdeps/s390/s390-32/multiarch/memchr.c | 21 ++++ sysdeps/s390/s390-64/multiarch/memchr.c | 21 ++++ wcsmbs/Makefile | 2 +- wcsmbs/test-wmemchr.c | 20 ++++ wcsmbs/wmemchr.c | 4 + 20 files changed, 795 insertions(+), 61 deletions(-) create mode 100644 benchtests/bench-wmemchr.c create mode 100644 sysdeps/s390/multiarch/memchr-vx.S create mode 100644 sysdeps/s390/multiarch/memchr.c create mode 100644 sysdeps/s390/multiarch/rawmemchr-c.c create mode 100644 sysdeps/s390/multiarch/rawmemchr-vx.S create mode 100644 sysdeps/s390/multiarch/rawmemchr.c create mode 100644 sysdeps/s390/multiarch/wmemchr-c.c create mode 100644 sysdeps/s390/multiarch/wmemchr-vx.S create mode 100644 sysdeps/s390/multiarch/wmemchr.c create mode 100644 sysdeps/s390/s390-32/multiarch/memchr.c create mode 100644 sysdeps/s390/s390-64/multiarch/memchr.c create mode 100644 wcsmbs/test-wmemchr.c diff --git a/ChangeLog b/ChangeLog index 4502084e45..c6df132715 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2015-08-26 Stefan Liebler + + * sysdeps/s390/multiarch/memchr-vx.S: New File. + * sysdeps/s390/multiarch/memchr.c: Likewise. + * sysdeps/s390/multiarch/rawmemchr-c.c: Likewise. + * sysdeps/s390/multiarch/rawmemchr-vx.S: Likewise. + * sysdeps/s390/multiarch/rawmemchr.c: Likewise. + * sysdeps/s390/multiarch/wmemchr-c.c: Likewise. + * sysdeps/s390/multiarch/wmemchr-vx.S: Likewise. + * sysdeps/s390/multiarch/wmemchr.c: Likewise. + * sysdeps/s390/s390-32/multiarch/memchr.c: Likewise. + * sysdeps/s390/s390-64/multiarch/memchr.c: Likewise. + * sysdeps/s390/multiarch/Makefile (sysdep_routines): Add memchr, wmemchr + and rawmemchr functions. + * sysdeps/s390/multiarch/ifunc-impl-list-common.c + (__libc_ifunc_impl_list_common): Add ifunc test for memchr, rawmemchr + and wmemchr. + * wcsmbs/wmemchr.c: Use WMEMCHR if defined. + * string/test-memchr.c: Add wmemchr support. + * wcsmbs/test-wmemchr.c: New File. + * wcsmbs/Makefile (strop-tests): Add wmemchr. + * benchtests/bench-memchr.c: Add wmemchr support. + * benchtests/bench-wmemchr.c: New File. + * benchtests/Makefile (wcsmbs-bench): wmemchr. + 2015-08-26 Stefan Liebler * sysdeps/s390/multiarch/strcspn-c.c: New File. diff --git a/benchtests/Makefile b/benchtests/Makefile index 46cb34f5b5..95712a32ae 100644 --- a/benchtests/Makefile +++ b/benchtests/Makefile @@ -37,7 +37,8 @@ string-bench := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \ strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok \ strcoll wcsmbs-bench := wcslen wcsnlen wcscpy wcpcpy wcsncpy wcpncpy wcscat wcsncat \ - wcscmp wcsncmp wcschr wcschrnul wcsrchr wcsspn wcspbrk wcscspn + wcscmp wcsncmp wcschr wcschrnul wcsrchr wcsspn wcspbrk wcscspn \ + wmemchr string-bench-all := $(string-bench) ${wcsmbs-bench} # We have to generate locales diff --git a/benchtests/bench-memchr.c b/benchtests/bench-memchr.c index 9879ec8473..3ead3cd456 100644 --- a/benchtests/bench-memchr.c +++ b/benchtests/bench-memchr.c @@ -16,31 +16,52 @@ License along with the GNU C Library; if not, see . */ +#ifndef WIDE +# define CHAR char +# define SMALL_CHAR 127 +#else +# include +# define CHAR wchar_t +# define SMALL_CHAR 1273 +#endif /* WIDE */ + #ifndef USE_AS_MEMRCHR # define TEST_MAIN -# define TEST_NAME "memchr" +# ifndef WIDE +# define TEST_NAME "memchr" +# else +# define TEST_NAME "wmemchr" +# endif /* WIDE */ # include "bench-string.h" -typedef char *(*proto_t) (const char *, int, size_t); -char *simple_memchr (const char *, int, size_t); +# ifndef WIDE +# define MEMCHR memchr +# define SIMPLE_MEMCHR simple_memchr +# else +# define MEMCHR wmemchr +# define SIMPLE_MEMCHR simple_wmemchr +# endif /* WIDE */ + +typedef CHAR *(*proto_t) (const CHAR *, int, size_t); +CHAR *SIMPLE_MEMCHR (const CHAR *, int, size_t); -IMPL (simple_memchr, 0) -IMPL (memchr, 1) +IMPL (SIMPLE_MEMCHR, 0) +IMPL (MEMCHR, 1) -char * -simple_memchr (const char *s, int c, size_t n) +CHAR * +SIMPLE_MEMCHR (const CHAR *s, int c, size_t n) { while (n--) - if (*s++ == (char) c) - return (char *) s - 1; + if (*s++ == (CHAR) c) + return (CHAR *) s - 1; return NULL; } -#endif +#endif /* !USE_AS_MEMRCHR */ static void -do_one_test (impl_t *impl, const char *s, int c, size_t n, char *exp_res) +do_one_test (impl_t *impl, const CHAR *s, int c, size_t n, CHAR *exp_res) { - char *res = CALL (impl, s, c, n); + CHAR *res = CALL (impl, s, c, n); size_t i, iters = INNER_LOOP_ITERS; timing_t start, stop, cur; @@ -68,36 +89,38 @@ static void do_test (size_t align, size_t pos, size_t len, int seek_char) { size_t i; - char *result; + CHAR *result; align &= 7; - if (align + len >= page_size) + if ((align + len) * sizeof (CHAR) >= page_size) return; + CHAR *buf = (CHAR *) (buf1); + for (i = 0; i < len; ++i) { - buf1[align + i] = 1 + 23 * i % 127; - if (buf1[align + i] == seek_char) - buf1[align + i] = seek_char + 1; + buf[align + i] = 1 + 23 * i % SMALL_CHAR; + if (buf[align + i] == seek_char) + buf[align + i] = seek_char + 1; } - buf1[align + len] = 0; + buf[align + len] = 0; if (pos < len) { - buf1[align + pos] = seek_char; - buf1[align + len] = -seek_char; - result = (char *) (buf1 + align + pos); + buf[align + pos] = seek_char; + buf[align + len] = -seek_char; + result = (CHAR *) (buf + align + pos); } else { result = NULL; - buf1[align + len] = seek_char; + buf[align + len] = seek_char; } printf ("Length %4zd, alignment %2zd:", pos, align); FOR_EACH_IMPL (impl, 0) - do_one_test (impl, (char *) (buf1 + align), seek_char, len, result); + do_one_test (impl, (CHAR *) (buf + align), seek_char, len, result); putchar ('\n'); } diff --git a/benchtests/bench-wmemchr.c b/benchtests/bench-wmemchr.c new file mode 100644 index 0000000000..d796a69726 --- /dev/null +++ b/benchtests/bench-wmemchr.c @@ -0,0 +1,20 @@ +/* Measure wmemchr functions. + Copyright (C) 2015 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 + . */ + +#define WIDE 1 +#include "bench-memchr.c" diff --git a/string/test-memchr.c b/string/test-memchr.c index 19c89781b2..fe7d82facb 100644 --- a/string/test-memchr.c +++ b/string/test-memchr.c @@ -1,4 +1,4 @@ -/* Test and measure memchr functions. +/* Test memchr functions. Copyright (C) 1999-2015 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek , 1999. @@ -18,28 +18,49 @@ . */ #define TEST_MAIN -#define TEST_NAME "memchr" +#ifndef WIDE +# define TEST_NAME "memchr" +#else +# define TEST_NAME "wmemchr" +#endif /* WIDE */ #include "test-string.h" -typedef char *(*proto_t) (const char *, int, size_t); -char *simple_memchr (const char *, int, size_t); - -IMPL (simple_memchr, 0) -IMPL (memchr, 1) - -char * -simple_memchr (const char *s, int c, size_t n) +#ifndef WIDE +# define MEMCHR memchr +# define CHAR char +# define UCHAR unsigned char +# define SIMPLE_MEMCHR simple_memchr +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +#else +# include +# define MEMCHR wmemchr +# define CHAR wchar_t +# define UCHAR wchar_t +# define SIMPLE_MEMCHR simple_wmemchr +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +#endif /* WIDE */ + +typedef CHAR *(*proto_t) (const CHAR *, int, size_t); +CHAR *SIMPLE_MEMCHR (const CHAR *, int, size_t); + +IMPL (SIMPLE_MEMCHR, 0) +IMPL (MEMCHR, 1) + +CHAR * +SIMPLE_MEMCHR (const CHAR *s, int c, size_t n) { while (n--) - if (*s++ == (char) c) - return (char *) s - 1; + if (*s++ == (CHAR) c) + return (CHAR *) s - 1; return NULL; } static void -do_one_test (impl_t *impl, const char *s, int c, size_t n, char *exp_res) +do_one_test (impl_t *impl, const CHAR *s, int c, size_t n, CHAR *exp_res) { - char *res = CALL (impl, s, c, n); + CHAR *res = CALL (impl, s, c, n); if (res != exp_res) { error (0, 0, "Wrong result in function %s %p %p", impl->name, @@ -53,34 +74,36 @@ static void do_test (size_t align, size_t pos, size_t len, int seek_char) { size_t i; - char *result; + CHAR *result; align &= 7; - if (align + len >= page_size) + if ((align + len) * sizeof (CHAR) >= page_size) return; + CHAR *buf = (CHAR *) (buf1); + for (i = 0; i < len; ++i) { - buf1[align + i] = 1 + 23 * i % 127; - if (buf1[align + i] == seek_char) - buf1[align + i] = seek_char + 1; + buf[align + i] = 1 + 23 * i % SMALL_CHAR; + if (buf[align + i] == seek_char) + buf[align + i] = seek_char + 1; } - buf1[align + len] = 0; + buf[align + len] = 0; if (pos < len) { - buf1[align + pos] = seek_char; - buf1[align + len] = -seek_char; - result = (char *) (buf1 + align + pos); + buf[align + pos] = seek_char; + buf[align + len] = -seek_char; + result = (CHAR *) (buf + align + pos); } else { result = NULL; - buf1[align + len] = seek_char; + buf[align + len] = seek_char; } FOR_EACH_IMPL (impl, 0) - do_one_test (impl, (char *) (buf1 + align), seek_char, len, result); + do_one_test (impl, (CHAR *) (buf + align), seek_char, len, result); } static void @@ -88,8 +111,8 @@ do_random_tests (void) { size_t i, j, n, align, pos, len; int seek_char; - char *result; - unsigned char *p = buf1 + page_size - 512; + CHAR *result; + UCHAR *p = (UCHAR *) (buf1 + page_size) - 512; for (n = 0; n < ITERATIONS; n++) { @@ -101,11 +124,11 @@ do_random_tests (void) if (pos >= len) len = pos + (random () & 7); if (len + align >= 512) - len = 512 - align - (random () & 7); - seek_char = random () & 255; + len = 512 - align - (random () & 7); + seek_char = random () & BIG_CHAR; j = len + align + 64; if (j > 512) - j = 512; + j = 512; for (i = 0; i < j; i++) { @@ -113,7 +136,7 @@ do_random_tests (void) p[i] = seek_char; else { - p[i] = random () & 255; + p[i] = random () & BIG_CHAR; if (i < pos + align && p[i] == seek_char) p[i] = seek_char + 13; } @@ -124,17 +147,17 @@ do_random_tests (void) size_t r = random (); if ((r & 31) == 0) len = ~(uintptr_t) (p + align) - ((r >> 5) & 31); - result = (char *) (p + pos + align); + result = (CHAR *) (p + pos + align); } else result = NULL; FOR_EACH_IMPL (impl, 1) - if (CALL (impl, (char *) (p + align), seek_char, len) != result) + if (CALL (impl, (CHAR *) (p + align), seek_char, len) != result) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %d, %zd, %zd) %p != %p, p %p", n, impl->name, align, seek_char, len, pos, - CALL (impl, (char *) (p + align), seek_char, len), + CALL (impl, (CHAR *) (p + align), seek_char, len), result, p); ret = 1; } diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile index 2c1fce019d..4a04c348a6 100644 --- a/sysdeps/s390/multiarch/Makefile +++ b/sysdeps/s390/multiarch/Makefile @@ -14,7 +14,9 @@ sysdep_routines += strlen strlen-vx strlen-c \ strrchr strrchr-vx strrchr-c \ strspn strspn-vx strspn-c \ strpbrk strpbrk-vx strpbrk-c \ - strcspn strcspn-vx strcspn-c + strcspn strcspn-vx strcspn-c \ + memchr memchr-vx \ + rawmemchr rawmemchr-vx rawmemchr-c endif ifeq ($(subdir),wcsmbs) @@ -33,5 +35,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \ wcsrchr wcsrchr-vx wcsrchr-c \ wcsspn wcsspn-vx wcsspn-c \ wcspbrk wcspbrk-vx wcspbrk-c \ - wcscspn wcscspn-vx wcscspn-c + wcscspn wcscspn-vx wcscspn-c \ + wmemchr wmemchr-vx wmemchr-c endif diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c index 7f62e4933d..d4c7c0d1da 100644 --- a/sysdeps/s390/multiarch/ifunc-impl-list.c +++ b/sysdeps/s390/multiarch/ifunc-impl-list.c @@ -127,6 +127,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, IFUNC_VX_IMPL (strcspn); IFUNC_VX_IMPL (wcscspn); + IFUNC_VX_IMPL (memchr); + IFUNC_VX_IMPL (wmemchr); + IFUNC_VX_IMPL (rawmemchr); + #endif /* HAVE_S390_VX_ASM_SUPPORT */ return i; diff --git a/sysdeps/s390/multiarch/memchr-vx.S b/sysdeps/s390/multiarch/memchr-vx.S new file mode 100644 index 0000000000..e0aa9e691b --- /dev/null +++ b/sysdeps/s390/multiarch/memchr-vx.S @@ -0,0 +1,159 @@ +/* Vector optimized 32/64 bit S/390 version of memchr. + Copyright (C) 2015 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 + . */ + +#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) + +# include "sysdep.h" +# include "asm-syntax.h" + + .text + +/* void *memchr (const void *s, int c, size_t n) + Scans memory for character c + and returns pointer to first c. + + Register usage: + -r0=tmp + -r1=tmp + -r2=s + -r3=c + -r4=n + -r5=current_len + -v16=part of s + -v17=index of found c + -v18=c replicated +*/ +ENTRY(__memchr_vx) + + .machine "z13" + .machinemode "zarch_nohighgprs" + +# if !defined __s390x__ + llgfr %r4,%r4 +# endif /* !defined __s390x__ */ + + clgije %r4,0,.Lnf_end /* If len == 0 then exit. */ + + vlbb %v16,0(%r2),6 /* Load s until next 4k-byte boundary. */ + lcbb %r0,0(%r2),6 /* Get bytes to 4k-byte boundary or 16. */ + llgfr %r0,%r0 /* Convert 32bit to 64bit. */ + + vlvgb %v18,%r3,0 /* Generate vector which elements are all c. + if c > 255, c will be truncated. */ + vrepb %v18,%v18,0 + lghi %r5,16 /* current_len = 16. */ + + clgrjhe %r0,%r4,.Llastcmp /* If (bytes to boundary) >= n, + jump to lastcmp. */ + + vfeebs %v17,%v16,%v18 /* Find c. */ + vlgvb %r1,%v17,7 /* Load byte index of c. */ + clgrjl %r1,%r0,.Lfound2 /* Found c is within loaded bytes. */ + + /* Align s to 16 byte. */ + risbgn %r1,%r2,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15. */ + slr %r5,%r1 /* Compute bytes to 16bytes boundary. */ + + lgr %r0,%r5 /* If %r5 + 64 < n? -> loop64. */ + aghi %r0,64 + clgrjl %r0,%r4,.Lloop64 +.Llt64: + vl %v16,0(%r5,%r2) + aghi %r5,16 + clgrjhe %r5,%r4,.Llastcmp /* Do last compare if curr-len >= n. */ + vfeebs %v17,%v16,%v18 /* Find c. */ + jl .Lfound /* Jump away if c was found. */ + + vl %v16,0(%r5,%r2) + aghi %r5,16 + clgrjhe %r5,%r4,.Llastcmp + vfeebs %v17,%v16,%v18 + jl .Lfound + + vl %v16,0(%r5,%r2) + aghi %r5,16 + clgrjhe %r5,%r4,.Llastcmp + vfeebs %v17,%v16,%v18 + jl .Lfound + + vl %v16,0(%r5,%r2) + aghi %r5,16 + +.Llastcmp: + /* Use comparision result only if located within first n characters. + %r5: current_len; + %r4: n; + (current_len - n): [0...16[ + first ignored match index: vr-width - (current_len - n) ]0...16] + */ + vfeebs %v17,%v16,%v18 /* Find c. */ + slgrk %r4,%r5,%r4 /* %r5 = current_len - n. */ + lghi %r0,16 /* Register width = 16. */ + vlgvb %r1,%v17,7 /* Extract found index or 16 if all equal. */ + slr %r0,%r4 /* %r0 = first ignored match index. */ + clrjl %r1,%r0,.Lfound2 /* Go away if miscompare is below n bytes. */ + /* c not found within n-bytes. */ +.Lnf_end: + lghi %r2,0 /* Return null. */ + br %r14 + +.Lfound48: + aghi %r5,16 +.Lfound32: + aghi %r5,16 +.Lfound16: + aghi %r5,16 +.Lfound0: + aghi %r5,16 +.Lfound: + vlgvb %r1,%v17,7 /* Load byte index of c. */ +.Lfound2: + slgfi %r5,16 /* current_len -=16 */ + algr %r5,%r1 /* Zero byte index is added to current len. */ + la %r2,0(%r5,%r2) /* Return pointer to c. */ + br %r14 + + +.Lloop64: + vl %v16,0(%r5,%r2) + vfeebs %v17,%v16,%v18 /* Find c. */ + jl .Lfound0 /* Jump away if c was found. */ + vl %v16,16(%r5,%r2) + vfeebs %v17,%v16,%v18 + jl .Lfound16 + vl %v16,32(%r5,%r2) + vfeebs %v17,%v16,%v18 + jl .Lfound32 + vl %v16,48(%r5,%r2) + vfeebs %v17,%v16,%v18 + jl .Lfound48 + + aghi %r5,64 + lgr %r0,%r5 /* If %r5 + 64 < n? -> loop64. */ + aghi %r0,64 + clgrjl %r0,%r4,.Lloop64 + + j .Llt64 +END(__memchr_vx) + +# define memchr __memchr_c +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(name) strong_alias(__memchr_c, __GI_memchr) +#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ + +#include diff --git a/sysdeps/s390/multiarch/memchr.c b/sysdeps/s390/multiarch/memchr.c new file mode 100644 index 0000000000..b653c1d8f4 --- /dev/null +++ b/sysdeps/s390/multiarch/memchr.c @@ -0,0 +1,24 @@ +/* Multiple versions of memchr. + Copyright (C) 2015 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 + . */ + +#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +# include +# include + +s390_vx_libc_ifunc2 (__memchr, memchr) +#endif diff --git a/sysdeps/s390/multiarch/rawmemchr-c.c b/sysdeps/s390/multiarch/rawmemchr-c.c new file mode 100644 index 0000000000..a85e83f8c0 --- /dev/null +++ b/sysdeps/s390/multiarch/rawmemchr-c.c @@ -0,0 +1,34 @@ +/* Default rawmemchr implementation for S/390. + Copyright (C) 2015 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 + . */ + +#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +# include + +# define RAWMEMCHR __rawmemchr_c +# undef weak_alias +# define weak_alias(a, b) +# ifdef SHARED +# undef libc_hidden_def +# define libc_hidden_def(name) \ + __hidden_ver1 (__rawmemchr_c, __GI___rawmemchr, __rawmemchr_c); +# endif /* SHARED */ + +extern __typeof (rawmemchr) __rawmemchr_c attribute_hidden; + +# include +#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ diff --git a/sysdeps/s390/multiarch/rawmemchr-vx.S b/sysdeps/s390/multiarch/rawmemchr-vx.S new file mode 100644 index 0000000000..0648296d15 --- /dev/null +++ b/sysdeps/s390/multiarch/rawmemchr-vx.S @@ -0,0 +1,92 @@ +/* Vector optimized 32/64 bit S/390 version of rawmemchr. + Copyright (C) 2015 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 + . */ + +#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) + +# include "sysdep.h" +# include "asm-syntax.h" + + .text + +/* void *rawmemchr (const void *s, int c) + Scans memory for character c + and returns pointer to first c. + + Register usage: + -r1=tmp + -r2=s + -r3=c + -r4=tmp + -r5=current_len + -v16=part of s + -v17=index of unequal + -v18=c replicated +*/ +ENTRY(__rawmemchr_vx) + .machine "z13" + .machinemode "zarch_nohighgprs" + + vlbb %v16,0(%r2),6 /* Load s until next 4k-byte boundary. */ + lcbb %r1,0(%r2),6 /* Get bytes to 4k-byte boundary or 16. */ + + vlvgb %v18,%r3,0 /* Generate vector which elements are all c. + If c > 255, c will be truncated. */ + vrepb %v18,%v18,0 + + vfeeb %v17,%v16,%v18 /* Vector find element equal. */ + vlgvb %r5,%v17,7 /* Load byte index of character or zero. */ + clrjl %r5,%r1,.Lend_found /* If found c is in loaded bytes, end. */ + + /* Align s to 16 byte. */ + risbgn %r1,%r2,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15. */ + lghi %r5,16 + slr %r5,%r1 /* Compute bytes to 16bytes boundary. */ + + /* Find c in a 16byte aligned loop. */ +.Lloop: + vl %v16,0(%r5,%r2) /* Load s. */ + vfeebs %v17,%v16,%v18 /* Vector find element equal. */ + jno .Lcharacter /* Jump away if element found. */ + vl %v16,16(%r5,%r2) + vfeebs %v17,%v16,%v18 + jno .Lcharacter16 + vl %v16,32(%r5,%r2) + vfeebs %v17,%v16,%v18 + jno .Lcharacter32 + vl %v16,48(%r5,%r2) + vfeebs %v17,%v16,%v18 + jno .Lcharacter48 + + aghi %r5,64 + j .Lloop /* No character found -> loop. */ + + /* Found character. */ +.Lcharacter48: + aghi %r5,16 +.Lcharacter32: + aghi %r5,16 +.Lcharacter16: + aghi %r5,16 +.Lcharacter: + vlgvb %r1,%v17,7 /* Load byte index of character. */ + algr %r5,%r1 +.Lend_found: + la %r2,0(%r5,%r2) /* Return pointer to character. */ + br %r14 +END(__rawmemchr_vx) +#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ diff --git a/sysdeps/s390/multiarch/rawmemchr.c b/sysdeps/s390/multiarch/rawmemchr.c new file mode 100644 index 0000000000..f93064c8f8 --- /dev/null +++ b/sysdeps/s390/multiarch/rawmemchr.c @@ -0,0 +1,28 @@ +/* Multiple versions of rawmemchr. + Copyright (C) 2015 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 + . */ + +#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +# include +# include + +s390_vx_libc_ifunc (__rawmemchr) +weak_alias (__rawmemchr, rawmemchr) + +#else +# include +#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ diff --git a/sysdeps/s390/multiarch/wmemchr-c.c b/sysdeps/s390/multiarch/wmemchr-c.c new file mode 100644 index 0000000000..c3b12ea599 --- /dev/null +++ b/sysdeps/s390/multiarch/wmemchr-c.c @@ -0,0 +1,37 @@ +/* Default wmemchr implementation for S/390. + Copyright (C) 2015 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 + . */ + +#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +# define WMEMCHR __wmemchr_c + +# include +extern __typeof (wmemchr) __wmemchr_c; +# undef weak_alias +# define weak_alias(name, alias) +# ifdef SHARED +# undef libc_hidden_def +# define libc_hidden_def(name) \ + __hidden_ver1 (__wmemchr_c, __GI___wmemchr, __wmemchr_c); +# undef libc_hidden_weak +# define libc_hidden_weak(name) \ + strong_alias (__wmemchr_c, __wmemchr_c_1); \ + __hidden_ver1 (__wmemchr_c_1, __GI_wmemchr, __wmemchr_c_1); +# endif /* SHARED */ + +# include +#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ diff --git a/sysdeps/s390/multiarch/wmemchr-vx.S b/sysdeps/s390/multiarch/wmemchr-vx.S new file mode 100644 index 0000000000..a32b2f22a4 --- /dev/null +++ b/sysdeps/s390/multiarch/wmemchr-vx.S @@ -0,0 +1,166 @@ +/* Vector optimized 32/64 bit S/390 version of wmemchr. + Copyright (C) 2015 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 + . */ + +#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) + +# include "sysdep.h" +# include "asm-syntax.h" + + .text + +/* wchar_t *wmemchr (const wchar_t *s, wchar_t c, size_t n) + Scans memory for character c + and returns pointer to first c. + + Register usage: + -r0=tmp + -r1=tmp + -r2=s + -r3=c + -r4=n + -r5=current_len + -v16=part of s + -v17=index of found c + -v18=c replicated +*/ +ENTRY(__wmemchr_vx) + .machine "z13" + .machinemode "zarch_nohighgprs" + +# if !defined __s390x__ + llgfr %r4,%r4 +# endif /* !defined __s390x__ */ + + clgije %r4,0,.Lnf_end /* If len == 0 then exit. */ + + vlbb %v16,0(%r2),6 /* Load s until next 4k-byte boundary. */ + lcbb %r0,0(%r2),6 /* Get bytes to 4k-byte boundary or 16. */ + llgfr %r0,%r0 /* Convert 32bit to 64bit. */ + + tmll %r2,3 /* Test if s is 4-byte aligned? */ + jne .Lfallback /* And use common-code variant if not. */ + + vlvgf %v18,%r3,0 /* Generate vector which elements are all c. */ + vrepf %v18,%v18,0 + lghi %r5,16 /* current_len = 16. */ + + /* Check range of maxlen and convert to byte-count. */ +# ifdef __s390x__ + tmhh %r4,49152 /* Test bit 0 or 1 of maxlen. */ + lghi %r1,-4 /* Max byte-count is 18446744073709551612. */ +# else + tmlh %r4,49152 /* Test bit 0 or 1 of maxlen. */ + llilf %r1,4294967292 /* Max byte-count is 4294967292. */ +# endif /* !__s390x__ */ + sllg %r4,%r4,2 /* Convert character-count to byte-count. */ + locgrne %r4,%r1 /* Use max byte-count, if bit 0/1 was one. */ + + clgrjhe %r0,%r4,.Llastcmp /* If (bytes to boundary) >= n, + jump to lastcmp. */ + + vfeefs %v17,%v16,%v18 /* Find c. */ + vlgvb %r1,%v17,7 /* Load byte index of c. */ + clgrjl %r1,%r0,.Lfound2 /* Found c is within loaded bytes. */ + + /* Align s to 16 byte. */ + risbgn %r1,%r2,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15. */ + slr %r5,%r1 /* Compute bytes to 16bytes boundary. */ + + lgr %r0,%r5 /* If %r5 + 64 < n? -> loop64. */ + aghi %r0,64 + clgrjl %r0,%r4,.Lloop64 +.Llt64: + vl %v16,0(%r5,%r2) + aghi %r5,16 + clgrjhe %r5,%r4,.Llastcmp /* Do last compare if curr-len >= n. */ + vfeefs %v17,%v16,%v18 /* Find c. */ + jl .Lfound /* Jump away if c was found. */ + + vl %v16,0(%r5,%r2) + aghi %r5,16 + clgrjhe %r5,%r4,.Llastcmp + vfeefs %v17,%v16,%v18 + jl .Lfound + + vl %v16,0(%r5,%r2) + aghi %r5,16 + clgrjhe %r5,%r4,.Llastcmp + vfeefs %v17,%v16,%v18 + jl .Lfound + + vl %v16,0(%r5,%r2) + aghi %r5,16 + +.Llastcmp: + /* Use comparision result only if located within first n characters. + %r5: current_len; + %r4: n; + (current_len - n): [0...16[ + first ignored match index = vr-width - (current_len - n) ]0...16] + */ + vfeefs %v17,%v16,%v18 /* Find c. */ + slgrk %r4,%r5,%r4 /* %r5 = current_len - n. */ + lghi %r0,16 /* Register width = 16. */ + vlgvb %r1,%v17,7 /* Extract found index or 16 if all equal. */ + slr %r0,%r4 /* %r0 = first ignored match index. */ + clrjl %r1,%r0,.Lfound2 /* Go away if miscompare is below n bytes. */ + /* c not found within n-bytes. */ +.Lnf_end: + lghi %r2,0 /* Return null. */ + br %r14 + +.Lfound48: + aghi %r5,16 +.Lfound32: + aghi %r5,16 +.Lfound16: + aghi %r5,16 +.Lfound0: + aghi %r5,16 +.Lfound: + vlgvb %r1,%v17,7 /* Load byte index of c. */ +.Lfound2: + slgfi %r5,16 /* current_len -=16 */ + algr %r5,%r1 /* Zero byte index is added to current len. */ + la %r2,0(%r5,%r2) /* Return pointer to c. */ + br %r14 + +.Lloop64: + vl %v16,0(%r5,%r2) + vfeefs %v17,%v16,%v18 /* Find c. */ + jl .Lfound0 /* Jump away if c was found. */ + vl %v16,16(%r5,%r2) + vfeefs %v17,%v16,%v18 + jl .Lfound16 + vl %v16,32(%r5,%r2) + vfeefs %v17,%v16,%v18 + jl .Lfound32 + vl %v16,48(%r5,%r2) + vfeefs %v17,%v16,%v18 + jl .Lfound48 + + aghi %r5,64 + lgr %r0,%r5 /* If %r5 + 64 < n? -> loop64. */ + aghi %r0,64 + clgrjl %r0,%r4,.Lloop64 + + j .Llt64 +.Lfallback: + jg __wmemchr_c +END(__wmemchr_vx) +#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */ diff --git a/sysdeps/s390/multiarch/wmemchr.c b/sysdeps/s390/multiarch/wmemchr.c new file mode 100644 index 0000000000..a44e6f7b87 --- /dev/null +++ b/sysdeps/s390/multiarch/wmemchr.c @@ -0,0 +1,29 @@ +/* Multiple versions of wmemchr. + Copyright (C) 2015 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 + . */ + +#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) +# include +# include + +s390_vx_libc_ifunc (__wmemchr) +weak_alias (__wmemchr, wmemchr) +libc_hidden_weak (wmemchr) + +#else +# include +#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */ diff --git a/sysdeps/s390/s390-32/multiarch/memchr.c b/sysdeps/s390/s390-32/multiarch/memchr.c new file mode 100644 index 0000000000..00958cd039 --- /dev/null +++ b/sysdeps/s390/s390-32/multiarch/memchr.c @@ -0,0 +1,21 @@ +/* Multiple versions of memchr. + Copyright (C) 2015 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 + . */ + +/* This wrapper-file is needed, because otherwise file + sysdeps/s390/s390-[32|64]/memchr.S will be used. */ +#include diff --git a/sysdeps/s390/s390-64/multiarch/memchr.c b/sysdeps/s390/s390-64/multiarch/memchr.c new file mode 100644 index 0000000000..00958cd039 --- /dev/null +++ b/sysdeps/s390/s390-64/multiarch/memchr.c @@ -0,0 +1,21 @@ +/* Multiple versions of memchr. + Copyright (C) 2015 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 + . */ + +/* This wrapper-file is needed, because otherwise file + sysdeps/s390/s390-[32|64]/memchr.S will be used. */ +#include diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile index 9c848ca83e..e8ce57969d 100644 --- a/wcsmbs/Makefile +++ b/wcsmbs/Makefile @@ -44,7 +44,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ strop-tests := wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \ wcpcpy wcsncpy wcpncpy wcscat wcsncat wcschrnul wcsspn wcspbrk \ - wcscspn + wcscspn wmemchr tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \ tst-wcrtomb tst-wcpncpy tst-mbsrtowcs tst-wchar-h tst-mbrtowc2 \ tst-c16c32-1 wcsatcliff $(addprefix test-,$(strop-tests)) diff --git a/wcsmbs/test-wmemchr.c b/wcsmbs/test-wmemchr.c new file mode 100644 index 0000000000..90c7f681f1 --- /dev/null +++ b/wcsmbs/test-wmemchr.c @@ -0,0 +1,20 @@ +/* Test wmemchr functions. + Copyright (C) 2015 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 + . */ + +#define WIDE 1 +#include "../string/test-memchr.c" diff --git a/wcsmbs/wmemchr.c b/wcsmbs/wmemchr.c index 266950c84b..9e8d57bd5d 100644 --- a/wcsmbs/wmemchr.c +++ b/wcsmbs/wmemchr.c @@ -18,6 +18,10 @@ #include +#ifdef WMEMCHR +# define __wmemchr WMEMCHR +#endif + wchar_t * __wmemchr (s, c, n) const wchar_t *s; -- cgit 1.4.1