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
This commit is contained in:
parent
a0ecf2224e
commit
c91cd7d03a
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue