^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0-only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/linkage.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #ifdef __LITTLE_ENDIAN__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) # define SHIFT_1(RX,RY,IMM) asl RX, RY, IMM ; <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) # define SHIFT_2(RX,RY,IMM) lsr RX, RY, IMM ; >>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) # define MERGE_1(RX,RY,IMM) asl RX, RY, IMM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) # define MERGE_2(RX,RY,IMM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) # define EXTRACT_1(RX,RY,IMM) and RX, RY, 0xFFFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) # define EXTRACT_2(RX,RY,IMM) lsr RX, RY, IMM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) # define SHIFT_1(RX,RY,IMM) lsr RX, RY, IMM ; >>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) # define SHIFT_2(RX,RY,IMM) asl RX, RY, IMM ; <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) # define MERGE_1(RX,RY,IMM) asl RX, RY, IMM ; <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) # define MERGE_2(RX,RY,IMM) asl RX, RY, IMM ; <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) # define EXTRACT_1(RX,RY,IMM) lsr RX, RY, IMM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) # define EXTRACT_2(RX,RY,IMM) lsr RX, RY, 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #ifdef CONFIG_ARC_HAS_LL64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) # define LOADX(DST,RX) ldd.ab DST, [RX, 8]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) # define STOREX(SRC,RX) std.ab SRC, [RX, 8]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) # define ZOLSHFT 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) # define ZOLAND 0x1F
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) # define LOADX(DST,RX) ld.ab DST, [RX, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) # define STOREX(SRC,RX) st.ab SRC, [RX, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) # define ZOLSHFT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) # define ZOLAND 0xF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ENTRY_CFI(memcpy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) mov.f 0, r2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) ;;; if size is zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) jz.d [blink]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) mov r3, r0 ; don;t clobber ret val
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) ;;; if size <= 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) cmp r2, 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) bls.d @.Lsmallchunk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) mov.f lp_count, r2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) and.f r4, r0, 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) rsub lp_count, r4, 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) lpnz @.Laligndestination
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) ;; LOOP BEGIN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) ldb.ab r5, [r1,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) sub r2, r2, 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) stb.ab r5, [r3,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .Laligndestination:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ;;; Check the alignment of the source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) and.f r4, r1, 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) bnz.d @.Lsourceunaligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ;;; CASE 0: Both source and destination are 32bit aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ;;; Convert len to Dwords, unfold x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) lsr.f lp_count, r2, ZOLSHFT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) lpnz @.Lcopy32_64bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ;; LOOP START
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) LOADX (r6, r1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) LOADX (r8, r1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) LOADX (r10, r1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) LOADX (r4, r1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) STOREX (r6, r3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) STOREX (r8, r3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) STOREX (r10, r3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) STOREX (r4, r3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) .Lcopy32_64bytes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) and.f lp_count, r2, ZOLAND ;Last remaining 31 bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .Lsmallchunk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) lpnz @.Lcopyremainingbytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) ;; LOOP START
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ldb.ab r5, [r1,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) stb.ab r5, [r3,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .Lcopyremainingbytes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) j [blink]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ;;; END CASE 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) .Lsourceunaligned:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) cmp r4, 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) beq.d @.LunalignedOffby2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) sub r2, r2, 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) bhi.d @.LunalignedOffby3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) ldb.ab r5, [r1, 1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ;;; CASE 1: The source is unaligned, off by 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ;; Hence I need to read 1 byte for a 16bit alignment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ;; and 2bytes to reach 32bit alignment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) ldh.ab r6, [r1, 2]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) sub r2, r2, 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ;; Convert to words, unfold x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) lsr.f lp_count, r2, 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) MERGE_1 (r6, r6, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) MERGE_2 (r5, r5, 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) or r5, r5, r6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) ;; Both src and dst are aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) lpnz @.Lcopy8bytes_1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ;; LOOP START
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ld.ab r6, [r1, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) ld.ab r8, [r1,4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) SHIFT_1 (r7, r6, 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) or r7, r7, r5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) SHIFT_2 (r5, r6, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) SHIFT_1 (r9, r8, 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) or r9, r9, r5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) SHIFT_2 (r5, r8, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) st.ab r7, [r3, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) st.ab r9, [r3, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .Lcopy8bytes_1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) ;; Write back the remaining 16bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) EXTRACT_1 (r6, r5, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) sth.ab r6, [r3, 2]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) ;; Write back the remaining 8bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) EXTRACT_2 (r5, r5, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) stb.ab r5, [r3, 1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) and.f lp_count, r2, 0x07 ;Last 8bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) lpnz @.Lcopybytewise_1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ;; LOOP START
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) ldb.ab r6, [r1,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) stb.ab r6, [r3,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .Lcopybytewise_1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) j [blink]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .LunalignedOffby2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ;;; CASE 2: The source is unaligned, off by 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ldh.ab r5, [r1, 2]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) sub r2, r2, 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) ;; Both src and dst are aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ;; Convert to words, unfold x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) lsr.f lp_count, r2, 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #ifdef __BIG_ENDIAN__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) asl.nz r5, r5, 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) lpnz @.Lcopy8bytes_2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ;; LOOP START
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ld.ab r6, [r1, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) ld.ab r8, [r1,4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) SHIFT_1 (r7, r6, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) or r7, r7, r5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) SHIFT_2 (r5, r6, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) SHIFT_1 (r9, r8, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) or r9, r9, r5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) SHIFT_2 (r5, r8, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) st.ab r7, [r3, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) st.ab r9, [r3, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .Lcopy8bytes_2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #ifdef __BIG_ENDIAN__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) lsr.nz r5, r5, 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) sth.ab r5, [r3, 2]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) and.f lp_count, r2, 0x07 ;Last 8bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) lpnz @.Lcopybytewise_2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ;; LOOP START
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) ldb.ab r6, [r1,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) stb.ab r6, [r3,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .Lcopybytewise_2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) j [blink]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .LunalignedOffby3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ;;; CASE 3: The source is unaligned, off by 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) ;;; Hence, I need to read 1byte for achieve the 32bit alignment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) ;; Both src and dst are aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ;; Convert to words, unfold x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) lsr.f lp_count, r2, 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #ifdef __BIG_ENDIAN__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) asl.ne r5, r5, 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) lpnz @.Lcopy8bytes_3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ;; LOOP START
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) ld.ab r6, [r1, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ld.ab r8, [r1,4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) SHIFT_1 (r7, r6, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) or r7, r7, r5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) SHIFT_2 (r5, r6, 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) SHIFT_1 (r9, r8, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) or r9, r9, r5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) SHIFT_2 (r5, r8, 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) st.ab r7, [r3, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) st.ab r9, [r3, 4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .Lcopy8bytes_3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) #ifdef __BIG_ENDIAN__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) lsr.nz r5, r5, 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) stb.ab r5, [r3, 1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) and.f lp_count, r2, 0x07 ;Last 8bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) lpnz @.Lcopybytewise_3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) ;; LOOP START
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) ldb.ab r6, [r1,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) stb.ab r6, [r3,1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) .Lcopybytewise_3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) j [blink]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) END_CFI(memcpy)