You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1314 lines
41 KiB

From 1026f1e15a84134fd19f58c98af85ec9474f7722 Mon Sep 17 00:00:00 2001
From: Stefan Liebler <stli@linux.vnet.ibm.com>
Date: Thu, 8 Oct 2015 11:21:50 +0200
Subject: [PATCH 19/30] S390: Optimize strncmp and wcsncmp. (AND COMMON-CODE
WCSNCMP - picked form upstream)
upstream-commit-id: cee82e70ccb7b2f054cd781b0a603ae244523e72
https://www.sourceware.org/ml/libc-alpha/2015-07/msg00087.html
common-code wcsncmp:
upstream-commit-id: 920a0395ba9fa5949ec87aaf5daa0259da16749d
https://www.sourceware.org/ml/libc-alpha/2015-04/msg00098.html
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.
---
benchtests/Makefile | 2 +-
benchtests/bench-strncmp.c | 104 +++++++++++++-----
benchtests/bench-wcsncmp.c | 20 ++++
localedata/tests-mbwc/dat_wcsncmp.c | 18 ++--
localedata/tests-mbwc/tst_wcsncmp.c | 2 +
string/strncmp.c | 2 +-
string/test-strncmp.c | 175 +++++++++++++++++++++---------
sysdeps/s390/multiarch/Makefile | 6 +-
sysdeps/s390/multiarch/ifunc-impl-list.c | 3 +
sysdeps/s390/multiarch/strncmp-c.c | 28 +++++
sysdeps/s390/multiarch/strncmp-vx.S | 137 ++++++++++++++++++++++++
sysdeps/s390/multiarch/strncmp.c | 30 ++++++
sysdeps/s390/multiarch/wcsncmp-c.c | 25 +++++
sysdeps/s390/multiarch/wcsncmp-vx.S | 177 +++++++++++++++++++++++++++++++
sysdeps/s390/multiarch/wcsncmp.c | 27 +++++
wcsmbs/Makefile | 2 +-
wcsmbs/test-wcsncmp-ifunc.c | 20 ++++
wcsmbs/test-wcsncmp.c | 2 +
wcsmbs/wcsncmp.c | 41 +++----
19 files changed, 716 insertions(+), 105 deletions(-)
create mode 100644 benchtests/bench-wcsncmp.c
create mode 100644 sysdeps/s390/multiarch/strncmp-c.c
create mode 100644 sysdeps/s390/multiarch/strncmp-vx.S
create mode 100644 sysdeps/s390/multiarch/strncmp.c
create mode 100644 sysdeps/s390/multiarch/wcsncmp-c.c
create mode 100644 sysdeps/s390/multiarch/wcsncmp-vx.S
create mode 100644 sysdeps/s390/multiarch/wcsncmp.c
create mode 100644 wcsmbs/test-wcsncmp-ifunc.c
create mode 100644 wcsmbs/test-wcsncmp.c
diff --git a/benchtests/Makefile b/benchtests/Makefile
index f6333eb..f6342da 100644
--- a/benchtests/Makefile
+++ b/benchtests/Makefile
@@ -39,7 +39,7 @@ string-bench := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \
strncasecmp strncat strncmp strncpy strnlen strpbrk strrchr \
strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok
wcsmbs-bench := wcslen wcsnlen wcscpy wcpcpy wcsncpy wcpncpy wcscat wcsncat \
- wcsncmp
+ wcsncmp wcsncmp
string-bench-all := $(string-bench) ${wcsmbs-bench}
stdlib-bench := strtod
diff --git a/benchtests/bench-strncmp.c b/benchtests/bench-strncmp.c
index 25df3db..496ed68 100644
--- a/benchtests/bench-strncmp.c
+++ b/benchtests/bench-strncmp.c
@@ -17,17 +17,66 @@
<http://www.gnu.org/licenses/>. */
#define TEST_MAIN
-#define TEST_NAME "strncmp"
+#ifdef WIDE
+# define TEST_NAME "wcsncmp"
+#else
+# define TEST_NAME "strncmp"
+#endif /* !WIDE */
#include "bench-string.h"
-typedef int (*proto_t) (const char *, const char *, size_t);
-int simple_strncmp (const char *, const char *, size_t);
-int stupid_strncmp (const char *, const char *, size_t);
+#ifdef WIDE
+# include <wchar.h>
+
+# define L(str) L##str
+# define STRNCMP wcsncmp
+# 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;
+}
-IMPL (stupid_strncmp, 0)
-IMPL (simple_strncmp, 0)
-IMPL (strncmp, 1)
+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
simple_strncmp (const char *s1, const char *s2, size_t n)
{
@@ -49,9 +98,16 @@ stupid_strncmp (const char *s1, const char *s2, size_t n)
while (n-- && (ret = *(unsigned char *) s1++ - * (unsigned char *) s2++) == 0);
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
-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)
{
size_t i, iters = INNER_LOOP_ITERS;
@@ -74,12 +130,12 @@ do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
int exp_result)
{
size_t i, align_n;
- char *s1, *s2;
+ CHAR *s1, *s2;
if (n == 0)
{
- s1 = (char*)(buf1 + page_size);
- s2 = (char*)(buf2 + page_size);
+ s1 = (CHAR*)(buf1 + page_size);
+ s2 = (CHAR*)(buf2 + page_size);
printf ("Length %4zd/%4zd:", len, n);
FOR_EACH_IMPL (impl, 0)
@@ -92,16 +148,16 @@ do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
align1 &= 15;
align2 &= 15;
- align_n = (page_size - n) & 15;
+ align_n = (page_size - n * CHARBYTES) & 15;
- s1 = (char*)(buf1 + page_size - n);
- s2 = (char*)(buf2 + page_size - n);
+ s1 = (CHAR*)(buf1 + page_size - n * CHARBYTES);
+ s2 = (CHAR*)(buf2 + page_size - n * CHARBYTES);
if (align1 < align_n)
- s1 -= (align_n - align1);
+ s1 = (CHAR *) ((char *) s1 - (align_n - align1));
if (align2 < align_n)
- s2 -= (align_n - align2);
+ s2 = (CHAR *) ((char *) s2 - (align_n - align2));
for (i = 0; i < n; i++)
s1[i] = s2[i] = 1 + 23 * i % max_char;
@@ -129,24 +185,24 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
int exp_result)
{
size_t i;
- char *s1, *s2;
+ CHAR *s1, *s2;
if (n == 0)
return;
- align1 &= 7;
- if (align1 + n + 1 >= page_size)
+ align1 &= 63;
+ if (align1 + (n + 1) * CHARBYTES >= page_size)
return;
align2 &= 7;
- if (align2 + n + 1 >= page_size)
+ if (align2 + (n + 1) * CHARBYTES >= page_size)
return;
- s1 = (char*)(buf1 + align1);
- s2 = (char*)(buf2 + align2);
+ s1 = (CHAR*)(buf1 + align1);
+ s2 = (CHAR*)(buf2 + align2);
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;
s2[n] = 23;
@@ -162,7 +218,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);
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');
}
diff --git a/benchtests/bench-wcsncmp.c b/benchtests/bench-wcsncmp.c
new file mode 100644
index 0000000..8720060
--- /dev/null
+++ b/benchtests/bench-wcsncmp.c
@@ -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"
diff --git a/localedata/tests-mbwc/dat_wcsncmp.c b/localedata/tests-mbwc/dat_wcsncmp.c
index 167ce48..f468a8b 100644
--- a/localedata/tests-mbwc/dat_wcsncmp.c
+++ b/localedata/tests-mbwc/dat_wcsncmp.c
@@ -33,7 +33,7 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
},
{ /*input.*/ { { 0x00D1,0x00D2,0x00D3,0x0000 },
{ 0x0000,0x00D2,0x00D3,0x0000 }, 3 }, /* #06 */
- /*expect*/ { 0,1,0x00D1, },
+ /*expect*/ { 0,1,1, },
},
{ /*input.*/ { { 0x00D1,0x00D2,0x00D3,0x0000 },
{ 0x00D1,0x00D2,0x00D9,0x0000 }, 2 }, /* #07 */
@@ -41,11 +41,11 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
},
{ /*input.*/ { { 0x00D1,0x00D2,0x00D3,0x0000 },
{ 0x00D1,0x00D2,0x00D9,0x0000 }, 3 }, /* #08 */
- /*expect*/ { 0,1,-0x0006, },
+ /*expect*/ { 0,1,-1, },
},
{ /*input.*/ { { 0x00D1,0x00D2,0x00D3,0x0000 },
{ 0x00D1,0x00D2,0x0000 }, 4 }, /* #09 */
- /*expect*/ { 0,1,0x00D3, },
+ /*expect*/ { 0,1,1, },
},
{ .is_last = 1 }
}
@@ -75,7 +75,7 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
},
{ /*input.*/ { { 0x0041,0x0042,0x0043,0x0000 },
{ 0x0000,0x0042,0x0043,0x0000 }, 3 }, /* #06 */
- /*expect*/ { 0,1,0x0041, },
+ /*expect*/ { 0,1,1, },
},
{ /*input.*/ { { 0x0041,0x0042,0x0043,0x0000 },
{ 0x0041,0x0042,0x0049,0x0000 }, 2 }, /* #07 */
@@ -83,11 +83,11 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
},
{ /*input.*/ { { 0x0041,0x0042,0x0043,0x0000 },
{ 0x0041,0x0042,0x0049,0x0000 }, 3 }, /* #08 */
- /*expect*/ { 0,1,-0x0006, },
+ /*expect*/ { 0,1,-1, },
},
{ /*input.*/ { { 0x0041,0x0042,0x0043,0x0000 },
{ 0x0041,0x0042,0x0000 }, 4 }, /* #09 */
- /*expect*/ { 0,1,0x0043, },
+ /*expect*/ { 0,1,1, },
},
{ .is_last = 1 }
}
@@ -117,7 +117,7 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
},
{ /*input.*/ { { 0x3041,0x3042,0x3043,0x0000 },
{ 0x0000,0x3042,0x3043,0x0000 }, 3 }, /* #06 */
- /*expect*/ { 0,1,0x3041, },
+ /*expect*/ { 0,1,1, },
},
{ /*input.*/ { { 0x3041,0x3042,0x3043,0x0000 },
{ 0x3041,0x3042,0x3049,0x0000 }, 2 }, /* #07 */
@@ -125,11 +125,11 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
},
{ /*input.*/ { { 0x3041,0x3042,0x3043,0x0000 },
{ 0x3041,0x3042,0x3049,0x0000 }, 3 }, /* #08 */
- /*expect*/ { 0,1,-0x0006, },
+ /*expect*/ { 0,1,-1, },
},
{ /*input.*/ { { 0x3041,0x3042,0x3043,0x0000 },
{ 0x3041,0x3042,0x0000 }, 4 }, /* #09 */
- /*expect*/ { 0,1,0x3043, },
+ /*expect*/ { 0,1,1, },
},
{ .is_last = 1 }
}
diff --git a/localedata/tests-mbwc/tst_wcsncmp.c b/localedata/tests-mbwc/tst_wcsncmp.c
index d046ecd..e378efb 100644
--- a/localedata/tests-mbwc/tst_wcsncmp.c
+++ b/localedata/tests-mbwc/tst_wcsncmp.c
@@ -24,6 +24,8 @@ tst_wcsncmp (FILE * fp, int debug_flg)
ws2 = TST_INPUT (wcsncmp).ws2;
n = TST_INPUT (wcsncmp).n;
ret = wcsncmp (ws1, ws2, n);
+ ret = (ret > 0 ? 1 : ret < 0 ? -1 : 0);
+
if (debug_flg)
{
diff --git a/string/strncmp.c b/string/strncmp.c
index d79305a..bd52138 100644
--- a/string/strncmp.c
+++ b/string/strncmp.c
@@ -21,7 +21,7 @@
#undef strncmp
#ifndef STRNCMP
-#define STRNCMP strncmp
+# define STRNCMP strncmp
#endif
/* Compare no more than N characters of S1 and S2,
diff --git a/string/test-strncmp.c b/string/test-strncmp.c
index 7169593..950bf24 100644
--- a/string/test-strncmp.c
+++ b/string/test-strncmp.c
@@ -1,5 +1,5 @@
/* Test and measure strncmp functions.
- Copyright (C) 1999-2012 Free Software Foundation, Inc.
+ 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.
@@ -18,18 +18,82 @@
<http://www.gnu.org/licenses/>. */
#define TEST_MAIN
-#define TEST_NAME "strncmp"
+#ifdef WIDE
+# define TEST_NAME "wcsncmp"
+#else
+# define TEST_NAME "strncmp"
+#endif
#include "test-string.h"
-typedef int (*proto_t) (const char *, const char *, size_t);
-int simple_strncmp (const char *, const char *, size_t);
-int stupid_strncmp (const char *, const char *, size_t);
+#ifdef WIDE
+# include <wchar.h>
+
+# define L(str) L##str
+# define STRNCMP wcsncmp
+# define STRCPY wcscpy
+# define STRDUP wcsdup
+# define MEMCPY wmemcpy
+# define SIMPLE_STRNCMP simple_wcsncmp
+# define STUPID_STRNCMP stupid_wcsncmp
+# define CHAR wchar_t
+# define UCHAR wchar_t
+# define CHARBYTES 4
+# define CHAR__MAX WCHAR_MAX
+# define CHAR__MIN WCHAR_MIN
+
+/* 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;
+}
-IMPL (stupid_strncmp, 0)
-IMPL (simple_strncmp, 0)
-IMPL (strncmp, 1)
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 STRCPY strcpy
+# define STRDUP strdup
+# define MEMCPY memcpy
+# define SIMPLE_STRNCMP simple_strncmp
+# define STUPID_STRNCMP stupid_strncmp
+# define CHAR char
+# define UCHAR unsigned char
+# define CHARBYTES 1
+# define CHAR__MAX CHAR_MAX
+# define CHAR__MIN CHAR_MIN
+
+/* Strncmp uses unsigned semantics for comparison. */
+int
simple_strncmp (const char *s1, const char *s2, size_t n)
{
int ret = 0;
@@ -50,9 +114,16 @@ stupid_strncmp (const char *s1, const char *s2, size_t n)
while (n-- && (ret = *(unsigned char *) s1++ - * (unsigned char *) s2++) == 0);
return ret;
}
+#endif
+
+typedef int (*proto_t) (const CHAR *, const CHAR *, size_t);
+
+IMPL (STUPID_STRNCMP, 0)
+IMPL (SIMPLE_STRNCMP, 0)
+IMPL (STRNCMP, 1)
static int
-check_result (impl_t *impl, const char *s1, const char *s2, size_t n,
+check_result (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t n,
int exp_result)
{
int result = CALL (impl, s1, s2, n);
@@ -70,7 +141,7 @@ check_result (impl_t *impl, const char *s1, const char *s2, size_t n,
}
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)
{
if (check_result (impl, s1, s2, n, exp_result) < 0)
@@ -82,12 +153,12 @@ do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
int exp_result)
{
size_t i, align_n;
- char *s1, *s2;
+ CHAR *s1, *s2;
if (n == 0)
{
- s1 = (char*)(buf1 + page_size);
- s2 = (char*)(buf2 + page_size);
+ s1 = (CHAR*) (buf1 + page_size);
+ s2 = (CHAR*) (buf2 + page_size);
FOR_EACH_IMPL (impl, 0)
do_one_test (impl, s1, s2, n, 0);
@@ -97,16 +168,16 @@ do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
align1 &= 15;
align2 &= 15;
- align_n = (page_size - n) & 15;
+ align_n = (page_size - n * CHARBYTES) & 15;
- s1 = (char*)(buf1 + page_size - n);
- s2 = (char*)(buf2 + page_size - n);
+ s1 = (CHAR*) (buf1 + page_size - n * CHARBYTES);
+ s2 = (CHAR*) (buf2 + page_size - n * CHARBYTES);
if (align1 < align_n)
- s1 -= (align_n - align1);
+ s1 = (CHAR *) ((char *) s1 - (align_n - align1));
if (align2 < align_n)
- s2 -= (align_n - align2);
+ s2 = (CHAR *) ((char *) s2 - (align_n - align2));
for (i = 0; i < n; i++)
s1[i] = s2[i] = 1 + 23 * i % max_char;
@@ -130,24 +201,24 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
int exp_result)
{
size_t i;
- char *s1, *s2;
+ CHAR *s1, *s2;
if (n == 0)
return;
- align1 &= 7;
- if (align1 + n + 1 >= page_size)
+ align1 &= 63;
+ if (align1 + (n + 1) * CHARBYTES >= page_size)
return;
align2 &= 7;
- if (align2 + n + 1 >= page_size)
+ if (align2 + (n + 1) * CHARBYTES >= page_size)
return;
- s1 = (char*)(buf1 + align1);
- s2 = (char*)(buf2 + align2);
+ s1 = (CHAR*) (buf1 + align1);
+ s2 = (CHAR*) (buf2 + align2);
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;
s2[n] = 23;
@@ -161,19 +232,20 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
s2[n - 1] -= exp_result;
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);
}
static void
-do_page_test (size_t offset1, size_t offset2, char *s2)
+do_page_test (size_t offset1, size_t offset2, CHAR *s2)
{
- char *s1;
+ CHAR *s1;
int exp_result;
- if (offset1 >= page_size || offset2 >= page_size)
+ if (offset1 * CHARBYTES >= page_size || offset2 * CHARBYTES >= page_size)
return;
- s1 = (char *) (buf1 + offset1);
+ s1 = (CHAR *) buf1;
+ s1 += offset1;
s2 += offset2;
exp_result= *s1;
@@ -191,8 +263,8 @@ do_random_tests (void)
size_t i, j, n, align1, align2, pos, len1, len2, size;
int result;
long r;
- unsigned char *p1 = buf1 + page_size - 512;
- unsigned char *p2 = buf2 + page_size - 512;
+ UCHAR *p1 = (UCHAR *) (buf1 + page_size - 512 * CHARBYTES);
+ UCHAR *p2 = (UCHAR *) (buf2 + page_size - 512 * CHARBYTES);
for (n = 0; n < ITERATIONS; n++)
{
@@ -240,7 +312,7 @@ do_random_tests (void)
}
result = 0;
- memcpy (p2 + align2, p1 + align1, pos);
+ MEMCPY (p2 + align2, p1 + align1, pos);
if (pos < len1)
{
if (p2[align2 + pos] == p1[align1 + pos])
@@ -263,7 +335,7 @@ do_random_tests (void)
FOR_EACH_IMPL (impl, 1)
{
- r = CALL (impl, (char*)(p1 + align1), (char*)(p2 + align2), size);
+ r = CALL (impl, (CHAR *)(p1 + align1), (CHAR *)(p2 + align2), size);
/* Test whether on 64-bit architectures where ABI requires
callee to promote has the promotion been done. */
asm ("" : "=g" (r) : "0" (r));
@@ -282,19 +354,26 @@ do_random_tests (void)
static void
check1 (void)
{
- char *s1 = (char *)(buf1 + 0xb2c);
- char *s2 = (char *)(buf1 + 0xfd8);
- size_t i;
+ CHAR *s1 = (CHAR *)(buf1 + 0xb2c);
+ CHAR *s2 = (CHAR *)(buf1 + 0xfd8);
+ size_t i, offset;
int exp_result;
- strcpy(s1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs");
- strcpy(s2, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV");
+ strcpy(s1, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs"));
+ strcpy(s2, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV"));
+
+ /* Check possible overflow bug for wcsncmp */
+ s1[4] = CHAR__MAX;
+ s2[4] = CHAR__MIN;
- for (i = 0; i < 80; i++)
+ for (offset = 0; offset < 6; offset++)
{
- exp_result = simple_strncmp (s1, s2, i);
- FOR_EACH_IMPL (impl, 0)
- check_result (impl, s1, s2, i, exp_result);
+ for (i = 0; i < 80; i++)
+ {
+ exp_result = SIMPLE_STRNCMP (s1 + offset, s2 + offset, i);
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s1 + offset, s2 + offset, i, exp_result);
+ }
}
}
@@ -302,17 +381,17 @@ static void
check2 (void)
{
size_t i;
- char *s1, *s2;
+ CHAR *s1, *s2;
- s1 = (char *) buf1;
- for (i = 0; i < page_size - 1; i++)
+ s1 = (CHAR *) buf1;
+ for (i = 0; i < (page_size / CHARBYTES) - 1; i++)
s1[i] = 23;
s1[i] = 0;
- s2 = strdup (s1);
+ s2 = STRDUP (s1);
for (i = 0; i < 64; ++i)
- do_page_test (3990 + i, 2635, s2);
+ do_page_test ((3988 / CHARBYTES) + i, (2636 / CHARBYTES), s2);
free (s2);
}
diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile
index d8fbd55..d77bee5 100644
--- a/sysdeps/s390/multiarch/Makefile
+++ b/sysdeps/s390/multiarch/Makefile
@@ -7,7 +7,8 @@ sysdep_routines += strlen strlen-vx strlen-c \
stpncpy stpncpy-vx stpncpy-c \
strcat strcat-vx strcat-c \
strncat strncat-vx strncat-c \
- strcmp strcmp-vx
+ strcmp strcmp-vx \
+ strncmp strncmp-vx strncmp-c
endif
ifeq ($(subdir),wcsmbs)
@@ -19,5 +20,6 @@ sysdep_routines += wcslen wcslen-vx wcslen-c \
wcpncpy wcpncpy-vx wcpncpy-c \
wcscat wcscat-vx wcscat-c \
wcsncat wcsncat-vx wcsncat-c \
- wcscmp wcscmp-vx wcscmp-c
+ wcscmp wcscmp-vx wcscmp-c \
+ wcsncmp wcsncmp-vx wcsncmp-c
endif
diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c
index 196d3ec..5bfc493 100644
--- a/sysdeps/s390/multiarch/ifunc-impl-list.c
+++ b/sysdeps/s390/multiarch/ifunc-impl-list.c
@@ -106,6 +106,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
IFUNC_VX_IMPL (strcmp);
IFUNC_VX_IMPL (wcscmp);
+ IFUNC_VX_IMPL (strncmp);
+ IFUNC_VX_IMPL (wcsncmp);
+
#endif /* HAVE_S390_VX_ASM_SUPPORT */
return i;
diff --git a/sysdeps/s390/multiarch/strncmp-c.c b/sysdeps/s390/multiarch/strncmp-c.c
new file mode 100644
index 0000000..75da859
--- /dev/null
+++ b/sysdeps/s390/multiarch/strncmp-c.c
@@ -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 && !defined NOT_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 && !defined NOT_IN_libc */
diff --git a/sysdeps/s390/multiarch/strncmp-vx.S b/sysdeps/s390/multiarch/strncmp-vx.S
new file mode 100644
index 0000000..36e99b8
--- /dev/null
+++ b/sysdeps/s390/multiarch/strncmp-vx.S
@@ -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 && !defined NOT_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 && !defined NOT_IN_libc */
diff --git a/sysdeps/s390/multiarch/strncmp.c b/sysdeps/s390/multiarch/strncmp.c
new file mode 100644
index 0000000..1e1e05a
--- /dev/null
+++ b/sysdeps/s390/multiarch/strncmp.c
@@ -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 && !defined NOT_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 && !defined NOT_IN_libc) */
diff --git a/sysdeps/s390/multiarch/wcsncmp-c.c b/sysdeps/s390/multiarch/wcsncmp-c.c
new file mode 100644
index 0000000..058cd0c
--- /dev/null
+++ b/sysdeps/s390/multiarch/wcsncmp-c.c
@@ -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 && !defined NOT_IN_libc
+# define WCSNCMP __wcsncmp_c
+
+# include <wchar.h>
+extern __typeof (wcsncmp) __wcsncmp_c;
+# include <wcsmbs/wcsncmp.c>
+#endif
diff --git a/sysdeps/s390/multiarch/wcsncmp-vx.S b/sysdeps/s390/multiarch/wcsncmp-vx.S
new file mode 100644
index 0000000..9a44424
--- /dev/null
+++ b/sysdeps/s390/multiarch/wcsncmp-vx.S
@@ -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 && !defined NOT_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 && !defined NOT_IN_libc */
diff --git a/sysdeps/s390/multiarch/wcsncmp.c b/sysdeps/s390/multiarch/wcsncmp.c
new file mode 100644
index 0000000..0d79661
--- /dev/null
+++ b/sysdeps/s390/multiarch/wcsncmp.c
@@ -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 && !defined NOT_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 && !defined NOT_IN_libc) */
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
index 44b1502..611b2c9 100644
--- a/wcsmbs/Makefile
+++ b/wcsmbs/Makefile
@@ -41,7 +41,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
isoc99_swscanf isoc99_vswscanf \
mbrtoc16 c16rtomb
-strop-tests := wcscmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \
+strop-tests := wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \
wcpcpy wcsncpy wcpncpy wcscat wcsncat
tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \
tst-wcrtomb tst-wcpncpy tst-mbsrtowcs tst-wchar-h tst-mbrtowc2 \
diff --git a/wcsmbs/test-wcsncmp-ifunc.c b/wcsmbs/test-wcsncmp-ifunc.c
new file mode 100644
index 0000000..35176f0
--- /dev/null
+++ b/wcsmbs/test-wcsncmp-ifunc.c
@@ -0,0 +1,20 @@
+/* Test and measure IFUNC implementations of wcsncmp function.
+ 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 TEST_IFUNC 1
+#include "test-wcsncmp.c"
diff --git a/wcsmbs/test-wcsncmp.c b/wcsmbs/test-wcsncmp.c
new file mode 100644
index 0000000..07757d8
--- /dev/null
+++ b/wcsmbs/test-wcsncmp.c
@@ -0,0 +1,2 @@
+#define WIDE 1
+#include "../string/test-strncmp.c"
diff --git a/wcsmbs/wcsncmp.c b/wcsmbs/wcsncmp.c
index 7f1704f..1522b6f 100644
--- a/wcsmbs/wcsncmp.c
+++ b/wcsmbs/wcsncmp.c
@@ -18,53 +18,56 @@
#include <wchar.h>
+#ifndef WCSNCMP
+# define WCSNCMP wcsncmp
+#endif
/* Compare no more than N characters of S1 and S2,
returning less than, equal to or greater than zero
if S1 is lexicographically less than, equal to or
greater than S2. */
int
-wcsncmp (s1, s2, n)
+WCSNCMP (s1, s2, n)
const wchar_t *s1;
const wchar_t *s2;
size_t n;
{
- wint_t c1 = L'\0';
- wint_t c2 = L'\0';
+ wchar_t c1 = L'\0';
+ wchar_t c2 = L'\0';
if (n >= 4)
{
size_t n4 = n >> 2;
do
{
- c1 = (wint_t) *s1++;
- c2 = (wint_t) *s2++;
+ c1 = *s1++;
+ c2 = *s2++;
if (c1 == L'\0' || c1 != c2)
- return c1 - c2;
- c1 = (wint_t) *s1++;
- c2 = (wint_t) *s2++;
+ return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
+ c1 = *s1++;
+ c2 = *s2++;
if (c1 == L'\0' || c1 != c2)
- return c1 - c2;
- c1 = (wint_t) *s1++;
- c2 = (wint_t) *s2++;
+ return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
+ c1 = *s1++;
+ c2 = *s2++;
if (c1 == L'\0' || c1 != c2)
- return c1 - c2;
- c1 = (wint_t) *s1++;
- c2 = (wint_t) *s2++;
+ return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
+ c1 = *s1++;
+ c2 = *s2++;
if (c1 == L'\0' || c1 != c2)
- return c1 - c2;
+ return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
} while (--n4 > 0);
n &= 3;
}
while (n > 0)
{
- c1 = (wint_t) *s1++;
- c2 = (wint_t) *s2++;
+ c1 = *s1++;
+ c2 = *s2++;
if (c1 == L'\0' || c1 != c2)
- return c1 - c2;
+ return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
n--;
}
- return c1 - c2;
+ return 0;
}
--
2.3.0