Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Dec 2023 17:20:15 GMT
From:      Robert Clausecker <fuz@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: cec0236976cd - stable/14 - lib/libc/amd64/string/strcspn.S: always return earliest match in 17--32 char case
Message-ID:  <202312281720.3BSHKFE6080732@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by fuz:

URL: https://cgit.FreeBSD.org/src/commit/?id=cec0236976cd0cce0c7c05b1031b7f4215ce9178

commit cec0236976cd0cce0c7c05b1031b7f4215ce9178
Author:     Robert Clausecker <fuz@FreeBSD.org>
AuthorDate: 2023-12-19 17:28:57 +0000
Commit:     Robert Clausecker <fuz@FreeBSD.org>
CommitDate: 2023-12-28 17:02:41 +0000

    lib/libc/amd64/string/strcspn.S: always return earliest match in 17--32 char case
    
    When matching against a set of 17--32 characters, strcspn() uses two
    invocations of PCMPISTRI to match against the first 16 characters
    of the set and then the remaining characters.  If a match was found in
    the first half of the set, the code originally immediately returned
    that match.  However, it is possible for a match in the second half of
    the set to occur earlier in the vector, leading to that match being
    overlooked.
    
    Fix the code by checking if there is a match in the second half of the
    set and taking the earlier of the two matches.
    
    The correctness of the function has been verified with extended unit
    tests and test runs against the glibc test suite.
    
    Approved by:    mjg (implicit, via IRC)
    MFC after:      1 week
    MFC to:         stable/14
    
    (cherry picked from commit c91cd7d03a9dee649ba3a1b9b4014df9de111bb8)
---
 lib/libc/amd64/string/strcspn.S | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/lib/libc/amd64/string/strcspn.S b/lib/libc/amd64/string/strcspn.S
index 53100eeea9a5..648635529e5b 100644
--- a/lib/libc/amd64/string/strcspn.S
+++ b/lib/libc/amd64/string/strcspn.S
@@ -255,19 +255,28 @@ ARCHENTRY(strcspn, x86_64_v2)
 	leave
 	ret
 
+	/* match in first set half during head */
+.Lheadmatchv2first:
+	mov		%ecx, %eax
+	pcmpistri	$0, %xmm0, %xmm3	# match in second set half?
+	cmp		%ecx, %eax		# before the first half match?
+	cmova		%ecx, %eax		# use the earlier match
+	leave
+	ret
+
 .Lgt16v2:
 	movdqu		48(%rsp, %rcx, 1), %xmm3 # second part of set
 
 	/* set is 17--32 bytes in size */
 	pcmpistri	$0, %xmm0, %xmm2	# match in first set half?
-	jb		.Lheadmatchv2
+	jb		.Lheadmatchv2first
 	pcmpistri	$0, %xmm0, %xmm3	# match in second set half or end of string?
 	jbe		.Lheadmatchv2
 
 	ALIGN_TEXT
 0:	movdqa		(%rax), %xmm0
 	pcmpistri	$0, %xmm0, %xmm2
-	jb		2f			# match in first set half?
+	jb		4f			# match in first set half?
 	pcmpistri	$0, %xmm0, %xmm3
 	jbe		1f			# match in second set half or end of string?
 	movdqa		16(%rax), %xmm0
@@ -277,7 +286,8 @@ ARCHENTRY(strcspn, x86_64_v2)
 	pcmpistri	$0, %xmm0, %xmm3
 	ja		0b			# neither match in 2nd half nor string end?
 
-3:	lea		-16(%rax), %rax		# go back to second half
+	/* match in second half or NUL */
+	lea		-16(%rax), %rax		# go back to second half
 1:	jc		2f			# jump if match found
 	pxor		%xmm1, %xmm1
 	pcmpeqb		%xmm1, %xmm0		# where is the NUL byte?
@@ -288,6 +298,17 @@ ARCHENTRY(strcspn, x86_64_v2)
 	leave
 	ret
 
+	/* match in first half */
+3:	sub		$16, %rax		# go back to second half
+4:	sub		%rdi, %rax		# offset of %xmm0 from beginning of string
+	mov		%ecx, %edx
+	pcmpistri	$0, %xmm0, %xmm3	# match in second set half?
+	cmp		%ecx, %edx		# before the first half match?
+	cmova		%ecx, %edx		# use the earlier match
+	add		%rdx, %rax		# return full ofset
+	leave
+	ret
+
 	/* set is empty, degrades to strlen */
 .Lstrlenv2:
 	leave



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202312281720.3BSHKFE6080732>