mirror of
https://github.com/thead-yocto-mirror/meta-riscv
synced 2026-09-09 18:26:58 +02:00
1984 lines
63 KiB
Diff
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();
|
|
+}
|