1 /* Optimized version of the standard memchr() function.
2 This file is part of the GNU C Library.
3 Copyright (C) 2000-2018 Free Software Foundation, Inc.
4 Contributed by Dan Pop <Dan.Pop@cern.ch>.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
20 /* Return: the address of the first occurence of chr in str or NULL
27 This implementation assumes little endian mode. For big endian mode,
28 the instruction czx1.r should be replaced by czx1.l.
30 The algorithm is fairly straightforward: search byte by byte until we
31 we get to a word aligned address, then search word by word as much as
32 possible; the remaining few bytes are searched one at a time.
34 The word by word search is performed by xor-ing the word with a word
35 containing chr in every byte. If there is a hit, the result will
36 contain a zero byte in the corresponding position. The presence and
37 position of that zero byte is detected with a czx instruction.
39 All the loops in this function could have had the internal branch removed
40 if br.ctop and br.cloop could be predicated :-(. */
59 alloc r2 = ar.pfs, 3, 0, 29, 32
61 .rotr value[MEMLAT+1], addr[MEMLAT+3], aux[2], poschr[2]
64 mov saved_lc = ar.lc // save the loop counter
66 mov saved_pr = pr // save the predicates
69 add last = str, in2 // last byte
71 cmp.ltu p6, p0 = last, str
74 and tmp = 7, str // tmp = str % 8
75 cmp.ne p7, p0 = r0, r0 // clear p7
76 extr.u chr = in1, 0, 8 // chr = (unsigned char) in1
78 cmp.gtu p6, p0 = 16, in2 // use a simple loop for short
79 (p6) br.cond.spnt .srchfew ;; // searches
80 sub loopcnt = 8, tmp // loopcnt = 8 - tmp
81 cmp.eq p6, p0 = tmp, r0
82 (p6) br.cond.sptk .str_aligned;;
83 sub len = len, loopcnt
84 adds loopcnt = -1, loopcnt;;
89 cmp.eq p6, p0 = val, chr
90 (p6) br.cond.spnt .foundit
93 cmp.ne p6, p0 = r0, r0 // clear p6
94 shr.u loopcnt = len, 3 // loopcnt = len / 8
95 and len = 7, len ;; // remaining len = len & 7
96 adds loopcnt = -1, loopcnt
97 mov ar.ec = MEMLAT + 3
98 mux1 chrx8 = chr, @brcst ;; // get a word full of chr
100 mov pr.rot = 1 << 16 ;;
102 (p[0]) mov addr[0] = ret0
103 (p[0]) ld8.s value[0] = [ret0], 8 // speculative load
104 (p[MEMLAT]) chk.s value[MEMLAT], .recovery // check and recovery
105 (p[MEMLAT]) xor aux[0] = value[MEMLAT], chrx8
106 (p[MEMLAT+1]) czx1.r poschr[0] = aux[1]
107 (p[MEMLAT+2]) cmp.ne p7, p0 = 8, poschr[1]
108 (p7) br.cond.dpnt .foundit
111 adds loopcnt = -1, len
112 cmp.eq p6, p0 = len, r0
113 (p6) br.cond.spnt .notfound ;;
118 cmp.eq p6, p0 = val, chr
119 (p6) br.cond.dpnt .foundit
122 cmp.ne p6, p0 = r0, r0 // clear p6 (p7 was already 0 when we got here)
123 mov ret0 = r0 ;; // return NULL
125 .pred.rel "mutex" p6, p7
126 (p6) adds ret0 = -1, ret0 // if we got here from l1 or l3
127 (p7) add ret0 = addr[MEMLAT+2], poschr[1] // if we got here from l2
128 mov pr = saved_pr, -1
134 # error "MEMLAT must be 6!"
136 (p[MEMLAT-6]) add ret0 = -8, ret0;;
137 (p[MEMLAT-5]) add ret0 = -8, ret0;;
138 (p[MEMLAT-4]) add ret0 = -8, ret0;;
139 (p[MEMLAT-3]) add ret0 = -8, ret0;;
140 (p[MEMLAT-2]) add ret0 = -8, ret0;;
141 (p[MEMLAT-1]) add ret0 = -8, ret0;;
142 (p[MEMLAT]) add ret0 = -8, ret0;;
143 (p[MEMLAT+1]) add ret0 = -8, ret0;;
144 (p[MEMLAT+2]) add ret0 = -8, ret0;;
146 mov addr[MEMLAT+2] = ret0
147 ld8 tmp = [ret0];; // load the first unchecked 8byte
148 xor aux[1] = tmp, chrx8;;
149 czx1.r poschr[1] = aux[1];;
150 cmp.ne p7, p0 = 8, poschr[1];;
151 (p7) add ret0 = addr[MEMLAT+2], poschr[1];;
152 (p7) cmp.geu p6, p7 = ret0, last // don't go over the last byte
153 (p6) br.cond.spnt .notfound;;
154 (p7) br.cond.spnt .foundit;;
155 adds ret0 = 8, ret0 // load the next unchecked 8byte
160 weak_alias (__memchr, memchr)
161 libc_hidden_builtin_def (memchr)