diff options
author | bo <bo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-07-18 23:08:31 +0000 |
---|---|---|
committer | bo <bo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-07-18 23:08:31 +0000 |
commit | 42c71854648155103fd4e46bcee04fd04831a335 (patch) | |
tree | 31860a62cf64b5a75a76259340d1e0a1ac48ef45 /libffi/src/x86 | |
parent | 397866b171c934ccb95f24beb7dc6aed913e48da (diff) | |
download | gcc-42c71854648155103fd4e46bcee04fd04831a335.tar.gz |
2002-07-16 Bo Thorsen <bo@suse.de>
* src/x86/ffi64.c: New file that adds x86-64 support.
* src/x86/unix64.S: New file that handles argument setup for
x86-64.
* src/x86/sysv.S: Don't use this on x86-64.
* src/x86/ffi.c: Don't use this on x86-64.
Remove unused vars.
* src/prep_cif.c (ffi_prep_cif): Don't do stack size calculation
for x86-64.
* src/ffitest.c (struct6): New test that tests a special case in
the x86-64 ABI.
(struct7): Likewise.
(struct8): Likewise.
(struct9): Likewise.
(closure_test_fn): Silence warning about this when it's not used.
(main): Add the new tests.
(main): Fix a couple of wrong casts and silence some compiler warnings.
* include/ffi.h.in: Add x86-64 ABI definition.
* fficonfig.h.in: Regenerate.
* Makefile.am: Add x86-64 support.
* configure.in: Likewise.
* Makefile.in: Regenerate.
* configure: Likewise.
2002-06-24 Bo Thorsen <bo@suse.de>
* src/types.c: Merge settings for similar architectures.
Add x86-64 sizes and alignments.
2002-06-23 Bo Thorsen <bo@suse.de>
* src/arm/ffi.c (ffi_prep_args): Remove unused vars.
* src/sparc/ffi.c (ffi_prep_args_v8): Likewise.
* src/mips/ffi.c (ffi_prep_args): Likewise.
* src/m68k/ffi.c (ffi_prep_args): Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@55571 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libffi/src/x86')
-rw-r--r-- | libffi/src/x86/ffi.c | 4 | ||||
-rw-r--r-- | libffi/src/x86/ffi64.c | 575 | ||||
-rw-r--r-- | libffi/src/x86/sysv.S | 6 | ||||
-rw-r--r-- | libffi/src/x86/unix64.S | 166 |
4 files changed, 750 insertions, 1 deletions
diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c index c2af395228b..2e47c5dc7bf 100644 --- a/libffi/src/x86/ffi.c +++ b/libffi/src/x86/ffi.c @@ -23,6 +23,8 @@ OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ +#ifndef __x86_64__ + #include <ffi.h> #include <ffi_common.h> @@ -491,3 +493,5 @@ ffi_raw_call(/*@dependent@*/ ffi_cif *cif, } #endif + +#endif /* __x86_64__ */ diff --git a/libffi/src/x86/ffi64.c b/libffi/src/x86/ffi64.c new file mode 100644 index 00000000000..3dd8cbbf315 --- /dev/null +++ b/libffi/src/x86/ffi64.c @@ -0,0 +1,575 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de> + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +#ifdef __x86_64__ + +#define MAX_GPR_REGS 6 +#define MAX_SSE_REGS 8 +typedef struct +{ + /* Registers for argument passing. */ + long gpr[MAX_GPR_REGS]; + __int128_t sse[MAX_SSE_REGS]; + + /* Stack space for arguments. */ + char argspace[0]; +} stackLayout; + +/* All reference to register classes here is identical to the code in + gcc/config/i386/i386.c. Do *not* change one without the other. */ + +/* Register class used for passing given 64bit part of the argument. + These represent classes as documented by the PS ABI, with the exception + of SSESF, SSEDF classes, that are basically SSE class, just gcc will + use SF or DFmode move instead of DImode to avoid reformating penalties. + + Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves + whenever possible (upper half does contain padding). + */ +enum x86_64_reg_class + { + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_CLASS, + X86_64_MEMORY_CLASS + }; + +#define MAX_CLASSES 4 + +/* x86-64 register passing implementation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. */ + +/* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. */ + +static enum x86_64_reg_class +merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) +{ + /* Rule #1: If both classes are equal, this is the resulting class. */ + if (class1 == class2) + return class1; + + /* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. */ + if (class1 == X86_64_NO_CLASS) + return class2; + if (class2 == X86_64_NO_CLASS) + return class1; + + /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) + || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) + return X86_64_INTEGERSI_CLASS; + if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS + || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) + return X86_64_INTEGER_CLASS; + + /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ + if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS + || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + See the x86-64 PS ABI for details. +*/ +static int +classify_argument (ffi_type *type, enum x86_64_reg_class classes[], + int *byte_offset) +{ + /* First, align to the right place. */ + *byte_offset = ALIGN(*byte_offset, type->alignment); + + switch (type->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + if (((*byte_offset) % 8 + type->size) <= 4) + classes[0] = X86_64_INTEGERSI_CLASS; + else + classes[0] = X86_64_INTEGER_CLASS; + return 1; + case FFI_TYPE_FLOAT: + if (((*byte_offset) % 8) == 0) + classes[0] = X86_64_SSESF_CLASS; + else + classes[0] = X86_64_SSE_CLASS; + return 1; + case FFI_TYPE_DOUBLE: + classes[0] = X86_64_SSEDF_CLASS; + return 1; + case FFI_TYPE_LONGDOUBLE: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2; + case FFI_TYPE_STRUCT: + { + const int UNITS_PER_WORD = 8; + int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + ffi_type **ptr; + int i; + enum x86_64_reg_class subclasses[MAX_CLASSES]; + + /* If the struct is larger than 16 bytes, pass it on the stack. */ + if (type->size > 16) + return 0; + + for (i = 0; i < words; i++) + classes[i] = X86_64_NO_CLASS; + + /* Merge the fields of structure. */ + for (ptr=type->elements; (*ptr)!=NULL; ptr++) + { + int num; + + num = classify_argument (*ptr, subclasses, byte_offset); + if (num == 0) + return 0; + for (i = 0; i < num; i++) + { + int pos = *byte_offset / 8; + classes[i + pos] = + merge_classes (subclasses[i], classes[i + pos]); + } + + if ((*ptr)->type != FFI_TYPE_STRUCT) + *byte_offset += (*ptr)->size; + } + + /* Final merger cleanup. */ + for (i = 0; i < words; i++) + { + /* If one class is MEMORY, everything should be passed in + memory. */ + if (classes[i] == X86_64_MEMORY_CLASS) + return 0; + + /* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS. */ + if (classes[i] == X86_64_SSEUP_CLASS + && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS)) + classes[i] = X86_64_SSE_CLASS; + + /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */ + if (classes[i] == X86_64_X87UP_CLASS + && (i == 0 || classes[i - 1] != X86_64_X87_CLASS)) + classes[i] = X86_64_SSE_CLASS; + } + return words; + } + + default: + FFI_ASSERT(0); + } + return 0; /* Never reached. */ +} + +/* Examine the argument and return set number of register required in each + class. Return 0 iff parameter should be passed in memory. */ +static int +examine_argument (ffi_type *type, int in_return, int *int_nregs,int *sse_nregs) +{ + enum x86_64_reg_class class[MAX_CLASSES]; + int offset = 0; + int n; + + n = classify_argument (type, class, &offset); + + if (n == 0) + return 0; + + *int_nregs = 0; + *sse_nregs = 0; + for (n--; n>=0; n--) + switch (class[n]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + (*int_nregs)++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + (*sse_nregs)++; + break; + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; + case X86_64_X87_CLASS: + case X86_64_X87UP_CLASS: + if (!in_return) + return 0; + break; + default: + abort (); + } + return 1; +} + +/* Functions to load floats and double to an SSE register placeholder. */ +extern void float2sse (float, __int128_t *); +extern void double2sse (double, __int128_t *); +extern void floatfloat2sse (void *, __int128_t *); + +/* Functions to put the floats and doubles back. */ +extern float sse2float (__int128_t *); +extern double sse2double (__int128_t *); +extern void sse2floatfloat(__int128_t *, void *); + +/*@-exportheader@*/ +void +ffi_prep_args (stackLayout *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + int gprcount, ssecount, i, g, s; + void **p_argv; + void *argp = &stack->argspace; + ffi_type **p_arg; + + /* First check if the return value should be passed in memory. If so, + pass the pointer as the first argument. */ + gprcount = ssecount = 0; + if (examine_argument (ecif->cif->rtype, 1, &g, &s) == 0) + (void *)stack->gpr[gprcount++] = ecif->rvalue; + + for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue; + i!=0; i--, p_arg++, p_argv++) + { + int in_register = 0; + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + if (gprcount < MAX_GPR_REGS) + { + stack->gpr[gprcount] = 0; + stack->gpr[gprcount++] = *(long long *)(*p_argv); + in_register = 1; + } + break; + + case FFI_TYPE_FLOAT: + if (ssecount < MAX_SSE_REGS) + { + float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]); + in_register = 1; + } + break; + + case FFI_TYPE_DOUBLE: + if (ssecount < MAX_SSE_REGS) + { + double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]); + in_register = 1; + } + break; + } + + if (in_register) + continue; + + /* Either all places in registers where filled, or this is a + type that potentially goes into a memory slot. */ + if (examine_argument (*p_arg, 0, &g, &s) == 0 + || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS) + { + /* Pass this argument in memory. */ + argp = (void *)ALIGN(argp, (*p_arg)->alignment); + memcpy (argp, *p_argv, (*p_arg)->size); + argp += (*p_arg)->size; + } + else + { + /* All easy cases are eliminated. Now fire the big guns. */ + + enum x86_64_reg_class classes[MAX_CLASSES]; + int offset = 0, j, num; + void *a; + + num = classify_argument (*p_arg, classes, &offset); + for (j=0, a=*p_argv; j<num; j++, a+=8) + { + switch (classes[j]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + stack->gpr[gprcount++] = *(long long *)a; + break; + case X86_64_SSE_CLASS: + floatfloat2sse (a, &stack->sse[ssecount++]); + break; + case X86_64_SSESF_CLASS: + float2sse (*(float *)a, &stack->sse[ssecount++]); + break; + case X86_64_SSEDF_CLASS: + double2sse (*(double *)a, &stack->sse[ssecount++]); + break; + default: + abort(); + } + } + } + } +} + +/* Perform machine dependent cif processing. */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + int gprcount, ssecount, i, g, s; + + gprcount = ssecount = 0; + + /* Reset the byte count. We handle this size estimation here. */ + cif->bytes = 0; + + /* If the return value should be passed in memory, pass the pointer + as the first argument. The actual memory isn't allocated here. */ + + if (examine_argument (cif->rtype, 1, &g, &s) == 0) + gprcount = 1; + + /* Go over all arguments and determine the way they should be passed. + If it's in a register and there is space for it, let that be so. If + not, add it's size to the stack byte count. */ + for (i=0; i<cif->nargs; i++) + { + if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0 + || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS) + { + /* This is passed in memory. First align to the basic type. */ + cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment); + + /* Stack arguments are *always* at least 8 byte aligned. */ + cif->bytes = ALIGN(cif->bytes, 8); + + /* Now add the size of this argument. */ + cif->bytes += cif->arg_types[i]->size; + } + else + { + gprcount += g; + ssecount += s; + } + } + + /* Set the flag for the closures return. */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + puts ("prep_machdep\n"); + + return FFI_OK; +} + +typedef struct +{ + long gpr[2]; + __int128_t sse[2]; + long double st0; +} return_value; + +void +ffi_fill_return_value (return_value *rv, extended_cif *ecif) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + int i = 0, num; + long *gpr = rv->gpr; + __int128_t *sse = rv->sse; + signed char sc; + signed short ss; + + /* This is needed because of the way x86-64 handles signed short + integers. */ + switch (ecif->cif->rtype->type) + { + case FFI_TYPE_SINT8: + sc = *(signed char *)gpr; + *(long long *)ecif->rvalue = (long long)sc; + return; + case FFI_TYPE_SINT16: + ss = *(signed short *)gpr; + *(long long *)ecif->rvalue = (long long)ss; + return; + default: + /* Just continue. */ + ; + } + + num = classify_argument (ecif->cif->rtype, classes, &i); + + if (num == 0) + /* Return in memory. */ + ecif->rvalue = (void *) rv->gpr[0]; + else if (num == 2 && classes[0] == X86_64_X87_CLASS && + classes[1] == X86_64_X87UP_CLASS) + /* This is a long double (this is easiest to handle this way instead + of an eightbyte at a time as in the loop below. */ + *((long double *)ecif->rvalue) = rv->st0; + else + { + void *a; + + for (i=0, a=ecif->rvalue; i<num; i++, a+=8) + { + switch (classes[i]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + *(long long *)a = *gpr; + gpr++; + break; + case X86_64_SSE_CLASS: + sse2floatfloat (sse++, a); + break; + case X86_64_SSESF_CLASS: + *(float *)a = sse2float (sse++); + break; + case X86_64_SSEDF_CLASS: + *(double *)a = sse2double (sse++); + break; + default: + abort(); + } + } + } +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *), + void (*) (return_value *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, /*@out@*/ unsigned *, void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + int dummy; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (examine_argument (cif->rtype, 1, &dummy, &dummy) == 0)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + /* Stack must always be 16byte aligned. Make it so. */ + cif->bytes = ALIGN(cif->bytes, 16); + + switch (cif->abi) + { + case FFI_SYSV: + /* Calling 32bit code from 64bit is not possible */ + FFI_ASSERT(0); + break; + + case FFI_UNIX64: + /*@-usedef@*/ + ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif, + cif->bytes, ecif.rvalue, fn); + /*@=usedef@*/ + break; + + default: + FFI_ASSERT(0); + break; + } +} + +#endif /* ifndef __x86_64__ */ diff --git a/libffi/src/x86/sysv.S b/libffi/src/x86/sysv.S index 32eb633b443..ad898ad1a97 100644 --- a/libffi/src/x86/sysv.S +++ b/libffi/src/x86/sysv.S @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- - sysv.S - Copyright (c) 1996, 1998, 2001 Cygnus Solutions + sysv.S - Copyright (c) 1996, 1998, 2001, 2002 Cygnus Solutions X86 Foreign Function Interface @@ -23,6 +23,8 @@ OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ +#ifndef __x86_64__ + #define LIBFFI_ASM #include <ffi.h> @@ -163,3 +165,5 @@ __FRAME_BEGIN__: .align 4 .LEFDE1: .set .LLFDE1,.LEFDE1-.LSFDE1 + +#endif /* ifndef __x86_64__ */ diff --git a/libffi/src/x86/unix64.S b/libffi/src/x86/unix64.S new file mode 100644 index 00000000000..2e64b4195bf --- /dev/null +++ b/libffi/src/x86/unix64.S @@ -0,0 +1,166 @@ +/* ----------------------------------------------------------------------- + unix64.S - Copyright (c) 2002 Bo Thorsen <bo@suse.de> + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifdef __x86_64__ +#define LIBFFI_ASM +#include <ffi.h> + + .section .rodata +.LC0: + .string "asm in progress %lld\n" +.LC1: + .string "asm in progress\n" +.text + .align 2 +.globl ffi_call_UNIX64 + .type ffi_call_UNIX64,@function + +ffi_call_UNIX64: +.LFB1: + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + /* Save all arguments */ + subq $48, %rsp +.LCFI2: + movq %rdi, -8(%rbp) /* ffi_prep_args */ + movq %rsi, -16(%rbp) /* ffi_fill_return_value */ + movq %rdx, -24(%rbp) /* ecif */ + movq %rcx, -32(%rbp) /* cif->bytes */ + movq %r8, -40(%rbp) /* ecif.rvalue */ + movq %r9, -48(%rbp) /* fn */ + + /* Make room for all of the new args and the register args */ + addl $176, %ecx +.LCFI3: + subq %rcx, %rsp +.LCFI4: + /* Setup the call to ffi_prep_args. */ + movq %rdi, %rax /* &ffi_prep_args */ + movq %rsp, %rdi /* stackLayout */ + movq %rdx, %rsi /* ecif */ + call *%rax /* ffi_prep_args(stackLayout, ecif);*/ + + /* ffi_prep_args have put all the register contents into the */ + /* stackLayout struct. Now put the register values in place. */ + movq (%rsp), %rdi + movq 8(%rsp), %rsi + movq 16(%rsp), %rdx + movq 24(%rsp), %rcx + movq 32(%rsp), %r8 + movq 40(%rsp), %r9 + movaps 48(%rsp), %xmm0 + movaps 64(%rsp), %xmm1 + movaps 80(%rsp), %xmm2 + movaps 96(%rsp), %xmm3 + movaps 112(%rsp), %xmm4 + movaps 128(%rsp), %xmm5 + movaps 144(%rsp), %xmm6 + movaps 160(%rsp), %xmm7 + + /* Remove space for stackLayout so stack arguments are placed + correctly for the call. */ +.LCFI5: + addq $176, %rsp +.LCFI6: + /* Call the user function. */ + call *-48(%rbp) + + /* Make stack space for the return_value struct. */ + subq $64, %rsp + + /* Fill in all potential return values to this struct. */ + movq %rax, (%rsp) + movq %rdx, 8(%rsp) + movaps %xmm0, 16(%rsp) + movaps %xmm1, 32(%rsp) + fstpt 48(%rsp) + + /* Now call ffi_fill_return_value. */ + movq %rsp, %rdi /* struct return_value */ + movq -24(%rbp), %rsi /* ecif */ + movq -16(%rbp), %rax /* &ffi_fill_return_value */ + call *%rax /* call it */ + + /* And the work is done. */ + leave + ret +.LFE1: +.ffi_call_UNIX64_end: + .size ffi_call_UNIX64,.ffi_call_UNIX64_end-ffi_call_UNIX64 + +.text + .align 2 +.globl float2sse + .type float2sse,@function +float2sse: + /* Save the contents of this sse-float in a pointer. */ + movaps %xmm0, (%rdi) + ret + + .align 2 +.globl floatfloat2sse + .type floatfloat2sse,@function +floatfloat2sse: + /* Save the contents of these two sse-floats in a pointer. */ + movq (%rdi), %xmm0 + movaps %xmm0, (%rsi) + ret + + .align 2 +.globl double2sse + .type double2sse,@function +double2sse: + /* Save the contents of this sse-double in a pointer. */ + movaps %xmm0, (%rdi) + ret + + .align 2 +.globl sse2float + .type sse2float,@function +sse2float: + /* Save the contents of this sse-float in a pointer. */ + movaps (%rdi), %xmm0 + ret + + .align 2 +.globl sse2double + .type sse2double,@function +sse2double: + /* Save the contents of this pointer in a sse-double. */ + movaps (%rdi), %xmm0 + ret + + .align 2 +.globl sse2floatfloat + .type sse2floatfloat,@function +sse2floatfloat: + /* Save the contents of this pointer in two sse-floats. */ + movaps (%rdi), %xmm0 + movq %xmm0, (%rsi) + ret + +#endif /* __x86_64__ */ |