diff options
Diffstat (limited to 'ext/ffi_c/libffi/src/x86/ffi64.c')
-rw-r--r-- | ext/ffi_c/libffi/src/x86/ffi64.c | 99 |
1 files changed, 70 insertions, 29 deletions
diff --git a/ext/ffi_c/libffi/src/x86/ffi64.c b/ext/ffi_c/libffi/src/x86/ffi64.c index c8eb455..5a5e043 100644 --- a/ext/ffi_c/libffi/src/x86/ffi64.c +++ b/ext/ffi_c/libffi/src/x86/ffi64.c @@ -1,9 +1,10 @@ /* ----------------------------------------------------------------------- - ffi64.c - Copyright (c) 20011 Anthony Green + ffi64.c - Copyright (c) 2013 The Written Word, Inc. + Copyright (c) 2011 Anthony Green Copyright (c) 2008, 2010 Red Hat, Inc. Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de> - - x86-64 Foreign Function Interface + + 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 @@ -37,11 +38,30 @@ #define MAX_GPR_REGS 6 #define MAX_SSE_REGS 8 +#if defined(__INTEL_COMPILER) +#include "xmmintrin.h" +#define UINT128 __m128 +#else +#if defined(__SUNPRO_C) +#include <sunmedia_types.h> +#define UINT128 __m128i +#else +#define UINT128 __int128_t +#endif +#endif + +union big_int_union +{ + UINT32 i32; + UINT64 i64; + UINT128 i128; +}; + struct register_args { /* Registers for argument passing. */ UINT64 gpr[MAX_GPR_REGS]; - __int128_t sse[MAX_SSE_REGS]; + union big_int_union sse[MAX_SSE_REGS]; }; extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, @@ -132,7 +152,7 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) See the x86-64 PS ABI for details. */ -static int +static size_t classify_argument (ffi_type *type, enum x86_64_reg_class classes[], size_t byte_offset) { @@ -148,7 +168,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], case FFI_TYPE_SINT64: case FFI_TYPE_POINTER: { - int size = byte_offset + type->size; + size_t size = byte_offset + type->size; if (size <= 4) { @@ -183,15 +203,17 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], case FFI_TYPE_DOUBLE: classes[0] = X86_64_SSEDF_CLASS; return 1; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: classes[0] = X86_64_X87_CLASS; classes[1] = X86_64_X87UP_CLASS; return 2; +#endif case FFI_TYPE_STRUCT: { - const int UNITS_PER_WORD = 8; - int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - ffi_type **ptr; + const size_t UNITS_PER_WORD = 8; + size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + ffi_type **ptr; int i; enum x86_64_reg_class subclasses[MAX_CLASSES]; @@ -213,7 +235,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], /* Merge the fields of structure. */ for (ptr = type->elements; *ptr != NULL; ptr++) { - int num; + size_t num; byte_offset = ALIGN (byte_offset, (*ptr)->alignment); @@ -222,7 +244,7 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], return 0; for (i = 0; i < num; i++) { - int pos = byte_offset / 8; + size_t pos = byte_offset / 8; classes[i + pos] = merge_classes (subclasses[i], classes[i + pos]); } @@ -286,11 +308,12 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], class. Return zero iff parameter should be passed in memory, otherwise the number of registers. */ -static int +static size_t examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], _Bool in_return, int *pngpr, int *pnsse) { - int i, n, ngpr, nsse; + size_t n; + int i, ngpr, nsse; n = classify_argument (type, classes, 0); if (n == 0) @@ -331,9 +354,9 @@ examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], ffi_status ffi_prep_cif_machdep (ffi_cif *cif) { - int gprcount, ssecount, i, avn, n, ngpr, nsse, flags; + int gprcount, ssecount, i, avn, ngpr, nsse, flags; enum x86_64_reg_class classes[MAX_CLASSES]; - size_t bytes; + size_t bytes, n; gprcount = ssecount = 0; @@ -391,7 +414,7 @@ ffi_prep_cif_machdep (ffi_cif *cif) if (ssecount) flags |= 1 << 11; cif->flags = flags; - cif->bytes = ALIGN (bytes, 8); + cif->bytes = (unsigned)ALIGN (bytes, 8); return FFI_OK; } @@ -427,15 +450,14 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) /* If the return value is passed in memory, add the pointer as the first integer argument. */ if (ret_in_memory) - reg_args->gpr[gprcount++] = (long) rvalue; + reg_args->gpr[gprcount++] = (unsigned long) rvalue; avn = cif->nargs; arg_types = cif->arg_types; for (i = 0; i < avn; ++i) { - size_t size = arg_types[i]->size; - int n; + size_t n, size = arg_types[i]->size; n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); if (n == 0 @@ -465,16 +487,33 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { case X86_64_INTEGER_CLASS: case X86_64_INTEGERSI_CLASS: - reg_args->gpr[gprcount] = 0; - memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8); + /* Sign-extend integer arguments passed in general + purpose registers, to cope with the fact that + LLVM incorrectly assumes that this will be done + (the x86-64 PS ABI does not specify this). */ + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + *(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT8 *) a); + break; + case FFI_TYPE_SINT16: + *(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT16 *) a); + break; + case FFI_TYPE_SINT32: + *(SINT64 *)®_args->gpr[gprcount] = (SINT64) *((SINT32 *) a); + break; + default: + reg_args->gpr[gprcount] = 0; + memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8); + } gprcount++; break; case X86_64_SSE_CLASS: case X86_64_SSEDF_CLASS: - reg_args->sse[ssecount++] = *(UINT64 *) a; + reg_args->sse[ssecount++].i64 = *(UINT64 *) a; break; case X86_64_SSESF_CLASS: - reg_args->sse[ssecount++] = *(UINT32 *) a; + reg_args->sse[ssecount++].i32 = *(UINT32 *) a; break; default: abort(); @@ -509,9 +548,11 @@ ffi_prep_closure_loc (ffi_closure* closure, tramp = (volatile unsigned short *) &closure->tramp[0]; tramp[0] = 0xbb49; /* mov <code>, %r11 */ - *(void * volatile *) &tramp[1] = ffi_closure_unix64; + *((unsigned long long * volatile) &tramp[1]) + = (unsigned long) ffi_closure_unix64; tramp[5] = 0xba49; /* mov <data>, %r10 */ - *(void * volatile *) &tramp[6] = codeloc; + *((unsigned long long * volatile) &tramp[6]) + = (unsigned long) codeloc; /* Set the carry bit iff the function uses any sse registers. This is clc or stc, together with the first byte of the jmp. */ @@ -545,12 +586,12 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, if (ret != FFI_TYPE_VOID) { enum x86_64_reg_class classes[MAX_CLASSES]; - int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); + size_t n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); if (n == 0) { /* The return value goes in memory. Arrange for the closure return value to go directly back to the original caller. */ - rvalue = (void *) reg_args->gpr[gprcount++]; + rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++]; /* We don't have to do anything in asm for the return. */ ret = FFI_TYPE_VOID; } @@ -568,11 +609,11 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, avn = cif->nargs; arg_types = cif->arg_types; - + for (i = 0; i < avn; ++i) { enum x86_64_reg_class classes[MAX_CLASSES]; - int n; + size_t n; n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); if (n == 0 |