summaryrefslogtreecommitdiff
path: root/src/sparc
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2014-10-26 13:16:03 -0700
committerRichard Henderson <rth@twiddle.net>2014-11-12 09:36:09 +0100
commitad89c2d9e93d5a713ae4113567b4ca6c4fbbf17c (patch)
treef1108e5d2f19d3685eb0df39c1cb845adf134488 /src/sparc
parent20da5b41324de524ea3ee1f84f402828b7c332dc (diff)
downloadlibffi-ad89c2d9e93d5a713ae4113567b4ca6c4fbbf17c.tar.gz
sparc: Add support for complex types
Diffstat (limited to 'src/sparc')
-rw-r--r--src/sparc/ffi.c92
-rw-r--r--src/sparc/ffi64.c48
-rw-r--r--src/sparc/ffitarget.h1
-rw-r--r--src/sparc/internal.h10
-rw-r--r--src/sparc/v8.S120
-rw-r--r--src/sparc/v9.S8
6 files changed, 216 insertions, 63 deletions
diff --git a/src/sparc/ffi.c b/src/sparc/ffi.c
index 1b8f48e..d319c03 100644
--- a/src/sparc/ffi.c
+++ b/src/sparc/ffi.c
@@ -90,6 +90,40 @@ ffi_prep_cif_machdep(ffi_cif *cif)
case FFI_TYPE_UINT64:
flags = SPARC_RET_INT64;
break;
+ case FFI_TYPE_COMPLEX:
+ rtt = rtype->elements[0]->type;
+ switch (rtt)
+ {
+ case FFI_TYPE_FLOAT:
+ flags = SPARC_RET_F_2;
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = SPARC_RET_F_4;
+ break;
+ case FFI_TYPE_LONGDOUBLE:
+ flags = SPARC_RET_F_8;
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ flags = SPARC_RET_INT128;
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ flags = SPARC_RET_INT64;
+ break;
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ flags = SP_V8_RET_CPLX16;
+ break;
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ flags = SP_V8_RET_CPLX8;
+ break;
+ default:
+ abort();
+ }
+ break;
default:
abort();
}
@@ -102,11 +136,24 @@ ffi_prep_cif_machdep(ffi_cif *cif)
size_t z = ty->size;
int tt = ty->type;
- if (tt == FFI_TYPE_STRUCT || tt == FFI_TYPE_LONGDOUBLE)
- /* Passed by reference. */
- z = 4;
- else
- z = ALIGN(z, 4);
+ switch (tt)
+ {
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_LONGDOUBLE:
+ by_reference:
+ /* Passed by reference. */
+ z = 4;
+ break;
+
+ case FFI_TYPE_COMPLEX:
+ tt = ty->elements[0]->type;
+ if (tt == FFI_TYPE_FLOAT || z > 8)
+ goto by_reference;
+ /* FALLTHRU */
+
+ default:
+ z = ALIGN(z, 4);
+ }
bytes += z;
}
@@ -169,11 +216,14 @@ ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
{
ffi_type *ty = p_arg[i];
void *a = avalue[i];
+ int tt = ty->type;
+ size_t z;
- switch (ty->type)
+ switch (tt)
{
case FFI_TYPE_STRUCT:
case FFI_TYPE_LONGDOUBLE:
+ by_reference:
*argp++ = (unsigned long)a;
break;
@@ -205,6 +255,23 @@ ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
*argp++ = *(SINT16 *)a;
break;
+ case FFI_TYPE_COMPLEX:
+ tt = ty->elements[0]->type;
+ z = ty->size;
+ if (tt == FFI_TYPE_FLOAT || z > 8)
+ goto by_reference;
+ if (z < 4)
+ {
+ memcpy((char *)argp + 4 - z, a, z);
+ argp++;
+ }
+ else
+ {
+ memcpy(argp, a, z);
+ argp += z / 4;
+ }
+ break;
+
default:
abort();
}
@@ -299,11 +366,13 @@ ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
ffi_type *ty = arg_types[i];
int tt = ty->type;
void *a = argp;
+ size_t z;
switch (tt)
{
case FFI_TYPE_STRUCT:
case FFI_TYPE_LONGDOUBLE:
+ by_reference:
/* Straight copy of invisible reference. */
a = (void *)*argp;
break;
@@ -336,6 +405,17 @@ ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
a += 3;
break;
+ case FFI_TYPE_COMPLEX:
+ tt = ty->elements[0]->type;
+ z = ty->size;
+ if (tt == FFI_TYPE_FLOAT || z > 8)
+ goto by_reference;
+ if (z < 4)
+ a += 4 - z;
+ else if (z > 4)
+ argp++;
+ break;
+
default:
abort();
}
diff --git a/src/sparc/ffi64.c b/src/sparc/ffi64.c
index ab3ed09..1e2d3f4 100644
--- a/src/sparc/ffi64.c
+++ b/src/sparc/ffi64.c
@@ -52,14 +52,28 @@
and addition work correctly. The mask is placed in the second byte. */
static int
-ffi_struct_float_mask (ffi_type *struct_type, int size_mask)
+ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
{
- ffi_type **elts, *t;
+ ffi_type **elts;
+ ffi_type *t;
- for (elts = struct_type->elements; (t = *elts) != NULL; elts++)
+ if (outer_type->type == FFI_TYPE_COMPLEX)
+ {
+ int m = 0, tt = outer_type->elements[0]->type;
+ size_t z = outer_type->size;
+
+ if (tt == FFI_TYPE_FLOAT
+ || tt == FFI_TYPE_DOUBLE
+ || tt == FFI_TYPE_LONGDOUBLE)
+ m = (1 << (z / 4)) - 1;
+ return (m << 8) | z;
+ }
+ FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT);
+
+ for (elts = outer_type->elements; (t = *elts) != NULL; elts++)
{
size_t z = t->size;
- int o, m;
+ int o, m, tt;
size_mask = ALIGN(size_mask, t->alignment);
switch (t->type)
@@ -67,6 +81,13 @@ ffi_struct_float_mask (ffi_type *struct_type, int size_mask)
case FFI_TYPE_STRUCT:
size_mask = ffi_struct_float_mask (t, size_mask);
continue;
+ case FFI_TYPE_COMPLEX:
+ tt = t->elements[0]->type;
+ if (tt != FFI_TYPE_FLOAT
+ && tt != FFI_TYPE_DOUBLE
+ && tt != FFI_TYPE_LONGDOUBLE)
+ break;
+ /* FALLTHRU */
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_LONGDOUBLE:
@@ -78,8 +99,8 @@ ffi_struct_float_mask (ffi_type *struct_type, int size_mask)
size_mask += z;
}
- size_mask = ALIGN(size_mask, struct_type->alignment);
- FFI_ASSERT ((size_mask & 0xff) == struct_type->size);
+ size_mask = ALIGN(size_mask, outer_type->alignment);
+ FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
return size_mask;
}
@@ -162,6 +183,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
flags = SPARC_RET_F_4;
break;
+ case FFI_TYPE_COMPLEX:
case FFI_TYPE_STRUCT:
if (rtype->size > 32)
{
@@ -194,7 +216,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
{
case 1: flags = SPARC_RET_F_1; break;
case 2: flags = SPARC_RET_F_2; break;
- case 3: flags = SPARC_RET_F_3; break;
+ case 3: flags = SP_V9_RET_F_3; break;
case 4: flags = SPARC_RET_F_4; break;
/* 5 word structures skipped; handled via RET_STRUCT. */
case 6: flags = SPARC_RET_F_6; break;
@@ -218,7 +240,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
break;
case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
- flags = SPARC_RET_SINT32;
+ flags = SP_V9_RET_SINT32;
break;
case FFI_TYPE_UINT32:
flags = SPARC_RET_UINT32;
@@ -242,6 +264,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
switch (ty->type)
{
+ case FFI_TYPE_COMPLEX:
case FFI_TYPE_STRUCT:
/* Large structs passed by reference. */
if (z > 16)
@@ -249,7 +272,12 @@ ffi_prep_cif_machdep(ffi_cif *cif)
a = z = 8;
break;
}
- /* ??? FALLTHRU -- check for fp members in the struct. */
+ /* Small structs may be passed in integer or fp regs or both. */
+ if (bytes >= 16*8)
+ break;
+ if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0)
+ break;
+ /* FALLTHRU */
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_LONGDOUBLE:
@@ -351,6 +379,7 @@ ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
break;
case FFI_TYPE_LONGDOUBLE:
+ case FFI_TYPE_COMPLEX:
case FFI_TYPE_STRUCT:
z = ty->size;
if (z > 16)
@@ -466,6 +495,7 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue,
argx = argn + 1;
switch (ty->type)
{
+ case FFI_TYPE_COMPLEX:
case FFI_TYPE_STRUCT:
z = ty->size;
if (z > 16)
diff --git a/src/sparc/ffitarget.h b/src/sparc/ffitarget.h
index ff4dc0b..f70c937 100644
--- a/src/sparc/ffitarget.h
+++ b/src/sparc/ffitarget.h
@@ -58,6 +58,7 @@ typedef enum ffi_abi {
#endif
#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
+#define FFI_TARGET_HAS_COMPLEX_TYPE
/* ---- Definitions for closures ----------------------------------------- */
diff --git a/src/sparc/internal.h b/src/sparc/internal.h
index b4494d9..f9387d4 100644
--- a/src/sparc/internal.h
+++ b/src/sparc/internal.h
@@ -5,16 +5,18 @@
#define SPARC_RET_UINT16 4
#define SPARC_RET_SINT16 5
#define SPARC_RET_UINT32 6
-#define SPARC_RET_SINT32 7 /* v9 only */
+#define SP_V9_RET_SINT32 7 /* v9 only */
+#define SP_V8_RET_CPLX16 7 /* v8 only */
#define SPARC_RET_INT64 8
-#define SPARC_RET_INT128 9 /* v9 only */
+#define SPARC_RET_INT128 9
/* Note that F_7 is missing, and is handled by SPARC_RET_STRUCT. */
#define SPARC_RET_F_8 10
-#define SPARC_RET_F_6 11 /* v9 only */
+#define SPARC_RET_F_6 11
#define SPARC_RET_F_4 12
#define SPARC_RET_F_2 13
-#define SPARC_RET_F_3 14 /* v9 only */
+#define SP_V9_RET_F_3 14 /* v9 only */
+#define SP_V8_RET_CPLX8 14 /* v8 only */
#define SPARC_RET_F_1 15
#define SPARC_FLAG_RET_MASK 15
diff --git a/src/sparc/v8.S b/src/sparc/v8.S
index 4adcf6d..e76d813 100644
--- a/src/sparc/v8.S
+++ b/src/sparc/v8.S
@@ -1,8 +1,8 @@
/* -----------------------------------------------------------------------
v8.S - Copyright (c) 2013 The Written Word, Inc.
Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc.
-
- SPARC Foreign Function Interface
+
+ SPARC Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -25,7 +25,7 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#define LIBFFI_ASM
+#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
#include <ffi_cfi.h>
@@ -45,7 +45,7 @@
.text
-#ifndef __GNUC__
+#ifndef __GNUC__
.align 8
.globl C(ffi_flush_icache)
.type C(ffi_flush_icache),@function
@@ -75,7 +75,7 @@ C(ffi_flush_icache):
.globl C(ffi_call_v8)
.type C(ffi_call_v8),@function
FFI_HIDDEN(C(ffi_call_v8))
-
+
C(ffi_call_v8):
cfi_startproc
! Allocate a stack frame sized by ffi_call.
@@ -139,26 +139,44 @@ E SPARC_RET_UINT32
7: st %o0, [%i2]
ret
restore
-E SPARC_RET_SINT32
- unimp
+E SP_V8_RET_CPLX16
+ sth %o0, [%i2+2]
+ b 9f
+ srl %o0, 16, %o0
E SPARC_RET_INT64
- std %o0, [%i2]
+ st %o0, [%i2]
+ st %o1, [%i2+4]
ret
restore
E SPARC_RET_INT128
- unimp
+ std %o0, [%i2]
+ std %o2, [%i2+8]
+ ret
+ restore
E SPARC_RET_F_8
- unimp
+ st %f7, [%i2+7*4]
+ nop
+ st %f6, [%i2+6*4]
+ nop
E SPARC_RET_F_6
- unimp
+ st %f5, [%i2+5*4]
+ nop
+ st %f4, [%i2+4*4]
+ nop
E SPARC_RET_F_4
- unimp
+ st %f3, [%i2+3*4]
+ nop
+ st %f2, [%i2+2*4]
+ nop
E SPARC_RET_F_2
- std %f0, [%i2]
+ st %f1, [%i2+4]
+ st %f0, [%i2]
ret
restore
-E SPARC_RET_F_3
- unimp
+E SP_V8_RET_CPLX8
+ stb %o0, [%i2+1]
+ b 10f
+ srl %o0, 8, %o0
E SPARC_RET_F_1
st %f0, [%i2]
ret
@@ -172,16 +190,22 @@ E SPARC_RET_F_1
ret
restore
+ .align 8
+9: sth %o0, [%i2]
+ ret
+ restore
+ .align 8
+10: stb %o0, [%i2]
+ ret
+ restore
+
cfi_endproc
.size C(ffi_call_v8),. - C(ffi_call_v8)
-#undef STACKFRAME
-#define STACKFRAME 104 /* 16*4 register window +
- 1*4 struct return +
- 6*4 args backing store +
- 2*4 return storage +
- 1*4 alignment */
+/* 16*4 register window + 1*4 struct return + 6*4 args backing store
+ + 8*4 return storage + 1*4 alignment. */
+#define STACKFRAME (16*4 + 4 + 6*4 + 8*4 + 4)
/* ffi_closure_v8(...)
@@ -211,7 +235,7 @@ C(ffi_closure_v8):
! Call ffi_closure_sparc_inner to do the bulk of the work.
mov %g2, %o0
- add %fp, -8, %o1
+ add %fp, -8*4, %o1
call ffi_closure_sparc_inner_v8
add %fp, 64, %o2
@@ -220,8 +244,8 @@ C(ffi_closure_v8):
1: sll %o0, 4, %o0 ! o0 = o0 * 16
add %o7, %o0, %o7 ! o7 = 0b + o0*16
jmp %o7+(2f-0b)
- nop
-
+ add %fp, -8*4, %i2
+
! Note that each entry is 4 insns, enforced by the E macro.
.align 16
2:
@@ -232,47 +256,63 @@ E SPARC_RET_STRUCT
jmp %i7+12
restore
E SPARC_RET_UINT8
- ldub [%fp-8+3], %i0
+ ldub [%i2+3], %i0
ret
restore
E SPARC_RET_SINT8
- ldsb [%fp-8+3], %i0
+ ldsb [%i2+3], %i0
ret
restore
E SPARC_RET_UINT16
- lduh [%fp-8+2], %i0
+ lduh [%i2+2], %i0
ret
restore
E SPARC_RET_SINT16
- ldsh [%fp-8+2], %i0
+ ldsh [%i2+2], %i0
ret
restore
E SPARC_RET_UINT32
- ld [%fp-8], %i0
+ ld [%i2], %i0
+ ret
+ restore
+E SP_V8_RET_CPLX16
+ ld [%i2], %i0
ret
restore
-E SPARC_RET_SINT32
- unimp
E SPARC_RET_INT64
- ldd [%fp-8], %i0
+ ldd [%i2], %i0
ret
restore
E SPARC_RET_INT128
- unimp
+ ldd [%i2], %i0
+ ldd [%i2+8], %i2
+ ret
+ restore
E SPARC_RET_F_8
- unimp
+ ld [%i2+7*4], %f7
+ nop
+ ld [%i2+6*4], %f6
+ nop
E SPARC_RET_F_6
- unimp
+ ld [%i2+5*4], %f5
+ nop
+ ld [%i2+4*4], %f4
+ nop
E SPARC_RET_F_4
- unimp
+ ld [%i2+3*4], %f3
+ nop
+ ld [%i2+2*4], %f2
+ nop
E SPARC_RET_F_2
- ldd [%fp-8], %f0
+ ldd [%i2], %f0
+ ret
+ restore
+E SP_V8_RET_CPLX8
+ lduh [%i2], %i0
ret
restore
-E SPARC_RET_F_3
- unimp
E SPARC_RET_F_1
- ld [%fp-8], %f0
+ ld [%i2], %f0
ret
restore
diff --git a/src/sparc/v9.S b/src/sparc/v9.S
index d893d2f..5c3f27b 100644
--- a/src/sparc/v9.S
+++ b/src/sparc/v9.S
@@ -137,7 +137,7 @@ E SPARC_RET_UINT32
srl %o0, 0, %i0
return %i7+8
stx %o0, [%o2]
-E SPARC_RET_SINT32
+E SP_V9_RET_SINT32
sra %o0, 0, %i0
return %i7+8
stx %o0, [%o2]
@@ -167,7 +167,7 @@ E SPARC_RET_F_4
E SPARC_RET_F_2
return %i7+8
std %f0, [%o2]
-E SPARC_RET_F_3
+E SP_V9_RET_F_3
st %f2, [%i2+2*4]
nop
st %f1, [%i2+1*4]
@@ -294,7 +294,7 @@ E SPARC_RET_UINT32
lduw [FP-160+4], %i0
return %i7+8
nop
-E SPARC_RET_SINT32
+E SP_V9_RET_SINT32
ldsw [FP-160+4], %i0
return %i7+8
nop
@@ -326,7 +326,7 @@ E SPARC_RET_F_2
ldd [FP-160], %f0
return %i7+8
nop
-E SPARC_RET_F_3
+E SP_V9_RET_F_3
ld [FP-160+2*4], %f2
nop
ld [FP-160+1*4], %f1