Move all files into ports/ subdirectory in preparation for merge with glibc
[glibc.git] / ports / sysdeps / alpha / alphaev6 / stxncpy.S
blob28495df004e1f9b722c48d60e2b1943c91101d68
1 /* Copyright (C) 2000-2012 Free Software Foundation, Inc.
2    Contributed by Richard Henderson (rth@tamu.edu)
3    EV6 optimized by Rick Gorton <rick.gorton@alpha-processor.com>.
4    This file is part of the GNU C Library.
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 /* Copy no more than COUNT bytes of the null-terminated string from
21    SRC to DST.
23    This is an internal routine used by strncpy, stpncpy, and strncat.
24    As such, it uses special linkage conventions to make implementation
25    of these public functions more efficient.
27    On input:
28         t9 = return address
29         a0 = DST
30         a1 = SRC
31         a2 = COUNT
33    Furthermore, COUNT may not be zero.
35    On output:
36         t0  = last word written
37         t8  = bitmask (with one bit set) indicating the last byte written
38         t10 = bitmask (with one bit set) indicating the byte position of
39               the end of the range specified by COUNT
40         a0  = unaligned address of the last *word* written
41         a2  = the number of full words left in COUNT
43    Furthermore, v0, a3-a5, t11, and t12 are untouched.
46 #include <sysdep.h>
48         .arch ev6
49         .set noat
50         .set noreorder
52         .text
53         .type   __stxncpy, @function
54         .globl  __stxncpy
55         .usepv  __stxncpy, no
57         cfi_startproc
58         cfi_return_column (t9)
60         /* On entry to this basic block:
61            t0 == the first destination word for masking back in
62            t1 == the first source word.  */
63         .align 4
64 stxncpy_aligned:
65         /* Create the 1st output word and detect 0's in the 1st input word.  */
66         lda     t2, -1          # E : build a mask against false zero
67         mskqh   t2, a1, t2      # U :   detection in the src word (stall)
68         mskqh   t1, a1, t3      # U :
69         ornot   t1, t2, t2      # E : (stall)
71         mskql   t0, a1, t0      # U : assemble the first output word
72         cmpbge  zero, t2, t7    # E : bits set iff null found
73         or      t0, t3, t0      # E : (stall)
74         beq     a2, $a_eoc      # U :
76         bne     t7, $a_eos      # U :
77         nop
78         nop
79         nop
81         /* On entry to this basic block:
82            t0 == a source word not containing a null.  */
84         /*
85          * nops here to:
86          *      separate store quads from load quads
87          *      limit of 1 bcond/quad to permit training
88          */
89 $a_loop:
90         stq_u   t0, 0(a0)       # L :
91         addq    a0, 8, a0       # E :
92         subq    a2, 1, a2       # E :
93         nop
95         ldq_u   t0, 0(a1)       # L :
96         addq    a1, 8, a1       # E :
97         cmpbge  zero, t0, t7    # E :
98         beq     a2, $a_eoc      # U :
100         beq     t7, $a_loop     # U :
101         nop
102         nop
103         nop
105         /* Take care of the final (partial) word store.  At this point
106            the end-of-count bit is set in t7 iff it applies.
108            On entry to this basic block we have:
109            t0 == the source word containing the null
110            t7 == the cmpbge mask that found it.  */
111 $a_eos:
112         negq    t7, t8          # E : find low bit set
113         and     t7, t8, t8      # E : (stall)
114         /* For the sake of the cache, don't read a destination word
115            if we're not going to need it.  */
116         and     t8, 0x80, t6    # E : (stall)
117         bne     t6, 1f          # U : (stall)
119         /* We're doing a partial word store and so need to combine
120            our source and original destination words.  */
121         ldq_u   t1, 0(a0)       # L :
122         subq    t8, 1, t6       # E :
123         or      t8, t6, t7      # E : (stall)
124         zapnot  t0, t7, t0      # U : clear src bytes > null (stall)
126         zap     t1, t7, t1      # .. e1 : clear dst bytes <= null
127         or      t0, t1, t0      # e1    : (stall)
128         nop
129         nop
131 1:      stq_u   t0, 0(a0)       # L :
132         ret     (t9)            # L0 : Latency=3
133         nop
134         nop
136         /* Add the end-of-count bit to the eos detection bitmask.  */
137 $a_eoc:
138         or      t10, t7, t7     # E :
139         br      $a_eos          # L0 : Latency=3
140         nop
141         nop
143         .align 4
144 __stxncpy:
145         /* Are source and destination co-aligned?  */
146         lda     t2, -1          # E :
147         xor     a0, a1, t1      # E :
148         and     a0, 7, t0       # E : find dest misalignment
149         nop                     # E :
151         srl     t2, 1, t2       # U :
152         and     t1, 7, t1       # E :
153         cmovlt  a2, t2, a2      # E : bound count to LONG_MAX (stall)
154         nop                     # E :
156         addq    a2, t0, a2      # E : bias count by dest misalignment
157         subq    a2, 1, a2       # E : (stall)
158         and     a2, 7, t2       # E : (stall)
159         lda     t10, 1          # E :
161         srl     a2, 3, a2       # U : a2 = loop counter = (count - 1)/8
162         sll     t10, t2, t10    # U : t10 = bitmask of last count byte
163         nop                     # E :
164         bne     t1, $unaligned  # U : (stall)
166         /* We are co-aligned; take care of a partial first word.  */
167         ldq_u   t1, 0(a1)       # L : load first src word
168         addq    a1, 8, a1       # E :
169         beq     t0, stxncpy_aligned # U : avoid loading dest word if not needed
170         ldq_u   t0, 0(a0)       # L :
172         br      stxncpy_aligned # U :
173         nop
174         nop
175         nop
179 /* The source and destination are not co-aligned.  Align the destination
180    and cope.  We have to be very careful about not reading too much and
181    causing a SEGV.  */
183         .align 4
184 $u_head:
185         /* We know just enough now to be able to assemble the first
186            full source word.  We can still find a zero at the end of it
187            that prevents us from outputting the whole thing.
189            On entry to this basic block:
190            t0 == the first dest word, unmasked
191            t1 == the shifted low bits of the first source word
192            t6 == bytemask that is -1 in dest word bytes */
194         ldq_u   t2, 8(a1)       # L : Latency=3 load second src word
195         addq    a1, 8, a1       # E :
196         mskql   t0, a0, t0      # U : mask trailing garbage in dst
197         extqh   t2, a1, t4      # U : (3 cycle stall on t2)
199         or      t1, t4, t1      # E : first aligned src word complete (stall)
200         mskqh   t1, a0, t1      # U : mask leading garbage in src (stall)
201         or      t0, t1, t0      # E : first output word complete (stall)
202         or      t0, t6, t6      # E : mask original data for zero test (stall)
204         cmpbge  zero, t6, t7    # E :
205         beq     a2, $u_eocfin   # U :
206         lda     t6, -1          # E :
207         nop
209         bne     t7, $u_final    # U :
210         mskql   t6, a1, t6      # U : mask out bits already seen
211         stq_u   t0, 0(a0)       # L : store first output word
212         or      t6, t2, t2      # E :
214         cmpbge  zero, t2, t7    # E : find nulls in second partial
215         addq    a0, 8, a0       # E :
216         subq    a2, 1, a2       # E :
217         bne     t7, $u_late_head_exit   # U :
219         /* Finally, we've got all the stupid leading edge cases taken care
220            of and we can set up to enter the main loop.  */
221         extql   t2, a1, t1      # U : position hi-bits of lo word
222         beq     a2, $u_eoc      # U :
223         ldq_u   t2, 8(a1)       # L : read next high-order source word
224         addq    a1, 8, a1       # E :
226         extqh   t2, a1, t0      # U : position lo-bits of hi word (stall)
227         cmpbge  zero, t2, t7    # E :
228         nop
229         bne     t7, $u_eos      # U :
231         /* Unaligned copy main loop.  In order to avoid reading too much,
232            the loop is structured to detect zeros in aligned source words.
233            This has, unfortunately, effectively pulled half of a loop
234            iteration out into the head and half into the tail, but it does
235            prevent nastiness from accumulating in the very thing we want
236            to run as fast as possible.
238            On entry to this basic block:
239            t0 == the shifted low-order bits from the current source word
240            t1 == the shifted high-order bits from the previous source word
241            t2 == the unshifted current source word
243            We further know that t2 does not contain a null terminator.  */
245         .align 4
246 $u_loop:
247         or      t0, t1, t0      # E : current dst word now complete
248         subq    a2, 1, a2       # E : decrement word count
249         extql   t2, a1, t1      # U : extract high bits for next time
250         addq    a0, 8, a0       # E :
252         stq_u   t0, -8(a0)      # L : save the current word
253         beq     a2, $u_eoc      # U :
254         ldq_u   t2, 8(a1)       # L : Latency=3 load high word for next time
255         addq    a1, 8, a1       # E :
257         extqh   t2, a1, t0      # U : extract low bits (2 cycle stall)
258         cmpbge  zero, t2, t7    # E : test new word for eos
259         nop
260         beq     t7, $u_loop     # U :
262         /* We've found a zero somewhere in the source word we just read.
263            If it resides in the lower half, we have one (probably partial)
264            word to write out, and if it resides in the upper half, we
265            have one full and one partial word left to write out.
267            On entry to this basic block:
268            t0 == the shifted low-order bits from the current source word
269            t1 == the shifted high-order bits from the previous source word
270            t2 == the unshifted current source word.  */
271 $u_eos:
272         or      t0, t1, t0      # E : first (partial) source word complete
273         nop
274         cmpbge  zero, t0, t7    # E : is the null in this first bit? (stall)
275         bne     t7, $u_final    # U : (stall)
277         stq_u   t0, 0(a0)       # L : the null was in the high-order bits
278         addq    a0, 8, a0       # E :
279         subq    a2, 1, a2       # E :
280         nop
282 $u_late_head_exit:
283         extql   t2, a1, t0      # U :
284         cmpbge  zero, t0, t7    # E :
285         or      t7, t10, t6     # E : (stall)
286         cmoveq  a2, t6, t7      # E : Latency=2, extra map slot (stall)
288         /* Take care of a final (probably partial) result word.
289            On entry to this basic block:
290            t0 == assembled source word
291            t7 == cmpbge mask that found the null.  */
292 $u_final:
293         negq    t7, t6          # E : isolate low bit set
294         and     t6, t7, t8      # E : (stall)
295         and     t8, 0x80, t6    # E : avoid dest word load if we can (stall)
296         bne     t6, 1f          # U : (stall)
298         ldq_u   t1, 0(a0)       # L :
299         subq    t8, 1, t6       # E :
300         or      t6, t8, t7      # E : (stall)
301         zapnot  t0, t7, t0      # U : kill source bytes > null
303         zap     t1, t7, t1      # U : kill dest bytes <= null
304         or      t0, t1, t0      # E : (stall)
305         nop
306         nop
308 1:      stq_u   t0, 0(a0)       # L :
309         ret     (t9)            # L0 : Latency=3
311         /* Got to end-of-count before end of string.
312            On entry to this basic block:
313            t1 == the shifted high-order bits from the previous source word  */
314 $u_eoc:
315         and     a1, 7, t6       # E :
316         sll     t10, t6, t6     # U : (stall)
317         and     t6, 0xff, t6    # E : (stall)
318         bne     t6, 1f          # U : (stall)
320         ldq_u   t2, 8(a1)       # L : load final src word
321         nop
322         extqh   t2, a1, t0      # U : extract low bits for last word (stall)
323         or      t1, t0, t1      # E : (stall)
325 1:      cmpbge  zero, t1, t7    # E :
326         mov     t1, t0
328 $u_eocfin:                      # end-of-count, final word
329         or      t10, t7, t7     # E :
330         br      $u_final        # L0 : Latency=3
332         /* Unaligned copy entry point.  */
333         .align 4
334 $unaligned:
336         ldq_u   t1, 0(a1)       # L : load first source word
337         and     a0, 7, t4       # E : find dest misalignment
338         and     a1, 7, t5       # E : find src misalignment
339         /* Conditionally load the first destination word and a bytemask
340            with 0xff indicating that the destination byte is sacrosanct.  */
341         mov     zero, t0        # E :
343         mov     zero, t6        # E :
344         beq     t4, 1f          # U :
345         ldq_u   t0, 0(a0)       # L :
346         lda     t6, -1          # E :
348         mskql   t6, a0, t6      # U :
349         nop
350         nop
351 1:      subq    a1, t4, a1      # E : sub dest misalignment from src addr
353         /* If source misalignment is larger than dest misalignment, we need
354            extra startup checks to avoid SEGV.  */
356         cmplt   t4, t5, t8      # E :
357         extql   t1, a1, t1      # U : shift src into place
358         lda     t2, -1          # E : for creating masks later
359         beq     t8, $u_head     # U : (stall)
361         mskqh   t2, t5, t2      # U : begin src byte validity mask
362         cmpbge  zero, t1, t7    # E : is there a zero?
363         extql   t2, a1, t2      # U :
364         or      t7, t10, t5     # E : test for end-of-count too
366         cmpbge  zero, t2, t3    # E :
367         cmoveq  a2, t5, t7      # E : Latency=2, extra map slot
368         nop                     # E : keep with cmoveq
369         andnot  t7, t3, t7      # E : (stall)
371         beq     t7, $u_head     # U :
372         /* At this point we've found a zero in the first partial word of
373            the source.  We need to isolate the valid source data and mask
374            it into the original destination data.  (Incidentally, we know
375            that we'll need at least one byte of that original dest word.) */
376         ldq_u   t0, 0(a0)       # L :
377         negq    t7, t6          # E : build bitmask of bytes <= zero
378         mskqh   t1, t4, t1      # U :
380         and     t6, t7, t8      # E :
381         subq    t8, 1, t6       # E : (stall)
382         or      t6, t8, t7      # E : (stall)
383         zapnot  t2, t7, t2      # U : prepare source word; mirror changes (stall)
385         zapnot  t1, t7, t1      # U : to source validity mask
386         andnot  t0, t2, t0      # E : zero place for source to reside
387         or      t0, t1, t0      # E : and put it there (stall both t0, t1)
388         stq_u   t0, 0(a0)       # L : (stall)
390         ret     (t9)            # L0 : Latency=3
392         cfi_endproc