summaryrefslogtreecommitdiff
path: root/src/mips
diff options
context:
space:
mode:
authorJames Cowgill <jcowgill@users.noreply.github.com>2018-04-19 01:28:23 +0100
committerAnthony Green <green@moxielogic.com>2018-04-18 20:28:23 -0400
commit159b94e5fd4aa2d88e1b5b389092cefd9472a741 (patch)
treec32e9065a401e971f248da608487198eb501fedd /src/mips
parentf2afda08e85b02888350449dcf39a6c37cfb7bc4 (diff)
downloadlibffi-159b94e5fd4aa2d88e1b5b389092cefd9472a741.tar.gz
Various MIPS Fixes (#425)
* mips: simplify closure #defines This commit should have no visible effect. * mips: add special handling of variadic functions MIPS requires special handling of variadic functions which pass floating point arguments: * In the o32 ABI, all float arguments are passed in integer registers. * In the n32/n64 ABIs, float arguments after the ellipsis are passed in integer registers. Implement this in libffi. To support this in n32/n64 closures, we need to add a new mips_nfixedargs field to ffi_cif which will break the libffi ABI. This fixes the libffi.call/cls_longdouble_va.c test which was failing on 64-bit MIPS. * mips: align argn for all 64-bit types in o32 closure handler Ensure that argn is pre-aligned for all 64-bit argument types (including doubles) and not just integer types. This fixes closures of the form "f(float, double, <some integer args>)". Previously the first integer argument would be read from a2 which is garbage at this point (the float arguments have already "consumed" a0-a3). After this commit, argn is correctly padded between the "float" and "double" arguments so that the first integer argument is read from the stack. Fixes "double f(float,double,int)" test in #371 * mips: do not read from floating point register if returning a struct In the o32 ABI, the pointer passed in a0 used to return structures indirectly is treated as the first argument for argument allocation purposes. This means that it should inhibit floating point registers the same way that other integer arguments do. Fixes "Double f(float,Double,double)" test in #371 * mips: fix pointer cast warnings Fix two pointer cast warnings when compiled on 64-bit mips by casting through uintptr_t. Fixes mips64el part of #404
Diffstat (limited to 'src/mips')
-rw-r--r--src/mips/ffi.c41
-rw-r--r--src/mips/ffitarget.h19
2 files changed, 36 insertions, 24 deletions
diff --git a/src/mips/ffi.c b/src/mips/ffi.c
index aa3e522..057b046 100644
--- a/src/mips/ffi.c
+++ b/src/mips/ffi.c
@@ -29,6 +29,7 @@
#include <ffi.h>
#include <ffi_common.h>
+#include <stdint.h>
#include <stdlib.h>
#ifdef __GNUC__
@@ -322,9 +323,10 @@ calc_n32_return_struct_flags(int soft_float, ffi_type *arg)
#endif
/* Perform machine dependent cif processing */
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+static ffi_status ffi_prep_cif_machdep_int(ffi_cif *cif, unsigned nfixedargs)
{
cif->flags = 0;
+ cif->mips_nfixedargs = nfixedargs;
#ifdef FFI_MIPS_O32
/* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT
@@ -333,7 +335,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32)
{
- if (cif->nargs > 0)
+ if (cif->nargs > 0 && cif->nargs == nfixedargs)
{
switch ((cif->arg_types)[0]->type)
{
@@ -450,7 +452,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
while (count-- > 0 && arg_reg < 8)
{
type = (cif->arg_types)[index]->type;
- if (soft_float)
+
+ // Pass variadic arguments in integer registers even if they're floats
+ if (soft_float || index >= nfixedargs)
{
switch (type)
{
@@ -476,7 +480,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
/* Align it. */
arg_reg = FFI_ALIGN(arg_reg, 2);
/* Treat it as two adjacent doubles. */
- if (soft_float)
+ if (soft_float || index >= nfixedargs)
{
arg_reg += 2;
}
@@ -493,7 +497,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
case FFI_TYPE_STRUCT:
loc = arg_reg * FFI_SIZEOF_ARG;
- cif->flags += calc_n32_struct_flags(soft_float,
+ cif->flags += calc_n32_struct_flags(soft_float || index >= nfixedargs,
(cif->arg_types)[index],
&loc, &arg_reg);
break;
@@ -578,6 +582,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
return FFI_OK;
}
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ return ffi_prep_cif_machdep_int(cif, cif->nargs);
+}
+
+ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
+ unsigned nfixedargs,
+ unsigned ntotalargs MAYBE_UNUSED)
+{
+ return ffi_prep_cif_machdep_int(cif, nfixedargs);
+}
+
/* Low level routine for calling O32 functions */
extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int),
extended_cif *, unsigned,
@@ -801,13 +817,14 @@ ffi_closure_mips_inner_O32 (ffi_cif *cif,
avalue = alloca (cif->nargs * sizeof (ffi_arg));
avaluep = alloca (cif->nargs * sizeof (ffi_arg));
- seen_int = (cif->abi == FFI_O32_SOFT_FLOAT);
+ seen_int = (cif->abi == FFI_O32_SOFT_FLOAT) || (cif->mips_nfixedargs != cif->nargs);
argn = 0;
if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
{
- rvalue = (void *)(UINT32)ar[0];
+ rvalue = (void *)(uintptr_t)ar[0];
argn = 1;
+ seen_int = 1;
}
i = 0;
@@ -816,6 +833,8 @@ ffi_closure_mips_inner_O32 (ffi_cif *cif,
while (i < avn)
{
+ if (arg_types[i]->alignment == 8 && (argn & 0x1))
+ argn++;
if (i < 2 && !seen_int &&
(arg_types[i]->type == FFI_TYPE_FLOAT ||
arg_types[i]->type == FFI_TYPE_DOUBLE ||
@@ -830,8 +849,6 @@ ffi_closure_mips_inner_O32 (ffi_cif *cif,
}
else
{
- if (arg_types[i]->alignment == 8 && (argn & 0x1))
- argn++;
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
@@ -981,8 +998,8 @@ ffi_closure_mips_inner_N32 (ffi_cif *cif,
|| arg_types[i]->type == FFI_TYPE_DOUBLE
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE)
{
- argp = (argn >= 8 || soft_float) ? ar + argn : fpr + argn;
- if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((unsigned)argp & (arg_types[i]->alignment-1)))
+ argp = (argn >= 8 || i >= cif->mips_nfixedargs || 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*)FFI_ALIGN(argp,arg_types[i]->alignment);
argn++;
@@ -1050,7 +1067,7 @@ ffi_closure_mips_inner_N32 (ffi_cif *cif,
it was passed in registers. */
avaluep[i] = alloca(arg_types[i]->size);
copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i],
- argn, 0, ar, fpr, soft_float);
+ argn, 0, ar, fpr, i >= cif->mips_nfixedargs || soft_float);
break;
}
diff --git a/src/mips/ffitarget.h b/src/mips/ffitarget.h
index 9715890..fffdb97 100644
--- a/src/mips/ffitarget.h
+++ b/src/mips/ffitarget.h
@@ -224,26 +224,21 @@ typedef enum ffi_abi {
#endif
} ffi_abi;
-#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag
+#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag; unsigned mips_nfixedargs
+#define FFI_TARGET_SPECIFIC_VARIADIC
#endif /* !LIBFFI_ASM */
/* ---- Definitions for closures ----------------------------------------- */
-#if defined(FFI_MIPS_O32)
#define FFI_CLOSURES 1
#define FFI_GO_CLOSURES 1
-#define FFI_TRAMPOLINE_SIZE 20
-#else
-/* N32/N64. */
-# define FFI_CLOSURES 1
-#define FFI_GO_CLOSURES 1
-#if _MIPS_SIM==_ABI64
-#define FFI_TRAMPOLINE_SIZE 56
+#define FFI_NATIVE_RAW_API 0
+
+#if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32)
+# define FFI_TRAMPOLINE_SIZE 20
#else
-#define FFI_TRAMPOLINE_SIZE 20
+# define FFI_TRAMPOLINE_SIZE 56
#endif
-#endif /* FFI_MIPS_O32 */
-#define FFI_NATIVE_RAW_API 0
#endif