Alpha ev6 memchr implementation.
[kopensolaris-gnu/glibc.git] / sysdeps / alpha / alphaev6 / memchr.S
1 /* Copyright (C) 2000 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by David Mosberger (davidm@cs.arizona.edu).
4    EV6 optimized by Rick Gorton <rick.gorton@alpha-processor.com>.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    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    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <sysdep.h>
22
23         .arch ev6
24         .set noreorder
25         .set noat
26
27 ENTRY(__memchr)
28 #ifdef PROF
29         ldgp    gp, 0(pv)
30         lda     AT, _mcount
31         jsr     AT, (AT), _mcount
32         .prologue 1
33 #else
34         .prologue 0
35 #endif
36
37         # Hack -- if someone passes in (size_t)-1, hoping to just
38         # search til the end of the address space, we will overflow
39         # below when we find the address of the last byte.  Given
40         # that we will never have a 56-bit address space, cropping
41         # the length is the easiest way to avoid trouble.
42         zap     $18, 0x80, $5   # U : Bound length
43         beq     $18, $not_found # U :
44         ldq_u   $1, 0($16)      # L : load first quadword Latency=3
45         and     $17, 0xff, $17  # E : L L U U : 00000000000000ch
46
47         insbl   $17, 1, $2      # U : 000000000000ch00
48         cmpult  $18, 9, $4      # E : small (< 1 quad) string?
49         or      $2, $17, $17    # E : 000000000000chch
50         lda     $3, -1($31)     # E : U L L U
51
52         sll     $17, 16, $2     # U : 00000000chch0000
53         addq    $16, $5, $5     # E : Max search address
54         or      $2, $17, $17    # E : 00000000chchchch
55         sll     $17, 32, $2     # U : U L L U : chchchch00000000
56
57         or      $2, $17, $17    # E : chchchchchchchch
58         extql   $1, $16, $7     # U : $7 is upper bits
59         beq     $4, $first_quad # U :
60         ldq_u   $6, -1($5)      # L : L U U L : eight or less bytes to search Latency=3
61
62         extqh   $6, $16, $6     # U : 2 cycle stall for $6
63         mov     $16, $0         # E :
64         nop                     # E :
65         or      $7, $6, $1      # E : L U L U $1 = quadword starting at $16
66
67         # Deal with the case where at most 8 bytes remain to be searched
68         # in $1.  E.g.:
69         #       $18 = 6
70         #       $1 = ????c6c5c4c3c2c1
71 $last_quad:
72         negq    $18, $6         # E :
73         xor     $17, $1, $1     # E :
74         srl     $3, $6, $6      # U : $6 = mask of $18 bits set
75         cmpbge  $31, $1, $2     # E : L U L U
76
77         nop
78         nop
79         and     $2, $6, $2      # E :
80         beq     $2, $not_found  # U : U L U L
81
82 $found_it:
83 #if defined(__alpha_fix__) && defined(__alpha_cix__)
84         /*
85          * Since we are guaranteed to have set one of the bits, we don't
86          * have to worry about coming back with a 0x40 out of cttz...
87          */
88         cttz    $2, $3          # U0 :
89         addq    $0, $3, $0      # E : All done
90         nop                     # E :
91         ret                     # L0 : L U L U
92 #else
93         /*
94          * Slow and clunky.  It can probably be improved.
95          * An exercise left for others.
96          */
97         negq    $2, $3          # E :
98         and     $2, $3, $2      # E :
99         and     $2, 0x0f, $1    # E :
100         addq    $0, 4, $3       # E :
101
102         cmoveq  $1, $3, $0      # E : Latency 2, extra map cycle
103         nop                     # E : keep with cmov
104         and     $2, 0x33, $1    # E :
105         addq    $0, 2, $3       # E : U L U L : 2 cycle stall on $0
106
107         cmoveq  $1, $3, $0      # E : Latency 2, extra map cycle
108         nop                     # E : keep with cmov
109         and     $2, 0x55, $1    # E :
110         addq    $0, 1, $3       # E : U L U L : 2 cycle stall on $0
111
112         cmoveq  $1, $3, $0      # E : Latency 2, extra map cycle
113         nop
114         nop
115         ret                     # L0 : L U L U
116 #endif
117
118         # Deal with the case where $18 > 8 bytes remain to be
119         # searched.  $16 may not be aligned.
120         .align 4
121 $first_quad:
122         andnot  $16, 0x7, $0    # E :
123         insqh   $3, $16, $2     # U : $2 = 0000ffffffffffff ($16<0:2> ff)
124         xor     $1, $17, $1     # E :
125         or      $1, $2, $1      # E : U L U L $1 = ====ffffffffffff
126
127         cmpbge  $31, $1, $2     # E :
128         bne     $2, $found_it   # U :
129         # At least one byte left to process.
130         ldq     $1, 8($0)       # L :
131         subq    $5, 1, $18      # E : U L U L
132
133         addq    $0, 8, $0       # E :
134         # Make $18 point to last quad to be accessed (the
135         # last quad may or may not be partial).
136         andnot  $18, 0x7, $18   # E :
137         cmpult  $0, $18, $2     # E :
138         beq     $2, $final      # U : U L U L
139
140         # At least two quads remain to be accessed.
141
142         subq    $18, $0, $4     # E : $4 <- nr quads to be processed
143         and     $4, 8, $4       # E : odd number of quads?
144         bne     $4, $odd_quad_count # U :
145         # At least three quads remain to be accessed
146         mov     $1, $4          # E : L U L U : move prefetched value to correct reg
147
148         .align  4
149 $unrolled_loop:
150         ldq     $1, 8($0)       # L : prefetch $1
151         xor     $17, $4, $2     # E :
152         cmpbge  $31, $2, $2     # E :
153         bne     $2, $found_it   # U : U L U L
154
155         addq    $0, 8, $0       # E :
156         nop                     # E :
157         nop                     # E :
158         nop                     # E :
159
160 $odd_quad_count:
161         xor     $17, $1, $2     # E :
162         ldq     $4, 8($0)       # L : prefetch $4
163         cmpbge  $31, $2, $2     # E :
164         addq    $0, 8, $6       # E :
165
166         bne     $2, $found_it   # U :
167         cmpult  $6, $18, $6     # E :
168         addq    $0, 8, $0       # E :
169         nop                     # E :
170
171         bne     $6, $unrolled_loop # U :
172         mov     $4, $1          # E : move prefetched value into $1
173         nop                     # E :
174         nop                     # E :
175
176 $final: subq    $5, $0, $18     # E : $18 <- number of bytes left to do
177         nop                     # E :
178         nop                     # E :
179         bne     $18, $last_quad # U :
180
181 $not_found:
182         mov     $31, $0         # E :
183         nop                     # E :
184         nop                     # E :
185         ret                     # L0 :
186
187         END(__memchr)
188
189 weak_alias (__memchr, memchr)
190 #if !__BOUNDED_POINTERS__
191 weak_alias (__memchr, __ubp_memchr)
192 #endif