1 
   2 
   3 
   4 
   5 
   6 
   7         .file   "M7memcpy.S"
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 
  43 
  44 
  45 
  46 
  47 
  48 
  49 
  50 
  51 
  52 
  53 
  54 
  55 
  56 
  57 
  58 
  59 
  60 
  61 
  62 
  63 
  64 
  65 
  66 
  67 
  68 
  69 
  70 
  71 
  72 
  73 
  74 
  75 
  76 
  77 
  78 
  79 
  80 
  81 
  82 
  83 
  84 
  85 
  86 
  87 
  88 
  89 
  90 
  91 #include <asm/visasm.h>
  92 #include <asm/asi.h>
  93 
  94 #if !defined(EX_LD) && !defined(EX_ST)
  95 #define NON_USER_COPY
  96 #endif
  97 
  98 #ifndef EX_LD
  99 #define EX_LD(x,y)      x
 100 #endif
 101 #ifndef EX_LD_FP
 102 #define EX_LD_FP(x,y)   x
 103 #endif
 104 
 105 #ifndef EX_ST
 106 #define EX_ST(x,y)      x
 107 #endif
 108 #ifndef EX_ST_FP
 109 #define EX_ST_FP(x,y)   x
 110 #endif
 111 
 112 #ifndef EX_RETVAL
 113 #define EX_RETVAL(x)    x
 114 #endif
 115 
 116 #ifndef LOAD
 117 #define LOAD(type,addr,dest)    type [addr], dest
 118 #endif
 119 
 120 #ifndef STORE
 121 #define STORE(type,src,addr)    type src, [addr]
 122 #endif
 123 
 124 
 125 
 126 
 127 
 128 
 129 
 130 
 131 
 132 
 133 #ifndef STORE_ASI
 134 #ifndef SIMULATE_NIAGARA_ON_NON_NIAGARA
 135 #define STORE_ASI       ASI_BLK_INIT_QUAD_LDD_P
 136 #else
 137 #define STORE_ASI       0x80            
 138 #endif
 139 #endif
 140 
 141 #ifndef STORE_MRU_ASI
 142 #ifndef SIMULATE_NIAGARA_ON_NON_NIAGARA
 143 #define STORE_MRU_ASI   ASI_ST_BLKINIT_MRU_P
 144 #else
 145 #define STORE_MRU_ASI   0x80            
 146 #endif
 147 #endif
 148 
 149 #ifndef STORE_INIT
 150 #define STORE_INIT(src,addr)    stxa src, [addr] STORE_ASI
 151 #endif
 152 
 153 #ifndef STORE_INIT_MRU
 154 #define STORE_INIT_MRU(src,addr)        stxa src, [addr] STORE_MRU_ASI
 155 #endif
 156 
 157 #ifndef FUNC_NAME
 158 #define FUNC_NAME       M7memcpy
 159 #endif
 160 
 161 #ifndef PREAMBLE
 162 #define PREAMBLE
 163 #endif
 164 
 165 #define BLOCK_SIZE      64
 166 #define SHORTCOPY       3
 167 #define SHORTCHECK      14
 168 #define SHORT_LONG      64      
 169                                 
 170 #define SMALL_MAX       128
 171 #define MED_UMAX        1024    
 172 #define MED_WMAX        1024    
 173 #define MED_MAX         1024    
 174 #define ST_CHUNK        24      
 175 #define ALIGN_PRE       24      
 176 
 177         .register       %g2,#scratch
 178 
 179         .section        ".text"
 180         .global         FUNC_NAME
 181         .type           FUNC_NAME, #function
 182         .align          16
 183 FUNC_NAME:
 184         srlx            %o2, 31, %g2
 185         cmp             %g2, 0
 186         tne             %xcc, 5
 187         PREAMBLE
 188         mov             %o0, %g1        ! save %o0
 189         brz,pn          %o2, .Lsmallx
 190          cmp            %o2, 3
 191         ble,pn          %icc, .Ltiny_cp
 192          cmp            %o2, 19
 193         ble,pn          %icc, .Lsmall_cp
 194          or             %o0, %o1, %g2
 195         cmp             %o2, SMALL_MAX
 196         bl,pn           %icc, .Lmedium_cp
 197          nop
 198 
 199 .Lmedium:
 200         neg     %o0, %o5
 201         andcc   %o5, 7, %o5             ! bytes till DST 8 byte aligned
 202         brz,pt  %o5, .Ldst_aligned_on_8
 203 
 204         ! %o5 has the bytes to be written in partial store.
 205          sub    %o2, %o5, %o2
 206         sub     %o1, %o0, %o1           ! %o1 gets the difference
 207 7:                                      ! dst aligning loop
 208         add     %o1, %o0, %o4
 209         EX_LD(LOAD(ldub, %o4, %o4), memcpy_retl_o2_plus_o5)     ! load one byte
 210         subcc   %o5, 1, %o5
 211         EX_ST(STORE(stb, %o4, %o0), memcpy_retl_o2_plus_o5_plus_1)
 212         bgu,pt  %xcc, 7b
 213          add    %o0, 1, %o0             ! advance dst
 214         add     %o1, %o0, %o1           ! restore %o1
 215 .Ldst_aligned_on_8:
 216         andcc   %o1, 7, %o5
 217         brnz,pt %o5, .Lsrc_dst_unaligned_on_8
 218          nop
 219 
 220 .Lsrc_dst_aligned_on_8:
 221         ! check if we are copying MED_MAX or more bytes
 222         set MED_MAX, %o3
 223         cmp %o2, %o3                    ! limit to store buffer size
 224         bgu,pn  %xcc, .Llarge_align8_copy
 225          nop
 226 
 227 
 228 
 229 
 230 
 231 .Lmedlong:
 232         subcc   %o2, 63, %o2            ! adjust length to allow cc test
 233         ble,pn  %xcc, .Lmedl63          ! skip big loop if less than 64 bytes
 234          nop
 235 .Lmedl64:
 236         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2_plus_63)      ! load
 237         subcc   %o2, 64, %o2            ! decrement length count
 238         EX_ST(STORE(stx, %o4, %o0), memcpy_retl_o2_plus_63_64)  ! and store
 239         EX_LD(LOAD(ldx, %o1+8, %o3), memcpy_retl_o2_plus_63_56) ! a block of 64
 240         EX_ST(STORE(stx, %o3, %o0+8), memcpy_retl_o2_plus_63_56)
 241         EX_LD(LOAD(ldx, %o1+16, %o4), memcpy_retl_o2_plus_63_48)
 242         EX_ST(STORE(stx, %o4, %o0+16), memcpy_retl_o2_plus_63_48)
 243         EX_LD(LOAD(ldx, %o1+24, %o3), memcpy_retl_o2_plus_63_40)
 244         EX_ST(STORE(stx, %o3, %o0+24), memcpy_retl_o2_plus_63_40)
 245         EX_LD(LOAD(ldx, %o1+32, %o4), memcpy_retl_o2_plus_63_32)! load and store
 246         EX_ST(STORE(stx, %o4, %o0+32), memcpy_retl_o2_plus_63_32)
 247         EX_LD(LOAD(ldx, %o1+40, %o3), memcpy_retl_o2_plus_63_24)! a block of 64
 248         add     %o1, 64, %o1            ! increase src ptr by 64
 249         EX_ST(STORE(stx, %o3, %o0+40), memcpy_retl_o2_plus_63_24)
 250         EX_LD(LOAD(ldx, %o1-16, %o4), memcpy_retl_o2_plus_63_16)
 251         add     %o0, 64, %o0            ! increase dst ptr by 64
 252         EX_ST(STORE(stx, %o4, %o0-16), memcpy_retl_o2_plus_63_16)
 253         EX_LD(LOAD(ldx, %o1-8, %o3), memcpy_retl_o2_plus_63_8)
 254         bgu,pt  %xcc, .Lmedl64          ! repeat if at least 64 bytes left
 255          EX_ST(STORE(stx, %o3, %o0-8), memcpy_retl_o2_plus_63_8)
 256 .Lmedl63:
 257         addcc   %o2, 32, %o2            ! adjust remaining count
 258         ble,pt  %xcc, .Lmedl31          ! to skip if 31 or fewer bytes left
 259          nop
 260         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2_plus_31)      ! load
 261         sub     %o2, 32, %o2            ! decrement length count
 262         EX_ST(STORE(stx, %o4, %o0), memcpy_retl_o2_plus_31_32)  ! and store
 263         EX_LD(LOAD(ldx, %o1+8, %o3), memcpy_retl_o2_plus_31_24) ! a block of 32
 264         add     %o1, 32, %o1            ! increase src ptr by 32
 265         EX_ST(STORE(stx, %o3, %o0+8), memcpy_retl_o2_plus_31_24)
 266         EX_LD(LOAD(ldx, %o1-16, %o4), memcpy_retl_o2_plus_31_16)
 267         add     %o0, 32, %o0            ! increase dst ptr by 32
 268         EX_ST(STORE(stx, %o4, %o0-16), memcpy_retl_o2_plus_31_16)
 269         EX_LD(LOAD(ldx, %o1-8, %o3), memcpy_retl_o2_plus_31_8)
 270         EX_ST(STORE(stx, %o3, %o0-8), memcpy_retl_o2_plus_31_8)
 271 .Lmedl31:
 272         addcc   %o2, 16, %o2            ! adjust remaining count
 273         ble,pt  %xcc, .Lmedl15          ! skip if 15 or fewer bytes left
 274          nop                            !
 275         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2_plus_15)
 276         add     %o1, 16, %o1            ! increase src ptr by 16
 277         EX_ST(STORE(stx, %o4, %o0), memcpy_retl_o2_plus_15)
 278         sub     %o2, 16, %o2            ! decrease count by 16
 279         EX_LD(LOAD(ldx, %o1-8, %o3), memcpy_retl_o2_plus_15_8)
 280         add     %o0, 16, %o0            ! increase dst ptr by 16
 281         EX_ST(STORE(stx, %o3, %o0-8), memcpy_retl_o2_plus_15_8)
 282 .Lmedl15:
 283         addcc   %o2, 15, %o2            ! restore count
 284         bz,pt   %xcc, .Lsmallx  ! exit if finished
 285          cmp    %o2, 8
 286         blt,pt  %xcc, .Lmedw7           ! skip if 7 or fewer bytes left
 287          tst    %o2
 288         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2)      ! load 8 bytes
 289         add     %o1, 8, %o1             ! increase src ptr by 8
 290         add     %o0, 8, %o0             ! increase dst ptr by 8
 291         subcc   %o2, 8, %o2             ! decrease count by 8
 292         bnz,pn  %xcc, .Lmedw7
 293          EX_ST(STORE(stx, %o4, %o0-8), memcpy_retl_o2_plus_8)   ! and store 8
 294         retl
 295          mov    EX_RETVAL(%g1), %o0     ! restore %o0
 296 
 297         .align 16
 298 .Lsrc_dst_unaligned_on_8:
 299         ! DST is 8-byte aligned, src is not
 300 2:
 301         andcc   %o1, 0x3, %o5           ! test word alignment
 302         bnz,pt  %xcc, .Lunalignsetup    ! branch to skip if not word aligned
 303          nop
 304 
 305 
 306 
 307 
 308 
 309 
 310 
 311 
 312         set MED_WMAX, %o3
 313         cmp %o2, %o3                    ! limit to store buffer size
 314         bge,pt  %xcc, .Lunalignrejoin   ! otherwise rejoin main loop
 315          nop
 316 
 317         subcc   %o2, 31, %o2            ! adjust length to allow cc test
 318                                         ! for end of loop
 319         ble,pt  %xcc, .Lmedw31          ! skip big loop if less than 16
 320 .Lmedw32:
 321         EX_LD(LOAD(ld, %o1, %o4), memcpy_retl_o2_plus_31)! move a block of 32
 322         sllx    %o4, 32, %o5
 323         EX_LD(LOAD(ld, %o1+4, %o4), memcpy_retl_o2_plus_31)
 324         or      %o4, %o5, %o5
 325         EX_ST(STORE(stx, %o5, %o0), memcpy_retl_o2_plus_31)
 326         subcc   %o2, 32, %o2            ! decrement length count
 327         EX_LD(LOAD(ld, %o1+8, %o4), memcpy_retl_o2_plus_31_24)
 328         sllx    %o4, 32, %o5
 329         EX_LD(LOAD(ld, %o1+12, %o4), memcpy_retl_o2_plus_31_24)
 330         or      %o4, %o5, %o5
 331         EX_ST(STORE(stx, %o5, %o0+8), memcpy_retl_o2_plus_31_24)
 332         add     %o1, 32, %o1            ! increase src ptr by 32
 333         EX_LD(LOAD(ld, %o1-16, %o4), memcpy_retl_o2_plus_31_16)
 334         sllx    %o4, 32, %o5
 335         EX_LD(LOAD(ld, %o1-12, %o4), memcpy_retl_o2_plus_31_16)
 336         or      %o4, %o5, %o5
 337         EX_ST(STORE(stx, %o5, %o0+16), memcpy_retl_o2_plus_31_16)
 338         add     %o0, 32, %o0            ! increase dst ptr by 32
 339         EX_LD(LOAD(ld, %o1-8, %o4), memcpy_retl_o2_plus_31_8)
 340         sllx    %o4, 32, %o5
 341         EX_LD(LOAD(ld, %o1-4, %o4), memcpy_retl_o2_plus_31_8)
 342         or      %o4, %o5, %o5
 343         bgu,pt  %xcc, .Lmedw32          ! repeat if at least 32 bytes left
 344          EX_ST(STORE(stx, %o5, %o0-8), memcpy_retl_o2_plus_31_8)
 345 .Lmedw31:
 346         addcc   %o2, 31, %o2            ! restore count
 347 
 348         bz,pt   %xcc, .Lsmallx  ! exit if finished
 349          nop
 350         cmp     %o2, 16
 351         blt,pt  %xcc, .Lmedw15
 352          nop
 353         EX_LD(LOAD(ld, %o1, %o4), memcpy_retl_o2)! move a block of 16 bytes
 354         sllx    %o4, 32, %o5
 355         subcc   %o2, 16, %o2            ! decrement length count
 356         EX_LD(LOAD(ld, %o1+4, %o4), memcpy_retl_o2_plus_16)
 357         or      %o4, %o5, %o5
 358         EX_ST(STORE(stx, %o5, %o0), memcpy_retl_o2_plus_16)
 359         add     %o1, 16, %o1            ! increase src ptr by 16
 360         EX_LD(LOAD(ld, %o1-8, %o4), memcpy_retl_o2_plus_8)
 361         add     %o0, 16, %o0            ! increase dst ptr by 16
 362         sllx    %o4, 32, %o5
 363         EX_LD(LOAD(ld, %o1-4, %o4), memcpy_retl_o2_plus_8)
 364         or      %o4, %o5, %o5
 365         EX_ST(STORE(stx, %o5, %o0-8), memcpy_retl_o2_plus_8)
 366 .Lmedw15:
 367         bz,pt   %xcc, .Lsmallx  ! exit if finished
 368          cmp    %o2, 8
 369         blt,pn  %xcc, .Lmedw7           ! skip if 7 or fewer bytes left
 370          tst    %o2
 371         EX_LD(LOAD(ld, %o1, %o4), memcpy_retl_o2)       ! load 4 bytes
 372         subcc   %o2, 8, %o2             ! decrease count by 8
 373         EX_ST(STORE(stw, %o4, %o0), memcpy_retl_o2_plus_8)! and store 4 bytes
 374         add     %o1, 8, %o1             ! increase src ptr by 8
 375         EX_LD(LOAD(ld, %o1-4, %o3), memcpy_retl_o2_plus_4)      ! load 4 bytes
 376         add     %o0, 8, %o0             ! increase dst ptr by 8
 377         EX_ST(STORE(stw, %o3, %o0-4), memcpy_retl_o2_plus_4)! and store 4 bytes
 378         bz,pt   %xcc, .Lsmallx  ! exit if finished
 379 .Lmedw7:                                ! count is ge 1, less than 8
 380         cmp     %o2, 4                  ! check for 4 bytes left
 381         blt,pn  %xcc, .Lsmallleft3      ! skip if 3 or fewer bytes left
 382          nop                            !
 383         EX_LD(LOAD(ld, %o1, %o4), memcpy_retl_o2)       ! load 4 bytes
 384         add     %o1, 4, %o1             ! increase src ptr by 4
 385         add     %o0, 4, %o0             ! increase dst ptr by 4
 386         subcc   %o2, 4, %o2             ! decrease count by 4
 387         bnz     .Lsmallleft3
 388          EX_ST(STORE(stw, %o4, %o0-4), memcpy_retl_o2_plus_4)! and store 4 bytes
 389         retl
 390          mov    EX_RETVAL(%g1), %o0
 391 
 392         .align 16
 393 .Llarge_align8_copy:                    ! Src and dst share 8 byte alignment
 394         ! align dst to 64 byte boundary
 395         andcc   %o0, 0x3f, %o3          ! %o3 == 0 means dst is 64 byte aligned
 396         brz,pn  %o3, .Laligned_to_64
 397          andcc  %o0, 8, %o3             ! odd long words to move?
 398         brz,pt  %o3, .Laligned_to_16
 399          nop
 400         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2)
 401         sub     %o2, 8, %o2
 402         add     %o1, 8, %o1             ! increment src ptr
 403         add     %o0, 8, %o0             ! increment dst ptr
 404         EX_ST(STORE(stx, %o4, %o0-8), memcpy_retl_o2_plus_8)
 405 .Laligned_to_16:
 406         andcc   %o0, 16, %o3            ! pair of long words to move?
 407         brz,pt  %o3, .Laligned_to_32
 408          nop
 409         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2)
 410         sub     %o2, 16, %o2
 411         EX_ST(STORE(stx, %o4, %o0), memcpy_retl_o2_plus_16)
 412         add     %o1, 16, %o1            ! increment src ptr
 413         EX_LD(LOAD(ldx, %o1-8, %o4), memcpy_retl_o2_plus_8)
 414         add     %o0, 16, %o0            ! increment dst ptr
 415         EX_ST(STORE(stx, %o4, %o0-8), memcpy_retl_o2_plus_8)
 416 .Laligned_to_32:
 417         andcc   %o0, 32, %o3            ! four long words to move?
 418         brz,pt  %o3, .Laligned_to_64
 419          nop
 420         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2)
 421         sub     %o2, 32, %o2
 422         EX_ST(STORE(stx, %o4, %o0), memcpy_retl_o2_plus_32)
 423         EX_LD(LOAD(ldx, %o1+8, %o4), memcpy_retl_o2_plus_24)
 424         EX_ST(STORE(stx, %o4, %o0+8), memcpy_retl_o2_plus_24)
 425         EX_LD(LOAD(ldx, %o1+16, %o4), memcpy_retl_o2_plus_16)
 426         EX_ST(STORE(stx, %o4, %o0+16), memcpy_retl_o2_plus_16)
 427         add     %o1, 32, %o1            ! increment src ptr
 428         EX_LD(LOAD(ldx, %o1-8, %o4), memcpy_retl_o2_plus_8)
 429         add     %o0, 32, %o0            ! increment dst ptr
 430         EX_ST(STORE(stx, %o4, %o0-8), memcpy_retl_o2_plus_8)
 431 .Laligned_to_64:
 432 !
 433 !       Using block init store (BIS) instructions to avoid fetching cache
 434 !       lines from memory. Use ST_CHUNK stores to first element of each cache
 435 !       line (similar to prefetching) to avoid overfilling STQ or miss buffers.
 436 !       Gives existing cache lines time to be moved out of L1/L2/L3 cache.
 437 !       Initial stores using MRU version of BIS to keep cache line in
 438 !       cache until we are ready to store final element of cache line.
 439 !       Then store last element using the LRU version of BIS.
 440 !
 441         andn    %o2, 0x3f, %o5          ! %o5 is multiple of block size
 442         and     %o2, 0x3f, %o2          ! residue bytes in %o2
 443 !
 444 !       We use STORE_MRU_ASI for the first seven stores to each cache line
 445 !       followed by STORE_ASI (mark as LRU) for the last store. That
 446 !       mixed approach reduces the probability that the cache line is removed
 447 !       before we finish setting it, while minimizing the effects on
 448 !       other cached values during a large memcpy
 449 !
 450 !       ST_CHUNK batches up initial BIS operations for several cache lines
 451 !       to allow multiple requests to not be blocked by overflowing the
 452 !       the store miss buffer. Then the matching stores for all those
 453 !       BIS operations are executed.
 454 !
 455 
 456         sub     %o0, 8, %o0             ! adjust %o0 for ASI alignment
 457 .Lalign_loop:
 458         cmp     %o5, ST_CHUNK*64
 459         blu,pt  %xcc, .Lalign_loop_fin
 460          mov    ST_CHUNK,%o3
 461 .Lalign_loop_start:
 462         prefetch [%o1 + (ALIGN_PRE * BLOCK_SIZE)], 21
 463         subcc   %o3, 1, %o3
 464         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2_plus_o5)
 465         add     %o1, 64, %o1
 466         add     %o0, 8, %o0
 467         EX_ST(STORE_INIT_MRU(%o4, %o0), memcpy_retl_o2_plus_o5)
 468         bgu     %xcc,.Lalign_loop_start
 469          add    %o0, 56, %o0
 470 
 471         mov     ST_CHUNK,%o3
 472         sllx    %o3, 6, %o4             ! ST_CHUNK*64
 473         sub     %o1, %o4, %o1           ! reset %o1
 474         sub     %o0, %o4, %o0           ! reset %o0
 475 
 476 .Lalign_loop_rest:
 477         EX_LD(LOAD(ldx, %o1+8, %o4), memcpy_retl_o2_plus_o5)
 478         add     %o0, 16, %o0
 479         EX_ST(STORE_INIT_MRU(%o4, %o0), memcpy_retl_o2_plus_o5)
 480         EX_LD(LOAD(ldx, %o1+16, %o4), memcpy_retl_o2_plus_o5)
 481         add     %o0, 8, %o0
 482         EX_ST(STORE_INIT_MRU(%o4, %o0), memcpy_retl_o2_plus_o5)
 483         subcc   %o3, 1, %o3
 484         EX_LD(LOAD(ldx, %o1+24, %o4), memcpy_retl_o2_plus_o5)
 485         add     %o0, 8, %o0
 486         EX_ST(STORE_INIT_MRU(%o4, %o0), memcpy_retl_o2_plus_o5)
 487         EX_LD(LOAD(ldx, %o1+32, %o4), memcpy_retl_o2_plus_o5)
 488         add     %o0, 8, %o0
 489         EX_ST(STORE_INIT_MRU(%o4, %o0), memcpy_retl_o2_plus_o5)
 490         EX_LD(LOAD(ldx, %o1+40, %o4), memcpy_retl_o2_plus_o5)
 491         add     %o0, 8, %o0
 492         EX_ST(STORE_INIT_MRU(%o4, %o0), memcpy_retl_o2_plus_o5)
 493         EX_LD(LOAD(ldx, %o1+48, %o4), memcpy_retl_o2_plus_o5)
 494         add     %o1, 64, %o1
 495         add     %o0, 8, %o0
 496         EX_ST(STORE_INIT_MRU(%o4, %o0), memcpy_retl_o2_plus_o5)
 497         add     %o0, 8, %o0
 498         EX_LD(LOAD(ldx, %o1-8, %o4), memcpy_retl_o2_plus_o5)
 499         sub     %o5, 64, %o5
 500         bgu     %xcc,.Lalign_loop_rest
 501         ! mark cache line as LRU
 502          EX_ST(STORE_INIT(%o4, %o0), memcpy_retl_o2_plus_o5_plus_64)
 503 
 504         cmp     %o5, ST_CHUNK*64
 505         bgu,pt  %xcc, .Lalign_loop_start
 506          mov    ST_CHUNK,%o3
 507 
 508         cmp     %o5, 0
 509         beq     .Lalign_done
 510          nop
 511 .Lalign_loop_fin:
 512         EX_LD(LOAD(ldx, %o1, %o4), memcpy_retl_o2_plus_o5)
 513         EX_ST(STORE(stx, %o4, %o0+8), memcpy_retl_o2_plus_o5)
 514         EX_LD(LOAD(ldx, %o1+8, %o4), memcpy_retl_o2_plus_o5)
 515         EX_ST(STORE(stx, %o4, %o0+8+8), memcpy_retl_o2_plus_o5)
 516         EX_LD(LOAD(ldx, %o1+16, %o4), memcpy_retl_o2_plus_o5)
 517         EX_ST(STORE(stx, %o4, %o0+8+16), memcpy_retl_o2_plus_o5)
 518         subcc   %o5, 64, %o5
 519         EX_LD(LOAD(ldx, %o1+24, %o4), memcpy_retl_o2_plus_o5_64)
 520         EX_ST(STORE(stx, %o4, %o0+8+24), memcpy_retl_o2_plus_o5_64)
 521         EX_LD(LOAD(ldx, %o1+32, %o4), memcpy_retl_o2_plus_o5_64)
 522         EX_ST(STORE(stx, %o4, %o0+8+32), memcpy_retl_o2_plus_o5_64)
 523         EX_LD(LOAD(ldx, %o1+40, %o4), memcpy_retl_o2_plus_o5_64)
 524         EX_ST(STORE(stx, %o4, %o0+8+40), memcpy_retl_o2_plus_o5_64)
 525         EX_LD(LOAD(ldx, %o1+48, %o4), memcpy_retl_o2_plus_o5_64)
 526         add     %o1, 64, %o1
 527         EX_ST(STORE(stx, %o4, %o0+8+48), memcpy_retl_o2_plus_o5_64)
 528         add     %o0, 64, %o0
 529         EX_LD(LOAD(ldx, %o1-8, %o4), memcpy_retl_o2_plus_o5_64)
 530         bgu     %xcc,.Lalign_loop_fin
 531          EX_ST(STORE(stx, %o4, %o0), memcpy_retl_o2_plus_o5_64)
 532 
 533 .Lalign_done:
 534         add     %o0, 8, %o0             ! restore %o0 from ASI alignment
 535         membar  #StoreStore
 536         sub     %o2, 63, %o2            ! adjust length to allow cc test
 537         ba      .Lmedl63                ! in .Lmedl63
 538          nop
 539 
 540         .align 16
 541         ! Dst is on 8 byte boundary; src is not; remaining count > SMALL_MAX
 542 .Lunalignsetup:
 543 .Lunalignrejoin:
 544         mov     %g1, %o3        ! save %g1 as VISEntryHalf clobbers it
 545 #ifdef NON_USER_COPY
 546         VISEntryHalfFast(.Lmedium_vis_entry_fail_cp)
 547 #else
 548         VISEntryHalf
 549 #endif
 550         mov     %o3, %g1        ! restore %g1
 551 
 552         set MED_UMAX, %o3
 553         cmp %o2, %o3            ! check for.Lmedium unaligned limit
 554         bge,pt  %xcc,.Lunalign_large
 555          prefetch [%o1 + (4 * BLOCK_SIZE)], 20
 556         andn    %o2, 0x3f, %o5          ! %o5 is multiple of block size
 557         and     %o2, 0x3f, %o2          ! residue bytes in %o2
 558         cmp     %o2, 8                  ! Insure we do not load beyond
 559         bgt     .Lunalign_adjust        ! end of source buffer
 560          andn   %o1, 0x7, %o4           ! %o4 has long word aligned src address
 561         add     %o2, 64, %o2            ! adjust to leave loop
 562         sub     %o5, 64, %o5            ! early if necessary
 563 .Lunalign_adjust:
 564         alignaddr %o1, %g0, %g0         ! generate %gsr
 565         add     %o1, %o5, %o1           ! advance %o1 to after blocks
 566         EX_LD_FP(LOAD(ldd, %o4, %f0), memcpy_retl_o2_plus_o5)
 567 .Lunalign_loop:
 568         EX_LD_FP(LOAD(ldd, %o4+8, %f2), memcpy_retl_o2_plus_o5)
 569         faligndata %f0, %f2, %f16
 570         EX_LD_FP(LOAD(ldd, %o4+16, %f4), memcpy_retl_o2_plus_o5)
 571         subcc   %o5, BLOCK_SIZE, %o5
 572         EX_ST_FP(STORE(std, %f16, %o0), memcpy_retl_o2_plus_o5_plus_64)
 573         faligndata %f2, %f4, %f18
 574         EX_LD_FP(LOAD(ldd, %o4+24, %f6), memcpy_retl_o2_plus_o5_plus_56)
 575         EX_ST_FP(STORE(std, %f18, %o0+8), memcpy_retl_o2_plus_o5_plus_56)
 576         faligndata %f4, %f6, %f20
 577         EX_LD_FP(LOAD(ldd, %o4+32, %f8), memcpy_retl_o2_plus_o5_plus_48)
 578         EX_ST_FP(STORE(std, %f20, %o0+16), memcpy_retl_o2_plus_o5_plus_48)
 579         faligndata %f6, %f8, %f22
 580         EX_LD_FP(LOAD(ldd, %o4+40, %f10), memcpy_retl_o2_plus_o5_plus_40)
 581         EX_ST_FP(STORE(std, %f22, %o0+24), memcpy_retl_o2_plus_o5_plus_40)
 582         faligndata %f8, %f10, %f24
 583         EX_LD_FP(LOAD(ldd, %o4+48, %f12), memcpy_retl_o2_plus_o5_plus_32)
 584         EX_ST_FP(STORE(std, %f24, %o0+32), memcpy_retl_o2_plus_o5_plus_32)
 585         faligndata %f10, %f12, %f26
 586         EX_LD_FP(LOAD(ldd, %o4+56, %f14), memcpy_retl_o2_plus_o5_plus_24)
 587         add     %o4, BLOCK_SIZE, %o4
 588         EX_ST_FP(STORE(std, %f26, %o0+40), memcpy_retl_o2_plus_o5_plus_24)
 589         faligndata %f12, %f14, %f28
 590         EX_LD_FP(LOAD(ldd, %o4, %f0), memcpy_retl_o2_plus_o5_plus_16)
 591         EX_ST_FP(STORE(std, %f28, %o0+48), memcpy_retl_o2_plus_o5_plus_16)
 592         faligndata %f14, %f0, %f30
 593         EX_ST_FP(STORE(std, %f30, %o0+56), memcpy_retl_o2_plus_o5_plus_8)
 594         add     %o0, BLOCK_SIZE, %o0
 595         bgu,pt  %xcc, .Lunalign_loop
 596          prefetch [%o4 + (5 * BLOCK_SIZE)], 20
 597         ba      .Lunalign_done
 598          nop
 599 
 600 .Lunalign_large:
 601         andcc   %o0, 0x3f, %o3          ! is dst 64-byte block aligned?
 602         bz      %xcc, .Lunalignsrc
 603          sub    %o3, 64, %o3            ! %o3 will be multiple of 8
 604         neg     %o3                     ! bytes until dest is 64 byte aligned
 605         sub     %o2, %o3, %o2           ! update cnt with bytes to be moved
 606         ! Move bytes according to source alignment
 607         andcc   %o1, 0x1, %o5
 608         bnz     %xcc, .Lunalignbyte     ! check for byte alignment
 609          nop
 610         andcc   %o1, 2, %o5             ! check for half word alignment
 611         bnz     %xcc, .Lunalignhalf
 612          nop
 613         ! Src is word aligned
 614 .Lunalignword:
 615         EX_LD_FP(LOAD(ld, %o1, %o4), memcpy_retl_o2_plus_o3)    ! load 4 bytes
 616         add     %o1, 8, %o1             ! increase src ptr by 8
 617         EX_ST_FP(STORE(stw, %o4, %o0), memcpy_retl_o2_plus_o3)  ! and store 4
 618         subcc   %o3, 8, %o3             ! decrease count by 8
 619         EX_LD_FP(LOAD(ld, %o1-4, %o4), memcpy_retl_o2_plus_o3_plus_4)! load 4
 620         add     %o0, 8, %o0             ! increase dst ptr by 8
 621         bnz     %xcc, .Lunalignword
 622          EX_ST_FP(STORE(stw, %o4, %o0-4), memcpy_retl_o2_plus_o3_plus_4)
 623         ba      .Lunalignsrc
 624          nop
 625 
 626         ! Src is half-word aligned
 627 .Lunalignhalf:
 628         EX_LD_FP(LOAD(lduh, %o1, %o4), memcpy_retl_o2_plus_o3)  ! load 2 bytes
 629         sllx    %o4, 32, %o5            ! shift left
 630         EX_LD_FP(LOAD(lduw, %o1+2, %o4), memcpy_retl_o2_plus_o3)
 631         or      %o4, %o5, %o5
 632         sllx    %o5, 16, %o5
 633         EX_LD_FP(LOAD(lduh, %o1+6, %o4), memcpy_retl_o2_plus_o3)
 634         or      %o4, %o5, %o5
 635         EX_ST_FP(STORE(stx, %o5, %o0), memcpy_retl_o2_plus_o3)
 636         add     %o1, 8, %o1
 637         subcc   %o3, 8, %o3
 638         bnz     %xcc, .Lunalignhalf
 639          add    %o0, 8, %o0
 640         ba      .Lunalignsrc
 641          nop
 642 
 643         ! Src is Byte aligned
 644 .Lunalignbyte:
 645         sub     %o0, %o1, %o0           ! share pointer advance
 646 .Lunalignbyte_loop:
 647         EX_LD_FP(LOAD(ldub, %o1, %o4), memcpy_retl_o2_plus_o3)
 648         sllx    %o4, 56, %o5
 649         EX_LD_FP(LOAD(lduh, %o1+1, %o4), memcpy_retl_o2_plus_o3)
 650         sllx    %o4, 40, %o4
 651         or      %o4, %o5, %o5
 652         EX_LD_FP(LOAD(lduh, %o1+3, %o4), memcpy_retl_o2_plus_o3)
 653         sllx    %o4, 24, %o4
 654         or      %o4, %o5, %o5
 655         EX_LD_FP(LOAD(lduh, %o1+5, %o4), memcpy_retl_o2_plus_o3)
 656         sllx    %o4,  8, %o4
 657         or      %o4, %o5, %o5
 658         EX_LD_FP(LOAD(ldub, %o1+7, %o4), memcpy_retl_o2_plus_o3)
 659         or      %o4, %o5, %o5
 660         add     %o0, %o1, %o0
 661         EX_ST_FP(STORE(stx, %o5, %o0), memcpy_retl_o2_plus_o3)
 662         sub     %o0, %o1, %o0
 663         subcc   %o3, 8, %o3
 664         bnz     %xcc, .Lunalignbyte_loop
 665          add    %o1, 8, %o1
 666         add     %o0,%o1, %o0            ! restore pointer
 667 
 668         ! Destination is now block (64 byte aligned)
 669 .Lunalignsrc:
 670         andn    %o2, 0x3f, %o5          ! %o5 is multiple of block size
 671         and     %o2, 0x3f, %o2          ! residue bytes in %o2
 672         add     %o2, 64, %o2            ! Insure we do not load beyond
 673         sub     %o5, 64, %o5            ! end of source buffer
 674 
 675         andn    %o1, 0x7, %o4           ! %o4 has long word aligned src address
 676         alignaddr %o1, %g0, %g0         ! generate %gsr
 677         add     %o1, %o5, %o1           ! advance %o1 to after blocks
 678 
 679         EX_LD_FP(LOAD(ldd, %o4, %f14), memcpy_retl_o2_plus_o5)
 680         add     %o4, 8, %o4
 681 .Lunalign_sloop:
 682         EX_LD_FP(LOAD(ldd, %o4, %f16), memcpy_retl_o2_plus_o5)
 683         faligndata %f14, %f16, %f0
 684         EX_LD_FP(LOAD(ldd, %o4+8, %f18), memcpy_retl_o2_plus_o5)
 685         faligndata %f16, %f18, %f2
 686         EX_LD_FP(LOAD(ldd, %o4+16, %f20), memcpy_retl_o2_plus_o5)
 687         faligndata %f18, %f20, %f4
 688         EX_ST_FP(STORE(std, %f0, %o0), memcpy_retl_o2_plus_o5)
 689         subcc   %o5, 64, %o5
 690         EX_LD_FP(LOAD(ldd, %o4+24, %f22), memcpy_retl_o2_plus_o5_plus_56)
 691         faligndata %f20, %f22, %f6
 692         EX_ST_FP(STORE(std, %f2, %o0+8), memcpy_retl_o2_plus_o5_plus_56)
 693         EX_LD_FP(LOAD(ldd, %o4+32, %f24), memcpy_retl_o2_plus_o5_plus_48)
 694         faligndata %f22, %f24, %f8
 695         EX_ST_FP(STORE(std, %f4, %o0+16), memcpy_retl_o2_plus_o5_plus_48)
 696         EX_LD_FP(LOAD(ldd, %o4+40, %f26), memcpy_retl_o2_plus_o5_plus_40)
 697         faligndata %f24, %f26, %f10
 698         EX_ST_FP(STORE(std, %f6, %o0+24), memcpy_retl_o2_plus_o5_plus_40)
 699         EX_LD_FP(LOAD(ldd, %o4+48, %f28), memcpy_retl_o2_plus_o5_plus_40)
 700         faligndata %f26, %f28, %f12
 701         EX_ST_FP(STORE(std, %f8, %o0+32), memcpy_retl_o2_plus_o5_plus_40)
 702         add     %o4, 64, %o4
 703         EX_LD_FP(LOAD(ldd, %o4-8, %f30), memcpy_retl_o2_plus_o5_plus_40)
 704         faligndata %f28, %f30, %f14
 705         EX_ST_FP(STORE(std, %f10, %o0+40), memcpy_retl_o2_plus_o5_plus_40)
 706         EX_ST_FP(STORE(std, %f12, %o0+48), memcpy_retl_o2_plus_o5_plus_40)
 707         add     %o0, 64, %o0
 708         EX_ST_FP(STORE(std, %f14, %o0-8), memcpy_retl_o2_plus_o5_plus_40)
 709         fsrc2   %f30, %f14
 710         bgu,pt  %xcc, .Lunalign_sloop
 711          prefetch [%o4 + (8 * BLOCK_SIZE)], 20
 712 
 713 .Lunalign_done:
 714         ! Handle trailing bytes, 64 to 127
 715         ! Dest long word aligned, Src not long word aligned
 716         cmp     %o2, 15
 717         bleu    %xcc, .Lunalign_short
 718 
 719          andn   %o2, 0x7, %o5           ! %o5 is multiple of 8
 720         and     %o2, 0x7, %o2           ! residue bytes in %o2
 721         add     %o2, 8, %o2
 722         sub     %o5, 8, %o5             ! insure we do not load past end of src
 723         andn    %o1, 0x7, %o4           ! %o4 has long word aligned src address
 724         add     %o1, %o5, %o1           ! advance %o1 to after multiple of 8
 725         EX_LD_FP(LOAD(ldd, %o4, %f0), memcpy_retl_o2_plus_o5)! fetch partialword
 726 .Lunalign_by8:
 727         EX_LD_FP(LOAD(ldd, %o4+8, %f2), memcpy_retl_o2_plus_o5)
 728         add     %o4, 8, %o4
 729         faligndata %f0, %f2, %f16
 730         subcc   %o5, 8, %o5
 731         EX_ST_FP(STORE(std, %f16, %o0), memcpy_retl_o2_plus_o5)
 732         fsrc2   %f2, %f0
 733         bgu,pt  %xcc, .Lunalign_by8
 734          add    %o0, 8, %o0
 735 
 736 .Lunalign_short:
 737 #ifdef NON_USER_COPY
 738         VISExitHalfFast
 739 #else
 740         VISExitHalf
 741 #endif
 742         ba      .Lsmallrest
 743          nop
 744 
 745 
 746 
 747 
 748 
 749 
 750 
 751 
 752 
 753 #ifdef NON_USER_COPY
 754 .Lmedium_vis_entry_fail_cp:
 755         or      %o0, %o1, %g2
 756 #endif
 757 .Lmedium_cp:
 758         LOAD(prefetch, %o1 + 0x40, #n_reads_strong)
 759         andcc   %g2, 0x7, %g0
 760         bne,pn  %xcc, .Lmedium_unaligned_cp
 761          nop
 762 
 763 .Lmedium_noprefetch_cp:
 764         andncc  %o2, 0x20 - 1, %o5
 765         be,pn   %xcc, 2f
 766          sub    %o2, %o5, %o2
 767 1:      EX_LD(LOAD(ldx, %o1 + 0x00, %o3), memcpy_retl_o2_plus_o5)
 768         EX_LD(LOAD(ldx, %o1 + 0x08, %g2), memcpy_retl_o2_plus_o5)
 769         EX_LD(LOAD(ldx, %o1 + 0x10, %g7), memcpy_retl_o2_plus_o5)
 770         EX_LD(LOAD(ldx, %o1 + 0x18, %o4), memcpy_retl_o2_plus_o5)
 771         add     %o1, 0x20, %o1
 772         subcc   %o5, 0x20, %o5
 773         EX_ST(STORE(stx, %o3, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_32)
 774         EX_ST(STORE(stx, %g2, %o0 + 0x08), memcpy_retl_o2_plus_o5_plus_24)
 775         EX_ST(STORE(stx, %g7, %o0 + 0x10), memcpy_retl_o2_plus_o5_plus_24)
 776         EX_ST(STORE(stx, %o4, %o0 + 0x18), memcpy_retl_o2_plus_o5_plus_8)
 777         bne,pt  %xcc, 1b
 778          add    %o0, 0x20, %o0
 779 2:      andcc   %o2, 0x18, %o5
 780         be,pt   %xcc, 3f
 781          sub    %o2, %o5, %o2
 782 1:      EX_LD(LOAD(ldx, %o1 + 0x00, %o3), memcpy_retl_o2_plus_o5)
 783         add     %o1, 0x08, %o1
 784         add     %o0, 0x08, %o0
 785         subcc   %o5, 0x08, %o5
 786         bne,pt  %xcc, 1b
 787          EX_ST(STORE(stx, %o3, %o0 - 0x08), memcpy_retl_o2_plus_o5_plus_8)
 788 3:      brz,pt  %o2, .Lexit_cp
 789          cmp    %o2, 0x04
 790         bl,pn   %xcc, .Ltiny_cp
 791          nop
 792         EX_LD(LOAD(lduw, %o1 + 0x00, %o3), memcpy_retl_o2)
 793         add     %o1, 0x04, %o1
 794         add     %o0, 0x04, %o0
 795         subcc   %o2, 0x04, %o2
 796         bne,pn  %xcc, .Ltiny_cp
 797          EX_ST(STORE(stw, %o3, %o0 - 0x04), memcpy_retl_o2_plus_4)
 798         ba,a,pt %xcc, .Lexit_cp
 799 
 800 .Lmedium_unaligned_cp:
 801         
 802         sub     %g0, %o0, %o3
 803         and     %o3, 0x7, %o3
 804         brz,pt  %o3, 2f
 805          sub    %o2, %o3, %o2
 806 
 807 1:      EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
 808         add     %o1, 1, %o1
 809         subcc   %o3, 1, %o3
 810         add     %o0, 1, %o0
 811         bne,pt  %xcc, 1b
 812          EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
 813 2:
 814         and     %o1, 0x7, %o3
 815         brz,pn  %o3, .Lmedium_noprefetch_cp
 816          sll    %o3, 3, %o3
 817         mov     64, %g2
 818         sub     %g2, %o3, %g2
 819         andn    %o1, 0x7, %o1
 820         EX_LD(LOAD(ldx, %o1 + 0x00, %o4), memcpy_retl_o2)
 821         sllx    %o4, %o3, %o4
 822         andn    %o2, 0x08 - 1, %o5
 823         sub     %o2, %o5, %o2
 824 
 825 1:      EX_LD(LOAD(ldx, %o1 + 0x08, %g3), memcpy_retl_o2_plus_o5)
 826         add     %o1, 0x08, %o1
 827         subcc   %o5, 0x08, %o5
 828         srlx    %g3, %g2, %g7
 829         or      %g7, %o4, %g7
 830         EX_ST(STORE(stx, %g7, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_8)
 831         add     %o0, 0x08, %o0
 832         bne,pt  %xcc, 1b
 833          sllx   %g3, %o3, %o4
 834         srl     %o3, 3, %o3
 835         add     %o1, %o3, %o1
 836         brz,pn  %o2, .Lexit_cp
 837          nop
 838         ba,pt   %xcc, .Lsmall_unaligned_cp
 839 
 840 .Ltiny_cp:
 841         EX_LD(LOAD(ldub, %o1 + 0x00, %o3), memcpy_retl_o2)
 842         subcc   %o2, 1, %o2
 843         be,pn   %xcc, .Lexit_cp
 844          EX_ST(STORE(stb, %o3, %o0 + 0x00), memcpy_retl_o2_plus_1)
 845         EX_LD(LOAD(ldub, %o1 + 0x01, %o3), memcpy_retl_o2)
 846         subcc   %o2, 1, %o2
 847         be,pn   %xcc, .Lexit_cp
 848          EX_ST(STORE(stb, %o3, %o0 + 0x01), memcpy_retl_o2_plus_1)
 849         EX_LD(LOAD(ldub, %o1 + 0x02, %o3), memcpy_retl_o2)
 850         ba,pt   %xcc, .Lexit_cp
 851          EX_ST(STORE(stb, %o3, %o0 + 0x02), memcpy_retl_o2)
 852 
 853 .Lsmall_cp:
 854         andcc   %g2, 0x3, %g0
 855         bne,pn  %xcc, .Lsmall_unaligned_cp
 856          andn   %o2, 0x4 - 1, %o5
 857         sub     %o2, %o5, %o2
 858 1:
 859         EX_LD(LOAD(lduw, %o1 + 0x00, %o3), memcpy_retl_o2_plus_o5)
 860         add     %o1, 0x04, %o1
 861         subcc   %o5, 0x04, %o5
 862         add     %o0, 0x04, %o0
 863         bne,pt  %xcc, 1b
 864          EX_ST(STORE(stw, %o3, %o0 - 0x04), memcpy_retl_o2_plus_o5_plus_4)
 865         brz,pt  %o2, .Lexit_cp
 866          nop
 867         ba,a,pt %xcc, .Ltiny_cp
 868 
 869 .Lsmall_unaligned_cp:
 870 1:      EX_LD(LOAD(ldub, %o1 + 0x00, %o3), memcpy_retl_o2)
 871         add     %o1, 1, %o1
 872         add     %o0, 1, %o0
 873         subcc   %o2, 1, %o2
 874         bne,pt  %xcc, 1b
 875          EX_ST(STORE(stb, %o3, %o0 - 0x01), memcpy_retl_o2_plus_1)
 876         ba,a,pt %xcc, .Lexit_cp
 877 
 878 .Lsmallrest:
 879         tst     %o2
 880         bz,pt   %xcc, .Lsmallx
 881          cmp    %o2, 4
 882         blt,pn  %xcc, .Lsmallleft3
 883          nop
 884         sub     %o2, 3, %o2
 885 .Lsmallnotalign4:
 886         EX_LD(LOAD(ldub, %o1, %o3), memcpy_retl_o2_plus_3)! read byte
 887         subcc   %o2, 4, %o2             ! reduce count by 4
 888         EX_ST(STORE(stb, %o3, %o0), memcpy_retl_o2_plus_7)! write byte & repeat
 889         EX_LD(LOAD(ldub, %o1+1, %o3), memcpy_retl_o2_plus_6)! for total of 4
 890         add     %o1, 4, %o1             ! advance SRC by 4
 891         EX_ST(STORE(stb, %o3, %o0+1), memcpy_retl_o2_plus_6)
 892         EX_LD(LOAD(ldub, %o1-2, %o3), memcpy_retl_o2_plus_5)
 893         add     %o0, 4, %o0             ! advance DST by 4
 894         EX_ST(STORE(stb, %o3, %o0-2), memcpy_retl_o2_plus_5)
 895         EX_LD(LOAD(ldub, %o1-1, %o3), memcpy_retl_o2_plus_4)
 896         bgu,pt  %xcc, .Lsmallnotalign4  ! loop til 3 or fewer bytes remain
 897         EX_ST(STORE(stb, %o3, %o0-1), memcpy_retl_o2_plus_4)
 898         addcc   %o2, 3, %o2             ! restore count
 899         bz,pt   %xcc, .Lsmallx
 900 .Lsmallleft3:                           ! 1, 2, or 3 bytes remain
 901         subcc   %o2, 1, %o2
 902         EX_LD(LOAD(ldub, %o1, %o3), memcpy_retl_o2_plus_1)      ! load one byte
 903         bz,pt   %xcc, .Lsmallx
 904         EX_ST(STORE(stb, %o3, %o0), memcpy_retl_o2_plus_1)      ! store one byte
 905         EX_LD(LOAD(ldub, %o1+1, %o3), memcpy_retl_o2)   ! load second byte
 906         subcc   %o2, 1, %o2
 907         bz,pt   %xcc, .Lsmallx
 908         EX_ST(STORE(stb, %o3, %o0+1), memcpy_retl_o2_plus_1)! store second byte
 909         EX_LD(LOAD(ldub, %o1+2, %o3), memcpy_retl_o2)   ! load third byte
 910         EX_ST(STORE(stb, %o3, %o0+2), memcpy_retl_o2)   ! store third byte
 911 .Lsmallx:
 912         retl
 913          mov    EX_RETVAL(%g1), %o0
 914 .Lsmallfin:
 915         tst     %o2
 916         bnz,pn  %xcc, .Lsmallleft3
 917          nop
 918         retl
 919          mov    EX_RETVAL(%g1), %o0     ! restore %o0
 920 .Lexit_cp:
 921         retl
 922          mov    EX_RETVAL(%g1), %o0
 923         .size  FUNC_NAME, .-FUNC_NAME