| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Optimized version of the standard memchr() function. | 
|  | 2 | This file is part of the GNU C Library. | 
|  | 3 | Copyright (C) 2000-2016 Free Software Foundation, Inc. | 
|  | 4 | Contributed by Dan Pop <Dan.Pop@cern.ch>. | 
|  | 5 |  | 
|  | 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. | 
|  | 10 |  | 
|  | 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. | 
|  | 15 |  | 
|  | 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/>.  */ | 
|  | 19 |  | 
|  | 20 | /* Return: the address of the first occurence of chr in str or NULL | 
|  | 21 |  | 
|  | 22 | Inputs: | 
|  | 23 | in0:	str | 
|  | 24 | in1:	chr | 
|  | 25 | in2:	byte count | 
|  | 26 |  | 
|  | 27 | This implementation assumes little endian mode.  For big endian mode, | 
|  | 28 | the instruction czx1.r should be replaced by czx1.l. | 
|  | 29 |  | 
|  | 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. | 
|  | 33 |  | 
|  | 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. | 
|  | 38 |  | 
|  | 39 | All the loops in this function could have had the internal branch removed | 
|  | 40 | if br.ctop and br.cloop could be predicated :-(.  */ | 
|  | 41 |  | 
|  | 42 | #include <sysdep.h> | 
|  | 43 | #undef ret | 
|  | 44 |  | 
|  | 45 | #define saved_pr	r15 | 
|  | 46 | #define saved_lc	r16 | 
|  | 47 | #define	chr		r17 | 
|  | 48 | #define len		r18 | 
|  | 49 | #define last		r20 | 
|  | 50 | #define val		r21 | 
|  | 51 | #define tmp		r24 | 
|  | 52 | #define chrx8		r25 | 
|  | 53 | #define loopcnt		r30 | 
|  | 54 |  | 
|  | 55 | #define str		in0 | 
|  | 56 |  | 
|  | 57 | ENTRY(__memchr) | 
|  | 58 | .prologue | 
|  | 59 | alloc r2 = ar.pfs, 3, 0, 29, 32 | 
|  | 60 | #include "softpipe.h" | 
|  | 61 | .rotr	value[MEMLAT+1], addr[MEMLAT+3], aux[2], poschr[2] | 
|  | 62 | .rotp	p[MEMLAT+3] | 
|  | 63 | .save ar.lc, saved_lc | 
|  | 64 | mov	saved_lc = ar.lc	// save the loop counter | 
|  | 65 | .save pr, saved_pr | 
|  | 66 | mov	saved_pr = pr		// save the predicates | 
|  | 67 | .body | 
|  | 68 | mov	ret0 = str | 
|  | 69 | add	last = str, in2		// last byte | 
|  | 70 | and	tmp = 7, str		// tmp = str % 8 | 
|  | 71 | cmp.ne	p7, p0 = r0, r0		// clear p7 | 
|  | 72 | extr.u	chr = in1, 0, 8		// chr = (unsigned char) in1 | 
|  | 73 | mov	len = in2 | 
|  | 74 | cmp.gtu	p6, p0 = 16, in2	// use a simple loop for short | 
|  | 75 | (p6)	br.cond.spnt .srchfew ;;	// searches | 
|  | 76 | sub	loopcnt = 8, tmp	// loopcnt = 8 - tmp | 
|  | 77 | cmp.eq	p6, p0 = tmp, r0 | 
|  | 78 | (p6)	br.cond.sptk	.str_aligned;; | 
|  | 79 | sub	len = len, loopcnt | 
|  | 80 | adds	loopcnt = -1, loopcnt;; | 
|  | 81 | mov	ar.lc = loopcnt | 
|  | 82 | .l1: | 
|  | 83 | ld1	val = [ret0], 1 | 
|  | 84 | ;; | 
|  | 85 | cmp.eq	p6, p0 = val, chr | 
|  | 86 | (p6)	br.cond.spnt	.foundit | 
|  | 87 | br.cloop.sptk	.l1 ;; | 
|  | 88 | .str_aligned: | 
|  | 89 | cmp.ne	p6, p0 = r0, r0		// clear p6 | 
|  | 90 | shr.u	loopcnt = len, 3	// loopcnt = len / 8 | 
|  | 91 | and	len = 7, len ;;		// remaining len = len & 7 | 
|  | 92 | adds	loopcnt = -1, loopcnt | 
|  | 93 | mov	ar.ec = MEMLAT + 3 | 
|  | 94 | mux1	chrx8 = chr, @brcst ;;	// get a word full of chr | 
|  | 95 | mov	ar.lc = loopcnt | 
|  | 96 | mov	pr.rot = 1 << 16 ;; | 
|  | 97 | .l2: | 
|  | 98 | (p[0])		mov	addr[0] = ret0 | 
|  | 99 | (p[0])		ld8.s	value[0] = [ret0], 8	 // speculative load | 
|  | 100 | (p[MEMLAT])	chk.s	value[MEMLAT], .recovery // check and recovery | 
|  | 101 | (p[MEMLAT])	xor	aux[0] = value[MEMLAT], chrx8 | 
|  | 102 | (p[MEMLAT+1])	czx1.r	poschr[0] = aux[1] | 
|  | 103 | (p[MEMLAT+2])	cmp.ne	p7, p0 = 8, poschr[1] | 
|  | 104 | (p7)		br.cond.dpnt .foundit | 
|  | 105 | br.ctop.dptk .l2 | 
|  | 106 | .srchfew: | 
|  | 107 | adds	loopcnt = -1, len | 
|  | 108 | cmp.eq	p6, p0 = len, r0 | 
|  | 109 | (p6)	br.cond.spnt .notfound ;; | 
|  | 110 | mov	ar.lc = loopcnt | 
|  | 111 | .l3: | 
|  | 112 | ld1	val = [ret0], 1 | 
|  | 113 | ;; | 
|  | 114 | cmp.eq	p6, p0 = val, chr | 
|  | 115 | (p6)	br.cond.dpnt	.foundit | 
|  | 116 | br.cloop.sptk	.l3 ;; | 
|  | 117 | .notfound: | 
|  | 118 | cmp.ne	p6, p0 = r0, r0	// clear p6 (p7 was already 0 when we got here) | 
|  | 119 | mov	ret0 = r0 ;;	// return NULL | 
|  | 120 | .foundit: | 
|  | 121 | .pred.rel "mutex" p6, p7 | 
|  | 122 | (p6)	adds	ret0 = -1, ret0			   // if we got here from l1 or l3 | 
|  | 123 | (p7)	add	ret0 = addr[MEMLAT+2], poschr[1]   // if we got here from l2 | 
|  | 124 | mov	pr = saved_pr, -1 | 
|  | 125 | mov	ar.lc = saved_lc | 
|  | 126 | br.ret.sptk.many b0 | 
|  | 127 |  | 
|  | 128 | .recovery: | 
|  | 129 | #if MEMLAT != 6 | 
|  | 130 | # error "MEMLAT must be 6!" | 
|  | 131 | #endif | 
|  | 132 | (p[MEMLAT-6])	add	ret0 = -8, ret0;; | 
|  | 133 | (p[MEMLAT-5])	add	ret0 = -8, ret0;; | 
|  | 134 | (p[MEMLAT-4])	add	ret0 = -8, ret0;; | 
|  | 135 | (p[MEMLAT-3])	add	ret0 = -8, ret0;; | 
|  | 136 | (p[MEMLAT-2])	add	ret0 = -8, ret0;; | 
|  | 137 | (p[MEMLAT-1])	add	ret0 = -8, ret0;; | 
|  | 138 | (p[MEMLAT])	add	ret0 = -8, ret0;; | 
|  | 139 | (p[MEMLAT+1])	add	ret0 = -8, ret0;; | 
|  | 140 | (p[MEMLAT+2])	add	ret0 = -8, ret0;; | 
|  | 141 | .l4: | 
|  | 142 | mov     addr[MEMLAT+2] = ret0 | 
|  | 143 | ld8	tmp = [ret0];;		// load the first unchecked 8byte | 
|  | 144 | xor	aux[1] = tmp, chrx8;; | 
|  | 145 | czx1.r	poschr[1] = aux[1];; | 
|  | 146 | cmp.ne	p7, p0 = 8, poschr[1];; | 
|  | 147 | (p7)	add	ret0 = addr[MEMLAT+2], poschr[1];; | 
|  | 148 | (p7)	cmp.geu	p6, p7 = ret0, last	// don't go over the last byte | 
|  | 149 | (p6)	br.cond.spnt	.notfound;; | 
|  | 150 | (p7)	br.cond.spnt	.foundit;; | 
|  | 151 | adds	ret0 = 8, ret0		// load the next unchecked 8byte | 
|  | 152 | br.sptk	.l4;; | 
|  | 153 |  | 
|  | 154 | END(__memchr) | 
|  | 155 |  | 
|  | 156 | weak_alias (__memchr, memchr) | 
|  | 157 | libc_hidden_builtin_def (memchr) |