2 * strrchr - find last position of a character in a string.
4 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 * See https://llvm.org/LICENSE.txt for license information.
6 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
15 #include "../asmdefs.h"
17 /* Arguments and results. */
42 #define vrepmask_c v16
48 For each 32-byte hunk we calculate a 64-bit syndrome value, with
49 two bits per byte (LSB is always in bits 0 and 1, for both big
50 and little-endian systems). For each tuple, bit 0 is set iff
51 the relevant byte matched the requested character; bit 1 is set
52 iff the relevant byte matched the NUL end of string (we trigger
53 off bit0 for the special case of looking for NUL). Since the bits
54 in the syndrome reflect exactly the order in which things occur
55 in the original string a count_trailing_zeros() operation will
56 identify exactly which byte is causing the termination, and why. */
58 ENTRY (__strrchr_aarch64)
59 /* Magic constant 0x40100401 to allow us to identify which lane
60 matches the requested byte. Magic constant 0x80200802 used
61 similarly for NUL termination. */
63 movk wtmp2, #0x4010, lsl #16
64 dup vrepchr.16b, chrin
65 bic src, srcin, #31 /* Work with aligned 32-byte hunks. */
66 dup vrepmask_c.4s, wtmp2
69 add vrepmask_0.4s, vrepmask_c.4s, vrepmask_c.4s /* equiv: lsl #1 */
72 /* Input string is not 32-byte aligned. Rather than forcing
73 the padding bytes to a safe value, we calculate the syndrome
74 for all the bytes, but then mask off those bits of the
75 syndrome that are related to the padding. */
76 ld1 {vdata1.16b, vdata2.16b}, [src], #32
78 cmeq vhas_nul1.16b, vdata1.16b, #0
79 cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b
80 cmeq vhas_nul2.16b, vdata2.16b, #0
81 cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b
82 and vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b
83 and vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b
84 and vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b
85 and vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b
86 addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul2.16b // 256->128
87 addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr2.16b // 256->128
88 addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul1.16b // 128->64
89 addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr1.16b // 128->64
90 mov nul_match, vhas_nul1.d[0]
93 mov chr_match, vhas_chr1.d[0]
94 lsr tmp3, const_m1, tmp1
96 bic nul_match, nul_match, tmp3 // Mask padding bits.
97 bic chr_match, chr_match, tmp3 // Mask padding bits.
98 cbnz nul_match, L(tail)
102 csel src_match, src, src_match, ne
103 csel src_offset, chr_match, src_offset, ne
105 ld1 {vdata1.16b, vdata2.16b}, [src], #32
106 cmeq vhas_nul1.16b, vdata1.16b, #0
107 cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b
108 cmeq vhas_nul2.16b, vdata2.16b, #0
109 cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b
110 addp vend1.16b, vhas_nul1.16b, vhas_nul2.16b // 256->128
111 and vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b
112 and vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b
113 addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr2.16b // 256->128
114 addp vend1.16b, vend1.16b, vend1.16b // 128->64
115 addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr1.16b // 128->64
116 mov nul_match, vend1.d[0]
117 mov chr_match, vhas_chr1.d[0]
118 cbz nul_match, L(loop)
120 and vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b
121 and vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b
122 addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul2.16b
123 addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul1.16b
124 mov nul_match, vhas_nul1.d[0]
127 /* Work out exactly where the string ends. */
128 sub tmp4, nul_match, #1
129 eor tmp4, tmp4, nul_match
130 ands chr_match, chr_match, tmp4
131 /* And pick the values corresponding to the last match. */
132 csel src_match, src, src_match, ne
133 csel src_offset, chr_match, src_offset, ne
135 /* Count down from the top of the syndrome to find the last match. */
137 /* Src_match points beyond the word containing the match, so we can
138 simply subtract half the bit-offset into the syndrome. Because
139 we are counting down, we need to go back one more character. */
141 sub result, src_match, tmp3, lsr #1
142 /* But if the syndrome shows no match was found, then return NULL. */
144 csel result, result, xzr, ne
148 END (__strrchr_aarch64)