RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / arch / alpha / lib / stxcpy.S
blobeaafa5676cefb1ee983eff2141e44257739d1708
1 /*
2  * arch/alpha/lib/stxcpy.S
3  * Contributed by Richard Henderson (rth@tamu.edu)
4  *
5  * Copy a null-terminated string from SRC to DST.
6  *
7  * This is an internal routine used by strcpy, stpcpy, and strcat.
8  * As such, it uses special linkage conventions to make implementation
9  * of these public functions more efficient.
10  *
11  * On input:
12  *      t9 = return address
13  *      a0 = DST
14  *      a1 = SRC
15  *
16  * On output:
17  *      t12 = bitmask (with one bit set) indicating the last byte written
18  *      a0  = unaligned address of the last *word* written
19  *
20  * Furthermore, v0, a3-a5, t11, and t12 are untouched.
21  */
23 #include <asm/regdef.h>
25         .set noat
26         .set noreorder
28         .text
31         .ent stxcpy_aligned
32         .align 3
33 stxcpy_aligned:
34         .frame sp, 0, t9
35         .prologue 0
37         /* On entry to this basic block:
38            t0 == the first destination word for masking back in
39            t1 == the first source word.  */
41         /* Create the 1st output word and detect 0's in the 1st input word.  */
42         lda     t2, -1          # e1    : build a mask against false zero
43         mskqh   t2, a1, t2      # e0    :   detection in the src word
44         mskqh   t1, a1, t3      # e0    :
45         ornot   t1, t2, t2      # .. e1 :
46         mskql   t0, a1, t0      # e0    : assemble the first output word
47         cmpbge  zero, t2, t8    # .. e1 : bits set iff null found
48         or      t0, t3, t1      # e0    :
49         bne     t8, $a_eos      # .. e1 :
51         /* On entry to this basic block:
52            t0 == the first destination word for masking back in
53            t1 == a source word not containing a null.  */
55 $a_loop:
56         stq_u   t1, 0(a0)       # e0    :
57         addq    a0, 8, a0       # .. e1 :
58         ldq_u   t1, 0(a1)       # e0    :
59         addq    a1, 8, a1       # .. e1 :
60         cmpbge  zero, t1, t8    # e0 (stall)
61         beq     t8, $a_loop     # .. e1 (zdb)
63         /* Take care of the final (partial) word store.
64            On entry to this basic block we have:
65            t1 == the source word containing the null
66            t8 == the cmpbge mask that found it.  */
67 $a_eos:
68         negq    t8, t6          # e0    : find low bit set
69         and     t8, t6, t12     # e1 (stall)
71         /* For the sake of the cache, don't read a destination word
72            if we're not going to need it.  */
73         and     t12, 0x80, t6   # e0    :
74         bne     t6, 1f          # .. e1 (zdb)
76         /* We're doing a partial word store and so need to combine
77            our source and original destination words.  */
78         ldq_u   t0, 0(a0)       # e0    :
79         subq    t12, 1, t6      # .. e1 :
80         zapnot  t1, t6, t1      # e0    : clear src bytes >= null
81         or      t12, t6, t8     # .. e1 :
82         zap     t0, t8, t0      # e0    : clear dst bytes <= null
83         or      t0, t1, t1      # e1    :
85 1:      stq_u   t1, 0(a0)       # e0    :
86         ret     (t9)            # .. e1 :
88         .end stxcpy_aligned
90         .align 3
91         .ent __stxcpy
92         .globl __stxcpy
93 __stxcpy:
94         .frame sp, 0, t9
95         .prologue 0
97         /* Are source and destination co-aligned?  */
98         xor     a0, a1, t0      # e0    :
99         unop                    #       :
100         and     t0, 7, t0       # e0    :
101         bne     t0, $unaligned  # .. e1 :
103         /* We are co-aligned; take care of a partial first word.  */
104         ldq_u   t1, 0(a1)       # e0    : load first src word
105         and     a0, 7, t0       # .. e1 : take care not to load a word ...
106         addq    a1, 8, a1               # e0    :
107         beq     t0, stxcpy_aligned      # .. e1 : ... if we wont need it
108         ldq_u   t0, 0(a0)       # e0    :
109         br      stxcpy_aligned  # .. e1 :
112 /* The source and destination are not co-aligned.  Align the destination
113    and cope.  We have to be very careful about not reading too much and
114    causing a SEGV.  */
116         .align 3
117 $u_head:
118         /* We know just enough now to be able to assemble the first
119            full source word.  We can still find a zero at the end of it
120            that prevents us from outputting the whole thing.
122            On entry to this basic block:
123            t0 == the first dest word, for masking back in, if needed else 0
124            t1 == the low bits of the first source word
125            t6 == bytemask that is -1 in dest word bytes */
127         ldq_u   t2, 8(a1)       # e0    :
128         addq    a1, 8, a1       # .. e1 :
130         extql   t1, a1, t1      # e0    :
131         extqh   t2, a1, t4      # e0    :
132         mskql   t0, a0, t0      # e0    :
133         or      t1, t4, t1      # .. e1 :
134         mskqh   t1, a0, t1      # e0    :
135         or      t0, t1, t1      # e1    :
137         or      t1, t6, t6      # e0    :
138         cmpbge  zero, t6, t8    # .. e1 :
139         lda     t6, -1          # e0    : for masking just below
140         bne     t8, $u_final    # .. e1 :
142         mskql   t6, a1, t6              # e0    : mask out the bits we have
143         or      t6, t2, t2              # e1    :   already extracted before
144         cmpbge  zero, t2, t8            # e0    :   testing eos
145         bne     t8, $u_late_head_exit   # .. e1 (zdb)
147         /* Finally, we've got all the stupid leading edge cases taken care
148            of and we can set up to enter the main loop.  */
150         stq_u   t1, 0(a0)       # e0    : store first output word
151         addq    a0, 8, a0       # .. e1 :
152         extql   t2, a1, t0      # e0    : position ho-bits of lo word
153         ldq_u   t2, 8(a1)       # .. e1 : read next high-order source word
154         addq    a1, 8, a1       # e0    :
155         cmpbge  zero, t2, t8    # .. e1 :
156         nop                     # e0    :
157         bne     t8, $u_eos      # .. e1 :
159         /* Unaligned copy main loop.  In order to avoid reading too much,
160            the loop is structured to detect zeros in aligned source words.
161            This has, unfortunately, effectively pulled half of a loop
162            iteration out into the head and half into the tail, but it does
163            prevent nastiness from accumulating in the very thing we want
164            to run as fast as possible.
166            On entry to this basic block:
167            t0 == the shifted high-order bits from the previous source word
168            t2 == the unshifted current source word
170            We further know that t2 does not contain a null terminator.  */
172         .align 3
173 $u_loop:
174         extqh   t2, a1, t1      # e0    : extract high bits for current word
175         addq    a1, 8, a1       # .. e1 :
176         extql   t2, a1, t3      # e0    : extract low bits for next time
177         addq    a0, 8, a0       # .. e1 :
178         or      t0, t1, t1      # e0    : current dst word now complete
179         ldq_u   t2, 0(a1)       # .. e1 : load high word for next time
180         stq_u   t1, -8(a0)      # e0    : save the current word
181         mov     t3, t0          # .. e1 :
182         cmpbge  zero, t2, t8    # e0    : test new word for eos
183         beq     t8, $u_loop     # .. e1 :
185         /* We've found a zero somewhere in the source word we just read.
186            If it resides in the lower half, we have one (probably partial)
187            word to write out, and if it resides in the upper half, we
188            have one full and one partial word left to write out.
190            On entry to this basic block:
191            t0 == the shifted high-order bits from the previous source word
192            t2 == the unshifted current source word.  */
193 $u_eos:
194         extqh   t2, a1, t1      # e0    :
195         or      t0, t1, t1      # e1    : first (partial) source word complete
197         cmpbge  zero, t1, t8    # e0    : is the null in this first bit?
198         bne     t8, $u_final    # .. e1 (zdb)
200 $u_late_head_exit:
201         stq_u   t1, 0(a0)       # e0    : the null was in the high-order bits
202         addq    a0, 8, a0       # .. e1 :
203         extql   t2, a1, t1      # e0    :
204         cmpbge  zero, t1, t8    # .. e1 :
206         /* Take care of a final (probably partial) result word.
207            On entry to this basic block:
208            t1 == assembled source word
209            t8 == cmpbge mask that found the null.  */
210 $u_final:
211         negq    t8, t6          # e0    : isolate low bit set
212         and     t6, t8, t12     # e1    :
214         and     t12, 0x80, t6   # e0    : avoid dest word load if we can
215         bne     t6, 1f          # .. e1 (zdb)
217         ldq_u   t0, 0(a0)       # e0    :
218         subq    t12, 1, t6      # .. e1 :
219         or      t6, t12, t8     # e0    :
220         zapnot  t1, t6, t1      # .. e1 : kill source bytes >= null
221         zap     t0, t8, t0      # e0    : kill dest bytes <= null
222         or      t0, t1, t1      # e1    :
224 1:      stq_u   t1, 0(a0)       # e0    :
225         ret     (t9)            # .. e1 :
227         /* Unaligned copy entry point.  */
228         .align 3
229 $unaligned:
231         ldq_u   t1, 0(a1)       # e0    : load first source word
233         and     a0, 7, t4       # .. e1 : find dest misalignment
234         and     a1, 7, t5       # e0    : find src misalignment
236         /* Conditionally load the first destination word and a bytemask
237            with 0xff indicating that the destination byte is sacrosanct.  */
239         mov     zero, t0        # .. e1 :
240         mov     zero, t6        # e0    :
241         beq     t4, 1f          # .. e1 :
242         ldq_u   t0, 0(a0)       # e0    :
243         lda     t6, -1          # .. e1 :
244         mskql   t6, a0, t6      # e0    :
246         subq    a1, t4, a1      # .. e1 : sub dest misalignment from src addr
248         /* If source misalignment is larger than dest misalignment, we need
249            extra startup checks to avoid SEGV.  */
251         cmplt   t4, t5, t12     # e0    :
252         beq     t12, $u_head    # .. e1 (zdb)
254         lda     t2, -1          # e1    : mask out leading garbage in source
255         mskqh   t2, t5, t2      # e0    :
256         nop                     # e0    :
257         ornot   t1, t2, t3      # .. e1 :
258         cmpbge  zero, t3, t8    # e0    : is there a zero?
259         beq     t8, $u_head     # .. e1 (zdb)
261         /* At this point we've found a zero in the first partial word of
262            the source.  We need to isolate the valid source data and mask
263            it into the original destination data.  (Incidentally, we know
264            that we'll need at least one byte of that original dest word.) */
266         ldq_u   t0, 0(a0)       # e0    :
268         negq    t8, t6          # .. e1 : build bitmask of bytes <= zero
269         and     t6, t8, t12     # e0    :
270         and     a1, 7, t5       # .. e1 :
271         subq    t12, 1, t6      # e0    :
272         or      t6, t12, t8     # e1    :
273         srl     t12, t5, t12    # e0    : adjust final null return value
275         zapnot  t2, t8, t2      # .. e1 : prepare source word; mirror changes
276         and     t1, t2, t1      # e1    : to source validity mask
277         extql   t2, a1, t2      # .. e0 :
278         extql   t1, a1, t1      # e0    :
280         andnot  t0, t2, t0      # .. e1 : zero place for source to reside
281         or      t0, t1, t1      # e1    : and put it there
282         stq_u   t1, 0(a0)       # .. e0 :
283         ret     (t9)            # e1    :
285         .end __stxcpy