Fix ASAN failure in FutureDAG test
[folly.git] / folly / memcpy.S
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * memcpy: An optimized memcpy implementation for x86_64. It uses AVX when
19  * __AVX__ is defined, and uses SSE2 otherwise.
20  *
21  * @author Bin Liu <binliu@fb.com>
22  */
23
24 #if defined(__x86_64__) && defined(__linux__) && !defined(__CYGWIN__)
25
26         .file     "memcpy.S"
27         .text
28
29 /*
30  * _memcpy_short is a local helper used when length < 8. It cannot be called
31  * from outside, because it expects a non-standard calling convention:
32  *
33  *    %rax:  destination buffer address.
34  *    %rsi:  source buffer address.
35  *    %edx:  length, in the range of [0, 7]
36  */
37         .type     _memcpy_short, @function
38 _memcpy_short:
39 .LSHORT:
40         .cfi_startproc
41         //        if (length == 0) return;
42         test      %edx, %edx
43         jz        .LEND
44
45         movzbl    (%rsi), %ecx
46         //        if (length - 4 < 0) goto LS4;
47         sub       $4, %edx
48         jb        .LS4
49
50         mov       (%rsi), %ecx
51         mov       (%rsi, %rdx), %edi
52         mov       %ecx, (%rax)
53         mov       %edi, (%rax, %rdx)
54 .LEND:
55         rep
56         ret
57         nop
58
59 .LS4:
60         //        At this point, length can be 1 or 2 or 3, and $cl contains
61         //        the first byte.
62         mov       %cl, (%rax)
63         //        if (length - 4 + 2 < 0) return;
64         add       $2, %edx
65         jnc       .LEND
66
67         //        length is 2 or 3 here. In either case, just copy the last
68         //        two bytes.
69         movzwl    (%rsi, %rdx), %ecx
70         mov       %cx, (%rax, %rdx)
71         ret
72
73         .cfi_endproc
74         .size     _memcpy_short, .-_memcpy_short
75
76
77 /*
78  * void* memcpy(void* dst, void* src, uint32_t length);
79  *
80  */
81         .align    16
82         .globl    memcpy
83         .type     memcpy, @function
84 memcpy:
85         .cfi_startproc
86
87         mov       %rdx, %rcx
88         mov       %rdi, %rax
89         cmp       $8, %rdx
90         jb        .LSHORT
91
92         mov       -8(%rsi, %rdx), %r8
93         mov       (%rsi), %r9
94         mov       %r8, -8(%rdi, %rdx)
95         and       $24, %rcx
96         jz        .L32
97
98         mov       %r9, (%rdi)
99         mov       %rcx, %r8
100         sub       $16, %rcx
101         jb        .LT32
102 #ifndef __AVX__
103         movdqu    (%rsi, %rcx), %xmm1
104         movdqu    %xmm1, (%rdi, %rcx)
105 #else
106         vmovdqu   (%rsi, %rcx), %xmm1
107         vmovdqu   %xmm1, (%rdi, %rcx)
108 #endif
109         //        Test if there are 32-byte groups
110 .LT32:
111         add       %r8, %rsi
112         and       $-32, %rdx
113         jnz       .L32_adjDI
114         ret
115
116         .align    16
117 .L32_adjDI:
118         add       %r8, %rdi
119 .L32:
120 #ifndef __AVX__
121         movdqu    (%rsi), %xmm0
122         movdqu    16(%rsi), %xmm1
123 #else
124         vmovdqu   (%rsi), %ymm0
125 #endif
126         shr       $6, %rdx
127         jnc       .L64_32read
128 #ifndef __AVX__
129         movdqu    %xmm0, (%rdi)
130         movdqu    %xmm1, 16(%rdi)
131 #else
132         vmovdqu   %ymm0, (%rdi)
133 #endif
134         lea       32(%rsi), %rsi
135         jnz       .L64_adjDI
136 #ifdef __AVX__
137         vzeroupper
138 #endif
139         ret
140
141 .L64_adjDI:
142         add       $32, %rdi
143
144 .L64:
145 #ifndef __AVX__
146         movdqu    (%rsi), %xmm0
147         movdqu    16(%rsi), %xmm1
148 #else
149         vmovdqu   (%rsi), %ymm0
150 #endif
151
152 .L64_32read:
153 #ifndef __AVX__
154         movdqu    32(%rsi), %xmm2
155         movdqu    48(%rsi), %xmm3
156         add       $64, %rsi
157         movdqu    %xmm0, (%rdi)
158         movdqu    %xmm1, 16(%rdi)
159         movdqu    %xmm2, 32(%rdi)
160         movdqu    %xmm3, 48(%rdi)
161 #else
162         vmovdqu   32(%rsi), %ymm1
163         add       $64, %rsi
164         vmovdqu   %ymm0, (%rdi)
165         vmovdqu   %ymm1, 32(%rdi)
166 #endif
167         add       $64, %rdi
168         dec       %rdx
169         jnz       .L64
170 #ifdef __AVX__
171         vzeroupper
172 #endif
173         ret
174
175         .cfi_endproc
176         .size memcpy, .-memcpy
177
178 #endif