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 */ 22 23#include <asm/regdef.h> 24 25 .set noat 26 .set noreorder 27 28 .text 29 30 31 .ent stxcpy_aligned 32 .align 3 33stxcpy_aligned: 34 .frame sp, 0, t9 35 .prologue 0 36 37 /* On entry to this basic block: 38 t0 == the first destination word for masking back in 39 t1 == the first source word. */ 40 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 : 50 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. */ 54 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) 62 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) 70 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) 75 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 : 84 851: stq_u t1, 0(a0) # e0 : 86 ret (t9) # .. e1 : 87 88 .end stxcpy_aligned 89 90 .align 3 91 .ent __stxcpy 92 .globl __stxcpy 93__stxcpy: 94 .frame sp, 0, t9 95 .prologue 0 96 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 : 102 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 : 110 111 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. */ 115 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. 121 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 */ 126 127 ldq_u t2, 8(a1) # e0 : 128 addq a1, 8, a1 # .. e1 : 129 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 : 136 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 : 141 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) 146 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. */ 149 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 : 158 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. 165 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 169 170 We further know that t2 does not contain a null terminator. */ 171 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 : 184 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. 189 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 196 197 cmpbge zero, t1, t8 # e0 : is the null in this first bit? 198 bne t8, $u_final # .. e1 (zdb) 199 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 : 205 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 : 213 214 and t12, 0x80, t6 # e0 : avoid dest word load if we can 215 bne t6, 1f # .. e1 (zdb) 216 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 : 223 2241: stq_u t1, 0(a0) # e0 : 225 ret (t9) # .. e1 : 226 227 /* Unaligned copy entry point. */ 228 .align 3 229$unaligned: 230 231 ldq_u t1, 0(a1) # e0 : load first source word 232 233 and a0, 7, t4 # .. e1 : find dest misalignment 234 and a1, 7, t5 # e0 : find src misalignment 235 236 /* Conditionally load the first destination word and a bytemask 237 with 0xff indicating that the destination byte is sacrosanct. */ 238 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 : 2451: 246 subq a1, t4, a1 # .. e1 : sub dest misalignment from src addr 247 248 /* If source misalignment is larger than dest misalignment, we need 249 extra startup checks to avoid SEGV. */ 250 251 cmplt t4, t5, t12 # e0 : 252 beq t12, $u_head # .. e1 (zdb) 253 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) 260 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.) */ 265 266 ldq_u t0, 0(a0) # e0 : 267 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 274 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 : 279 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 : 284 285 .end __stxcpy 286