Skip to content

Commit

Permalink
S390: Optimize memchr, rawmemchr and wmemchr.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Stefan Liebler authored and Andreas Krebbel committed Aug 26, 2015
1 parent b4c2160 commit 88eefd3
Show file tree
Hide file tree
Showing 20 changed files with 795 additions and 61 deletions.
25 changes: 25 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
2015-08-26 Stefan Liebler <stli@linux.vnet.ibm.com>

* 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 <stli@linux.vnet.ibm.com>

* sysdeps/s390/multiarch/strcspn-c.c: New File.
Expand Down
3 changes: 2 additions & 1 deletion benchtests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 46 additions & 23 deletions benchtests/bench-memchr.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,52 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

#ifndef WIDE
# define CHAR char
# define SMALL_CHAR 127
#else
# include <wchar.h>
# 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;

Expand Down Expand Up @@ -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');
}
Expand Down
20 changes: 20 additions & 0 deletions benchtests/bench-wmemchr.c
Original file line number Diff line number Diff line change
@@ -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
<http://www.gnu.org/licenses/>. */

#define WIDE 1
#include "bench-memchr.c"
91 changes: 57 additions & 34 deletions string/test-memchr.c
Original file line number Diff line number Diff line change
@@ -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 <jakub@redhat.com>, 1999.
Expand All @@ -18,28 +18,49 @@
<http://www.gnu.org/licenses/>. */

#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 <wchar.h>
# 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,
Expand All @@ -53,43 +74,45 @@ 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
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++)
{
Expand All @@ -101,19 +124,19 @@ 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++)
{
if (i == pos + align)
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;
}
Expand All @@ -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;
}
Expand Down
7 changes: 5 additions & 2 deletions sysdeps/s390/multiarch/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
4 changes: 4 additions & 0 deletions sysdeps/s390/multiarch/ifunc-impl-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 88eefd3

Please sign in to comment.