mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 19:19:53 +00:00
Address #1034 - add handling for 8-16 byte structs in FFI.
This commit is contained in:
parent
6a899968a9
commit
3479841c77
@ -134,12 +134,47 @@ void void_ret_fn(int x) {
|
||||
printf("void fn ran: %d\n", x);
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
int intintint_fn_2(intintint iii, int i) {
|
||||
return i * (iii.a + iii.b + iii.c);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int a, b;
|
||||
float c, d;
|
||||
} Split;
|
||||
|
||||
typedef struct {
|
||||
float c, d;
|
||||
int a, b;
|
||||
} SplitFlip;
|
||||
|
||||
EXPORTER
|
||||
float split_fn(Split s) {
|
||||
return s.a * s.c + s.b * s.d;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
float split_flip_fn(SplitFlip s) {
|
||||
return s.a * s.c + s.b * s.d;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
Split split_ret_fn(int x, float y) {
|
||||
Split ret;
|
||||
ret.a = x;
|
||||
ret.b = x;
|
||||
ret.c = y;
|
||||
ret.d = y;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
SplitFlip split_flip_ret_fn(int x, float y) {
|
||||
SplitFlip ret;
|
||||
ret.a = x;
|
||||
ret.b = x;
|
||||
ret.c = y;
|
||||
ret.d = y;
|
||||
return ret;
|
||||
}
|
||||
|
@ -44,9 +44,15 @@
|
||||
i :double
|
||||
j :double])
|
||||
(ffi/defbind void-fn-2 :void [y :double])
|
||||
(ffi/defbind intintint-fn-2 :int [iii intintint i :int])
|
||||
|
||||
(def split (ffi/struct :int :int :float :float))
|
||||
(def split-flip (ffi/struct :float :float :int :int))
|
||||
(ffi/defbind split-fn :float [s split])
|
||||
(ffi/defbind split-flip-fn :float [s split-flip])
|
||||
(ffi/defbind split-ret-fn split [x :int y :float])
|
||||
(ffi/defbind split-flip-ret-fn split-flip [x :int y :float])
|
||||
|
||||
#
|
||||
# Struct reading and writing
|
||||
#
|
||||
@ -87,6 +93,10 @@
|
||||
# Call functions
|
||||
#
|
||||
|
||||
(tracev (split-ret-fn 10 12))
|
||||
(tracev (split-flip-ret-fn 10 12))
|
||||
(tracev (split-flip-ret-fn 12 10))
|
||||
(tracev (intintint-fn-2 [10 20 30] 3))
|
||||
(tracev (split-fn [5 6 1.2 3.4]))
|
||||
(tracev (void-fn-2 10.3))
|
||||
(tracev (double-many 1 2 3 4 5 6))
|
||||
@ -104,6 +114,10 @@
|
||||
(tracev (double-lots 1 2 3 4 5 6 700 800 9 10))
|
||||
(tracev (struct-big 11 99.5))
|
||||
|
||||
(assert (= [10 10 12 12] (split-ret-fn 10 12)))
|
||||
(assert (= [12 12 10 10] (split-flip-ret-fn 10 12)))
|
||||
(assert (= 183 (intintint-fn-2 [10 20 31] 3)))
|
||||
(assert (= 264 (math/round (* 10 (split-fn [5 6 1.2 3.4])))))
|
||||
(assert (= 9876543210 (double-lots-2 0 1 2 3 4 5 6 7 8 9)))
|
||||
(assert (= 60 (int-fn 10 20)))
|
||||
(assert (= 42 (double-fn 1.5 2.5 3.5)))
|
||||
|
166
src/core/ffi.c
166
src/core/ffi.c
@ -123,9 +123,10 @@ typedef enum {
|
||||
JANET_SYSV64_INTEGER,
|
||||
JANET_SYSV64_SSE,
|
||||
JANET_SYSV64_SSEUP,
|
||||
JANET_SYSV64_X87,
|
||||
JANET_SYSV64_X87UP,
|
||||
JANET_SYSV64_COMPLEX_X87,
|
||||
JANET_SYSV64_PAIR_INTINT,
|
||||
JANET_SYSV64_PAIR_INTSSE,
|
||||
JANET_SYSV64_PAIR_SSEINT,
|
||||
JANET_SYSV64_PAIR_SSESSE,
|
||||
JANET_SYSV64_NO_CLASS,
|
||||
JANET_SYSV64_MEMORY,
|
||||
JANET_WIN64_REGISTER,
|
||||
@ -623,6 +624,45 @@ static JanetFFIWordSpec sysv64_classify(JanetFFIType type) {
|
||||
if (st->size > 16) return JANET_SYSV64_MEMORY;
|
||||
if (!st->is_aligned) return JANET_SYSV64_MEMORY;
|
||||
JanetFFIWordSpec clazz = JANET_SYSV64_NO_CLASS;
|
||||
if (st->size > 8 && st->size <= 16) {
|
||||
/* map to pair classification */
|
||||
int has_int_lo = 0;
|
||||
int has_int_hi = 0;
|
||||
for (uint32_t i = 0; i < st->field_count; i++) {
|
||||
JanetFFIWordSpec next_class = sysv64_classify(st->fields[i].type);
|
||||
switch (next_class) {
|
||||
default:
|
||||
break;
|
||||
case JANET_SYSV64_INTEGER:
|
||||
case JANET_SYSV64_PAIR_INTINT:
|
||||
case JANET_SYSV64_PAIR_INTSSE:
|
||||
case JANET_SYSV64_PAIR_SSEINT: {
|
||||
/* since everything is aligned, nothing should straddle an 8-byte or be in memory */
|
||||
if (st->fields[i].offset >= 8) {
|
||||
has_int_hi = 2;
|
||||
} else {
|
||||
has_int_lo = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (has_int_hi + has_int_lo) {
|
||||
case 0:
|
||||
clazz = JANET_SYSV64_PAIR_SSESSE;
|
||||
break;
|
||||
case 1:
|
||||
clazz = JANET_SYSV64_PAIR_INTSSE;
|
||||
break;
|
||||
case 2:
|
||||
clazz = JANET_SYSV64_PAIR_SSEINT;
|
||||
break;
|
||||
case 3:
|
||||
clazz = JANET_SYSV64_PAIR_INTINT;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Normal struct classification */
|
||||
for (uint32_t i = 0; i < st->field_count; i++) {
|
||||
JanetFFIWordSpec next_class = sysv64_classify(st->fields[i].type);
|
||||
if (next_class != clazz) {
|
||||
@ -632,14 +672,12 @@ static JanetFFIWordSpec sysv64_classify(JanetFFIType type) {
|
||||
clazz = JANET_SYSV64_MEMORY;
|
||||
} else if (clazz == JANET_SYSV64_INTEGER || next_class == JANET_SYSV64_INTEGER) {
|
||||
clazz = JANET_SYSV64_INTEGER;
|
||||
} else if (next_class == JANET_SYSV64_X87 || next_class == JANET_SYSV64_X87UP
|
||||
|| next_class == JANET_SYSV64_COMPLEX_X87) {
|
||||
clazz = JANET_SYSV64_MEMORY;
|
||||
} else {
|
||||
clazz = JANET_SYSV64_SSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
case JANET_FFI_TYPE_VOID:
|
||||
@ -753,6 +791,8 @@ JANET_CORE_FN(cfun_ffi_signature,
|
||||
JanetFFIWordSpec ret_spec = sysv64_classify(ret.type);
|
||||
ret.spec = ret_spec;
|
||||
if (ret_spec == JANET_SYSV64_SSE) variant = 1;
|
||||
if (ret_spec == JANET_SYSV64_PAIR_INTSSE) variant = 2;
|
||||
if (ret_spec == JANET_SYSV64_PAIR_SSEINT) variant = 3;
|
||||
/* Spill register overflow to memory */
|
||||
uint32_t next_register = 0;
|
||||
uint32_t next_fp_register = 0;
|
||||
@ -781,8 +821,8 @@ JANET_CORE_FN(cfun_ffi_signature,
|
||||
mappings[i].offset = stack_count;
|
||||
stack_count += el_size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case JANET_SYSV64_SSE: {
|
||||
if (next_fp_register < max_fp_regs) {
|
||||
mappings[i].offset = next_fp_register++;
|
||||
@ -791,12 +831,57 @@ JANET_CORE_FN(cfun_ffi_signature,
|
||||
mappings[i].offset = stack_count;
|
||||
stack_count += el_size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case JANET_SYSV64_MEMORY: {
|
||||
mappings[i].offset = stack_count;
|
||||
stack_count += el_size;
|
||||
}
|
||||
break;
|
||||
case JANET_SYSV64_PAIR_INTINT: {
|
||||
if (next_register + 1 < max_regs) {
|
||||
mappings[i].offset = next_register++;
|
||||
mappings[i].offset2 = next_register++;
|
||||
} else {
|
||||
mappings[i].spec = JANET_SYSV64_MEMORY;
|
||||
mappings[i].offset = stack_count;
|
||||
stack_count += el_size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JANET_SYSV64_PAIR_INTSSE: {
|
||||
if (next_register < max_regs && next_fp_register < max_fp_regs) {
|
||||
mappings[i].offset = next_register++;
|
||||
mappings[i].offset2 = next_fp_register++;
|
||||
} else {
|
||||
mappings[i].spec = JANET_SYSV64_MEMORY;
|
||||
mappings[i].offset = stack_count;
|
||||
stack_count += el_size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JANET_SYSV64_PAIR_SSEINT: {
|
||||
if (next_register < max_regs && next_fp_register < max_fp_regs) {
|
||||
mappings[i].offset = next_fp_register++;
|
||||
mappings[i].offset2 = next_register++;
|
||||
} else {
|
||||
mappings[i].spec = JANET_SYSV64_MEMORY;
|
||||
mappings[i].offset = stack_count;
|
||||
stack_count += el_size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JANET_SYSV64_PAIR_SSESSE: {
|
||||
if (next_fp_register < max_fp_regs) {
|
||||
mappings[i].offset = next_fp_register++;
|
||||
mappings[i].offset2 = next_fp_register++;
|
||||
} else {
|
||||
mappings[i].spec = JANET_SYSV64_MEMORY;
|
||||
mappings[i].offset = stack_count;
|
||||
stack_count += el_size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -832,23 +917,38 @@ typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
} sysv64_sse_return;
|
||||
typedef struct {
|
||||
uint64_t x;
|
||||
double y;
|
||||
} sysv64_intsse_return;
|
||||
typedef struct {
|
||||
double y;
|
||||
uint64_t x;
|
||||
} sysv64_sseint_return;
|
||||
typedef sysv64_int_return janet_sysv64_variant_1(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, uint64_t f,
|
||||
double r1, double r2, double r3, double r4, double r5, double r6, double r7, double r8);
|
||||
typedef sysv64_sse_return janet_sysv64_variant_2(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, uint64_t f,
|
||||
double r1, double r2, double r3, double r4, double r5, double r6, double r7, double r8);
|
||||
typedef sysv64_intsse_return janet_sysv64_variant_3(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, uint64_t f,
|
||||
double r1, double r2, double r3, double r4, double r5, double r6, double r7, double r8);
|
||||
typedef sysv64_sseint_return janet_sysv64_variant_4(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, uint64_t f,
|
||||
double r1, double r2, double r3, double r4, double r5, double r6, double r7, double r8);
|
||||
|
||||
static Janet janet_ffi_sysv64(JanetFFISignature *signature, void *function_pointer, const Janet *argv) {
|
||||
union {
|
||||
sysv64_int_return int_return;
|
||||
sysv64_sse_return sse_return;
|
||||
sysv64_sseint_return sseint_return;
|
||||
sysv64_intsse_return intsse_return;
|
||||
} retu;
|
||||
uint64_t pair[2];
|
||||
uint64_t regs[6];
|
||||
double fp_regs[8];
|
||||
JanetFFIWordSpec ret_spec = signature->ret.spec;
|
||||
void *ret_mem = &int_return;
|
||||
void *ret_mem = &retu.int_return;
|
||||
if (ret_spec == JANET_SYSV64_MEMORY) {
|
||||
ret_mem = alloca(type_size(signature->ret.type));
|
||||
regs[0] = (uint64_t) ret_mem;
|
||||
} else if (ret_spec == JANET_SYSV64_SSE) {
|
||||
ret_mem = &sse_return;
|
||||
}
|
||||
uint64_t *stack = alloca(sizeof(uint64_t) * signature->stack_count);
|
||||
for (uint32_t i = 0; i < signature->arg_count; i++) {
|
||||
@ -867,21 +967,55 @@ static Janet janet_ffi_sysv64(JanetFFISignature *signature, void *function_point
|
||||
case JANET_SYSV64_MEMORY:
|
||||
to = stack + arg.offset;
|
||||
break;
|
||||
case JANET_SYSV64_PAIR_INTINT:
|
||||
janet_ffi_write_one(pair, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
regs[arg.offset] = pair[0];
|
||||
regs[arg.offset2] = pair[1];
|
||||
continue;
|
||||
case JANET_SYSV64_PAIR_INTSSE:
|
||||
janet_ffi_write_one(pair, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
regs[arg.offset] = pair[0];
|
||||
((uint64_t *) fp_regs)[arg.offset2] = pair[1];
|
||||
continue;
|
||||
case JANET_SYSV64_PAIR_SSEINT:
|
||||
janet_ffi_write_one(pair, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
((uint64_t *) fp_regs)[arg.offset] = pair[0];
|
||||
regs[arg.offset2] = pair[1];
|
||||
continue;
|
||||
case JANET_SYSV64_PAIR_SSESSE:
|
||||
janet_ffi_write_one(pair, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
((uint64_t *) fp_regs)[arg.offset] = pair[0];
|
||||
((uint64_t *) fp_regs)[arg.offset2] = pair[1];
|
||||
continue;
|
||||
}
|
||||
janet_ffi_write_one(to, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
}
|
||||
|
||||
if (signature->variant) {
|
||||
sse_return = ((janet_sysv64_variant_2 *)(function_pointer))(
|
||||
switch (signature->variant) {
|
||||
case 0:
|
||||
retu.int_return = ((janet_sysv64_variant_1 *)(function_pointer))(
|
||||
regs[0], regs[1], regs[2], regs[3], regs[4], regs[5],
|
||||
fp_regs[0], fp_regs[1], fp_regs[2], fp_regs[3],
|
||||
fp_regs[4], fp_regs[5], fp_regs[6], fp_regs[7]);
|
||||
} else {
|
||||
int_return = ((janet_sysv64_variant_1 *)(function_pointer))(
|
||||
break;
|
||||
case 1:
|
||||
retu.sse_return = ((janet_sysv64_variant_2 *)(function_pointer))(
|
||||
regs[0], regs[1], regs[2], regs[3], regs[4], regs[5],
|
||||
fp_regs[0], fp_regs[1], fp_regs[2], fp_regs[3],
|
||||
fp_regs[4], fp_regs[5], fp_regs[6], fp_regs[7]);
|
||||
|
||||
break;
|
||||
case 2:
|
||||
retu.intsse_return = ((janet_sysv64_variant_3 *)(function_pointer))(
|
||||
regs[0], regs[1], regs[2], regs[3], regs[4], regs[5],
|
||||
fp_regs[0], fp_regs[1], fp_regs[2], fp_regs[3],
|
||||
fp_regs[4], fp_regs[5], fp_regs[6], fp_regs[7]);
|
||||
break;
|
||||
case 3:
|
||||
retu.sseint_return = ((janet_sysv64_variant_4 *)(function_pointer))(
|
||||
regs[0], regs[1], regs[2], regs[3], regs[4], regs[5],
|
||||
fp_regs[0], fp_regs[1], fp_regs[2], fp_regs[3],
|
||||
fp_regs[4], fp_regs[5], fp_regs[6], fp_regs[7]);
|
||||
break;
|
||||
}
|
||||
|
||||
return janet_ffi_read_one(ret_mem, signature->ret.type, JANET_FFI_MAX_RECUR);
|
||||
|
Loading…
Reference in New Issue
Block a user