diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2021-08-31 07:14:47 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2021-10-20 05:35:52 -0700 |
commit | 92456a4e5658e138e2cea79e390e3306b07685b0 (patch) | |
tree | 6ef878e933b504a902035f1ae89510fde96a976d /libffi/src/kvx | |
parent | d738405e7fe62cc8eb9580948a6ea39005cd7170 (diff) | |
download | gcc-92456a4e5658e138e2cea79e390e3306b07685b0.zip gcc-92456a4e5658e138e2cea79e390e3306b07685b0.tar.gz gcc-92456a4e5658e138e2cea79e390e3306b07685b0.tar.bz2 |
libffi: Sync with libffi 3.4.2
Merged commit: f9ea41683444ebe11cfa45b05223899764df28fb
Diffstat (limited to 'libffi/src/kvx')
-rw-r--r-- | libffi/src/kvx/asm.h | 5 | ||||
-rw-r--r-- | libffi/src/kvx/ffi.c | 273 | ||||
-rw-r--r-- | libffi/src/kvx/ffitarget.h | 75 | ||||
-rw-r--r-- | libffi/src/kvx/sysv.S | 127 |
4 files changed, 480 insertions, 0 deletions
diff --git a/libffi/src/kvx/asm.h b/libffi/src/kvx/asm.h new file mode 100644 index 0000000..4edba41 --- /dev/null +++ b/libffi/src/kvx/asm.h @@ -0,0 +1,5 @@ +/* args are passed on registers from r0 up to r11 => 12*8 bytes */ +#define REG_ARGS_SIZE (12*8) +#define KVX_REGISTER_SIZE (8) +#define KVX_ABI_SLOT_SIZE (KVX_REGISTER_SIZE) +#define KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE (4*KVX_ABI_SLOT_SIZE) diff --git a/libffi/src/kvx/ffi.c b/libffi/src/kvx/ffi.c new file mode 100644 index 0000000..58f6aef --- /dev/null +++ b/libffi/src/kvx/ffi.c @@ -0,0 +1,273 @@ +/* Copyright (c) 2020 Kalray + +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 THE AUTHORS OR COPYRIGHT HOLDERS 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. */ + +#if defined(__kvx__) +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <fficonfig.h> +#include <ffi.h> +#include "ffi_common.h" +#include "asm.h" + +#define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1) +#define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define KVX_ABI_STACK_ALIGNMENT (32) +#define KVX_ABI_STACK_ARG_ALIGNMENT (8) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +#ifdef FFI_DEBUG +#define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); } while(0) +#else +#define DEBUG_PRINT(...) +#endif + +struct ret_value { + unsigned long int r0; + unsigned long int r1; + unsigned long int r2; + unsigned long int r3; +}; + +extern struct ret_value ffi_call_SYSV(unsigned total_size, + unsigned size, + extended_cif *ecif, + unsigned *rvalue_addr, + void *fn, + unsigned int_ext_method); + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + cif->flags = cif->rtype->size; + return FFI_OK; +} + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void *ffi_prep_args(char *stack, unsigned int arg_slots_size, extended_cif *ecif) +{ + char *stacktemp = stack; + char *current_arg_passed_by_value = stack + arg_slots_size; + int i, s; + ffi_type **arg; + int count = 0; + ffi_cif *cif = ecif->cif; + void **argv = ecif->avalue; + + arg = cif->arg_types; + + DEBUG_PRINT("stack: %p\n", stack); + DEBUG_PRINT("arg_slots_size: %u\n", arg_slots_size); + DEBUG_PRINT("current_arg_passed_by_value: %p\n", current_arg_passed_by_value); + DEBUG_PRINT("ecif: %p\n", ecif); + DEBUG_PRINT("ecif->avalue: %p\n", ecif->avalue); + + for (i = 0; i < cif->nargs; i++) { + + s = KVX_ABI_SLOT_SIZE; + switch((*arg)->type) { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + DEBUG_PRINT("INT64/32/16/8/FLOAT/DOUBLE or POINTER @%p\n", stack); + *(uint64_t *) stack = *(uint64_t *)(* argv); + break; + + case FFI_TYPE_COMPLEX: + if ((*arg)->size == 8) + *(_Complex float *) stack = *(_Complex float *)(* argv); + else if ((*arg)->size == 16) { + *(_Complex double *) stack = *(_Complex double *)(* argv); + s = 16; + } else + abort(); + break; + case FFI_TYPE_STRUCT: { + char *value; + unsigned int written_size = 0; + DEBUG_PRINT("struct by value @%p\n", stack); + if ((*arg)->size > KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE) { + DEBUG_PRINT("big struct\n"); + *(uint64_t *) stack = (uintptr_t)current_arg_passed_by_value; + value = current_arg_passed_by_value; + current_arg_passed_by_value += (*arg)->size; + written_size = KVX_ABI_SLOT_SIZE; + } else { + value = stack; + written_size = (*arg)->size; + } + memcpy(value, *argv, (*arg)->size); + s = ALIGN(written_size, KVX_ABI_STACK_ARG_ALIGNMENT); + break; + } + default: + printf("Error: unsupported arg type %d\n", (*arg)->type); + abort(); + break; + + } + stack += s; + count += s; + argv++; + arg++; + } +#ifdef FFI_DEBUG + FFI_ASSERT(((intptr_t)(stacktemp + REG_ARGS_SIZE) & (KVX_ABI_STACK_ALIGNMENT-1)) == 0); +#endif + return stacktemp + REG_ARGS_SIZE; +} + +/* Perform machine dependent cif processing when we have a variadic function */ + +ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, + unsigned int ntotalargs) +{ + cif->flags = cif->rtype->size; + return FFI_OK; +} + +static unsigned long handle_small_int_ext(kvx_intext_method *int_ext_method, + const ffi_type *rtype) +{ + switch (rtype->type) { + case FFI_TYPE_SINT8: + *int_ext_method = KVX_RET_SXBD; + return KVX_REGISTER_SIZE; + + case FFI_TYPE_SINT16: + *int_ext_method = KVX_RET_SXHD; + return KVX_REGISTER_SIZE; + + case FFI_TYPE_SINT32: + *int_ext_method = KVX_RET_SXWD; + return KVX_REGISTER_SIZE; + + case FFI_TYPE_UINT8: + *int_ext_method = KVX_RET_ZXBD; + return KVX_REGISTER_SIZE; + + case FFI_TYPE_UINT16: + *int_ext_method = KVX_RET_ZXHD; + return KVX_REGISTER_SIZE; + + case FFI_TYPE_UINT32: + *int_ext_method = KVX_RET_ZXWD; + return KVX_REGISTER_SIZE; + + default: + *int_ext_method = KVX_RET_NONE; + return rtype->size; + } +} + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + int i; + unsigned long int slot_fitting_args_size = 0; + unsigned long int total_size = 0; + unsigned long int big_struct_size = 0; + kvx_intext_method int_extension_method; + ffi_type **arg; + struct ret_value local_rvalue = {0}; + size_t wb_size; + + + /* Calculate size to allocate on stack */ + for (i = 0, arg = cif->arg_types; i < cif->nargs; i++, arg++) { + DEBUG_PRINT("argument %d, type %d, size %lu\n", i, (*arg)->type, (*arg)->size); + if (((*arg)->type == FFI_TYPE_STRUCT) || ((*arg)->type == FFI_TYPE_COMPLEX)) { + if ((*arg)->size <= KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE) { + slot_fitting_args_size += ALIGN((*arg)->size, KVX_ABI_SLOT_SIZE); + } else { + slot_fitting_args_size += KVX_ABI_SLOT_SIZE; /* aggregate passed by reference */ + big_struct_size += ALIGN((*arg)->size, KVX_ABI_SLOT_SIZE); + } + } else if ((*arg)->size <= KVX_ABI_SLOT_SIZE) { + slot_fitting_args_size += KVX_ABI_SLOT_SIZE; + } else { + printf("Error: unsupported arg size %ld arg type %d\n", (*arg)->size, (*arg)->type); + abort(); /* should never happen? */ + } + } + + extended_cif ecif; + ecif.cif = cif; + ecif.avalue = avalue; + ecif.rvalue = rvalue; + + /* This implementation allocates anyway for all register based args */ + slot_fitting_args_size = max(slot_fitting_args_size, REG_ARGS_SIZE); + total_size = slot_fitting_args_size + big_struct_size; + total_size = ALIGN(total_size, KVX_ABI_STACK_ALIGNMENT); + + /* wb_size: write back size, the size we will need to write back to user + * provided buffer. In theory it should always be cif->flags which is + * cif->rtype->size. But libffi API mandates that for integral types + * of size <= system register size, then we *MUST* write back + * the size of system register size. + * in our case, if size <= 8 bytes we must write back 8 bytes. + * floats, complex and structs are not affected, only integrals. + */ + wb_size = handle_small_int_ext(&int_extension_method, cif->rtype); + + switch (cif->abi) { + case FFI_SYSV: + DEBUG_PRINT("total_size: %lu\n", total_size); + DEBUG_PRINT("slot fitting args size: %lu\n", slot_fitting_args_size); + DEBUG_PRINT("rvalue: %p\n", rvalue); + DEBUG_PRINT("fn: %p\n", fn); + DEBUG_PRINT("rsize: %u\n", cif->flags); + DEBUG_PRINT("wb_size: %u\n", wb_size); + DEBUG_PRINT("int_extension_method: %u\n", int_extension_method); + local_rvalue = ffi_call_SYSV(total_size, slot_fitting_args_size, + &ecif, rvalue, fn, int_extension_method); + if ((cif->flags <= KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE) + && (cif->rtype->type != FFI_TYPE_VOID)) + memcpy(rvalue, &local_rvalue, wb_size); + break; + default: + abort(); + break; + } +} + +/* Closures not supported yet */ +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + return FFI_BAD_ABI; +} + +#endif /* (__kvx__) */ diff --git a/libffi/src/kvx/ffitarget.h b/libffi/src/kvx/ffitarget.h new file mode 100644 index 0000000..8df8735 --- /dev/null +++ b/libffi/src/kvx/ffitarget.h @@ -0,0 +1,75 @@ +/* ----------------------------------------------------------------------- + ffitarget.h - Copyright (c) 2020 Kalray + + KVX Target configuration macros + + 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 THE AUTHORS OR COPYRIGHT + HOLDERS 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. + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_H +#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." +#endif + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; + +/* Those values are set depending on return type + * they are used in the assembly code in sysv.S + */ +typedef enum kvx_intext_method { + KVX_RET_NONE = 0, + KVX_RET_SXBD = 1, + KVX_RET_SXHD = 2, + KVX_RET_SXWD = 3, + KVX_RET_ZXBD = 4, + KVX_RET_ZXHD = 5, + KVX_RET_ZXWD = 6 +} kvx_intext_method; + +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +/* This is only to allow Python to compile + * but closures are not supported yet + */ +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 0 + +#define FFI_NATIVE_RAW_API 0 +#define FFI_TARGET_SPECIFIC_VARIADIC 1 +#define FFI_TARGET_HAS_COMPLEX_TYPE + +#endif + diff --git a/libffi/src/kvx/sysv.S b/libffi/src/kvx/sysv.S new file mode 100644 index 0000000..952afc7 --- /dev/null +++ b/libffi/src/kvx/sysv.S @@ -0,0 +1,127 @@ +/* Copyright (c) 2020 Kalray + +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 THE AUTHORS OR COPYRIGHT HOLDERS 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. */ + +#if defined(__kvx__) +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#include <ffi_cfi.h> +#include <kvx/asm.h> + +.text +.global ffi_call_SYSV +.type ffi_call_SYSV, @function +.type ffi_prep_args, @function +.align 8 + +/* ffi_call_SYSV + + r0: total size to allocate on stack + r1: size of arg slots + r2: extended cif structure, DO NOT REMOVE: it is used by ffi_prep_args() + r3: return value address + r4: function to call + r5: integer sign extension method to be used +*/ +ffi_call_SYSV: + addd $r12 = $r12, -64 + so (-32)[$r12] = $r20r21r22r23 + ;; + sd (0)[$r12] = $r24 + ;; + get $r23 = $ra + copyd $r20 = $r12 + sbfd $r12 = $r0, $r12 + ;; + copyd $r0 = $r12 + copyd $r21 = $r3 + copyd $r22 = $r4 + copyd $r24 = $r5 + call ffi_prep_args + ;; + lo $r8r9r10r11 = (64)[$r12] + ;; + lo $r4r5r6r7 = (32)[$r12] + ;; + lo $r0r1r2r3 = (0)[$r12] + copyd $r12 = $r0 + /* $r15 is the register used by the ABI to return big (>32 bytes) + * structs by value. + * It is also referred to as the "struct register" in the ABI. + */ + copyd $r15 = $r21 + icall $r22 + ;; + pcrel $r4 = @pcrel(.Ltable) + cb.deqz $r24 ? .Lend + ;; + addx8d $r24 = $r24, $r4 + ;; + igoto $r24 + ;; +.Ltable: +0: /* we should never arrive here */ + goto .Lerror + nop + ;; +1: /* Sign extend byte to double */ + sxbd $r0 = $r0 + goto .Lend + ;; +2: /* Sign extend half to double */ + sxhd $r0 = $r0 + goto .Lend + ;; +3: /* Sign extend word to double */ + sxwd $r0 = $r0 + goto .Lend + ;; +4: /* Zero extend byte to double */ + zxbd $r0 = $r0 + goto .Lend + ;; +5: /* Zero extend half to double */ + zxhd $r0 = $r0 + goto .Lend + ;; +6: /* Zero extend word to double */ + zxwd $r0 = $r0 + /* Fallthrough to .Lend */ + ;; +.Lend: + ld $r24 = (0)[$r12] + ;; + set $ra = $r23 + lo $r20r21r22r23 = (32)[$r20] + addd $r12 = $r20, 64 + ;; + ret + ;; +.Lerror: + errop + ;; + +#endif /* __kvx__ */ + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",%progbits +#endif + |