Home | History | Annotate | Download | only in gen
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 	.file	"strchr.s"
     28 
     29 /*
     30  * The strchr() function returns a pointer to the first occurrence of c
     31  * (converted to a char) in string s, or a null pointer if c does not occur
     32  * in the string.
     33  */
     34 
     35 #include <sys/asm_linkage.h>
     36 
     37 	! Here, we start by checking to see if we're searching the dest
     38 	! string for a null byte.  We have fast code for this, so it's
     39 	! an important special case.  Otherwise, if the string is not
     40 	! word aligned, we check a for the search char a byte at a time
     41 	! until we've reached a word boundary.  Once this has happened
     42 	! some zero-byte finding values are initialized and the string
     43 	! is checked a word at a time
     44 
     45 	ENTRY(strchr)
     46 
     47 	.align 32
     48 
     49 	andcc	%o1, 0xff, %o1		! search only for this one byte
     50 	bz,pn	%ncc, .searchnullbyte	! faster code for searching null
     51 	andcc	%o0, 3, %o4		! str word aligned ?
     52 	bz,a,pn	%ncc, .prepword2	! yup, prepare for word-wise search
     53 	sll	%o1, 8, %g1		! start spreading findchar across word
     54 
     55 	ldub	[%o0], %o2		! str[0]
     56 	cmp	%o2, %o1		! str[0] == findchar ?
     57 	be,pn	%ncc, .done		! yup, done
     58 	tst	%o2			! str[0] == 0 ?
     59 	bz,pn	%ncc, .notfound		! yup, return null pointer
     60 	cmp	%o4, 3			! only one byte needed to align?
     61 	bz,pn	%ncc, .prepword		! yup, prepare for word-wise search
     62 	inc	%o0			! str++
     63 	ldub	[%o0], %o2		! str[1]
     64 	cmp	%o2, %o1		! str[1] == findchar ?
     65 	be,pn	%ncc, .done		! yup, done
     66 	tst	%o2			! str[1] == 0 ?
     67 	bz,pn	%ncc, .notfound		! yup, return null pointer
     68 	cmp	%o4, 2			! only two bytes needed to align?
     69 	bz,pn	%ncc, .prepword		! yup, prepare for word-wise search
     70 	inc	%o0			! str++
     71 	ldub	[%o0], %o2		! str[2]
     72 	cmp	%o2, %o1		! str[2] == findchar ?
     73 	be,pn	%ncc, .done		! yup, done
     74 	tst	%o2			! str[2] == 0 ?
     75 	bz,pn	%ncc, .notfound		! yup, return null pointer
     76 	inc	%o0			! str++
     77 
     78 .prepword:
     79 	sll	%o1, 8, %g1		! spread findchar ------+
     80 .prepword2:							!
     81 	sethi	%hi(0x01010101), %o4	! Alan Mycroft's magic1 !
     82 	or	%o1, %g1, %o1		!  across all <---------+
     83 	sethi	%hi(0x80808080), %o5	! Alan Mycroft's magic2	!
     84 	sll	%o1, 16, %g1		!   four bytes <--------+
     85 	or	%o4, %lo(0x01010101), %o4			!
     86 	or	%o1, %g1, %o1		!    of a word <--------+
     87 	or	%o5, %lo(0x80808080), %o5
     88 
     89 .searchchar:
     90 	lduw	[%o0], %o2		! src word
     91 	andn	%o5, %o2, %o3		! ~word & 0x80808080
     92 	sub	%o2, %o4, %g1		! word = (word - 0x01010101)
     93 	andcc	%o3, %g1, %g0		! ((word - 0x01010101) & ~word & 0x80808080)
     94 	bnz,pn	%ncc, .haszerobyte	! zero byte if magic expression != 0
     95 	xor	%o2, %o1, %g1		! tword = word ^ findchar
     96 	andn	%o5, %g1, %o3		! ~tword & 0x80808080
     97 	sub	%g1, %o4, %o2		! (tword - 0x01010101)
     98 	andcc	%o3, %o2, %g0		! ((tword - 0x01010101) & ~tword & 0x80808080)
     99 	bz,a,pt	%ncc, .searchchar	! no findchar if magic expression == 0
    100 	add	%o0, 4, %o0		! str += 4
    101 
    102 	! here we know "word" contains the searched character, but no null
    103 	! byte. if there was a null byte, we would have gone to .haszerobyte
    104 	! "tword" has null bytes where "word" had findchar. Examine "tword"
    105 
    106 .foundchar:
    107 	set	0xff000000, %o4		! mask for 1st byte
    108 	andcc	%g1, %o4, %g0		! first byte zero (= found search char) ?
    109 	bz,pn	%ncc, .done		! yup, done
    110 	set	0x00ff0000, %o5		! mask for 2nd byte
    111 	inc	%o0			! str++
    112 	andcc	%g1, %o5, %g0		! second byte zero (= found search char) ?
    113 	bz,pn	%ncc, .done		! yup, done
    114 	srl	%o4, 16, %o4		! 0x0000ff00 = mask for 3rd byte
    115 	inc	%o0			! str++
    116 	andcc	%g1, %o4, %g0		! third byte zero (= found search char) ?
    117 	bnz,a	%ncc, .done		! nope, increment in delay slot
    118 	inc	%o0			! str++
    119 
    120 .done:
    121 	retl				! done with leaf function
    122 	nop				! padding
    123 
    124 	! Here we know that "word" contains a null byte indicating the
    125 	! end of the string. However, "word" might also contain findchar
    126 	! "tword" (in %g1) has null bytes where "word" had findchar. So
    127 	! check both "tword" and "word"
    128 
    129 .haszerobyte:
    130 	set	0xff000000, %o4		! mask for 1st byte
    131 	andcc	%g1, %o4, %g0		! first byte == findchar ?
    132 	bz,pn	%ncc, .done		! yup, done
    133 	andcc	%o2, %o4, %g0		! first byte == 0 ?
    134 	bz,pn	%ncc, .notfound		! yup, return null pointer
    135 	set	0x00ff0000, %o4		! mask for 2nd byte
    136 	inc	%o0			! str++
    137 	andcc	%g1, %o4, %g0		! second byte == findchar ?
    138 	bz,pn	%ncc, .done		! yup, done
    139 	andcc	%o2, %o4, %g0		! second byte == 0 ?
    140 	bz,pn	%ncc, .notfound		! yup, return null pointer
    141 	srl	%o4, 8, %o4		! mask for 3rd byte = 0x0000ff00
    142 	inc	%o0			! str++
    143 	andcc	%g1, %o4, %g0		! third byte == findchar ?
    144 	bz,pn	%ncc, .done		! yup, done
    145 	andcc	%o2, %o4, %g0		! third byte == 0 ?
    146 	bz,pn	%ncc, .notfound		! yup, return null pointer
    147 	andcc	%g1, 0xff, %g0		! fourth byte == findchar ?
    148 	bz,pn	%ncc, .done		! yup, done
    149 	inc	%o0			! str++
    150 
    151 .notfound:
    152 	retl				! done with leaf function
    153 	xor	%o0, %o0, %o0		! return null pointer
    154 
    155 	! since findchar == 0, we only have to do one test per item
    156 	! instead of two. This makes the search much faster.
    157 
    158 .searchnullbyte:
    159 	bz,pn	%ncc, .straligned	! str is word aligned
    160 	nop				! padding
    161 
    162 	cmp	%o4, 2			! str halfword aligned ?
    163 	be,pn	%ncc, .s2aligned	! yup
    164 	ldub	[%o0], %o1		! str[0]
    165 	tst	%o1			! byte zero?
    166 	bz,pn	%ncc, .done		! yup, done
    167 	cmp	%o4, 3			! only one byte needed to align?
    168 	bz,pn	%ncc, .straligned	! yup
    169 	inc	%o0			! str++
    170 
    171 	! check to see if we're half word aligned, which it better than
    172 	! not being aligned at all.  Search the first half of the word
    173 	! if we are, and then search by whole word.
    174 
    175 .s2aligned:
    176 	lduh	[%o0], %o1		! str[]
    177 	srl	%o1, 8, %o4		! %o4<7:0> = first byte
    178 	tst	%o4			! first byte zero ?
    179 	bz,pn	%ncc, .done2		! yup, done
    180 	andcc	%o1, 0xff, %g0		! second byte zero ?
    181 	bz,a,pn	%ncc, .done2		! yup, done
    182 	inc	%o0			! str++
    183 	add	%o0, 2, %o0		! str+=2
    184 
    185 .straligned:
    186 	sethi	%hi(0x01010101), %o4	! Alan Mycroft's magic1
    187 	sethi	%hi(0x80808080), %o5	! Alan Mycroft's magic2
    188 	or	%o4, %lo(0x01010101), %o4
    189 	or	%o5, %lo(0x80808080), %o5
    190 
    191 .searchword:
    192 	lduw	[%o0], %o1		! src word
    193 	andn	%o5, %o1, %o3		! ~word & 0x80808080
    194 	sub	%o1, %o4, %g1		! word = (word - 0x01010101)
    195 	andcc	%o3, %g1, %g0		! ((word - 0x01010101) & ~word & 0x80808080)
    196 	bz,a,pt	%ncc, .searchword	! no zero byte if magic expression == 0
    197 	add	%o0, 4, %o0		! str += 4
    198 
    199 .zerobyte:
    200 	set	0xff000000, %o4		! mask for 1st byte
    201 	andcc	%o1, %o4, %g0		! first byte zero?
    202 	bz,pn	%ncc, .done2		! yup, done
    203 	set	0x00ff0000, %o5		! mask for 2nd byte
    204 	inc	%o0			! str++
    205 	andcc	%o1, %o5, %g0		! second byte zero?
    206 	bz,pn	%ncc, .done2		! yup, done
    207 	srl	%o4, 16, %o4		! 0x0000ff00 = mask for 3rd byte
    208 	inc	%o0			! str++
    209 	andcc	%o1, %o4, %g0		! third byte zero?
    210 	bnz,a	%ncc, .done2		! nope, increment in delay slot
    211 	inc	%o0			! str++
    212 .done2:
    213     	retl				! return from leaf function
    214 	nop				! padding
    215 
    216 	SET_SIZE(strchr)
    217