1 /* strrchr: find the last instance of a character in a string.
3 Copyright (C) 2014-2016 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library. If not, see
19 <http://www.gnu.org/licenses/>. */
29 /* Arguments and results. */
54 #define vrepmask_c v16
60 For each 32-byte hunk we calculate a 64-bit syndrome value, with
61 two bits per byte (LSB is always in bits 0 and 1, for both big
62 and little-endian systems). For each tuple, bit 0 is set iff
63 the relevant byte matched the requested character; bit 1 is set
64 iff the relevant byte matched the NUL end of string (we trigger
65 off bit0 for the special case of looking for NUL). Since the bits
66 in the syndrome reflect exactly the order in which things occur
67 in the original string a count_trailing_zeros() operation will
68 identify exactly which byte is causing the termination, and why. */
71 cbz x1, L(null_search)
72 /* Magic constant 0x40100401 to allow us to identify which lane
73 matches the requested byte. Magic constant 0x80200802 used
74 similarly for NUL termination. */
76 movk wtmp2, #0x4010, lsl #16
77 dup vrepchr.16b, chrin
78 bic src, srcin, #31 /* Work with aligned 32-byte hunks. */
79 dup vrepmask_c.4s, wtmp2
82 add vrepmask_0.4s, vrepmask_c.4s, vrepmask_c.4s /* equiv: lsl #1 */
85 /* Input string is not 32-byte aligned. Rather than forcing
86 the padding bytes to a safe value, we calculate the syndrome
87 for all the bytes, but then mask off those bits of the
88 syndrome that are related to the padding. */
89 ld1 {vdata1.16b, vdata2.16b}, [src], #32
91 cmeq vhas_nul1.16b, vdata1.16b, #0
92 cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b
93 cmeq vhas_nul2.16b, vdata2.16b, #0
94 cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b
95 and vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b
96 and vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b
97 and vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b
98 and vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b
99 addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul2.16b // 256->128
100 addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr2.16b // 256->128
101 addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul1.16b // 128->64
102 addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr1.16b // 128->64
103 mov nul_match, vhas_nul1.2d[0]
106 mov chr_match, vhas_chr1.2d[0]
107 lsr tmp3, const_m1, tmp1
109 bic nul_match, nul_match, tmp3 // Mask padding bits.
110 bic chr_match, chr_match, tmp3 // Mask padding bits.
111 cbnz nul_match, L(tail)
115 csel src_match, src, src_match, ne
116 csel src_offset, chr_match, src_offset, ne
118 ld1 {vdata1.16b, vdata2.16b}, [src], #32
119 cmeq vhas_nul1.16b, vdata1.16b, #0
120 cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b
121 cmeq vhas_nul2.16b, vdata2.16b, #0
122 cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b
123 addp vend1.16b, vhas_nul1.16b, vhas_nul2.16b // 256->128
124 and vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b
125 and vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b
126 addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr2.16b // 256->128
127 addp vend1.16b, vend1.16b, vend1.16b // 128->64
128 addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr1.16b // 128->64
129 mov nul_match, vend1.2d[0]
130 mov chr_match, vhas_chr1.2d[0]
131 cbz nul_match, L(loop)
133 and vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b
134 and vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b
135 addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul2.16b
136 addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul1.16b
137 mov nul_match, vhas_nul1.2d[0]
140 /* Work out exactly where the string ends. */
141 sub tmp4, nul_match, #1
142 eor tmp4, tmp4, nul_match
143 ands chr_match, chr_match, tmp4
144 /* And pick the values corresponding to the last match. */
145 csel src_match, src, src_match, ne
146 csel src_offset, chr_match, src_offset, ne
148 /* Count down from the top of the syndrome to find the last match. */
150 /* Src_match points beyond the word containing the match, so we can
151 simply subtract half the bit-offset into the syndrome. Because
152 we are counting down, we need to go back one more character. */
154 sub result, src_match, tmp3, lsr #1
155 /* But if the syndrome shows no match was found, then return NULL. */
157 csel result, result, xzr, ne
164 weak_alias (strrchr, rindex)
165 libc_hidden_builtin_def (strrchr)