Use iterator adapters in decl_class_parents
[hiphop-php.git] / hphp / util / memcpy-x64.S
blob85b9652f6c7cc44c1b4043a6b5ff01b274142e53
1 /*
2    +----------------------------------------------------------------------+
3    | HipHop for PHP                                                       |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com)  |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
17 #include "hphp/util/etch-helpers.h"
19 #if defined(__x86_64__)
20               .file "hphp/util/memcpy-x64.S"
21               ETCH_SECTION(memcpy)
24  * _memcpy_short is a local helper used when length < 8. It cannot be called
25  * from outside, because it expects a non-standard calling convention:
26  *
27  *    %rax:  destination buffer address.
28  *    %rsi:  source buffer address.
29  *    %rdx:  length, in the range of [0, 7]
30  */
31               ETCH_TYPE(ETCH_NAME(_memcpy_short), @function)
32 ETCH_NAME(_memcpy_short):
33 ETCH_LABEL(SHORT):
34               CFI(startproc)
35               //    if (length == 0) return;
36               test  %edx, %edx
37               jz    ETCH_LABEL(END)
39               //    We can safely read a byte here.
40               movzbl (%rsi), %ecx
41               //    if (length - 4 < 0) goto S4 ;
42               sub   $4, %edx
43               jb    ETCH_LABEL(S4)
44               mov   (%rsi), %ecx
45               mov   (%rsi, %rdx), %edi
46               mov   %ecx, (%rax)
47               mov   %edi, (%rax, %rdx)
48 ETCH_LABEL(END):
49               rep
50               ret
51               nop
53 ETCH_LABEL(S4):
54               //    At this point, length can be 1 or 2 or 3, and $cl contains
55               //    the first byte.
56               mov   %cl, (%rax)
57               //    if (length - 4 + 2 < 0) return;
58               add   $2, %edx
59               jnc   ETCH_LABEL(END)
61               //    length is 2 or 3 here. In either case, just copy the last
62               //    two bytes.
63               movzwl (%rsi, %rdx), %ecx
64               mov   %cx, (%rax, %rdx)
65               ret
67               CFI(endproc)
68               ETCH_SIZE(_memcpy_short)
72  * void* _memcpy8(void* dst, void* src, size_t length);
73  *
74  * This is the same as
75  *     memcpy(dst, src, (length + 7) / 8 * 8)
76  * except that it returns dst + length instead of dst. It always copy 8-byte
77  * groups, and could overrun the buffers. If both src and dst starts at
78  * addresses aligned to 8-byte boundary, it is generally safe.
79  */
80               ETCH_ALIGN16
81               .globl ETCH_NAME(_memcpy8)
82               ETCH_TYPE(ETCH_NAME(_memcpy8), @function)
83 ETCH_NAME(_memcpy8):
84               CFI(startproc)
85               lea   (%rdi, %rdx), %rax
86               add   $7, %rdx
87               mov   %rdx, %rcx
88               and   $-8, %rdx
89               jnz   ETCH_LABEL(L8)
90               ret
92               CFI(endproc)
93               ETCH_SIZE(_memcpy8)
96  * void* memcpy(void* dst, void* src, size_t length);
97  */
98               ETCH_ALIGN16
99               .globl ETCH_NAME(_hhvm_memcpy)
100               ETCH_TYPE(ETCH_NAME(_hhvm_memcpy), @function)
101 ETCH_NAME(_hhvm_memcpy):
102               CFI(startproc)
104               mov   %rdx, %rcx
105               mov   %rdi, %rax
106               cmp   $8, %rdx
107               jb    ETCH_LABEL(SHORT)
109               mov   -8(%rsi, %rdx), %r8
110 ETCH_LABEL(L8):
111               mov   (%rsi), %r9
112               //    This stores garbage if coming from _memcpy8, but it won't
113               //    cause corretness problem. The address is writable, and the
114               //    data there will be overwritten later. I don't want to move
115               //    this store before L8 because that will slow down the
116               //    loading of (%rsi).
117               mov   %r8, -8(%rdi, %rdx)
118               and   $24, %rcx
119               jz    ETCH_LABEL(L32)
121               mov   %r9, (%rdi)
122               mov   %rcx, %r8
123               sub   $16, %rcx
124               jb    ETCH_LABEL(T32)
126               movdqu (%rsi, %rcx), %xmm1
127               movdqu %xmm1, (%rdi, %rcx)
129               // Test if there are 32-byte groups
130 ETCH_LABEL(T32):
131               add   %r8, %rsi
132               and   $-32, %rdx
133               jnz   ETCH_LABEL(R32_adjDI)
134 ETCH_LABEL(END2):
135               rep
136               ret
137               nop
139 ETCH_LABEL(R32_adjDI):
140               add   %r8, %rdi
142  * void* _bcopy32(void* dst, void* src, size_t length);
144  * This is the same as
145  *     assert(length >= 32);
146  *     memcpy(dst, src, length / 32 * 32);
147  * except that the return value cannot be used.
148  */
149               .globl ETCH_NAME(_bcopy32)
150               ETCH_TYPE(ETCH_NAME(_bcopy32), @function)
151 ETCH_NAME(_bcopy32):
152 ETCH_LABEL(L32):
153               // Multiples of 32 bytes.
154               movdqu (%rsi), %xmm0
155 ETCH_LABEL(L32_16read):
156               movdqu 16(%rsi), %xmm1
158               //    if ((rdx & 32) == 0) goto R64Byte_32read
159               shr   $6, %rdx
160               jnc   ETCH_LABEL(R64Byte_32read)
162               movdqu %xmm0, (%rdi)
163               movdqu %xmm1, 16(%rdi)
164               lea   32(%rsi), %rsi
165               jnz   ETCH_LABEL(R64_adjDI)
166               ret
168 ETCH_LABEL(R64_adjDI):
169               add   $32, %rdi
172  * void _bcopy_in_64(void* dst, void* src, size_t lengthIn64Bytes);
174  * This is the same as
175  *     assert(lengthIn64Bytes > 0);
176  *     memcpy(dst, src, 64 * lengthIn64Bytes);
177  * except that the return value cannot be used.
179  * Note that the length being copied is 64 * %rdx.
180  */
181               .globl ETCH_NAME(_bcopy_in_64)
182               ETCH_TYPE(ETCH_NAME(_bcopy_in_64), @function)
183 ETCH_NAME(_bcopy_in_64):
184 ETCH_LABEL(R64Byte):
185               // Multiples of 64 bytes.
186               movdqu (%rsi), %xmm0
187               movdqu 16(%rsi), %xmm1
188 ETCH_LABEL(R64Byte_32read):
189               movdqu 32(%rsi), %xmm2
190               movdqu 48(%rsi), %xmm3
191               add   $64, %rsi
192               movdqu %xmm0, (%rdi)
193               movdqu %xmm1, 16(%rdi)
194               movdqu %xmm2, 32(%rdi)
195               movdqu %xmm3, 48(%rdi)
196               add   $64, %rdi
197               dec   %rdx
198               jnz   ETCH_LABEL(R64Byte)
199               ret
202  * void* _memcpy16(void* dst, void* src, size_t length);
204  * This is the same as
205  *     assert(length % 16 == 0 && length > 0);
206  *     memcpy(dst, src, length);
207  */
208               .globl ETCH_NAME(_memcpy16)
209               ETCH_TYPE(ETCH_NAME(_memcpy16), @function)
210 ETCH_NAME(_memcpy16):
211               movdqu -16(%rsi, %rdx), %xmm3
212               movdqu (%rsi), %xmm0
213               mov   %rdi, %rax
215               //    if (length & 16 == 0), it must be at least 32 bytes.
216               test  $16, %dl
217               jz    ETCH_LABEL(L32_16read)
219               movdqu %xmm3, -16(%rdi, %rdx)
220               shr   $6, %rdx
221               jz    ETCH_LABEL(32_OR_0)
223               //    We have at least 64 bytes remaining.  CF indicates whether
224               //    we need to copy 32 bytes first.
225               movdqu 16(%rsi), %xmm1
226               jnc   ETCH_LABEL(R64Byte_32read)
228               //    Need to copy another 32 bytes and adjust rdi/rsi
229               movdqu %xmm0, (%rdi)
230               add   $32, %rsi
231               movdqu %xmm1, 16(%rdi)
232               add   $32, %rdi
233               jmp   ETCH_LABEL(R64Byte)
235 ETCH_LABEL(32_OR_0):
236               //    The path for length == 16 comes through several conditional
237               //    jumps. We expect (and should make) such sitatuions rare
238               //    when this is invoked.
239               jnc   ETCH_LABEL(END16)
240               movdqu 16(%rsi), %xmm1
241               movdqu %xmm0, (%rdi)
242               movdqu %xmm1, 16(%rdi)
244 ETCH_LABEL(END16):
245               rep
246               ret
248               CFI(endproc)
249               ETCH_SIZE(_hhvm_memcpy)
251 // When AVX2 is enabled, we use folly's memcpy instead of _hhvm_memcpy.
252               .globl    ETCH_NAME(memcpy)
253 #ifdef __AVX2__
254               ETCH_NAME(memcpy) = ETCH_NAME(_folly_memcpy)
255 #else
256               ETCH_NAME(memcpy) = ETCH_NAME(_hhvm_memcpy)
257 #endif
259               .ident "GCC: (GNU) 4.8.2"
260 #ifdef __linux__
261               .section .note.GNU-stack,"",@progbits
262 #endif
264 #endif