Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libffi / src / x86 / unix64.S
blobc9e0792764eeb5771fade2b17bfe9344a1f6c772
1 /* -----------------------------------------------------------------------
2    unix64.S - Copyright (c) 2002  Bo Thorsen <bo@suse.de>
4    x86-64 Foreign Function Interface 
6    Permission is hereby granted, free of charge, to any person obtaining
7    a copy of this software and associated documentation files (the
8    ``Software''), to deal in the Software without restriction, including
9    without limitation the rights to use, copy, modify, merge, publish,
10    distribute, sublicense, and/or sell copies of the Software, and to
11    permit persons to whom the Software is furnished to do so, subject to
12    the following conditions:
14    The above copyright notice and this permission notice shall be included
15    in all copies or substantial portions of the Software.
17    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23    OTHER DEALINGS IN THE SOFTWARE.
24    ----------------------------------------------------------------------- */
26 #ifdef __x86_64__
27 #define LIBFFI_ASM      
28 #include <fficonfig.h>
29 #include <ffi.h>
31 .text
33 /* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
34                     void *raddr, void (*fnaddr)());
36    Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
37    for this function.  This has been allocated by ffi_call.  We also
38    deallocate some of the stack that has been alloca'd.  */
40         .align  2
41         .globl  ffi_call_unix64
42         .type   ffi_call_unix64,@function
44 ffi_call_unix64:
45 .LUW0:
46         movq    (%rsp), %r10            /* Load return address.  */
47         leaq    (%rdi, %rsi), %rax      /* Find local stack base.  */
48         movq    %rdx, (%rax)            /* Save flags.  */
49         movq    %rcx, 8(%rax)           /* Save raddr.  */
50         movq    %rbp, 16(%rax)          /* Save old frame pointer.  */
51         movq    %r10, 24(%rax)          /* Relocate return address.  */
52         movq    %rax, %rbp              /* Finalize local stack frame.  */
53 .LUW1:
54         movq    %rdi, %r10              /* Save a copy of the register area. */
55         movq    %r8, %r11               /* Save a copy of the target fn.  */
57         /* Load up all argument registers.  */
58         movq    (%r10), %rdi
59         movq    8(%r10), %rsi
60         movq    16(%r10), %rdx
61         movq    24(%r10), %rcx
62         movq    32(%r10), %r8
63         movq    40(%r10), %r9
64         movdqa  48(%r10), %xmm0
65         movdqa  64(%r10), %xmm1
66         movdqa  80(%r10), %xmm2
67         movdqa  96(%r10), %xmm3
68         movdqa  112(%r10), %xmm4
69         movdqa  128(%r10), %xmm5
70         movdqa  144(%r10), %xmm6
71         movdqa  160(%r10), %xmm7
73         /* Deallocate the reg arg area.  */
74         leaq    176(%r10), %rsp
76         /* Call the user function.  */
77         call    *%r11
79         /* Deallocate stack arg area; local stack frame in redzone.  */
80         leaq    24(%rbp), %rsp
82         movq    0(%rbp), %rcx           /* Reload flags.  */
83         movq    8(%rbp), %rdi           /* Reload raddr.  */
84         movq    16(%rbp), %rbp          /* Reload old frame pointer.  */
85 .LUW2:
87         /* The first byte of the flags contains the FFI_TYPE.  */
88         movzbl  %cl, %r10d
89         leaq    .Lstore_table(%rip), %r11
90         movslq  (%r11, %r10, 4), %r10
91         addq    %r11, %r10
92         jmp     *%r10
94         .section .rodata
95 .Lstore_table:
96         .long   .Lst_void-.Lstore_table         /* FFI_TYPE_VOID */
97         .long   .Lst_sint32-.Lstore_table       /* FFI_TYPE_INT */
98         .long   .Lst_float-.Lstore_table        /* FFI_TYPE_FLOAT */
99         .long   .Lst_double-.Lstore_table       /* FFI_TYPE_DOUBLE */
100         .long   .Lst_ldouble-.Lstore_table      /* FFI_TYPE_LONGDOUBLE */
101         .long   .Lst_uint8-.Lstore_table        /* FFI_TYPE_UINT8 */
102         .long   .Lst_sint8-.Lstore_table        /* FFI_TYPE_SINT8 */
103         .long   .Lst_uint16-.Lstore_table       /* FFI_TYPE_UINT16 */
104         .long   .Lst_sint16-.Lstore_table       /* FFI_TYPE_SINT16 */
105         .long   .Lst_uint32-.Lstore_table       /* FFI_TYPE_UINT32 */
106         .long   .Lst_sint32-.Lstore_table       /* FFI_TYPE_SINT32 */
107         .long   .Lst_int64-.Lstore_table        /* FFI_TYPE_UINT64 */
108         .long   .Lst_int64-.Lstore_table        /* FFI_TYPE_SINT64 */
109         .long   .Lst_struct-.Lstore_table       /* FFI_TYPE_STRUCT */
110         .long   .Lst_int64-.Lstore_table        /* FFI_TYPE_POINTER */
112         .text
113         .align 2
114 .Lst_void:
115         ret
116         .align 2
118 .Lst_uint8:
119         movzbq  %al, %rax
120         movq    %rax, (%rdi)
121         ret
122         .align 2
123 .Lst_sint8:
124         movsbq  %al, %rax
125         movq    %rax, (%rdi)
126         ret
127         .align 2
128 .Lst_uint16:
129         movzwq  %ax, %rax
130         movq    %rax, (%rdi)
131         .align 2
132 .Lst_sint16:
133         movswq  %ax, %rax
134         movq    %rax, (%rdi)
135         ret
136         .align 2
137 .Lst_uint32:
138         movl    %eax, %eax
139         movq    %rax, (%rdi)
140         .align 2
141 .Lst_sint32:
142         cltq
143         movq    %rax, (%rdi)
144         ret
145         .align 2
146 .Lst_int64:
147         movq    %rax, (%rdi)
148         ret
150         .align 2
151 .Lst_float:
152         movss   %xmm0, (%rdi)
153         ret
154         .align 2
155 .Lst_double:
156         movsd   %xmm0, (%rdi)
157         ret
158 .Lst_ldouble:
159         fstpt   (%rdi)
160         ret
162         .align 2
163 .Lst_struct:
164         leaq    -20(%rsp), %rsi         /* Scratch area in redzone.  */
166         /* We have to locate the values now, and since we don't want to
167            write too much data into the user's return value, we spill the
168            value to a 16 byte scratch area first.  Bits 8, 9, and 10
169            control where the values are located.  Only one of the three
170            bits will be set; see ffi_prep_cif_machdep for the pattern.  */
171         movd    %xmm0, %r10
172         movd    %xmm1, %r11
173         testl   $0x100, %ecx
174         cmovnz  %rax, %rdx
175         cmovnz  %r10, %rax
176         testl   $0x200, %ecx
177         cmovnz  %r10, %rdx
178         testl   $0x400, %ecx
179         cmovnz  %r10, %rax
180         cmovnz  %r11, %rdx
181         movq    %rax, (%rsi)
182         movq    %rdx, 8(%rsi)
184         /* Bits 11-31 contain the true size of the structure.  Copy from
185            the scratch area to the true destination.  */
186         shrl    $11, %ecx
187         rep movsb
188         ret
189 .LUW3:
190         .size    ffi_call_unix64,.-ffi_call_unix64
192         .align  2
193         .globl ffi_closure_unix64
194         .type   ffi_closure_unix64,@function
196 ffi_closure_unix64:
197 .LUW4:
198         subq    $200, %rsp
199 .LUW5:
201         movq    %rdi, (%rsp)
202         movq    %rsi, 8(%rsp)
203         movq    %rdx, 16(%rsp)
204         movq    %rcx, 24(%rsp)
205         movq    %r8, 32(%rsp)
206         movq    %r9, 40(%rsp)
207         movdqa  %xmm0, 48(%rsp)
208         movdqa  %xmm1, 64(%rsp)
209         movdqa  %xmm2, 80(%rsp)
210         movdqa  %xmm3, 96(%rsp)
211         movdqa  %xmm4, 112(%rsp)
212         movdqa  %xmm5, 128(%rsp)
213         movdqa  %xmm6, 144(%rsp)
214         movdqa  %xmm7, 160(%rsp)
216         movq    %r10, %rdi
217         leaq    176(%rsp), %rsi
218         movq    %rsp, %rdx
219         leaq    208(%rsp), %rcx
220         call    ffi_closure_unix64_inner@PLT
222         /* Deallocate stack frame early; return value is now in redzone.  */
223         addq    $200, %rsp
224 .LUW6:
226         /* The first byte of the return value contains the FFI_TYPE.  */
227         movzbl  %al, %r10d
228         leaq    .Lload_table(%rip), %r11
229         movslq  (%r11, %r10, 4), %r10
230         addq    %r11, %r10
231         jmp     *%r10
233         .section .rodata
234 .Lload_table:
235         .long   .Lld_void-.Lload_table          /* FFI_TYPE_VOID */
236         .long   .Lld_int32-.Lload_table         /* FFI_TYPE_INT */
237         .long   .Lld_float-.Lload_table         /* FFI_TYPE_FLOAT */
238         .long   .Lld_double-.Lload_table        /* FFI_TYPE_DOUBLE */
239         .long   .Lld_ldouble-.Lload_table       /* FFI_TYPE_LONGDOUBLE */
240         .long   .Lld_int8-.Lload_table          /* FFI_TYPE_UINT8 */
241         .long   .Lld_int8-.Lload_table          /* FFI_TYPE_SINT8 */
242         .long   .Lld_int16-.Lload_table         /* FFI_TYPE_UINT16 */
243         .long   .Lld_int16-.Lload_table         /* FFI_TYPE_SINT16 */
244         .long   .Lld_int32-.Lload_table         /* FFI_TYPE_UINT32 */
245         .long   .Lld_int32-.Lload_table         /* FFI_TYPE_SINT32 */
246         .long   .Lld_int64-.Lload_table         /* FFI_TYPE_UINT64 */
247         .long   .Lld_int64-.Lload_table         /* FFI_TYPE_SINT64 */
248         .long   .Lld_struct-.Lload_table        /* FFI_TYPE_STRUCT */
249         .long   .Lld_int64-.Lload_table         /* FFI_TYPE_POINTER */
251         .text
252         .align 2
253 .Lld_void:
254         ret
256         .align 2
257 .Lld_int8:
258         movzbl  -24(%rsp), %eax
259         ret
260         .align 2
261 .Lld_int16:
262         movzwl  -24(%rsp), %eax
263         ret
264         .align 2
265 .Lld_int32:
266         movl    -24(%rsp), %eax
267         ret
268         .align 2
269 .Lld_int64:
270         movq    -24(%rsp), %rax
271         ret
273         .align 2
274 .Lld_float:
275         movss   -24(%rsp), %xmm0
276         ret
277         .align 2
278 .Lld_double:
279         movsd   -24(%rsp), %xmm0
280         ret
281         .align 2
282 .Lld_ldouble:
283         fldt    -24(%rsp)
284         ret
286         .align 2
287 .Lld_struct:
288         /* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
289            %rax/%xmm0, %xmm0/%xmm1.  We collapse two by always loading
290            both rdx and xmm1 with the second word.  For the remaining,
291            bit 8 set means xmm0 gets the second word, and bit 9 means
292            that rax gets the second word.  */
293         movq    -24(%rsp), %rcx
294         movq    -16(%rsp), %rdx
295         movq    -16(%rsp), %xmm1
296         testl   $0x100, %eax
297         cmovnz  %rdx, %rcx
298         movd    %rcx, %xmm0
299         testl   $0x200, %eax
300         movq    -24(%rsp), %rax
301         cmovnz  %rdx, %rax
302         ret
303 .LUW7:
304         .size   ffi_closure_unix64,.-ffi_closure_unix64
306         .section        .eh_frame,"a",@progbits
307 .Lframe1:
308         .long   .LECIE1-.LSCIE1         /* CIE Length */
309 .LSCIE1:
310         .long   0                       /* CIE Identifier Tag */
311         .byte   1                       /* CIE Version */
312         .ascii "zR\0"                   /* CIE Augmentation */
313         .uleb128 1                      /* CIE Code Alignment Factor */
314         .sleb128 -8                     /* CIE Data Alignment Factor */
315         .byte   0x10                    /* CIE RA Column */
316         .uleb128 1                      /* Augmentation size */
317         .byte   0x1b                    /* FDE Encoding (pcrel sdata4) */
318         .byte   0xc                     /* DW_CFA_def_cfa, %rsp offset 8 */
319         .uleb128 7
320         .uleb128 8
321         .byte   0x80+16                 /* DW_CFA_offset, %rip offset 1*-8 */
322         .uleb128 1
323         .align 8
324 .LECIE1:
325 .LSFDE1:
326         .long   .LEFDE1-.LASFDE1        /* FDE Length */
327 .LASFDE1:
328         .long   .LASFDE1-.Lframe1       /* FDE CIE offset */
329         .long   .LUW0-.                 /* FDE initial location */
330         .long   .LUW3-.LUW0             /* FDE address range */
331         .uleb128 0x0                    /* Augmentation size */
333         .byte   0x4                     /* DW_CFA_advance_loc4 */
334         .long   .LUW1-.LUW0
336         /* New stack frame based off rbp.  This is a itty bit of unwind
337            trickery in that the CFA *has* changed.  There is no easy way
338            to describe it correctly on entry to the function.  Fortunately,
339            it doesn't matter too much since at all points we can correctly
340            unwind back to ffi_call.  Note that the location to which we
341            moved the return address is (the new) CFA-8, so from the
342            perspective of the unwind info, it hasn't moved.  */
343         .byte   0xc                     /* DW_CFA_def_cfa, %rbp offset 32 */
344         .uleb128 6
345         .uleb128 32
346         .byte   0x80+6                  /* DW_CFA_offset, %rbp offset 2*-8 */
347         .uleb128 2
349         .byte   0x4                     /* DW_CFA_advance_loc4 */
350         .long   .LUW2-.LUW1
351         .byte   0xc                     /* DW_CFA_def_cfa, %rsp offset 8 */
352         .uleb128 7
353         .uleb128 8
354         .byte   0xc0+6                  /* DW_CFA_restore, %rbp */
355         .align 8
356 .LEFDE1:
357 .LSFDE3:
358         .long   .LEFDE3-.LASFDE3        /* FDE Length */
359 .LASFDE3:
360         .long   .LASFDE3-.Lframe1       /* FDE CIE offset */
361         .long   .LUW4-.                 /* FDE initial location */
362         .long   .LUW7-.LUW4             /* FDE address range */
363         .uleb128 0x0                    /* Augmentation size */
364         .byte   0x4                     /* DW_CFA_advance_loc4 */
365         .long   .LUW5-.LUW4
366         .byte   0xe                     /* DW_CFA_def_cfa_offset */
367         .uleb128 208
368         .byte   0x4                     /* DW_CFA_advance_loc4 */
369         .long   .LUW6-.LUW5
370         .byte   0xe                     /* DW_CFA_def_cfa_offset */
371         .uleb128 8
372         .align 8
373 .LEFDE3:
375 #endif /* __x86_64__ */