S390: Optimize strncmp and wcsncmp.

This patch provides optimized versions of strncmp and wcsncmp with the z13
vector instructions.

ChangeLog:

	* sysdeps/s390/multiarch/strncmp-c.c: New File.
	* sysdeps/s390/multiarch/strncmp-vx.S: Likewise.
	* sysdeps/s390/multiarch/strncmp.c: Likewise.
	* sysdeps/s390/multiarch/wcsncmp-c.c: Likewise.
	* sysdeps/s390/multiarch/wcsncmp-vx.S: Likewise.
	* sysdeps/s390/multiarch/wcsncmp.c: Likewise.
	* sysdeps/s390/multiarch/Makefile (sysdep_routines): Add strncmp and
	wcsncmp functions.
	* sysdeps/s390/multiarch/ifunc-impl-list.c
	(__libc_ifunc_impl_list): Add ifunc test for strncmp, wcsncmp.
	* wcsmbs/wcsncmp.c (WCSNCMP): Define and use macro.
	* benchtests/bench-strncmp.c: Add wcsncmp support.
	* benchtests/bench-wcsncmp.c: New File.
	* benchtests/Makefile (wcsmbs-bench): Add wcsncmp.
This commit is contained in:
Stefan Liebler 2015-08-26 10:26:22 +02:00 committed by Andreas Krebbel
parent 63724a6db6
commit cee82e70cc
13 changed files with 558 additions and 29 deletions

View File

@ -1,3 +1,20 @@
2015-08-26 Stefan Liebler <stli@linux.vnet.ibm.com>
* sysdeps/s390/multiarch/strncmp-c.c: New File.
* sysdeps/s390/multiarch/strncmp-vx.S: Likewise.
* sysdeps/s390/multiarch/strncmp.c: Likewise.
* sysdeps/s390/multiarch/wcsncmp-c.c: Likewise.
* sysdeps/s390/multiarch/wcsncmp-vx.S: Likewise.
* sysdeps/s390/multiarch/wcsncmp.c: Likewise.
* sysdeps/s390/multiarch/Makefile (sysdep_routines): Add strncmp and
wcsncmp functions.
* sysdeps/s390/multiarch/ifunc-impl-list.c
(__libc_ifunc_impl_list): Add ifunc test for strncmp, wcsncmp.
* wcsmbs/wcsncmp.c (WCSNCMP): Define and use macro.
* benchtests/bench-strncmp.c: Add wcsncmp support.
* benchtests/bench-wcsncmp.c: New File.
* benchtests/Makefile (wcsmbs-bench): Add wcsncmp.
2015-08-26 Stefan Liebler <stli@linux.vnet.ibm.com> 2015-08-26 Stefan Liebler <stli@linux.vnet.ibm.com>
* sysdeps/s390/multiarch/strcmp-vx.S: New File. * sysdeps/s390/multiarch/strcmp-vx.S: New File.

View File

@ -37,7 +37,7 @@ string-bench := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \
strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok \ strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok \
strcoll strcoll
wcsmbs-bench := wcslen wcsnlen wcscpy wcpcpy wcsncpy wcpncpy wcscat wcsncat \ wcsmbs-bench := wcslen wcsnlen wcscpy wcpcpy wcsncpy wcpncpy wcscat wcsncat \
wcscmp wcscmp wcsncmp
string-bench-all := $(string-bench) ${wcsmbs-bench} string-bench-all := $(string-bench) ${wcsmbs-bench}
# We have to generate locales # We have to generate locales

View File

@ -17,17 +17,68 @@
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#define TEST_MAIN #define TEST_MAIN
#define TEST_NAME "strncmp" #ifdef WIDE
# define TEST_NAME "wcsncmp"
#else
# define TEST_NAME "strncmp"
#endif /* !WIDE */
#include "bench-string.h" #include "bench-string.h"
typedef int (*proto_t) (const char *, const char *, size_t); #ifdef WIDE
int simple_strncmp (const char *, const char *, size_t); # include <wchar.h>
int stupid_strncmp (const char *, const char *, size_t);
IMPL (stupid_strncmp, 0) # define L(str) L##str
IMPL (simple_strncmp, 0) # define STRNCMP wcsncmp
IMPL (strncmp, 1) # define SIMPLE_STRNCMP simple_wcsncmp
# define STUPID_STRNCMP stupid_wcsncmp
# define CHAR wchar_t
# define CHARBYTES 4
/* Wcsncmp uses signed semantics for comparison, not unsigned.
Avoid using substraction since possible overflow. */
int
simple_wcsncmp (const CHAR *s1, const CHAR *s2, size_t n)
{
wchar_t c1, c2;
while (n--)
{
c1 = *s1++;
c2 = *s2++;
if (c1 == L ('\0') || c1 != c2)
return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
}
return 0;
}
int
stupid_wcsncmp (const CHAR *s1, const CHAR *s2, size_t n)
{
wchar_t c1, c2;
size_t ns1 = wcsnlen (s1, n) + 1, ns2 = wcsnlen (s2, n) + 1;
n = ns1 < n ? ns1 : n;
n = ns2 < n ? ns2 : n;
while (n--)
{
c1 = *s1++;
c2 = *s2++;
if (c1 != c2)
return c1 > c2 ? 1 : -1;
}
return 0;
}
#else
# define L(str) str
# define STRNCMP strncmp
# define SIMPLE_STRNCMP simple_strncmp
# define STUPID_STRNCMP stupid_strncmp
# define CHAR char
# define CHARBYTES 1
/* Strncmp uses unsigned semantics for comparison. */
int int
simple_strncmp (const char *s1, const char *s2, size_t n) simple_strncmp (const char *s1, const char *s2, size_t n)
{ {
@ -46,12 +97,21 @@ stupid_strncmp (const char *s1, const char *s2, size_t n)
n = ns1 < n ? ns1 : n; n = ns1 < n ? ns1 : n;
n = ns2 < n ? ns2 : n; n = ns2 < n ? ns2 : n;
while (n-- && (ret = *(unsigned char *) s1++ - * (unsigned char *) s2++) == 0); while (n-- && (ret = *(unsigned char *) s1++ - *(unsigned char *) s2++) == 0);
return ret; return ret;
} }
#endif /* !WIDE */
typedef int (*proto_t) (const CHAR *, const CHAR *, size_t);
IMPL (STUPID_STRNCMP, 0)
IMPL (SIMPLE_STRNCMP, 0)
IMPL (STRNCMP, 1)
static void static void
do_one_test (impl_t *impl, const char *s1, const char *s2, size_t n, do_one_test (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t n,
int exp_result) int exp_result)
{ {
size_t i, iters = INNER_LOOP_ITERS; size_t i, iters = INNER_LOOP_ITERS;
@ -74,12 +134,12 @@ do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
int exp_result) int exp_result)
{ {
size_t i, align_n; size_t i, align_n;
char *s1, *s2; CHAR *s1, *s2;
if (n == 0) if (n == 0)
{ {
s1 = (char*)(buf1 + page_size); s1 = (CHAR *) (buf1 + page_size);
s2 = (char*)(buf2 + page_size); s2 = (CHAR *) (buf2 + page_size);
printf ("Length %4zd/%4zd:", len, n); printf ("Length %4zd/%4zd:", len, n);
FOR_EACH_IMPL (impl, 0) FOR_EACH_IMPL (impl, 0)
@ -92,16 +152,16 @@ do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
align1 &= 15; align1 &= 15;
align2 &= 15; align2 &= 15;
align_n = (page_size - n) & 15; align_n = (page_size - n * CHARBYTES) & 15;
s1 = (char*)(buf1 + page_size - n); s1 = (CHAR *) (buf1 + page_size - n * CHARBYTES);
s2 = (char*)(buf2 + page_size - n); s2 = (CHAR *) (buf2 + page_size - n * CHARBYTES);
if (align1 < align_n) if (align1 < align_n)
s1 -= (align_n - align1); s1 = (CHAR *) ((char *) s1 - (align_n - align1));
if (align2 < align_n) if (align2 < align_n)
s2 -= (align_n - align2); s2 = (CHAR *) ((char *) s2 - (align_n - align2));
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
s1[i] = s2[i] = 1 + 23 * i % max_char; s1[i] = s2[i] = 1 + 23 * i % max_char;
@ -129,24 +189,24 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
int exp_result) int exp_result)
{ {
size_t i; size_t i;
char *s1, *s2; CHAR *s1, *s2;
if (n == 0) if (n == 0)
return; return;
align1 &= 7; align1 &= 63;
if (align1 + n + 1 >= page_size) if (align1 + (n + 1) * CHARBYTES >= page_size)
return; return;
align2 &= 7; align2 &= 7;
if (align2 + n + 1 >= page_size) if (align2 + (n + 1) * CHARBYTES >= page_size)
return; return;
s1 = (char*)(buf1 + align1); s1 = (CHAR *) (buf1 + align1);
s2 = (char*)(buf2 + align2); s2 = (CHAR *) (buf2 + align2);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
s1[i] = s2[i] = 1 + 23 * i % max_char; s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % max_char;
s1[n] = 24 + exp_result; s1[n] = 24 + exp_result;
s2[n] = 23; s2[n] = 23;
@ -162,7 +222,7 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
printf ("Length %4zd/%4zd, alignment %2zd/%2zd:", len, n, align1, align2); printf ("Length %4zd/%4zd, alignment %2zd/%2zd:", len, n, align1, align2);
FOR_EACH_IMPL (impl, 0) FOR_EACH_IMPL (impl, 0)
do_one_test (impl, (char*)s1, (char*)s2, n, exp_result); do_one_test (impl, s1, s2, n, exp_result);
putchar ('\n'); putchar ('\n');
} }

View File

@ -0,0 +1,20 @@
/* Measure wcsncmp 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-strncmp.c"

View File

@ -7,7 +7,8 @@ sysdep_routines += strlen strlen-vx strlen-c \
stpncpy stpncpy-vx stpncpy-c \ stpncpy stpncpy-vx stpncpy-c \
strcat strcat-vx strcat-c \ strcat strcat-vx strcat-c \
strncat strncat-vx strncat-c \ strncat strncat-vx strncat-c \
strcmp strcmp-vx strcmp strcmp-vx \
strncmp strncmp-vx strncmp-c
endif endif
ifeq ($(subdir),wcsmbs) ifeq ($(subdir),wcsmbs)
@ -19,5 +20,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \
wcpncpy wcpncpy-vx wcpncpy-c \ wcpncpy wcpncpy-vx wcpncpy-c \
wcscat wcscat-vx wcscat-c \ wcscat wcscat-vx wcscat-c \
wcsncat wcsncat-vx wcsncat-c \ wcsncat wcsncat-vx wcsncat-c \
wcscmp wcscmp-vx wcscmp-c wcscmp wcscmp-vx wcscmp-c \
wcsncmp wcsncmp-vx wcsncmp-c
endif endif

View File

@ -106,6 +106,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
IFUNC_VX_IMPL (strcmp); IFUNC_VX_IMPL (strcmp);
IFUNC_VX_IMPL (wcscmp); IFUNC_VX_IMPL (wcscmp);
IFUNC_VX_IMPL (strncmp);
IFUNC_VX_IMPL (wcsncmp);
#endif /* HAVE_S390_VX_ASM_SUPPORT */ #endif /* HAVE_S390_VX_ASM_SUPPORT */
return i; return i;

View File

@ -0,0 +1,28 @@
/* Default strncmp 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
<http://www.gnu.org/licenses/>. */
#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
# define STRNCMP __strncmp_c
# ifdef SHARED
# undef libc_hidden_builtin_def
# define libc_hidden_builtin_def(name) \
__hidden_ver1 (__strncmp_c, __GI_strncmp, __strncmp_c);
# endif /* SHARED */
# include <string/strncmp.c>
#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */

View File

@ -0,0 +1,137 @@
/* Vector optimized 32/64 bit S/390 version of strncmp.
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/>. */
#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
# include "sysdep.h"
# include "asm-syntax.h"
.text
/* int strncmp (const char *s1, const char *s2, size_t n)
Compare at most n characters of two strings.
Register usage:
-r0=tmp
-r1=tmp
-r2=s1
-r3=s2
-r4=n
-r5=current_len
-v16=part of s1
-v17=part of s2
-v18=index of unequal
*/
ENTRY(__strncmp_vx)
.machine "z13"
.machinemode "zarch_nohighgprs"
# if !defined __s390x__
llgfr %r4,%r4
# endif /* !defined __s390x__ */
clgije %r4,0,.Lend_equal /* Nothing to do if n == 0, */
lghi %r5,0 /* current_len = 0. */
.Lloop:
vlbb %v16,0(%r5,%r2),6 /* Load s1 to block boundary. */
vlbb %v17,0(%r5,%r3),6 /* Load s2 to block boundary. */
lcbb %r0,0(%r5,%r2),6 /* Get loaded byte count of s1. */
jo .Llt16_1 /* Jump away if vr is not fully loaded. */
lcbb %r1,0(%r5,%r3),6 /* Get loaded byte count of s2. */
jo .Llt16_2 /* Jump away if vr is not fully loaded. */
aghi %r5,16 /* Both vrs are fully loaded. */
clgrjhe %r5,%r4,.Llastcmp /* If current_len >= n ->last compare. */
vfenezbs %v18,%v16,%v17 /* Compare not equal with zero search. */
jno .Lfound
vlbb %v16,0(%r5,%r2),6
vlbb %v17,0(%r5,%r3),6
lcbb %r0,0(%r5,%r2),6
jo .Llt16_1
lcbb %r1,0(%r5,%r3),6
jo .Llt16_2
aghi %r5,16
clgrjhe %r5,%r4,.Llastcmp
vfenezbs %v18,%v16,%v17
jno .Lfound
vlbb %v16,0(%r5,%r2),6
vlbb %v17,0(%r5,%r3),6
lcbb %r0,0(%r5,%r2),6
jo .Llt16_1
lcbb %r1,0(%r5,%r3),6
jo .Llt16_2
aghi %r5,16
clgrjhe %r5,%r4,.Llastcmp
vfenezbs %v18,%v16,%v17
jno .Lfound
vlbb %v16,0(%r5,%r2),6
vlbb %v17,0(%r5,%r3),6
lcbb %r0,0(%r5,%r2),6
jo .Llt16_1
lcbb %r1,0(%r5,%r3),6
jo .Llt16_2
aghi %r5,16
clgrjhe %r5,%r4,.Llastcmp
vfenezbs %v18,%v16,%v17
jno .Lfound
j .Lloop
.Llt16_1:
lcbb %r1,0(%r5,%r3),6 /* Get loaded byte count ofs2. */
.Llt16_2:
clr %r0,%r1 /* Compare logical. */
locrh %r0,%r1 /* Compute minimum of bytes loaded. */
algfr %r5,%r0 /* Add smallest loaded bytes to current_len. */
clgrj %r5,%r4,10,.Llastcmp /* If current_len >= n ->last compare. */
vfenezbs %v18,%v16,%v17 /* Compare not equal with zero search. */
vlgvb %r1,%v18,7 /* Get not equal index or 16 if all equal. */
clrjl %r1,%r0,.Lfound /* Jump away if miscompare is within
loaded bytes (index < loaded-bytes) */
j .Lloop
.Llastcmp:
/* Use comparision result only if located within first n characters.
%r0: loaded byte count in vreg;
%r5: current_len;
%r4: n;
(current_len - n): [0...16[
First ignored match index: loaded bytes - (current_len-n): ]0...16]
*/
slgr %r5,%r4 /* %r5 = current_len - n. */
slr %r0,%r5 /* %r0 = first ignored match index. */
vfenezbs %v18,%v16,%v17 /* Compare not equal with zero search. */
vlgvb %r1,%v18,7 /* Get not equal index or 16 if all equal. */
clrjl %r1,%r0,.Lfound /* Jump away if miscompare is within
loaded bytes and below n bytes. */
j .Lend_equal /* Miscompare after n-bytes -> end equal. */
.Lfound:
/* Difference or end of string. */
je .Lend_equal
lghi %r2,1
lghi %r1,-1
locgrl %r2,%r1
br %r14
.Lend_equal:
lghi %r2,0
br %r14
END(__strncmp_vx)
#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */

View File

@ -0,0 +1,30 @@
/* Multiple versions of strncmp.
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/>. */
#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
# include <string.h>
# include <ifunc-resolve.h>
# undef strcmp
extern __typeof (strncmp) __strncmp;
s390_vx_libc_ifunc2 (__strncmp, strncmp)
#else
# include <string/strncmp.c>
#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */

View File

@ -0,0 +1,25 @@
/* Default wcsncmp 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
<http://www.gnu.org/licenses/>. */
#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
# define WCSNCMP __wcsncmp_c
# include <wchar.h>
extern __typeof (wcsncmp) __wcsncmp_c;
# include <wcsmbs/wcsncmp.c>
#endif

View File

@ -0,0 +1,177 @@
/* Vector optimized 32/64 bit S/390 version of wcsncmp.
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/>. */
#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
# include "sysdep.h"
# include "asm-syntax.h"
.text
/* int wcsncmp (const wchar_t *s1, const wchar_t *s2, size_t n)
Compare at most n characters of two strings.
Register usage:
-r0=tmp
-r1=tmp
-r2=s1
-r3=s2
-r4=n
-r5=current_len
-v16=part of s1
-v17=part of s2
-v18=index of unequal
*/
ENTRY(__wcsncmp_vx)
.machine "z13"
.machinemode "zarch_nohighgprs"
# if !defined __s390x__
llgfr %r4,%r4
# endif /* !defined __s390x__ */
clgije %r4,0,.Lend_equal /* Nothing to do if n == 0. */
/* Check range of n 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. */
/* Check first character without vector load. */
lghi %r5,4 /* current_len = 4 bytes. */
/* Check s1/2[0]. */
lt %r0,0(%r2)
l %r1,0(%r3)
je .Lend_cmp_one_char
crjne %r0,%r1,.Lend_cmp_one_char
.Lloop:
vlbb %v17,0(%r5,%r3),6 /* Load s2 to block boundary. */
vlbb %v16,0(%r5,%r2),6 /* Load s1 to block boundary. */
lcbb %r0,0(%r5,%r2),6 /* Get loaded byte count of s1. */
jo .Llt16_1 /* Jump away if vector not fully loaded. */
lcbb %r1,0(%r5,%r3),6 /* Get loaded byte count of s2. */
jo .Llt16_2 /* Jump away if vector not fully loaded. */
aghi %r5,16 /* Both vectors are fully loaded. */
vfenezfs %v18,%v16,%v17 /* Compare not equal with zero search. */
clgrjhe %r5,%r4,.Llastcmp /* If current_len >= n ->last compare. */
jno .Lfound
vlbb %v17,0(%r5,%r3),6
vlbb %v16,0(%r5,%r2),6
lcbb %r0,0(%r5,%r2),6
jo .Llt16_1
lcbb %r1,0(%r5,%r3),6
jo .Llt16_2
aghi %r5,16
vfenezfs %v18,%v16,%v17
clgrjhe %r5,%r4,.Llastcmp
jno .Lfound
vlbb %v17,0(%r5,%r3),6
vlbb %v16,0(%r5,%r2),6
lcbb %r0,0(%r5,%r2),6
jo .Llt16_1
lcbb %r1,0(%r5,%r3),6
jo .Llt16_2
aghi %r5,16
vfenezfs %v18,%v16,%v17
clgrjhe %r5,%r4,.Llastcmp
jno .Lfound
vlbb %v17,0(%r5,%r3),6
vlbb %v16,0(%r5,%r2),6
lcbb %r0,0(%r5,%r2),6
jo .Llt16_1
lcbb %r1,0(%r5,%r3),6
jo .Llt16_2
aghi %r5,16
vfenezfs %v18,%v16,%v17
clgrjhe %r5,%r4,.Llastcmp
jno .Lfound
j .Lloop
.Llt16_1:
lcbb %r1,0(%r5,%r3),6 /* Get loaded byte count of s2. */
.Llt16_2:
clr %r0,%r1 /* Compare logical. */
locrh %r0,%r1 /* Compute minimum of bytes loaded. */
nill %r0,65532 /* Align bytes loaded to full characters. */
jz .Lcmp_one_char /* Jump away if no full char is available. */
.Llt_cmp:
algfr %r5,%r0 /* Add smallest loaded bytes to current_len. */
vfenezfs %v18,%v16,%v17 /* Compare not equal with zero search. */
clgrj %r5,%r4,10,.Llastcmp /* If current_len >= n -> last compare */
vlgvb %r1,%v18,7 /* Get not equal index or 16 if all equal. */
clrjl %r1,%r0,.Lfound /* Jump away if miscompare is within
loaded bytes; (index < loaded-bytes) */
j .Lloop
.Lcmp_one_char:
/* At least one of both strings is not 4-byte aligned
and there is no full character before next block-boundary.
Compare one character to get over the boundary and
proceed with normal loop! */
vlef %v16,0(%r5,%r2),0 /* Load one character. */
lghi %r0,4 /* Loaded byte count is 4. */
vlef %v17,0(%r5,%r3),0
j .Llt_cmp /* Proceed with comparision. */
.Llastcmp:
/* Use comparision result only if located within first n characters.
%r0: loaded byte count in vreg;
%r5: current_len;
%r4: n;
(current_len - n): [0...16[
First ignored match index: loaded bytes - (current_len-n): ]0...16]
*/
slgr %r5,%r4 /* %r5 = current_len - n. */
slr %r0,%r5 /* %r0 = first ignored match index. */
vlgvb %r4,%v18,7 /* Get not equal index or 16 if all equal. */
clrjl %r4,%r0,.Lfound2 /* Jump away if miscompare is within
loaded bytes and below n bytes. */
.Lend_equal:
lghi %r2,0
br %r14
.Lfound:
/* Difference or end of string. */
/* vfenezf found an unequal element or zero.
This instruction compares unsigned words, but wchar_t is signed.
Thus we have to compare the found element again. */
vlgvb %r4,%v18,7 /* Extract not equal byte-index. */
.Lfound2:
srl %r4,2 /* And convert it to character-index. */
vlgvf %r0,%v16,0(%r4) /* Load character-values. */
vlgvf %r1,%v17,0(%r4)
.Lend_cmp_one_char:
cr %r0,%r1
je .Lend_equal
lghi %r2,1
lghi %r1,-1
locgrl %r2,%r1
br %r14
END(__wcsncmp_vx)
#endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */

View File

@ -0,0 +1,27 @@
/* Multiple versions of wcsncmp.
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/>. */
#if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
# include <wchar.h>
# include <ifunc-resolve.h>
s390_vx_libc_ifunc2 (__wcsncmp, wcsncmp)
#else
# include <wcsmbs/wcsncmp.c>
#endif /* !(defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)) */

View File

@ -18,13 +18,16 @@
#include <wchar.h> #include <wchar.h>
#ifndef WCSNCMP
# define WCSNCMP wcsncmp
#endif
/* Compare no more than N characters of S1 and S2, /* Compare no more than N characters of S1 and S2,
returning less than, equal to or greater than zero returning less than, equal to or greater than zero
if S1 is lexicographically less than, equal to or if S1 is lexicographically less than, equal to or
greater than S2. */ greater than S2. */
int int
wcsncmp (s1, s2, n) WCSNCMP (s1, s2, n)
const wchar_t *s1; const wchar_t *s1;
const wchar_t *s2; const wchar_t *s2;
size_t n; size_t n;