1/* SPDX-License-Identifier: GPL-2.0 */ 2/* memcpy.S: Sparc optimized memcpy and memmove code 3 * Hand optimized from GNU libc's memcpy and memmove 4 * Copyright (C) 1991,1996 Free Software Foundation 5 * Copyright (C) 1995 Linus Torvalds (Linus.Torvalds@helsinki.fi) 6 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 7 * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) 8 * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 9 */ 10 11#include <asm/export.h> 12#define FUNC(x) \ 13 .globl x; \ 14 .type x,@function; \ 15 .align 4; \ 16x: 17 18/* Both these macros have to start with exactly the same insn */ 19#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ 20 ldd [%src + (offset) + 0x00], %t0; \ 21 ldd [%src + (offset) + 0x08], %t2; \ 22 ldd [%src + (offset) + 0x10], %t4; \ 23 ldd [%src + (offset) + 0x18], %t6; \ 24 st %t0, [%dst + (offset) + 0x00]; \ 25 st %t1, [%dst + (offset) + 0x04]; \ 26 st %t2, [%dst + (offset) + 0x08]; \ 27 st %t3, [%dst + (offset) + 0x0c]; \ 28 st %t4, [%dst + (offset) + 0x10]; \ 29 st %t5, [%dst + (offset) + 0x14]; \ 30 st %t6, [%dst + (offset) + 0x18]; \ 31 st %t7, [%dst + (offset) + 0x1c]; 32 33#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ 34 ldd [%src + (offset) + 0x00], %t0; \ 35 ldd [%src + (offset) + 0x08], %t2; \ 36 ldd [%src + (offset) + 0x10], %t4; \ 37 ldd [%src + (offset) + 0x18], %t6; \ 38 std %t0, [%dst + (offset) + 0x00]; \ 39 std %t2, [%dst + (offset) + 0x08]; \ 40 std %t4, [%dst + (offset) + 0x10]; \ 41 std %t6, [%dst + (offset) + 0x18]; 42 43#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ 44 ldd [%src - (offset) - 0x10], %t0; \ 45 ldd [%src - (offset) - 0x08], %t2; \ 46 st %t0, [%dst - (offset) - 0x10]; \ 47 st %t1, [%dst - (offset) - 0x0c]; \ 48 st %t2, [%dst - (offset) - 0x08]; \ 49 st %t3, [%dst - (offset) - 0x04]; 50 51#define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1, t2, t3) \ 52 ldd [%src - (offset) - 0x10], %t0; \ 53 ldd [%src - (offset) - 0x08], %t2; \ 54 std %t0, [%dst - (offset) - 0x10]; \ 55 std %t2, [%dst - (offset) - 0x08]; 56 57#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ 58 ldub [%src - (offset) - 0x02], %t0; \ 59 ldub [%src - (offset) - 0x01], %t1; \ 60 stb %t0, [%dst - (offset) - 0x02]; \ 61 stb %t1, [%dst - (offset) - 0x01]; 62 63 .text 64 .align 4 65 66FUNC(memmove) 67EXPORT_SYMBOL(memmove) 68 cmp %o0, %o1 69 mov %o0, %g7 70 bleu 9f 71 sub %o0, %o1, %o4 72 73 add %o1, %o2, %o3 74 cmp %o3, %o0 75 bleu 0f 76 andcc %o4, 3, %o5 77 78 add %o1, %o2, %o1 79 add %o0, %o2, %o0 80 sub %o1, 1, %o1 81 sub %o0, 1, %o0 82 831: /* reverse_bytes */ 84 85 ldub [%o1], %o4 86 subcc %o2, 1, %o2 87 stb %o4, [%o0] 88 sub %o1, 1, %o1 89 bne 1b 90 sub %o0, 1, %o0 91 92 retl 93 mov %g7, %o0 94 95/* NOTE: This code is executed just for the cases, 96 where %src (=%o1) & 3 is != 0. 97 We need to align it to 4. So, for (%src & 3) 98 1 we need to do ldub,lduh 99 2 lduh 100 3 just ldub 101 so even if it looks weird, the branches 102 are correct here. -jj 103 */ 10478: /* dword_align */ 105 106 andcc %o1, 1, %g0 107 be 4f 108 andcc %o1, 2, %g0 109 110 ldub [%o1], %g2 111 add %o1, 1, %o1 112 stb %g2, [%o0] 113 sub %o2, 1, %o2 114 bne 3f 115 add %o0, 1, %o0 1164: 117 lduh [%o1], %g2 118 add %o1, 2, %o1 119 sth %g2, [%o0] 120 sub %o2, 2, %o2 121 b 3f 122 add %o0, 2, %o0 123 124FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ 125EXPORT_SYMBOL(memcpy) 126 127 sub %o0, %o1, %o4 128 mov %o0, %g7 1299: 130 andcc %o4, 3, %o5 1310: 132 bne 86f 133 cmp %o2, 15 134 135 bleu 90f 136 andcc %o1, 3, %g0 137 138 bne 78b 1393: 140 andcc %o1, 4, %g0 141 142 be 2f 143 mov %o2, %g1 144 145 ld [%o1], %o4 146 sub %g1, 4, %g1 147 st %o4, [%o0] 148 add %o1, 4, %o1 149 add %o0, 4, %o0 1502: 151 andcc %g1, 0xffffff80, %g0 152 be 3f 153 andcc %o0, 4, %g0 154 155 be 82f + 4 1565: 157 MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) 158 MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) 159 MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) 160 MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) 161 sub %g1, 128, %g1 162 add %o1, 128, %o1 163 cmp %g1, 128 164 bge 5b 165 add %o0, 128, %o0 1663: 167 andcc %g1, 0x70, %g4 168 be 80f 169 andcc %g1, 8, %g0 170 171 sethi %hi(80f), %o5 172 srl %g4, 1, %o4 173 add %g4, %o4, %o4 174 add %o1, %g4, %o1 175 sub %o5, %o4, %o5 176 jmpl %o5 + %lo(80f), %g0 177 add %o0, %g4, %o0 178 17979: /* memcpy_table */ 180 181 MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5) 182 MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5) 183 MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5) 184 MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5) 185 MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5) 186 MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5) 187 MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5) 188 18980: /* memcpy_table_end */ 190 be 81f 191 andcc %g1, 4, %g0 192 193 ldd [%o1], %g2 194 add %o0, 8, %o0 195 st %g2, [%o0 - 0x08] 196 add %o1, 8, %o1 197 st %g3, [%o0 - 0x04] 198 19981: /* memcpy_last7 */ 200 201 be 1f 202 andcc %g1, 2, %g0 203 204 ld [%o1], %g2 205 add %o1, 4, %o1 206 st %g2, [%o0] 207 add %o0, 4, %o0 2081: 209 be 1f 210 andcc %g1, 1, %g0 211 212 lduh [%o1], %g2 213 add %o1, 2, %o1 214 sth %g2, [%o0] 215 add %o0, 2, %o0 2161: 217 be 1f 218 nop 219 220 ldub [%o1], %g2 221 stb %g2, [%o0] 2221: 223 retl 224 mov %g7, %o0 225 22682: /* ldd_std */ 227 MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) 228 MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) 229 MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) 230 MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) 231 subcc %g1, 128, %g1 232 add %o1, 128, %o1 233 cmp %g1, 128 234 bge 82b 235 add %o0, 128, %o0 236 237 andcc %g1, 0x70, %g4 238 be 84f 239 andcc %g1, 8, %g0 240 241 sethi %hi(84f), %o5 242 add %o1, %g4, %o1 243 sub %o5, %g4, %o5 244 jmpl %o5 + %lo(84f), %g0 245 add %o0, %g4, %o0 246 24783: /* amemcpy_table */ 248 249 MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3, g4, g5) 250 MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3, g4, g5) 251 MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3, g4, g5) 252 MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5) 253 MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5) 254 MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5) 255 MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5) 256 25784: /* amemcpy_table_end */ 258 be 85f 259 andcc %g1, 4, %g0 260 261 ldd [%o1], %g2 262 add %o0, 8, %o0 263 std %g2, [%o0 - 0x08] 264 add %o1, 8, %o1 26585: /* amemcpy_last7 */ 266 be 1f 267 andcc %g1, 2, %g0 268 269 ld [%o1], %g2 270 add %o1, 4, %o1 271 st %g2, [%o0] 272 add %o0, 4, %o0 2731: 274 be 1f 275 andcc %g1, 1, %g0 276 277 lduh [%o1], %g2 278 add %o1, 2, %o1 279 sth %g2, [%o0] 280 add %o0, 2, %o0 2811: 282 be 1f 283 nop 284 285 ldub [%o1], %g2 286 stb %g2, [%o0] 2871: 288 retl 289 mov %g7, %o0 290 29186: /* non_aligned */ 292 cmp %o2, 6 293 bleu 88f 294 nop 295 296 save %sp, -96, %sp 297 andcc %i0, 3, %g0 298 be 61f 299 andcc %i0, 1, %g0 300 be 60f 301 andcc %i0, 2, %g0 302 303 ldub [%i1], %g5 304 add %i1, 1, %i1 305 stb %g5, [%i0] 306 sub %i2, 1, %i2 307 bne 61f 308 add %i0, 1, %i0 30960: 310 ldub [%i1], %g3 311 add %i1, 2, %i1 312 stb %g3, [%i0] 313 sub %i2, 2, %i2 314 ldub [%i1 - 1], %g3 315 add %i0, 2, %i0 316 stb %g3, [%i0 - 1] 31761: 318 and %i1, 3, %g2 319 and %i2, 0xc, %g3 320 and %i1, -4, %i1 321 cmp %g3, 4 322 sll %g2, 3, %g4 323 mov 32, %g2 324 be 4f 325 sub %g2, %g4, %l0 326 327 blu 3f 328 cmp %g3, 0x8 329 330 be 2f 331 srl %i2, 2, %g3 332 333 ld [%i1], %i3 334 add %i0, -8, %i0 335 ld [%i1 + 4], %i4 336 b 8f 337 add %g3, 1, %g3 3382: 339 ld [%i1], %i4 340 add %i0, -12, %i0 341 ld [%i1 + 4], %i5 342 add %g3, 2, %g3 343 b 9f 344 add %i1, -4, %i1 3453: 346 ld [%i1], %g1 347 add %i0, -4, %i0 348 ld [%i1 + 4], %i3 349 srl %i2, 2, %g3 350 b 7f 351 add %i1, 4, %i1 3524: 353 ld [%i1], %i5 354 cmp %i2, 7 355 ld [%i1 + 4], %g1 356 srl %i2, 2, %g3 357 bleu 10f 358 add %i1, 8, %i1 359 360 ld [%i1], %i3 361 add %g3, -1, %g3 3625: 363 sll %i5, %g4, %g2 364 srl %g1, %l0, %g5 365 or %g2, %g5, %g2 366 st %g2, [%i0] 3677: 368 ld [%i1 + 4], %i4 369 sll %g1, %g4, %g2 370 srl %i3, %l0, %g5 371 or %g2, %g5, %g2 372 st %g2, [%i0 + 4] 3738: 374 ld [%i1 + 8], %i5 375 sll %i3, %g4, %g2 376 srl %i4, %l0, %g5 377 or %g2, %g5, %g2 378 st %g2, [%i0 + 8] 3799: 380 ld [%i1 + 12], %g1 381 sll %i4, %g4, %g2 382 srl %i5, %l0, %g5 383 addcc %g3, -4, %g3 384 or %g2, %g5, %g2 385 add %i1, 16, %i1 386 st %g2, [%i0 + 12] 387 add %i0, 16, %i0 388 bne,a 5b 389 ld [%i1], %i3 39010: 391 sll %i5, %g4, %g2 392 srl %g1, %l0, %g5 393 srl %l0, 3, %g3 394 or %g2, %g5, %g2 395 sub %i1, %g3, %i1 396 andcc %i2, 2, %g0 397 st %g2, [%i0] 398 be 1f 399 andcc %i2, 1, %g0 400 401 ldub [%i1], %g2 402 add %i1, 2, %i1 403 stb %g2, [%i0 + 4] 404 add %i0, 2, %i0 405 ldub [%i1 - 1], %g2 406 stb %g2, [%i0 + 3] 4071: 408 be 1f 409 nop 410 ldub [%i1], %g2 411 stb %g2, [%i0 + 4] 4121: 413 ret 414 restore %g7, %g0, %o0 415 41688: /* short_end */ 417 418 and %o2, 0xe, %o3 41920: 420 sethi %hi(89f), %o5 421 sll %o3, 3, %o4 422 add %o0, %o3, %o0 423 sub %o5, %o4, %o5 424 add %o1, %o3, %o1 425 jmpl %o5 + %lo(89f), %g0 426 andcc %o2, 1, %g0 427 428 MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3) 429 MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3) 430 MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3) 431 MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3) 432 MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3) 433 MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3) 434 MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3) 435 43689: /* short_table_end */ 437 438 be 1f 439 nop 440 441 ldub [%o1], %g2 442 stb %g2, [%o0] 4431: 444 retl 445 mov %g7, %o0 446 44790: /* short_aligned_end */ 448 bne 88b 449 andcc %o2, 8, %g0 450 451 be 1f 452 andcc %o2, 4, %g0 453 454 ld [%o1 + 0x00], %g2 455 ld [%o1 + 0x04], %g3 456 add %o1, 8, %o1 457 st %g2, [%o0 + 0x00] 458 st %g3, [%o0 + 0x04] 459 add %o0, 8, %o0 4601: 461 b 81b 462 mov %o2, %g1 463