Page MenuHomeFreeBSD

D42122.id128410.diff
No OneTemporary

D42122.id128410.diff

diff --git a/lib/libc/amd64/string/Makefile.inc b/lib/libc/amd64/string/Makefile.inc
--- a/lib/libc/amd64/string/Makefile.inc
+++ b/lib/libc/amd64/string/Makefile.inc
@@ -13,6 +13,7 @@
strcpy.c \
strcspn.S \
strlen.S \
+ strncmp.S \
strnlen.c \
strpbrk.c \
strspn.S \
diff --git a/lib/libc/amd64/string/strncmp.S b/lib/libc/amd64/string/strncmp.S
new file mode 100644
--- /dev/null
+++ b/lib/libc/amd64/string/strncmp.S
@@ -0,0 +1,488 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+#include <machine/asm.h>
+#include <machine/param.h>
+
+#include "amd64_archlevel.h"
+
+#define ALIGN_TEXT .p2align 4, 0x90
+
+ARCHFUNCS(strncmp)
+ ARCHFUNC(strncmp, scalar)
+ ARCHFUNC(strncmp, baseline)
+ENDARCHFUNCS(strncmp)
+
+/*
+ * This is just the scalar loop unrolled a bunch of times.
+ */
+ARCHENTRY(strncmp, scalar)
+ xor %eax, %eax
+ sub $4, %rdx # 4 chars left to compare?
+ jbe 1f
+
+ ALIGN_TEXT
+0: movzbl (%rdi), %ecx
+ test %ecx, %ecx # NUL char in first string?
+ jz .L0
+ cmpb (%rsi), %cl # mismatch between strings?
+ jnz .L0
+
+ movzbl 1(%rdi), %ecx
+ test %ecx, %ecx
+ jz .L1
+ cmpb 1(%rsi), %cl
+ jnz .L1
+
+ movzbl 2(%rdi), %ecx
+ test %ecx, %ecx
+ jz .L2
+ cmpb 2(%rsi), %cl
+ jnz .L2
+
+ movzbl 3(%rdi), %ecx
+ test %ecx, %ecx
+ jz .L3
+ cmpb 3(%rsi), %cl
+ jnz .L3
+
+ add $4, %rdi # advance to next iteration
+ add $4, %rsi
+ sub $4, %rdx
+ ja 0b
+
+ /* end of string within the next 4 characters */
+1: cmp $-4, %edx # end of string reached immediately?
+ jz .Leq
+ movzbl (%rdi), %ecx
+ test %ecx, %ecx
+ jz .L0
+ cmpb (%rsi), %cl
+ jnz .L0
+
+ cmp $-3, %edx # end of string reached after 1 char?
+ jz .Leq
+ movzbl 1(%rdi), %ecx
+ test %ecx, %ecx
+ jz .L1
+ cmpb 1(%rsi), %cl
+ jnz .L1
+
+ cmp $-2, %edx
+ jz .Leq
+ movzbl 2(%rdi), %ecx
+ test %ecx, %ecx
+ jz .L2
+ cmpb 2(%rsi), %cl
+ jnz .L2
+
+ cmp $-1, %edx # either end of string after 3 chars,
+ jz .Leq # or it boils down to the last char
+
+.L3: inc %eax
+.L2: inc %eax
+.L1: inc %eax
+.L0: movzbl (%rsi, %rax, 1), %ecx
+ movzbl (%rdi, %rax, 1), %eax
+ sub %ecx, %eax
+.Leq: ret
+ARCHEND(strncmp, scalar)
+
+ARCHENTRY(strncmp, baseline)
+ push %rbx
+ sub $1, %rdx # RDX--, so RDX points to the last byte to compare
+ jb .Lempty # where there any bytes to compare at all?
+
+ lea 15(%rdi), %r8d # end of head
+ lea 15(%rsi), %r9d
+ mov %edi, %eax
+ mov %esi, %ebx
+ xor %edi, %r8d # bits that changed between first and last byte
+ xor %esi, %r9d
+ and $~0xf, %rdi # align heads to 16 bytes
+ and $~0xf, %rsi
+ or %r8d, %r9d
+ and $0xf, %eax # offset from alignment
+ and $0xf, %ebx
+ movdqa (%rdi), %xmm0 # load aligned heads
+ movdqa (%rsi), %xmm2
+ pxor %xmm1, %xmm1
+ cmp $16, %rdx # end of buffer within the first 32 bytes?
+ jb .Llt16
+
+ test $PAGE_SIZE, %r9d # did the page change?
+ jz 0f # if not, take fast path
+
+
+ /* heads may cross page boundary, avoid unmapped loads */
+ movdqa %xmm0, -32(%rsp) # stash copies of the heads on the stack
+ movdqa %xmm2, -16(%rsp)
+ mov $-1, %r8d
+ mov $-1, %r9d
+ mov %eax, %ecx
+ shl %cl, %r8d # string head in XMM0
+ mov %ebx, %ecx
+ shl %cl, %r9d # string head in XMM2
+ pcmpeqb %xmm1, %xmm0
+ pcmpeqb %xmm1, %xmm2
+ pmovmskb %xmm0, %r10d
+ pmovmskb %xmm2, %r11d
+ test %r8d, %r10d # NUL byte present in first string?
+ lea -32(%rsp), %r8
+ cmovz %rdi, %r8
+ test %r9d, %r11d # NUL byte present in second string?
+ lea -16(%rsp), %r9
+ cmovz %rsi, %r9
+ movdqu (%r8, %rax, 1), %xmm0 # load true (or fake) heads
+ movdqu (%r9, %rbx, 1), %xmm4
+ jmp 1f
+
+ /* rdx == 0 */
+.Lempty:
+ xor %eax, %eax # zero-length buffers compare equal
+ pop %rbx
+ ret
+
+0: movdqu (%rdi, %rax, 1), %xmm0 # load true heads
+ movdqu (%rsi, %rbx, 1), %xmm4
+1: pxor %xmm2, %xmm2
+ pcmpeqb %xmm0, %xmm2 # NUL byte present?
+ pcmpeqb %xmm0, %xmm4 # which bytes match?
+ pandn %xmm4, %xmm2 # match and not NUL byte?
+ pmovmskb %xmm2, %r9d
+ xor $0xffff, %r9d # mismatch or NUL byte?
+ jnz .Lhead_mismatch
+
+ /* load head and second chunk */
+ movdqa 16(%rdi), %xmm2 # load second chunks
+ movdqa 16(%rsi), %xmm3
+ lea -16(%rdx, %rbx, 1), %rdx # account for length of RSI chunk
+ sub %rbx, %rax # is a&0xf >= b&0xf?
+ jb .Lswapped # if not, proceed with swapped operands
+ jmp .Lnormal
+
+ /* buffer ends within the first 16 bytes */
+.Llt16: test $PAGE_SIZE, %r9d # did the page change?
+ jz 0f # if not, take fast path
+
+ /* heads may cross page boundary */
+ movdqa %xmm0, -32(%rsp) # stash copies of the heads on the stack
+ movdqa %xmm2, -16(%rsp)
+ mov $-1, %r8d
+ mov $-1, %r9d
+ mov %eax, %ecx
+ shl %cl, %r8d # string head in XMM0
+ mov %ebx, %ecx
+ shl %cl, %r9d # string head in XMM2
+ pcmpeqb %xmm1, %xmm0
+ pcmpeqb %xmm1, %xmm2
+ pmovmskb %xmm0, %r10d
+ pmovmskb %xmm2, %r11d
+ lea (%rdx, %rax, 1), %ecx # location of last buffer byte in xmm0
+ bts %ecx, %r10d # treat as if NUL byte present
+ lea (%rdx, %rbx, 1), %ecx
+ bts %ecx, %r11d
+ test %r8w, %r10w # NUL byte present in first string head?
+ lea -32(%rsp), %r8
+ cmovz %rdi, %r8
+ test %r9w, %r11w # NUL byte present in second string head?
+ lea -16(%rsp), %r9
+ cmovz %rsi, %r9
+ movdqu (%r8, %rax, 1), %xmm0 # load true (or fake) heads
+ movdqu (%r9, %rbx, 1), %xmm4
+ jmp 1f
+
+0: movdqu (%rdi, %rax, 1), %xmm0 # load true heads
+ movdqu (%rsi, %rbx, 1), %xmm4
+1: pxor %xmm2, %xmm2
+ pcmpeqb %xmm0, %xmm2 # NUL byte present?
+ pcmpeqb %xmm0, %xmm4 # which bytes match?
+ pandn %xmm4, %xmm2 # match and not NUL byte?
+ pmovmskb %xmm2, %r9d
+ btr %edx, %r9d # induce mismatch in last byte of buffer
+ not %r9d # mismatch or NUL byte?
+
+ /* mismatch in true heads */
+ ALIGN_TEXT
+.Lhead_mismatch:
+ tzcnt %r9d, %r9d # where is the mismatch?
+ add %rax, %rdi # return to true heads
+ add %rbx, %rsi
+ movzbl (%rdi, %r9, 1), %eax # mismatching characters
+ movzbl (%rsi, %r9, 1), %ecx
+ sub %ecx, %eax
+ pop %rbx
+ ret
+
+ /* rax >= 0 */
+ ALIGN_TEXT
+.Lnormal:
+ neg %rax
+ movdqu 16(%rsi, %rax, 1), %xmm0
+ sub %rdi, %rsi # express RSI as distance from RDI
+ lea (%rsi, %rax, 1), %rbx # point RBX to offset in second string
+ neg %rax # ... corresponding to RDI
+ pcmpeqb %xmm3, %xmm1 # NUL present?
+ pcmpeqb %xmm2, %xmm0 # Mismatch between chunks?
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ mov $16, %ecx
+ cmp %rcx, %rdx # does the buffer end within (RDI,RSI,1)?
+ cmovb %edx, %ecx # ECX = min(16, RDX)
+ add $32, %rdi # advance to next iteration
+ bts %ecx, %r8d # mark end-of-buffer as if there was a NUL byte
+ test %r8w, %r8w # NUL or end of buffer found?
+ jnz .Lnul_found2
+ xor $0xffff, %r9d
+ jnz .Lmismatch2
+ sub $48, %rdx # end of buffer within first main loop iteration?
+ jb .Ltail # if yes, process tail
+
+ /*
+ * During the main loop, the layout of the two strings is something like:
+ *
+ * v ------1------ v ------2------ v
+ * RDI: AAAAAAAAAAAAABBBBBBBBBBBBBBBB...
+ * RSI: AAAAAAAAAAAAABBBBBBBBBBBBBBBBCCC...
+ *
+ * where v indicates the alignment boundaries and corresponding chunks
+ * of the strings have the same letters. Chunk A has been checked in
+ * the previous iteration. This iteration, we first check that string
+ * RSI doesn't end within region 2, then we compare chunk B between the
+ * two strings. As RSI is known not to hold a NUL byte in regsions 1
+ * and 2 at this point, this also ensures that RDI has not ended yet.
+ */
+ ALIGN_TEXT
+0: movdqu (%rdi, %rbx, 1), %xmm0 # chunk of 2nd string corresponding to RDI
+ pxor %xmm1, %xmm1
+ pcmpeqb (%rdi, %rsi, 1), %xmm1 # end of string in RSI?
+ pcmpeqb (%rdi), %xmm0 # where do the chunks match?
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ test %r8d, %r8d
+ jnz .Lnul_found
+ xor $0xffff, %r9d # any mismatches?
+ jnz .Lmismatch
+
+ /* main loop unrolled twice */
+ movdqu 16(%rdi, %rbx, 1), %xmm0
+ pxor %xmm1, %xmm1
+ pcmpeqb 16(%rdi, %rsi, 1), %xmm1
+ pcmpeqb 16(%rdi), %xmm0
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ add $32, %rdi
+ test %r8d, %r8d
+ jnz .Lnul_found2
+ xor $0xffff, %r9d
+ jnz .Lmismatch2
+ sub $32, %rdx # end of buffer within next iteration?
+ jae 0b
+
+ /* end of buffer will occur in next 32 bytes */
+.Ltail: movdqu (%rdi, %rbx, 1), %xmm0 # chunk of 2nd string corresponding to RDI
+ pxor %xmm1, %xmm1
+ pcmpeqb (%rdi, %rsi, 1), %xmm1 # end of string in RSI?
+ pcmpeqb (%rdi), %xmm0 # where do the chunks match?
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ bts %edx, %r8d # indicate NUL byte at last byte in buffer
+ test %r8w, %r8w # NUL byte in first chunk?
+ jnz .Lnul_found
+ xor $0xffff, %r9d # any mismatches?
+ jnz .Lmismatch
+
+ /* main loop unrolled twice */
+ movdqu 16(%rdi, %rbx, 1), %xmm0
+ pxor %xmm1, %xmm1
+ pcmpeqb 16(%rdi, %rsi, 1), %xmm1
+ pcmpeqb 16(%rdi), %xmm0
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ sub $16, %edx # take first half into account
+ bts %edx, %r8d # indicate NUL byte at last byte in buffer
+ add $32, %rdi
+
+.Lnul_found2:
+ sub $16, %rdi
+
+.Lnul_found:
+ mov %eax, %ecx
+ mov %r8d, %r10d
+ shl %cl, %r8d # adjust NUL mask to positions in RDI/RBX
+ not %r9d # mask of mismatches
+ or %r8w, %r9w # NUL bytes als count as mismatches
+ jnz .Lmismatch
+
+ /*
+ * (RDI) == (RSI) and NUL is past the string.
+ * compare (RSI) with the corresponding part
+ * of the other string until the NUL byte.
+ */
+ movdqu (%rdi, %rax, 1), %xmm0
+ pcmpeqb (%rdi, %rsi, 1), %xmm0
+ add %rdi, %rsi # restore RSI pointer
+ add %rax, %rdi # point RDI to chunk corresponding to (RSI)
+ pmovmskb %xmm0, %ecx # mask of matches
+ not %ecx # mask of mismatches
+ or %r10d, %ecx # mask of mismatches or NUL bytes
+ tzcnt %ecx, %ecx # location of first mismatch
+ movzbl (%rdi, %rcx, 1), %eax
+ movzbl (%rsi, %rcx, 1), %ecx
+ sub %ecx, %eax
+ pop %rbx
+ ret
+
+.Lmismatch2:
+ sub $16, %rdi
+
+ /* a mismatch has been found between RBX and RSI */
+.Lmismatch:
+ tzcnt %r9d, %r9d # where is the mismatch?
+ add %rdi, %rbx # turn RBX from offset into pointer
+ movzbl (%rbx, %r9, 1), %ecx
+ movzbl (%rdi, %r9, 1), %eax
+ sub %ecx, %eax
+ pop %rbx
+ ret
+
+ /* rax < 0 */
+ ALIGN_TEXT
+.Lswapped:
+ movdqu 16(%rdi, %rax, 1), %xmm0
+ sub %rsi, %rdi # express RDI as distance from RDI
+ lea (%rdi, %rax, 1), %rbx # point RBX to offset in first string
+ pcmpeqb %xmm2, %xmm1 # NUL present?
+ pcmpeqb %xmm3, %xmm0 # mismatch between chunks?
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ add %rax, %rdx # RDX points to buffer end in RSI
+ neg %rax # ... corresponding to RSI
+ mov $16, %ecx
+ cmp %rcx, %rdx # does the buffer end within (RSI,RDI,1)?
+ cmovb %edx, %ecx # ECX = min(16, RDX)
+ add $32, %rsi
+ bts %ecx, %r8d # mark end-of-buffer as if there was a NUL byte
+ test %r8w, %r8w # NUL or end of buffer found?
+ jnz .Lnul_found2s
+ xor $0xffff, %r9d
+ jnz .Lmismatch2s
+ sub $48, %rdx # end of buffer within first main loop iteration?
+ jb .Ltails # if yes, process tail
+
+ ALIGN_TEXT
+0: movdqu (%rsi, %rbx, 1), %xmm0 # chunk of 1st string corresponding to RSI
+ pxor %xmm1, %xmm1
+ pcmpeqb (%rsi, %rdi, 1), %xmm1 # end of string in RDI?
+ pcmpeqb (%rsi), %xmm0 # where do the chunks match?
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ test %r8d, %r8d
+ jnz .Lnul_founds
+ xor $0xffff, %r9d # any mismatches?
+ jnz .Lmismatchs
+
+ /* main loop unrolled twice */
+ movdqu 16(%rsi, %rbx, 1), %xmm0
+ pxor %xmm1, %xmm1
+ pcmpeqb 16(%rsi, %rdi, 1), %xmm1
+ pcmpeqb 16(%rsi), %xmm0
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ add $32, %rsi
+ test %r8d, %r8d
+ jnz .Lnul_found2s
+ xor $0xffff, %r9d
+ jnz .Lmismatch2s
+ sub $32, %rdx # end of buffer within next iteration?
+ jae 0b
+
+ /* end of buffer will occur in next 32 bytes */
+.Ltails:
+ movdqu (%rsi, %rbx, 1), %xmm0 # chunk of 1st string corresponding to RSI
+ pxor %xmm1, %xmm1
+ pcmpeqb (%rsi, %rdi, 1), %xmm1 # end of string in RDI?
+ pcmpeqb (%rsi), %xmm0 # where do the chunks match?
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ bts %edx, %r8d # indicate NUL byte at laste byte in buffer
+ test %r8w, %r8w # NUL byte in first chunk?
+ jnz .Lnul_founds
+ xor $0xffff, %r9d # any mismatches?
+ jnz .Lmismatchs
+
+ /* main loop unrolled twice */
+ movdqu 16(%rsi, %rbx, 1), %xmm0
+ pxor %xmm1, %xmm1
+ pcmpeqb 16(%rsi, %rdi, 1), %xmm1
+ pcmpeqb 16(%rsi), %xmm0
+ pmovmskb %xmm1, %r8d
+ pmovmskb %xmm0, %r9d
+ sub $16, %edx # take first half into account
+ bts %edx, %r8d # indicate NUL byte at laste byte in buffer
+ add $32, %rsi
+
+.Lnul_found2s:
+ sub $16, %rsi
+
+.Lnul_founds:
+ mov %eax, %ecx
+ mov %r8d, %r10d
+ shl %cl, %r8d # adjust NUL mask to positions in RSI/RBX
+ not %r9d # mask of mismatches
+ or %r8w, %r9w # NUL bytes also count as mismatches
+ jnz .Lmismatchs
+
+ movdqu (%rsi, %rax, 1), %xmm0
+ pcmpeqb (%rsi, %rdi, 1), %xmm0
+ add %rsi, %rdi # restore RDI pointer
+ add %rax, %rsi # point RSI to chunk corresponding to (RDI)
+ pmovmskb %xmm0, %ecx # mask of matches
+ not %ecx # mask of mismatches
+ or %r10d, %ecx # mask of mismatches or NUL bytes
+ tzcnt %ecx, %ecx # location of first mismatch
+ movzbl (%rdi, %rcx, 1), %eax
+ movzbl (%rsi, %rcx, 1), %ecx
+ sub %ecx, %eax
+ pop %rbx
+ ret
+
+.Lmismatch2s:
+ sub $16, %rsi
+
+.Lmismatchs:
+ tzcnt %r9d, %r9d # where is the mismatch?
+ add %rsi, %rbx # turn RBX from offset into pointer
+ movzbl (%rbx, %r9, 1), %eax
+ movzbl (%rsi, %r9, 1), %ecx
+ sub %ecx, %eax
+ pop %rbx
+ ret
+ARCHEND(strncmp, baseline)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/tests/string/Makefile b/lib/libc/tests/string/Makefile
--- a/lib/libc/tests/string/Makefile
+++ b/lib/libc/tests/string/Makefile
@@ -11,6 +11,7 @@
ATF_TESTS_C+= flsll_test
ATF_TESTS_C+= memcmp_test
ATF_TESTS_C+= memset_s_test
+ATF_TESTS_C+= strncmp_test
ATF_TESTS_C+= stpncpy_test
ATF_TESTS_C+= strcmp2_test
ATF_TESTS_C+= strcspn_test
diff --git a/lib/libc/tests/string/strncmp_test.c b/lib/libc/tests/string/strncmp_test.c
new file mode 100644
--- /dev/null
+++ b/lib/libc/tests/string/strncmp_test.c
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE
+ */
+
+#include <sys/cdefs.h>
+
+#include <atf-c.h>
+#include <dlfcn.h>
+#include <string.h>
+
+int (*volatile strncmp_fn)(const char *, const char *, size_t);
+
+static void
+alignment_testcase(char *a, char *b, int want, size_t len)
+{
+ int res;
+
+ res = strncmp_fn(a, b, len);
+ ATF_CHECK_MSG(want == (res > 0) - (res < 0),
+ "strcmp(%p \"%s\", %p \"%s\", %zu) = %d != %d",
+ (void *)a, a, (void *)b, b, len, res, want);
+}
+
+static void
+check_strncmp_alignments(char a[], char b[],
+ size_t a_off, size_t b_off, size_t len, size_t pos)
+{
+ char *a_str, *b_str, a_orig, b_orig;
+
+ a[a_off] = '\0';
+ b[b_off] = '\0';
+
+ a_str = a + a_off + 1;
+ b_str = b + b_off + 1;
+
+ a_str[len] = '\0';
+ b_str[len] = '\0';
+ a_str[len+1] = 'A';
+ b_str[len+1] = 'B';
+
+ a_orig = a_str[pos];
+ b_orig = b_str[pos];
+
+ alignment_testcase(a_str, b_str, 0, len + 16);
+ alignment_testcase(a_str, b_str, 0, len + 1);
+ alignment_testcase(a_str, b_str, 0, len);
+
+ if (pos < len) {
+ a_str[pos] = '\0';
+ alignment_testcase(a_str, b_str, -1, len + 16);
+ alignment_testcase(a_str, b_str, -1, len + 1);
+ alignment_testcase(a_str, b_str, -1, len);
+ alignment_testcase(a_str, b_str, -1, pos + 1);
+ alignment_testcase(a_str, b_str, 0, pos);
+ a_str[pos] = a_orig;
+
+ b_str[pos] = '\0';
+ alignment_testcase(a_str, b_str, 1, len + 16);
+ alignment_testcase(a_str, b_str, 1, len + 1);
+ alignment_testcase(a_str, b_str, 1, len);
+ alignment_testcase(a_str, b_str, 1, pos + 1);
+ alignment_testcase(a_str, b_str, 0, pos);
+ b_str[pos] = b_orig;
+ }
+
+ a_str[pos] = 'X';
+ alignment_testcase(a_str, b_str, 1, len + 16);
+ alignment_testcase(a_str, b_str, 0, pos);
+ alignment_testcase(a_str, b_str, 1, pos + 1);
+ if (pos < len) {
+ alignment_testcase(a_str, b_str, 1, len);
+ alignment_testcase(a_str, b_str, 1, len + 1);
+ }
+ a_str[pos] = a_orig;
+
+ b_str[pos] = 'X';
+ alignment_testcase(a_str, b_str, -1, len + 16);
+ alignment_testcase(a_str, b_str, 0, pos);
+ alignment_testcase(a_str, b_str, -1, pos + 1);
+ if (pos < len) {
+ alignment_testcase(a_str, b_str, -1, len);
+ alignment_testcase(a_str, b_str, -1, len + 1);
+ }
+ b_str[pos] = b_orig;
+
+ a[a_off] = '-';
+ b[b_off] = '-';
+ a_str[len] = '-';
+ b_str[len] = '-';
+ a_str[len+1] = '-';
+ b_str[len+1] = '-';
+}
+
+ATF_TC(strncmp_alignments);
+ATF_TC_HEAD(strncmp_alignments, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test strncmp(3) with various alignments");
+}
+
+ATF_TC_BODY(strncmp_alignments, tc)
+{
+ size_t a_off, b_off, len, pos;
+ char a[64+16+16+3], b[64+16+16+3];
+
+ memset(a, '-', sizeof(a));
+ memset(b, '-', sizeof(b));
+ a[sizeof(a) - 1] = '\0';
+ b[sizeof(b) - 1] = '\0';
+
+ for (a_off = 0; a_off < 16; a_off++)
+ for (b_off = 0; b_off < 16; b_off++)
+ for (len = 1; len <= 64; len++)
+ for (pos = 0; pos <= len; pos++)
+ check_strncmp_alignments(a, b, a_off, b_off, len, pos);
+}
+
+ATF_TC(strncmp_null);
+ATF_TC_HEAD(strncmp_null, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test strncmp(3) with null pointers");
+}
+
+ATF_TC_BODY(strncmp_null, tc)
+{
+ alignment_testcase(NULL, NULL, 0, 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ strncmp_fn = dlsym(dl_handle, "test_strncmp");
+ if (strncmp_fn == NULL)
+ strncmp_fn = strncmp;
+
+ ATF_TP_ADD_TC(tp, strncmp_alignments);
+ ATF_TP_ADD_TC(tp, strncmp_null);
+
+ return atf_no_error();
+}
diff --git a/share/man/man7/simd.7 b/share/man/man7/simd.7
--- a/share/man/man7/simd.7
+++ b/share/man/man7/simd.7
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE
.
-.Dd September 25, 2023
+.Dd October 7, 2023
.Dt SIMD 7
.Os
.Sh NAME
@@ -72,7 +72,7 @@
.It strcpy Ta Ta Ta S1 Ta S Ta S2
.It strcspn Ta Ta Ta S2
.It strlen Ta Ta S Ta S1
-.It strncmp Ta Ta S Ta Ta S
+.It strncmp Ta Ta S Ta S1 Ta S
.It strncpy Ta Ta Ta Ta Ta S2
.It strnlen Ta Ta Ta S1
.It strrchr Ta S Ta Ta Ta S

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 1, 3:13 PM (11 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28396917
Default Alt Text
D42122.id128410.diff (20 KB)

Event Timeline