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
1314 lines
41 KiB
7 years ago
|
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
|