Files
meta-riscv/recipes-support/libffi/files/0001-Add-riscv-support.patch
Khem Raj f4ba684c5f libffi: Add riscv64 support
Signed-off-by: Khem Raj <raj.khem@gmail.com>
2017-10-04 11:44:33 -07:00

1984 lines
63 KiB
Diff

From ca569f8a61e1c127166862f32548a7671009b289 Mon Sep 17 00:00:00 2001
From: Khem Raj <raj.khem@gmail.com>
Date: Wed, 4 Oct 2017 11:08:06 -0700
Subject: [PATCH] Add riscv support
Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
Makefile.am | 4 +
README.md | 23 ++
configure.ac | 5 +-
misc/parse_tests.py | 50 +++
misc/riscv-sim.exp | 6 +
misc/run_test.sh | 3 +
src/prep_cif.c | 5 +-
src/riscv/asm.py | 37 ++
src/riscv/ffi.c | 746 ++++++++++++++++++++++++++++++++++++++++
src/riscv/ffitarget.h | 120 +++++++
src/riscv/sysv.S | 782 ++++++++++++++++++++++++++++++++++++++++++
testsuite/Makefile.am | 2 +-
testsuite/libffi.call/many3.c | 59 ++++
13 files changed, 1837 insertions(+), 5 deletions(-)
create mode 100644 README.md
create mode 100644 misc/parse_tests.py
create mode 100644 misc/riscv-sim.exp
create mode 100644 misc/run_test.sh
create mode 100644 src/riscv/asm.py
create mode 100644 src/riscv/ffi.c
create mode 100644 src/riscv/ffitarget.h
create mode 100644 src/riscv/sysv.S
create mode 100644 testsuite/libffi.call/many3.c
Index: libffi-3.2.1/Makefile.am
===================================================================
--- libffi-3.2.1.orig/Makefile.am
+++ libffi-3.2.1/Makefile.am
@@ -32,6 +32,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 Change
src/powerpc/asm.h src/powerpc/aix.S src/powerpc/darwin.S \
src/powerpc/aix_closure.S src/powerpc/darwin_closure.S \
src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h \
+ src/riscv/ffi.c src/riscv/ffitarget.h src/riscv/sysv.S \
src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h \
src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h src/sh64/ffi.c \
src/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S \
@@ -122,6 +123,9 @@ endif
if MIPS
nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S
endif
+if RISCV
+nodist_libffi_la_SOURCES += src/riscv/ffi.c src/riscv/sysv.S
+endif
if BFIN
nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S
endif
Index: libffi-3.2.1/README.md
===================================================================
--- /dev/null
+++ libffi-3.2.1/README.md
@@ -0,0 +1,23 @@
+RISC-V Port of libffi
+=====================
+
+Compile and run:
+
+```
+./configure --host=riscv64-unknown-elf
+make
+```
+
+Run tests in Spike:
+
+```
+make check RUNTESTFLAGS="--target_board=riscv-sim --all"
+```
+
+Run an individual test:
+
+Go to `testsuite/libffi.call` directory and run:
+
+```
+../../misc/run_test.sh <test_name.c>
+```
Index: libffi-3.2.1/configure.ac
===================================================================
--- libffi-3.2.1.orig/configure.ac
+++ libffi-3.2.1/configure.ac
@@ -260,7 +260,9 @@ case "$host" in
powerpc*-*-rtems*)
TARGET=POWERPC; TARGETDIR=powerpc
;;
-
+ riscv*-*-*)
+ TARGET=RISCV; TARGETDIR=riscv
+ ;;
s390-*-* | s390x-*-*)
TARGET=S390; TARGETDIR=s390
;;
@@ -298,6 +300,7 @@ if test $TARGETDIR = unknown; then
fi
AM_CONDITIONAL(MIPS, test x$TARGET = xMIPS)
+AM_CONDITIONAL(RISCV, test x$TARGET = xRISCV)
AM_CONDITIONAL(BFIN, test x$TARGET = xBFIN)
AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC)
AM_CONDITIONAL(X86, test x$TARGET = xX86)
Index: libffi-3.2.1/misc/parse_tests.py
===================================================================
--- /dev/null
+++ libffi-3.2.1/misc/parse_tests.py
@@ -0,0 +1,50 @@
+#!/bin/python
+
+import sys
+
+def print_help():
+ print "Usage: python " + sys.argv[0] + " <test result file>"
+
+if len(sys.argv) != 2:
+ exit(1)
+
+summary = ""
+passed = []
+failed = []
+fname = sys.argv[1]
+f = open(fname, 'r')
+for l in f.readlines():
+ if l.startswith("PASS"):
+ z = l.split()
+ if not z[1] in passed:
+ passed.append(z[1])
+ elif l.startswith("FAIL"):
+ z = l.split()
+ if not z[1] in failed:
+ failed.append(z[1])
+ elif l.startswith("#"):
+ summary += l
+
+i = 0
+while i < len(passed):
+ if passed[i] in failed:
+ del passed[i]
+ continue
+ i += 1
+
+p_num = len(passed)
+f_num = len(failed)
+total = p_num + f_num
+
+print "---TEST FILES PASSED---"
+for t in passed: print t
+print
+print "---TEST FILES FAILED---"
+for t in failed: print t
+print
+print "------TEST SUMMARY------"
+print "Passed: " + str(p_num) + " (" + str(round(float(p_num)/total*100, 1)) + "%)"
+print "Failed: " + str(f_num) + " (" + str(round(float(f_num)/total*100, 1)) + "%)"
+print "Total: " + str(total)
+print
+print summary
Index: libffi-3.2.1/misc/riscv-sim.exp
===================================================================
--- /dev/null
+++ libffi-3.2.1/misc/riscv-sim.exp
@@ -0,0 +1,6 @@
+load_generic_config "sim"
+set_board_info sim "spike pk"
+set_board_info compiler "[find_gcc]"
+set_board_info ldflags "-static"
+set_board_info gdb,nosignals 1
+set_board_info is_simulator 1
Index: libffi-3.2.1/misc/run_test.sh
===================================================================
--- /dev/null
+++ libffi-3.2.1/misc/run_test.sh
@@ -0,0 +1,3 @@
+#/bin/bash
+riscv64-unknown-elf-gcc -g -I../../riscv64-unknown-elf/include -I../../riscv64-unknown-elf -L../../riscv64-unknown-elf/.libs/ $1 -lffi
+spike pk a.out
Index: libffi-3.2.1/src/prep_cif.c
===================================================================
--- libffi-3.2.1.orig/src/prep_cif.c
+++ libffi-3.2.1/src/prep_cif.c
@@ -143,8 +143,8 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(
/* Perform a sanity check on the return type */
FFI_ASSERT_VALID_TYPE(cif->rtype);
- /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
-#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+ /* x86, x86-64, s390, and riscv stack space allocation is handled in prep_machdep. */
+#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA && (defined __riscv && __riscv_xlen != 64)
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef SPARC
@@ -205,7 +205,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(
if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4)
bytes = 6*4;
#endif
-
bytes += STACK_ARG_SIZE((*ptr)->size);
}
#endif
Index: libffi-3.2.1/src/riscv/asm.py
===================================================================
--- /dev/null
+++ libffi-3.2.1/src/riscv/asm.py
@@ -0,0 +1,37 @@
+#!/bin/python
+
+def set_args_64(i):
+ return """
+####################
+## SET ARGUMENT """ + str(i) + """ ##
+####################
+
+set_arg""" + str(i) + """:
+ srli t1, t0, FFI_FLAG_BITS_X""" + str(i) + """ # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg""" + str(i) + """_float
+ REG_L a""" + str(i) + """, FFI_SIZEOF_ARG_X""" + str(i) + """(sp) # load argument
+ j set_arg""" + str(i+1) + """
+
+set_arg""" + str(i) + """_float:
+ addi t1, t1, -1
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg""" + str(i) + """_double
+ flw fa""" + str(i) + """, FFI_SIZEOF_ARG_X""" + str(i) + """(sp) # load argument
+ j set_arg""" + str(i+1) + """
+
+set_arg""" + str(i) + """_double:
+ # otherwise it must be a double we're dealing with
+ fld fa""" + str(i) + """, FFI_SIZEOF_ARG_X""" + str(i) + """(sp)
+"""
+
+def gen64_setargs_string():
+ setargs = ""
+ for i in range(8):
+ setargs += set_args_64(i)
+ return setargs
+
+print gen64_setargs_string()
Index: libffi-3.2.1/src/riscv/ffi.c
===================================================================
--- /dev/null
+++ libffi-3.2.1/src/riscv/ffi.c
@@ -0,0 +1,746 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
+ 2015 Andrew Waterman <waterman@cs.berkeley.edu>
+ Based on MIPS N32/64 port
+
+ RISC-V 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 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.
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+static void ffi_prep_args(char *stack, extended_cif *ecif, int bytes, int flags)
+{
+ int i;
+ void **p_argv;
+ char *argp, *cpy_struct;
+ ffi_type **p_arg;
+
+ argp = stack;
+ cpy_struct = stack + ALIGN(bytes, 16);
+
+ memset(stack, 0, bytes);
+
+ if (ecif->cif->rstruct_flag != 0)
+ {
+ *(ffi_arg *) argp = (ffi_arg) ecif->rvalue;
+ argp += sizeof(ffi_arg);
+ }
+
+ p_argv = ecif->avalue;
+
+ for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; i++, p_arg++)
+ {
+ size_t z;
+ unsigned int a;
+
+ /* Align if necessary. */
+ a = (*p_arg)->alignment;
+ if (a < sizeof(ffi_arg))
+ a = sizeof(ffi_arg);
+
+ if ((a - 1) & (unsigned long) argp)
+ {
+ argp = (char *) ALIGN(argp, a);
+ }
+
+ z = (*p_arg)->size;
+ if (z <= sizeof(ffi_arg))
+ {
+ int type = (*p_arg)->type;
+ z = sizeof(ffi_arg);
+
+ /* The size of a pointer depends on the ABI */
+ if (type == FFI_TYPE_POINTER)
+ #if defined(__riscv) && __riscv_xlen == 64
+ type = FFI_TYPE_SINT64;
+ #else
+ type = FFI_TYPE_SINT32;
+ #endif
+
+ if (i < 8 && (ecif->cif->abi == FFI_RV32_SOFT_FLOAT || ecif->cif->abi == FFI_RV64_SOFT_FLOAT))
+ {
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ type = FFI_TYPE_UINT32;
+ break;
+ case FFI_TYPE_DOUBLE:
+ type = FFI_TYPE_UINT64;
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (type)
+ {
+ case FFI_TYPE_SINT8:
+ *(ffi_arg *)argp = *(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(ffi_arg *)argp = *(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(ffi_arg *)argp = *(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(ffi_arg *)argp = *(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ *(ffi_arg *)argp = *(SINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT32:
+ *(ffi_arg *)argp = *(UINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT64:
+ *(ffi_arg *)argp = *(SINT64 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT64:
+ *(ffi_arg *)argp = *(UINT64 *)(* p_argv);
+ break;
+
+ /* This can only happen with 64bit slots. */
+ case FFI_TYPE_FLOAT:
+ *(float *) argp = *(float *)(* p_argv);
+ break;
+
+ /* Handle structures. */
+ default:
+ memcpy(argp, *p_argv, (*p_arg)->size);
+ break;
+ }
+ }
+ else if (z <= 2*sizeof(ffi_arg))
+ {
+ /* Check if the data will fit within the register space.
+ Handle it if it doesn't. */
+
+ unsigned long end = (unsigned long) argp + z;
+ unsigned long cap = (unsigned long) stack + bytes;
+
+ if (end <= cap)
+ memcpy(argp, *p_argv, z);
+ else
+ {
+ unsigned long portion = cap - (unsigned long)argp;
+
+ memcpy(argp, *p_argv, portion);
+ argp = stack;
+ z -= portion;
+ memcpy(argp, (void*)((unsigned long)(*p_argv) + portion), z);
+ }
+ }
+ else if(i < 8 && z > 2*sizeof(ffi_arg))
+ {
+ /* It's too big to pass in any registers or on the stack,
+ so we pass a pointer, and copy the struct to pass by value.
+ But, we can't _just_ copy it onto the stack! We need to actually
+ make sure it gets onto the "bottom" (really the top, high memory
+ addresses) of the stack frame... */
+
+ /* Update pointer to where our struct location on the stack is */
+ cpy_struct -= ALIGN(z, a);
+
+ memcpy(cpy_struct, *p_argv, z);
+
+ /* Pass pointer in register */
+ *(ffi_arg *)argp = (ffi_arg) cpy_struct;
+
+ z = sizeof(ffi_arg);
+ }
+ else
+ {
+ /* Just some big struct, pass it by value by copying it onto
+ the stack. */
+ memcpy(argp, *p_argv, z);
+ }
+
+ p_argv++;
+ argp += z;
+ }
+}
+
+/* This code traverses structure definitions
+ and generates the appropriate flags. */
+
+static unsigned calc_riscv_struct_flags(int soft_float, ffi_type *arg, size_t size, unsigned *loc, unsigned *arg_reg)
+{
+ unsigned flags = 0;
+ unsigned index = 0;
+ ffi_type *e;
+
+ if (soft_float)
+ return 0;
+
+ /* The struct is too big to pass on the stack, so we pass it by reference */
+ if (size > 2 * FFI_SIZEOF_ARG)
+ {
+ (*arg_reg)++;
+ return 0;
+ }
+
+ while ((e = arg->elements[index]))
+ {
+ /* Align this object. */
+ *loc = ALIGN(*loc, e->alignment);
+
+ if (e->type == FFI_TYPE_DOUBLE)
+ {
+ /* Already aligned to FFI_SIZEOF_ARG. */
+ *arg_reg = *loc / FFI_SIZEOF_ARG;
+
+ if (*arg_reg > 7)
+ break;
+
+ flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS));
+ *loc += e->size;
+ }
+ else
+ *loc += e->size;
+
+ index++;
+ }
+
+ /* Next Argument register at alignment of FFI_SIZEOF_ARG. */
+ *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+
+ return flags;
+}
+
+/* The flags output of this routine should match the various struct cases
+ described in ffitarget.h */
+
+static unsigned calc_riscv_return_struct_flags(int soft_float, ffi_type *arg)
+{
+ unsigned flags = 0;
+ unsigned small = FFI_TYPE_SMALLSTRUCT;
+ ffi_type *e;
+
+ /* Returning structures under n32 is a tricky thing.
+ A struct with only one or two floating point fields
+ is returned in $f0 (and $f2 if necessary). Any other
+ struct results at most 128 bits are returned in $2
+ (the first 64 bits) and $3 (remainder, if necessary).
+ Larger structs are handled normally. */
+
+ if (arg->size > 2 * FFI_SIZEOF_ARG)
+ return 0;
+
+ if (arg->size > 8)
+ small = FFI_TYPE_SMALLSTRUCT2;
+
+ e = arg->elements[0];
+ if (e->type == FFI_TYPE_DOUBLE)
+ flags = FFI_TYPE_DOUBLE;
+ else if (e->type == FFI_TYPE_FLOAT)
+ flags = FFI_TYPE_FLOAT;
+
+ if (flags && (e = arg->elements[1]))
+ {
+ if (e->type == FFI_TYPE_DOUBLE)
+ flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
+ else if (e->type == FFI_TYPE_FLOAT)
+ flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS;
+ else
+ return small;
+
+ if (flags && (arg->elements[2]))
+ {
+ /* There are three arguments and the first two are
+ floats! This must be passed the old way. */
+ return small;
+ }
+
+ if (soft_float)
+ flags += FFI_TYPE_STRUCT_SOFT;
+ }
+ else if (!flags)
+ return small;
+
+ return flags;
+}
+
+/* Generate the flags word for processing arguments and
+ putting them into their proper registers in the
+ assembly routine. */
+
+void ffi_prep_cif_machdep_flags(ffi_cif *cif, unsigned int isvariadic, unsigned int nfixedargs)
+{
+ int type;
+ unsigned arg_reg = 0;
+ unsigned loc = 0;
+ unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
+ unsigned index = 0;
+
+ unsigned int struct_flags = 0;
+ int soft_float = cif->abi == FFI_RV64_SOFT_FLOAT || cif->abi == FFI_RV32_SOFT_FLOAT;;
+
+ cif->flags = 0;
+
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ struct_flags = calc_riscv_return_struct_flags(soft_float, cif->rtype);
+ if (struct_flags == 0)
+ {
+ /* This means that the structure is being passed as
+ a hidden argument */
+ arg_reg = 1;
+ count = (cif->nargs < 7) ? cif->nargs : 7;
+ cif->rstruct_flag = !0;
+ }
+ else
+ cif->rstruct_flag = 0;
+ }
+ else
+ cif->rstruct_flag = 0;
+
+ /* Set the first 8 existing argument types in the flag bit string
+ *
+ * We only describe the two argument types we care about:
+ * - Whether or not its a float/double
+ * - Whether or not its a struct
+ *
+ * This is is two bits per argument accounting for the first 16 bits
+ * of cif->flags.
+ *
+ * The last 16 bits are just used to describe the return type
+ *
+ * FFI_FLAG_BITS = 2
+ */
+
+ while (count-- > 0 && arg_reg < 8)
+ {
+ type = (cif->arg_types)[index]->type;
+
+ /* Handle float argument types for soft float case */
+ if (soft_float || (isvariadic && arg_reg >= nfixedargs))
+ {
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ type = FFI_TYPE_UINT32;
+ break;
+ case FFI_TYPE_DOUBLE:
+ type = FFI_TYPE_UINT64;
+ break;
+ default:
+ break;
+ }
+ }
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT: /* = 2 = 0b10 */
+ case FFI_TYPE_DOUBLE: /* = 3 = 0b11 */
+ cif->flags += ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS));
+ arg_reg++;
+ break;
+ case FFI_TYPE_STRUCT:
+ loc = arg_reg * FFI_SIZEOF_ARG;
+ cif->flags += calc_riscv_struct_flags(soft_float, (cif->arg_types)[index], (cif->arg_types)[index]->size, &loc, &arg_reg);
+ break;
+ default:
+ arg_reg++;
+ break;
+ }
+ index++;
+ }
+
+ /* Set the return type flag */
+
+ type = cif->rtype->type;
+
+ /* Handle float return types for soft float case */
+ if (soft_float)
+ {
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ type = FFI_TYPE_UINT32;
+ break;
+ case FFI_TYPE_DOUBLE:
+ type = FFI_TYPE_UINT64;
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (type)
+ {
+ case FFI_TYPE_STRUCT:
+ if (struct_flags != 0)
+ {
+ /* The structure is returned via some tricky mechanism */
+ cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
+ cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8));
+ }
+ /* else the structure is returned through a hidden
+ first argument. Do nothing, 'cause FFI_TYPE_VOID is 0 */
+ break;
+ case FFI_TYPE_VOID:
+ /* Do nothing, 'cause FFI_TYPE_VOID is 0 */
+ break;
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
+ break;
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8);
+ break;
+ default:
+ cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
+ break;
+ }
+}
+
+/* Count how big our argspace is in bytes. Here, we always
+ allocate at least 8 pointer words and handle big structs
+ being passed in registers. */
+
+void ffi_prep_cif_machdep_bytes(ffi_cif *cif)
+{
+ int i;
+ ffi_type **ptr;
+ unsigned bytes = 0, extra_bytes = 0;
+
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ bytes = STACK_ARG_SIZE(sizeof(void*));
+
+ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+ {
+ /* Add any padding if necessary */
+ if (((*ptr)->alignment - 1) & bytes)
+ bytes = (unsigned)ALIGN(bytes, (*ptr)->alignment);
+
+ /* When we pass big structs in registers, we copy it onto the stack and assign a pointer to it */
+ if ((*ptr)->size > 2 * FFI_SIZEOF_ARG && bytes < 8 * FFI_SIZEOF_ARG)
+ {
+ bytes += sizeof(void*);
+ extra_bytes += STACK_ARG_SIZE((*ptr)->size);
+ }
+ else
+ {
+ bytes += STACK_ARG_SIZE((*ptr)->size);
+ }
+ }
+
+ if (bytes < 8 * FFI_SIZEOF_ARG)
+ bytes = 8 * FFI_SIZEOF_ARG;
+
+ bytes += extra_bytes;
+
+ cif->bytes = bytes;
+}
+
+/* Perform machine dependent cif processing */
+
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ ffi_prep_cif_machdep_bytes(cif);
+ ffi_prep_cif_machdep_flags(cif, 0, 0);
+ cif->isvariadic = 0;
+ return FFI_OK;
+}
+
+/* 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)
+{
+ ffi_prep_cif_machdep_bytes(cif);
+ ffi_prep_cif_machdep_flags(cif, 1, nfixedargs);
+ cif->isvariadic = 1;
+ return FFI_OK;
+}
+
+/* Low level routine for calling RV64 functions */
+extern int ffi_call_asm(void (*)(char *, extended_cif *, int, int),
+ extended_cif *, unsigned, unsigned,
+ unsigned *, void (*)(void))
+ __attribute__((visibility("hidden")));
+
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ extended_cif ecif;
+
+ 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) && (cif->rtype->type == FFI_TYPE_STRUCT))
+ ecif.rvalue = alloca(cif->rtype->size);
+ else
+ ecif.rvalue = rvalue;
+
+ ffi_call_asm(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn);
+}
+
+#if FFI_CLOSURES
+
+extern void ffi_closure_asm(void) __attribute__((visibility("hidden")));
+
+ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void *codeloc)
+{
+ unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+
+ uintptr_t fn = (uintptr_t) ffi_closure_asm;
+ FFI_ASSERT(tramp == codeloc);
+
+ /* Remove when more than just rv64 is supported */
+ if (cif->abi != FFI_RV64)
+ return FFI_BAD_ABI;
+
+ if (cif->abi == FFI_RV32 || cif->abi == FFI_RV32_SOFT_FLOAT || fn < 0x7ffff000U)
+ {
+ /* auipc t0, 0 (i.e. t0 <- codeloc) */
+ tramp[0] = 0x00000297;
+ /* lui t1, %hi(fn) */
+ tramp[1] = 0x00000337 | ((fn + 0x800) & 0xFFFFF000);
+ /* jalr x0, t1, %lo(fn) */
+ tramp[2] = 0x00030067 | ((fn & 0xFFF) << 20);
+ /* nops */
+ tramp[3] = 0x00000013;
+ tramp[4] = 0x00000013;
+ tramp[5] = 0x00000013;
+ }
+ else
+ {
+ /* auipc t0, 0 (i.e. t0 <- codeloc) */
+ tramp[0] = 0x00000297;
+ /* ld t1, 16(t0) */
+ tramp[1] = 0x0102b303;
+ /* jalr x0, t1, %lo(fn) */
+ tramp[2] = 0x00030067;
+ /* nop */
+ tramp[3] = 0x00000013;
+ /* fn */
+ tramp[4] = fn;
+ tramp[5] = fn >> 32;
+ }
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+ __builtin___clear_cache(codeloc, codeloc + FFI_TRAMPOLINE_SIZE);
+
+ return FFI_OK;
+}
+
+static void copy_struct(char *target, unsigned offset, ffi_abi abi, ffi_type *type, int argn, unsigned arg_offset, ffi_arg *ar, ffi_arg *fpr, int soft_float)
+{
+ ffi_type **elt_typep = type->elements;
+
+ while(*elt_typep)
+ {
+ ffi_type *elt_type = *elt_typep;
+ unsigned o;
+ char *tp;
+ char *argp;
+ char *fpp;
+
+ o = ALIGN(offset, elt_type->alignment);
+ arg_offset += o - offset;
+ offset = o;
+ argn += arg_offset / sizeof(ffi_arg);
+ arg_offset = arg_offset % sizeof(ffi_arg);
+ argp = (char *)(ar + argn);
+ fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn);
+ tp = target + offset;
+
+ if (elt_type->type == FFI_TYPE_DOUBLE && !soft_float)
+ *(double *)tp = *(double *)fpp;
+ else
+ memcpy(tp, argp + arg_offset, elt_type->size);
+
+ offset += elt_type->size;
+ arg_offset += elt_type->size;
+ elt_typep++;
+ argn += arg_offset / sizeof(ffi_arg);
+ arg_offset = arg_offset % sizeof(ffi_arg);
+ }
+}
+
+/*
+* Decodes the arguments to a function, which will be stored on the
+* stack. AR is the pointer to the beginning of the integer
+* arguments. FPR is a pointer to the area where floating point
+* registers have been saved.
+*
+* RVALUE is the location where the function return value will be
+* stored. CLOSURE is the prepared closure to invoke.
+*
+* This function should only be called from assembly, which is in
+* turn called from a trampoline.
+*
+* Returns the function return flags.
+*
+*/
+int ffi_closure_riscv_inner(ffi_closure *closure, void *rvalue, ffi_arg *ar, ffi_arg *fpr)
+{
+ ffi_cif *cif;
+ void **avaluep;
+ ffi_arg *avalue;
+ ffi_type **arg_types;
+ int i, avn, argn;
+ int soft_float;
+ ffi_arg *argp;
+ size_t z;
+
+ cif = closure->cif;
+ soft_float = cif->abi == FFI_RV64_SOFT_FLOAT || cif->abi == FFI_RV32_SOFT_FLOAT;
+ avalue = alloca(cif->nargs * sizeof (ffi_arg));
+ avaluep = alloca(cif->nargs * sizeof (ffi_arg));
+ argn = 0;
+
+ if (cif->rstruct_flag)
+ {
+ rvalue = (void *)ar[0];
+ argn = 1;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ while (i < avn)
+ {
+ z = arg_types[i]->size;
+ if (arg_types[i]->type == FFI_TYPE_FLOAT || arg_types[i]->type == FFI_TYPE_DOUBLE || arg_types[i]->type == FFI_TYPE_LONGDOUBLE)
+ {
+ argp = (argn >= 8 || cif->isvariadic || soft_float) ? ar + argn : fpr + argn;
+ if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((uintptr_t)argp & (arg_types[i]->alignment-1)))
+ {
+ argp = (ffi_arg*)ALIGN(argp, arg_types[i]->alignment);
+ argn++;
+ }
+ avaluep[i] = (char *) argp;
+ }
+ else
+ {
+ unsigned type = arg_types[i]->type;
+
+ if (arg_types[i]->alignment > sizeof(ffi_arg))
+ argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
+
+ argp = ar + argn;
+
+ /* The size of a pointer depends on the ABI */
+ if (type == FFI_TYPE_POINTER)
+ type = (cif->abi == FFI_RV64 || cif->abi == FFI_RV64_SOFT_FLOAT) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+ if (soft_float && type == FFI_TYPE_FLOAT)
+ type = FFI_TYPE_UINT32;
+
+ switch (type)
+ {
+ case FFI_TYPE_SINT8:
+ avaluep[i] = &avalue[i];
+ *(SINT8 *) &avalue[i] = (SINT8) *argp;
+ break;
+
+ case FFI_TYPE_UINT8:
+ avaluep[i] = &avalue[i];
+ *(UINT8 *) &avalue[i] = (UINT8) *argp;
+ break;
+
+ case FFI_TYPE_SINT16:
+ avaluep[i] = &avalue[i];
+ *(SINT16 *) &avalue[i] = (SINT16) *argp;
+ break;
+
+ case FFI_TYPE_UINT16:
+ avaluep[i] = &avalue[i];
+ *(UINT16 *) &avalue[i] = (UINT16) *argp;
+ break;
+
+ case FFI_TYPE_SINT32:
+ avaluep[i] = &avalue[i];
+ *(SINT32 *) &avalue[i] = (SINT32) *argp;
+ break;
+
+ case FFI_TYPE_UINT32:
+ avaluep[i] = &avalue[i];
+ *(UINT32 *) &avalue[i] = (UINT32) *argp;
+ break;
+
+ case FFI_TYPE_SINT64:
+ avaluep[i] = &avalue[i];
+ *(SINT64 *) &avalue[i] = (SINT64) *argp;
+ break;
+
+ case FFI_TYPE_UINT64:
+ avaluep[i] = &avalue[i];
+ *(UINT64 *) &avalue[i] = (UINT64) *argp;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ if (argn < 8 && arg_types[i]->size <= 2*sizeof(ffi_arg))
+ {
+ /* Allocate space to copy structs that were passed in registers */
+ avaluep[i] = alloca(arg_types[i]->size);
+ copy_struct(avaluep[i], 0, cif->abi, arg_types[i], argn, 0, ar, fpr, soft_float);
+ break;
+ }
+ else
+ {
+ /* The struct was too big to be passed in registers, so it was passed on the stack
+ with pointers in the registers. We need to properly pass the pointer AND set
+ the correct size to increment by! */
+ avaluep[i] = (void *) *argp;
+ z = 1;
+ break;
+ }
+
+ /* Else fall through. */
+ default:
+ avaluep[i] = (char *) argp;
+ break;
+ }
+ }
+ argn += ALIGN(z, sizeof(ffi_arg)) / sizeof(ffi_arg);
+ i++;
+ }
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rvalue, avaluep, closure->user_data);
+ return cif->flags >> (FFI_FLAG_BITS * 8);
+}
+
+#endif /* FFI_CLOSURES */
Index: libffi-3.2.1/src/riscv/ffitarget.h
===================================================================
--- /dev/null
+++ libffi-3.2.1/src/riscv/ffitarget.h
@@ -0,0 +1,120 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - 2014 Michael Knyszek
+
+ Target configuration macros for RISC-V.
+
+ 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
+
+#if defined(__riscv) && __riscv_xlen != 64
+# error We currently only support RV64.
+#endif
+
+#ifdef __LP64__
+# define FFI_SIZEOF_ARG 8
+#else
+# define FFI_SIZEOF_ARG 4
+#endif
+
+#define FFI_FLAG_BITS 2
+
+#ifndef LIBFFI_ASM
+
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_RV32,
+ FFI_RV32_SOFT_FLOAT,
+ FFI_RV64,
+ FFI_RV64_SOFT_FLOAT,
+ FFI_LAST_ABI,
+
+#if defined(__riscv) && __riscv_xlen == 64
+ #ifdef __riscv_soft_float
+ FFI_DEFAULT_ABI = FFI_RV64_SOFT_FLOAT
+ #else
+ FFI_DEFAULT_ABI = FFI_RV64
+ #endif
+#else
+ #ifdef __riscv_soft_float
+ FFI_DEFAULT_ABI = FFI_RV32_SOFT_FLOAT
+ #else
+ FFI_DEFAULT_ABI = FFI_RV32
+ #endif
+#endif /* __riscv_soft_float */
+} ffi_abi;
+
+#else
+
+#if defined(__riscv) && __riscv_xlen == 64
+ #define REG_S sd
+ #define REG_L ld
+#else
+ #define REG_S sw
+ #define REG_L lw
+#endif
+
+#endif /* LIBFFI_ASM */
+
+#define FFI_ARGS_D FFI_TYPE_DOUBLE
+#define FFI_ARGS_F FFI_TYPE_FLOAT
+#define FFI_ARGS_DD ((FFI_TYPE_DOUBLE << FFI_FLAG_BITS) + FFI_TYPE_DOUBLE)
+#define FFI_ARGS_FF ((FFI_TYPE_FLOAT << FFI_FLAG_BITS) + FFI_TYPE_FLOAT)
+#define FFI_ARGS_FD ((FFI_TYPE_DOUBLE << FFI_FLAG_BITS) + FFI_TYPE_FLOAT)
+#define FFI_ARGS_DF ((FFI_TYPE_FLOAT << FFI_FLAG_BITS) + FFI_TYPE_DOUBLE)
+#define FFI_TYPE_SMALLSTRUCT FFI_TYPE_UINT8
+#define FFI_TYPE_SMALLSTRUCT2 FFI_TYPE_SINT8
+#define FFI_TYPE_STRUCT_D (FFI_TYPE_STRUCT + (FFI_ARGS_D << 4))
+#define FFI_TYPE_STRUCT_F (FFI_TYPE_STRUCT + (FFI_ARGS_F << 4))
+#define FFI_TYPE_STRUCT_DD (FFI_TYPE_STRUCT + (FFI_ARGS_DD << 4))
+#define FFI_TYPE_STRUCT_FF (FFI_TYPE_STRUCT + (FFI_ARGS_FF << 4))
+#define FFI_TYPE_STRUCT_FD (FFI_TYPE_STRUCT + (FFI_ARGS_FD << 4))
+#define FFI_TYPE_STRUCT_DF (FFI_TYPE_STRUCT + (FFI_ARGS_DF << 4))
+#define FFI_TYPE_STRUCT_SMALL (FFI_TYPE_STRUCT + (5 << 4))
+#define FFI_TYPE_STRUCT_SMALL2 (FFI_TYPE_STRUCT + (6 << 4))
+#define FFI_TYPE_STRUCT_D_SOFT (FFI_TYPE_STRUCT_D + 256)
+#define FFI_TYPE_STRUCT_F_SOFT (FFI_TYPE_STRUCT_F + 256)
+#define FFI_TYPE_STRUCT_DD_SOFT (FFI_TYPE_STRUCT_DD + 256)
+#define FFI_TYPE_STRUCT_FF_SOFT (FFI_TYPE_STRUCT_FF + 256)
+#define FFI_TYPE_STRUCT_FD_SOFT (FFI_TYPE_STRUCT_FD + 256)
+#define FFI_TYPE_STRUCT_DF_SOFT (FFI_TYPE_STRUCT_DF + 256)
+#define FFI_TYPE_STRUCT_SOFT 16
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag; char isvariadic
+#define FFI_TARGET_SPECIFIC_VARIADIC 1
+
+#endif
+
Index: libffi-3.2.1/src/riscv/sysv.S
===================================================================
--- /dev/null
+++ libffi-3.2.1/src/riscv/sysv.S
@@ -0,0 +1,782 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
+ 2015 Andrew Waterman <waterman@cs.berkeley.edu>
+ Based on MIPS N32/64 port
+
+ RISC-V 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 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.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+#define callback a0
+#define ecif a1
+#define bytes a2
+#define flags a3
+#define rvalue a4
+#define fn a5
+#define fp s0
+
+#define FFI_SIZEOF_ARG_X0 (0 * FFI_SIZEOF_ARG)
+#define FFI_SIZEOF_ARG_X1 (1 * FFI_SIZEOF_ARG)
+#define FFI_SIZEOF_ARG_X2 (2 * FFI_SIZEOF_ARG)
+#define FFI_SIZEOF_ARG_X3 (3 * FFI_SIZEOF_ARG)
+#define FFI_SIZEOF_ARG_X4 (4 * FFI_SIZEOF_ARG)
+#define FFI_SIZEOF_ARG_X5 (5 * FFI_SIZEOF_ARG)
+#define FFI_SIZEOF_ARG_X6 (6 * FFI_SIZEOF_ARG)
+#define FFI_SIZEOF_ARG_X7 (7 * FFI_SIZEOF_ARG)
+#define FFI_SIZEOF_ARG_X8 (8 * FFI_SIZEOF_ARG)
+
+#define ARG_MASK 65535
+
+#define FFI_FLAG_BITS_X0 (0 * FFI_FLAG_BITS)
+#define FFI_FLAG_BITS_X1 (1 * FFI_FLAG_BITS)
+#define FFI_FLAG_BITS_X2 (2 * FFI_FLAG_BITS)
+#define FFI_FLAG_BITS_X3 (3 * FFI_FLAG_BITS)
+#define FFI_FLAG_BITS_X4 (4 * FFI_FLAG_BITS)
+#define FFI_FLAG_BITS_X5 (5 * FFI_FLAG_BITS)
+#define FFI_FLAG_BITS_X6 (6 * FFI_FLAG_BITS)
+#define FFI_FLAG_BITS_X7 (7 * FFI_FLAG_BITS)
+
+# Stack pointer needs to be 16-byte aligned, so frame size is rounded up
+#define SIZEOF_FRAME (6 * FFI_SIZEOF_ARG)
+
+ .text
+ .align 2
+ .globl ffi_call_asm
+ .type ffi_call_asm, @function
+ffi_call_asm:
+ .cfi_startproc
+
+ ### Prologue
+
+ # a0 - ffi_prep_args pointer
+ # a1 - extended_cif pointer
+ # a2 - bytes
+ # a3 - flags
+ # a4 - rvalue
+ # a5 - function ptr
+
+ add sp, sp, -SIZEOF_FRAME # move stack pointer by frame size
+ # must be 16-byte aligned
+
+ # stack ptr points to first argument on stack,
+ # but there should be no arguments on the stack
+
+ .cfi_def_cfa_offset SIZEOF_FRAME
+
+ REG_S ra, FFI_SIZEOF_ARG_X5(sp) # save return address
+ REG_S fp, FFI_SIZEOF_ARG_X4(sp) # save frame pointer
+ REG_S flags, FFI_SIZEOF_ARG_X3(sp) # save flags
+ REG_S fn, FFI_SIZEOF_ARG_X2(sp) # save function pointer
+ REG_S rvalue, FFI_SIZEOF_ARG_X1(sp) # save return value pointer
+
+ .cfi_offset 1, -8
+ .cfi_offset 8, -16
+
+ add fp, sp, SIZEOF_FRAME # new frame pointer is old stack pointer
+
+ .cfi_def_cfa 8, 0
+
+ add t4, callback, zero # function ptr to prep_args
+
+ # Here we're setting up our argspace and its size
+
+ add t0, bytes, 15 # make sure it is aligned
+ andi t0, t0, -16 # to a 16 byte boundry
+
+thirtytwo:
+ sub sp, sp, t0 # move the stack pointer to reflect the arg space
+
+ # a0 is the stack with proper arg space allocated
+ add a0, sp, zero
+
+ # a1 is ecif
+ # a2 is bytes
+ # a3 is flags
+
+ jalr t4 # call ffi_prep_args
+
+ REG_L t0, -FFI_SIZEOF_ARG_X3(fp) # load the flags word
+ srli t2, t0, 16 # shift our return type into t2
+
+ li t1, ARG_MASK
+ and t0, t0, t1 # mask out the arg types into t0
+
+ # time to load the arguments for the call
+
+#ifndef __riscv_soft_float
+
+####################
+## SET ARGUMENT 0 ##
+####################
+
+set_arg0:
+ srli t1, t0, FFI_FLAG_BITS_X0 # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg0_float
+ REG_L a0, FFI_SIZEOF_ARG_X0(sp) # load argument
+ j set_arg1
+
+set_arg0_float:
+ addi t1, t1, -2
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg0_double
+ flw fa0, FFI_SIZEOF_ARG_X0(sp) # load argument
+ j set_arg1
+
+set_arg0_double:
+ # otherwise it must be a double we're dealing with
+ fld fa0, FFI_SIZEOF_ARG_X0(sp)
+
+####################
+## SET ARGUMENT 1 ##
+####################
+
+set_arg1:
+ srli t1, t0, FFI_FLAG_BITS_X1 # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg1_float
+ REG_L a1, FFI_SIZEOF_ARG_X1(sp) # load argument
+ j set_arg2
+
+set_arg1_float:
+ addi t1, t1, -2
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg1_double
+ flw fa1, FFI_SIZEOF_ARG_X1(sp) # load argument
+ j set_arg2
+
+set_arg1_double:
+ # otherwise it must be a double we're dealing with
+ fld fa1, FFI_SIZEOF_ARG_X1(sp)
+
+####################
+## SET ARGUMENT 2 ##
+####################
+
+set_arg2:
+ srli t1, t0, FFI_FLAG_BITS_X2 # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg2_float
+ REG_L a2, FFI_SIZEOF_ARG_X2(sp) # load argument
+ j set_arg3
+
+set_arg2_float:
+ addi t1, t1, -2
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg2_double
+ flw fa2, FFI_SIZEOF_ARG_X2(sp) # load argument
+ j set_arg3
+
+set_arg2_double:
+ # otherwise it must be a double we're dealing with
+ fld fa2, FFI_SIZEOF_ARG_X2(sp)
+
+####################
+## SET ARGUMENT 3 ##
+####################
+
+set_arg3:
+ srli t1, t0, FFI_FLAG_BITS_X3 # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg3_float
+ REG_L a3, FFI_SIZEOF_ARG_X3(sp) # load argument
+ j set_arg4
+
+set_arg3_float:
+ addi t1, t1, -2
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg3_double
+ flw fa3, FFI_SIZEOF_ARG_X3(sp) # load argument
+ j set_arg4
+
+set_arg3_double:
+ # otherwise it must be a double we're dealing with
+ fld fa3, FFI_SIZEOF_ARG_X3(sp)
+
+####################
+## SET ARGUMENT 4 ##
+####################
+
+set_arg4:
+ srli t1, t0, FFI_FLAG_BITS_X4 # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg4_float
+ REG_L a4, FFI_SIZEOF_ARG_X4(sp) # load argument
+ j set_arg5
+
+set_arg4_float:
+ addi t1, t1, -2
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg4_double
+ flw fa4, FFI_SIZEOF_ARG_X4(sp) # load argument
+ j set_arg5
+
+set_arg4_double:
+ # otherwise it must be a double we're dealing with
+ fld fa4, FFI_SIZEOF_ARG_X4(sp)
+
+####################
+## SET ARGUMENT 5 ##
+####################
+
+set_arg5:
+ srli t1, t0, FFI_FLAG_BITS_X5 # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg5_float
+ REG_L a5, FFI_SIZEOF_ARG_X5(sp) # load argument
+ j set_arg6
+
+set_arg5_float:
+ addi t1, t1, -2
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg5_double
+ flw fa5, FFI_SIZEOF_ARG_X5(sp) # load argument
+ j set_arg6
+
+set_arg5_double:
+ # otherwise it must be a double we're dealing with
+ fld fa5, FFI_SIZEOF_ARG_X5(sp)
+
+####################
+## SET ARGUMENT 6 ##
+####################
+
+set_arg6:
+ srli t1, t0, FFI_FLAG_BITS_X6 # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg6_float
+ REG_L a6, FFI_SIZEOF_ARG_X6(sp) # load argument
+ j set_arg7
+
+set_arg6_float:
+ addi t1, t1, -2
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg6_double
+ flw fa6, FFI_SIZEOF_ARG_X6(sp) # load argument
+ j set_arg7
+
+set_arg6_double:
+ # otherwise it must be a double we're dealing with
+ fld fa6, FFI_SIZEOF_ARG_X6(sp)
+
+####################
+## SET ARGUMENT 7 ##
+####################
+
+set_arg7:
+ srli t1, t0, FFI_FLAG_BITS_X7 # Shift to get the bits for this argument
+ andi t1, t1, 3 # Mask out the bits for this argument
+
+ # when its zero, it means its just a word-sized int/ptr
+ bne t1, zero, set_arg7_float
+ REG_L a7, FFI_SIZEOF_ARG_X7(sp) # load argument
+ j call_it
+
+set_arg7_float:
+ addi t1, t1, -2
+
+ # when its zero, it means its just a word-sized float
+ bne t1, zero, set_arg7_double
+ flw fa7, FFI_SIZEOF_ARG_X7(sp) # load argument
+ j call_it
+
+set_arg7_double:
+ # otherwise it must be a double we're dealing with
+ fld fa7, FFI_SIZEOF_ARG_X7(sp)
+
+#else
+
+## START RISCV SOFT-FLOAT LOADING ##
+
+ # In the soft-float case, we have no primitive datatype
+ # that has a size of >8 bytes. Therefore, we can
+ # just load everything quite easily and nicely.
+
+ REG_L a0, FFI_SIZEOF_ARG_X0(sp) # load argument
+ REG_L a1, FFI_SIZEOF_ARG_X1(sp) # load argument
+ REG_L a2, FFI_SIZEOF_ARG_X2(sp) # load argument
+ REG_L a3, FFI_SIZEOF_ARG_X3(sp) # load argument
+ REG_L a4, FFI_SIZEOF_ARG_X4(sp) # load argument
+ REG_L a5, FFI_SIZEOF_ARG_X5(sp) # load argument
+ REG_L a6, FFI_SIZEOF_ARG_X6(sp) # load argument
+ REG_L a7, FFI_SIZEOF_ARG_X7(sp) # load argument
+
+#endif
+
+call_it:
+ # First, we fix the stack pointer to point to the first argument
+ # passed on the stack.
+ add sp, sp, FFI_SIZEOF_ARG_X8
+
+ # Load the function pointer
+ REG_L t4, -FFI_SIZEOF_ARG_X4(fp)
+
+ # When the return value pointer is NULL, assume no return value.
+ REG_L t1, -FFI_SIZEOF_ARG_X5(fp)
+ beq t1, zero, return_void
+
+ # is the return type an int? if not, jump ahead
+ ori t3, zero, FFI_TYPE_INT
+ bne t2, t3, return_int32
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ REG_S a0, 0(t0)
+ j epilogue
+
+return_int32:
+ ori t3, zero, FFI_TYPE_SINT32
+#ifndef __riscv_soft_float
+ bne t2, t3, return_float
+#else
+ bne t2, t3, return_struct_d_soft
+#endif
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ sw a0, 0(t0)
+ j epilogue
+
+#ifndef __riscv_soft_float
+return_float:
+ # is the return type a float? if not, jump ahead
+ ori t3, zero, FFI_TYPE_FLOAT
+ bne t2, t3, return_double
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ fsw fa0, FFI_SIZEOF_ARG_X0(t0)
+ j epilogue
+
+return_double:
+ # is the return type a double? if not, give up
+ ori t3, zero, FFI_TYPE_DOUBLE
+ bne t2, t3, return_struct_d
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ fsd fa0, FFI_SIZEOF_ARG_X0(t0)
+ j epilogue
+
+### Handle struct special cases (hard float)
+
+ # Here the struct to return is less than
+ # or equal to 2 pointer-words in size. We
+ # need to specifically handle the floats/doubles.
+
+return_struct_d:
+ # is the return type a struct with a double? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_D
+ bne t2, t3, return_struct_f
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ fsd fa0, FFI_SIZEOF_ARG_X0(t0)
+ j epilogue
+
+return_struct_f:
+ # is the return type a struct with a float? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_F
+ bne t2, t3, return_struct_d_d
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ fsw fa0, FFI_SIZEOF_ARG_X0(t0)
+ j epilogue
+
+return_struct_d_d:
+ # is the return type a struct with two doubles? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_DD
+ bne t2, t3, return_struct_f_f
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ fsd fa0, FFI_SIZEOF_ARG_X0(t0)
+ fsd fa1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+return_struct_f_f:
+ # is the return type a struct with two floats? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_FF
+ bne t2, t3, return_struct_d_f
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ fsw fa0, FFI_SIZEOF_ARG_X0(t0)
+ fsw fa1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+return_struct_d_f:
+ # is the return type a struct with a double then float? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_DF
+ bne t2, t3, return_struct_f_d
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ fsd fa0, FFI_SIZEOF_ARG_X0(t0)
+ fsw fa1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+return_struct_f_d:
+ # is the return type a struct with a float then double? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_FD
+ bne t2, t3, return_struct_small
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ fsw fa0, FFI_SIZEOF_ARG_X0(t0)
+ fsd fa1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+#else
+
+### Handle struct special cases (soft float)
+
+ # Here the struct to return is less than
+ # or equal to 2 pointer-words in size. We
+ # need to specifically handle the floats/doubles.
+
+return_struct_d_soft:
+ # is the return type a struct with a double? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_D_SOFT
+ bne t2, t3, return_struct_f_soft
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ sd a0, FFI_SIZEOF_ARG_X0(t0)
+ j epilogue
+
+return_struct_f_soft:
+ # is the return type a struct with a float? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_F_SOFT
+ bne t2, t3, return_struct_d_d_soft
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ sw a0, FFI_SIZEOF_ARG_X0(t0)
+ j epilogue
+
+return_struct_d_d_soft:
+ # is the return type a struct with two doubles? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_DD_SOFT
+ bne t2, t3, return_struct_f_f_soft
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ sd a0, FFI_SIZEOF_ARG_X0(t0)
+ sd a1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+return_struct_f_f_soft:
+ # is the return type a struct with two floats? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_FF_SOFT
+ bne t2, t3, return_struct_d_f_soft
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ sw a0, FFI_SIZEOF_ARG_X0(t0)
+ sw a1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+return_struct_d_f_soft:
+ # is the return type a struct with a double then float? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_DF_SOFT
+ bne t2, t3, return_struct_f_d_soft
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ sd a0, FFI_SIZEOF_ARG_X0(t0)
+ sw a1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+return_struct_f_d_soft:
+ # is the return type a struct with a float then double? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_FD_SOFT
+ bne t2, t3, return_struct_small
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ sw a0, FFI_SIZEOF_ARG_X0(t0)
+ sd a1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+#endif
+
+### Handle struct special cases (tiny structs)
+
+return_struct_small:
+ # is the return type a struct with a float then double? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_SMALL
+ bne t2, t3, return_struct_small2
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ REG_S a0, FFI_SIZEOF_ARG_X0(t0)
+ j epilogue
+
+return_struct_small2:
+ # is the return type a struct with a float then double? if not, give up
+ ori t3, zero, FFI_TYPE_STRUCT_SMALL2
+ bne t2, t3, return_struct
+
+ jalr t4 # call the function
+
+ # We reload the return pointer because it was in a temp reg and
+ # there was just a function call.
+ REG_L t0, -FFI_SIZEOF_ARG_X5(fp)
+ REG_S a0, FFI_SIZEOF_ARG_X0(t0)
+ REG_S a1, FFI_SIZEOF_ARG_X1(t0)
+ j epilogue
+
+### Any other struct is returned through memory
+return_struct:
+return_void:
+ jalr t4 # call the function
+
+epilogue:
+ add sp, fp, zero # Fix stack pointer
+ REG_L fp, -FFI_SIZEOF_ARG_X2(sp) # Restore frame pointer
+ REG_L ra, -FFI_SIZEOF_ARG_X1(sp) # Restore return address
+ jr ra
+
+ .cfi_endproc
+ .size ffi_call_asm, .-ffi_call_asm
+
+
+/* ffi_closure_asm. Expects address of the passed-in ffi_closure in t0. */
+
+#define SIZEOF_FRAME2 (20 * FFI_SIZEOF_ARG)
+#define A7_OFF2 (19 * FFI_SIZEOF_ARG)
+#define A6_OFF2 (18 * FFI_SIZEOF_ARG)
+#define A5_OFF2 (17 * FFI_SIZEOF_ARG)
+#define A4_OFF2 (16 * FFI_SIZEOF_ARG)
+#define A3_OFF2 (15 * FFI_SIZEOF_ARG)
+#define A2_OFF2 (14 * FFI_SIZEOF_ARG)
+#define A1_OFF2 (13 * FFI_SIZEOF_ARG)
+#define A0_OFF2 (12 * FFI_SIZEOF_ARG)
+#define FA7_OFF2 (11 * FFI_SIZEOF_ARG)
+#define FA6_OFF2 (10 * FFI_SIZEOF_ARG)
+#define FA5_OFF2 ( 9 * FFI_SIZEOF_ARG)
+#define FA4_OFF2 ( 8 * FFI_SIZEOF_ARG)
+#define FA3_OFF2 ( 7 * FFI_SIZEOF_ARG)
+#define FA2_OFF2 ( 6 * FFI_SIZEOF_ARG)
+#define FA1_OFF2 ( 5 * FFI_SIZEOF_ARG)
+#define FA0_OFF2 ( 4 * FFI_SIZEOF_ARG)
+#define V1_OFF2 ( 3 * FFI_SIZEOF_ARG)
+#define V0_OFF2 ( 2 * FFI_SIZEOF_ARG)
+#define RA_OFF2 ( 1 * FFI_SIZEOF_ARG)
+
+ .align 2
+ .globl ffi_closure_asm
+ .type ffi_closure_asm, @function
+ffi_closure_asm:
+ .cfi_startproc
+
+ addi sp, sp, -SIZEOF_FRAME2
+
+ .cfi_def_cfa_offset SIZEOF_FRAME2
+
+ REG_S ra, RA_OFF2(sp) # Save return address
+
+ .cfi_offset 1, -19*FFI_SIZEOF_ARG
+ .cfi_def_cfa 2, SIZEOF_FRAME2
+
+ # Store all possible argument registers. If there are more than
+ # fit in registers, then they were stored on the stack.
+ REG_S a0, A0_OFF2(sp)
+ REG_S a1, A1_OFF2(sp)
+ REG_S a2, A2_OFF2(sp)
+ REG_S a3, A3_OFF2(sp)
+ REG_S a4, A4_OFF2(sp)
+ REG_S a5, A5_OFF2(sp)
+ REG_S a6, A6_OFF2(sp)
+ REG_S a7, A7_OFF2(sp)
+
+ # Store all possible float/double registers.
+ fsd fa0, FA0_OFF2(sp)
+ fsd fa1, FA1_OFF2(sp)
+ fsd fa2, FA2_OFF2(sp)
+ fsd fa3, FA3_OFF2(sp)
+ fsd fa4, FA4_OFF2(sp)
+ fsd fa5, FA5_OFF2(sp)
+ fsd fa6, FA6_OFF2(sp)
+ fsd fa7, FA7_OFF2(sp)
+
+ # Call ffi_closure_riscv_inner to do the real work.
+ move a0, t0 # Pointer to the ffi_closure
+ addi a1, sp, V0_OFF2
+ addi a2, sp, A0_OFF2
+ addi a3, sp, FA0_OFF2
+ call ffi_closure_riscv_inner
+
+ # Return flags are in a0
+ li t0, FFI_TYPE_INT
+ bne a0, t0, cls_retint32
+ REG_L a0, V0_OFF2(sp)
+ j cls_epilogue
+
+cls_retint32:
+ li t0, FFI_TYPE_SINT32
+ bne a0, t0, cls_retfloat
+ lw a0, V0_OFF2(sp)
+ j cls_epilogue
+
+cls_retfloat:
+ li t0, FFI_TYPE_FLOAT
+ bne a0, t0, cls_retdouble
+ flw fa0, V0_OFF2(sp)
+ j cls_epilogue
+
+cls_retdouble:
+ li t0, FFI_TYPE_DOUBLE
+ bne a0, t0, cls_retstruct_d
+ fld fa0, V0_OFF2(sp)
+ j cls_epilogue
+
+cls_retstruct_d:
+ li t0, FFI_TYPE_STRUCT_D
+ bne a0, t0, cls_retstruct_f
+ fld fa0, V0_OFF2(sp)
+ j cls_epilogue
+
+cls_retstruct_f:
+ li t0, FFI_TYPE_STRUCT_F
+ bne a0, t0, cls_retstruct_d_d
+ flw fa0, V0_OFF2(sp)
+ j cls_epilogue
+
+cls_retstruct_d_d:
+ li t0, FFI_TYPE_STRUCT_DD
+ bne a0, t0, cls_retstruct_f_f
+ fld fa0, V0_OFF2(sp)
+ fld fa1, V1_OFF2(sp)
+ j cls_epilogue
+
+cls_retstruct_f_f:
+ li t0, FFI_TYPE_STRUCT_FF
+ bne a0, t0, cls_retstruct_d_f
+ flw fa0, V0_OFF2(sp)
+ flw fa1, V1_OFF2(sp)
+ j cls_epilogue
+
+cls_retstruct_d_f:
+ li t0, FFI_TYPE_STRUCT_DF
+ bne a0, t0, cls_retstruct_f_d
+ fld fa0, V0_OFF2(sp)
+ flw fa1, V1_OFF2(sp)
+ j cls_epilogue
+
+cls_retstruct_f_d:
+ li t0, FFI_TYPE_STRUCT_FD
+ bne a0, t0, cls_retstruct_small2
+ flw fa0, V0_OFF2(sp)
+ fld fa1, V1_OFF2(sp)
+ j cls_epilogue
+
+cls_retstruct_small2:
+ REG_L a0, V0_OFF2(sp)
+ REG_L a1, V1_OFF2(sp)
+
+# Epilogue
+cls_epilogue:
+ REG_L ra, RA_OFF2(sp) # Restore return address
+ addi sp, sp, SIZEOF_FRAME2
+ ret
+
+ .cfi_endproc
+ .size ffi_closure_asm, .-ffi_closure_asm
Index: libffi-3.2.1/testsuite/Makefile.am
===================================================================
--- libffi-3.2.1.orig/testsuite/Makefile.am
+++ libffi-3.2.1/testsuite/Makefile.am
@@ -34,7 +34,7 @@ libffi.call/cls_12byte.c libffi.call/cls
libffi.call/cls_align_longdouble_split2.c libffi.call/return_dbl2.c \
libffi.call/return_fl3.c libffi.call/stret_medium.c \
libffi.call/nested_struct6.c libffi.call/closure_fn3.c \
-libffi.call/float3.c libffi.call/many2.c \
+libffi.call/float3.c libffi.call/many2.c libffi.call/many3.c \
libffi.call/closure_simple.c libffi.call/cls_align_uint16.c \
libffi.call/cls_9byte1.c libffi.call/closure_fn6.c \
libffi.call/cls_double_va.c libffi.call/cls_align_pointer.c \
Index: libffi-3.2.1/testsuite/libffi.call/many3.c
===================================================================
--- /dev/null
+++ libffi-3.2.1/testsuite/libffi.call/many3.c
@@ -0,0 +1,59 @@
+/* Area: ffi_call
+ Purpose: Check return value int, with many arguments
+ Limitations: none.
+ PR: none.
+ Originator: From the original ffitest.c */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+#include <stdlib.h>
+//#include <int.h>
+#include <math.h>
+
+static int ABI_ATTR many(int f1, int f2, int f3, int f4, int f5, int f6, int f7, int f8, int f9, int f10, int f11, int f12, int f13)
+{
+#if 0
+ printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
+ (double) f1, (double) f2, (double) f3, (double) f4, (double) f5,
+ (double) f6, (double) f7, (double) f8, (double) f9, (double) f10,
+ (double) f11, (double) f12, (double) f13);
+#endif
+
+ return f1+f2+f3+f4+f5+f6+f7+f8+f9+f10+f11+f12+f13;
+}
+
+int main (void)
+{
+ ffi_cif cif;
+ ffi_type *args[13];
+ void *values[13];
+ int fa[13];
+ int f, ff;
+ int i;
+
+ for (i = 0; i < 13; i++)
+ {
+ args[i] = &ffi_type_sint;
+ values[i] = &fa[i];
+ fa[i] = (int) i;
+ }
+
+ /* Initialize the cif */
+ CHECK(ffi_prep_cif(&cif, ABI_NUM, 13,
+ &ffi_type_sint, args) == FFI_OK);
+
+ ffi_call(&cif, FFI_FN(many), &f, values);
+
+ ff = many(fa[0], fa[1],
+ fa[2], fa[3],
+ fa[4], fa[5],
+ fa[6], fa[7],
+ fa[8], fa[9],
+ fa[10],fa[11],fa[12]);
+
+ if (f == ff)
+ exit(0);
+ else
+ abort();
+}