From 12631cb1424419380adfa82fe84077a022a93794 Mon Sep 17 00:00:00 2001 From: dzaima Date: Fri, 27 May 2022 23:53:01 +0300 Subject: [PATCH] ffi tests --- .gitignore | 3 ++ src/ffi.c | 4 +- test/README.md | 1 + test/ffi/ffiTest.c | 85 ++++++++++++++++++++++++++++++++++++++++++ test/ffi/makefile | 7 ++++ test/ffi/test.bqn | 71 +++++++++++++++++++++++++++++++++++ test/ffi/test.expected | 61 ++++++++++++++++++++++++++++++ 7 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 test/ffi/ffiTest.c create mode 100644 test/ffi/makefile create mode 100644 test/ffi/test.bqn create mode 100644 test/ffi/test.expected diff --git a/.gitignore b/.gitignore index a0334f5f..16843744 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ perf.* /Singeli /local/ CBQNHeapDump +/test/ffi/ffiTest.o +/test/ffi/test.got +/test/ffi/lib.so diff --git a/src/ffi.c b/src/ffi.c index e5f67ee1..a8ad2878 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -22,7 +22,7 @@ static BQNV makeX(B x) { void bqn_free(BQNV v) { dec(getB(v)); } -static void freeTagged (BQNV v) { } +static void freeTagged(BQNV v) { } #define DIRECT_BQNV 1 double bqn_toF64 (BQNV v) { double r = o2fu(getB(v)); freeTagged(v); return r; } @@ -444,7 +444,7 @@ usz genObj(BQNFFIEnt ent, B c, bool anyMut) { if (!isArr(c)) thrF("FFI: Expected array corresponding to \"*%S\"", sty_names[o2cu(e)]); usz ia = a(c)->ia; bool mut = t->a[0].mutPtr; - switch(o2cu(e)) { default: thrF("FFI: Unimplemented pointer to \"%S\"", sty_names[o2cu(e)]); + switch(o2cu(e)) { default: thrF("FFI: \"*%S\" argument type NYI", sty_names[o2cu(e)]); case sty_i8: cG = mut? taga(cpyI8Arr (c)) : toI8Any (c); break; case sty_i16: cG = mut? taga(cpyI16Arr(c)) : toI16Any(c); break; case sty_i32: cG = mut? taga(cpyI32Arr(c)) : toI32Any(c); break; diff --git a/test/README.md b/test/README.md index 8ee599c1..9f6ef6ff 100644 --- a/test/README.md +++ b/test/README.md @@ -12,4 +12,5 @@ test/moreCfgs.sh path/to/mlochbaum/BQN // run "2+2" in a bunch of configurations ./BQN test/bitcpy.bqn // fuzz-test bit_cpy; requires a CBQN build with -DTEST_BITCPY ./BQN test/squeeze.bqn // fuzz-test squeezing; requires a CBQN build with -DEEQUAL_NEGZERO ./BQN test/random.bqn // various random tests +make -C test/ffi // test FFI functionality ``` \ No newline at end of file diff --git a/test/ffi/ffiTest.c b/test/ffi/ffiTest.c new file mode 100644 index 00000000..b81ea232 --- /dev/null +++ b/test/ffi/ffiTest.c @@ -0,0 +1,85 @@ +#include +#include +#include "../../src/ffi.h" + +void do_nothing() { } + +BQNV timesTen(BQNV v) { + size_t len = bqn_bound(v); + int32_t* buf = malloc(len*4); + bqn_readI32Arr(v, buf); + for (int i = 0; i < len; i++) buf[i] = buf[i] * 10; + BQNV res = bqn_makeI32Vec(len, buf); + free(buf); + bqn_free(v); + return res; +} + +BQNV add_args(BQNV t, BQNV x) { + return bqn_makeF64(bqn_toF64(t) + bqn_toF64(x)); +} +BQNV bind_add(BQNV x) { + BQNV r = bqn_makeBoundFn1(add_args, x); + bqn_free(x); + return r; +} + + + +void printArgs(int8_t i8, int16_t i16, int32_t i32, uint8_t u8, uint16_t u16, uint32_t u32, float f, double d) { + printf("args: %d %d %d %u %u %u %.18f %.18f\n", i8, i16, i32, u8, u16, u32, f, d); +} +void noopArgs(int8_t i8, int16_t i16, int32_t i32, uint8_t u8, uint16_t u16, uint32_t u32, float f, double d) { } + +void printPtrArgs(int8_t* i8, int16_t* i16, int32_t* i32, uint8_t* u8, uint16_t* u16, uint32_t* u32, float* f, double* d) { + printf("args: %d %d %d %u %u %u %.18f %.18f\n", *i8, *i16, *i32, *u8, *u16, *u32, *f, *d); +} + +float printU64s(uint64_t a, uint64_t* b) { + printf("%llx %llx %llx %llx\n", (long long)a, (long long)b[0], (long long)b[1], (long long)b[2]); + return 12345678; +} + + + +int32_t multiplyI32Ptrs(int32_t* a, int32_t* b, int32_t len) { + int32_t r = 0; + for (int i = 0; i < len; i++) { + r+= a[i]*b[i]; + } + return r; +} +float sumF32Arr(float* f, int len) { + float r = 0; + for (int i = 0; i < len; i++) r+= f[i]; + return r; +} + + +void incI32s(int32_t* a, int32_t len) { + for (int i = 0; i < len; i++) a[i]++; +} + +void incInts(int32_t* a, int16_t* b, int8_t* c) { + printf("%d %d %d\n", *a, *b, *c); + (*a)++; + (*b)++; + (*c)++; +} + +uint64_t ident_u64(uint64_t x) { return x; } +double ident_f64(double a) { return a; } + +void* pick_ptr(void** arr, int idx) { + return arr[idx]; +} +uint64_t pick_u64(uint64_t* arr, int idx) { + return arr[idx]; +} + + + + +int plusone(int x) { + return x + 1; +} diff --git a/test/ffi/makefile b/test/ffi/makefile new file mode 100644 index 00000000..37676f95 --- /dev/null +++ b/test/ffi/makefile @@ -0,0 +1,7 @@ +test: build + @../../BQN test.bqn > test.got + @diff --color -su test.expected test.got + +build: + $(CC) -O3 -g -c -fpic ffiTest.c -o ffiTest.o + $(CC) -shared -olib.so ffiTest.o \ No newline at end of file diff --git a/test/ffi/test.bqn b/test/ffi/test.bqn new file mode 100644 index 00000000..9d82309d --- /dev/null +++ b/test/ffi/test.bqn @@ -0,0 +1,71 @@ +f←@ +Section ← {•Out 𝕩∾˜@+10} + +f ↩ "lib.so" •FFI ""‿"do_nothing" ⋄ •Show F ⟨⟩ + +Section "# ""a""" +f ↩ "lib.so" •FFI "a"‿"timesTen"‿"a" ⋄ •Show F ⟨↕10⟩ +bind ← "lib.so" •FFI "a"‿"bind_add"‿">a" ⋄ g ← Bind 4 ⋄ •Show G 123 + +Section "# print args" +f ↩ "lib.so" •FFI ""‿"printArgs"‿"i8"‿"i16"‿"i32"‿"u8"‿"u16"‿"u32"‿"f32"‿"f64" ⋄ •Show F ¯123‿¯12323‿¯212312312‿250‿50000‿3123456789‿π∾⋆1 +f ↩ "lib.so" •FFI ""‿ "noopArgs"‿"i8"‿"i16"‿"i32"‿"u8"‿"u16"‿"u32"‿"f32"‿"f64" ⋄ •Show F ¯123‿¯12323‿¯212312312‿250‿50000‿3123456789‿π∾⋆1 +f ↩ "lib.so" •FFI ""‿"printPtrArgs"‿"*i8"‿"*i16"‿"*i32"‿"*u8"‿"*u16"‿"*u32"‿"*f32"‿"*f64" ⋄ •Show F ⥊¨¯123‿¯12323‿¯212312312‿250‿50000‿3123456789‿π∾⋆1 +f ↩ "lib.so" •FFI ""‿"printPtrArgs"‿"&i8"‿"&i16"‿"&i32"‿"&u8"‿"&u16"‿"&u32"‿"&f32"‿"&f64" ⋄ •Show F ⥊¨¯123‿¯12323‿¯212312312‿250‿50000‿3123456789‿π∾⋆1 + +f ↩ "lib.so" •FFI "f32"‿"printU64s"‿"u64:c8"‿"*u64:c8" ⋄ •Show F ⟨"hellowor", "aaaaaaaa12345678texttext"⟩ +f ↩ "lib.so" •FFI "f32"‿"printU64s"‿"u64:u1"‿"*u64:u1" ⋄ •Show F ⟨64↑∾×∘↕¨↕12, 192↑∾×∘↕¨↕21⟩ + +! 3 ≡ •Type "lib.so" •FFI ""‿"printArgs"‿"i8"‿"i16:c8"‿"i32"‿"u8"‿"u16"‿"u32"‿"f32"‿"f64" +! 3 ≡ •Type "lib.so" •FFI ""‿"printArgs"‿"i8"‿"i16:c16"‿"i32"‿"u8"‿"u16"‿"u32"‿"f32"‿"f64" +! 3 ≡ •Type "lib.so" •FFI ""‿"printArgs"‿"i8:c8"‿"i16"‿"i32"‿"u8"‿"u16"‿"u32"‿"f32"‿"f64" + +Section "# read pointers" +f ↩ "lib.so" •FFI "i32"‿"multiplyI32Ptrs"‿"*i32"‿"*i32"‿"i32" ⋄ •Show F ⟨↕10 ⋄ •Show ⌽↕10 ⋄ •Show 10⟩ +f ↩ "lib.so" •FFI "f32"‿"sumF32Arr"‿"*f32:i32"‿"i32" ⋄ •Show F ⟨1065353216‿1073741824‿1077936128‿1082130432‿1084227584‿1086324736‿1088421888‿1090519040‿1091567616‿1092616192,10⟩ + +Section "# mutate i32*" +f ↩ "lib.so" •FFI ⟨"","incI32s","&u32", "i32"⟩ ⋄ •Show F ⟨1e8×20+↕10 ⋄ 10⟩ +f ↩ "lib.so" •FFI ⟨"","incI32s","&i32:u1", "i32"⟩ ⋄ •Show ⊑F ⟨1‿0‿1‿0‿1‿0‿1‿0‿0‿1‿0‿1‿0‿0‿1‿1‿0‿1‿1‿0‿0‿0‿0‿1‿0‿1‿0‿1‿0‿0‿1‿0‿0‿0‿1‿0‿0‿0‿1‿0‿0‿0‿1‿1‿1‿0‿1‿1‿1‿1‿1‿1‿0‿0‿1‿1‿0‿0‿1‿0‿0‿1‿0‿0, 2⟩ +f ↩ "lib.so" •FFI ⟨"","incI32s","&i32:c8", "i32"⟩ ⋄ •Show ⊑F ⟨"helloworld", 2⟩ +f ↩ "lib.so" •FFI ⟨"","incI32s",">𝕨&i32:c8",">i32"⟩ ⋄ •Show ⊑ "helloworld" F 2 + +f ↩ "lib.so" •FFI ⟨"", "incI32s", "&i32:c8", "i32"⟩ ⋄ •Show ⊑F ⟨"helloworld", 2⟩ +f ↩ "lib.so" •FFI ⟨"", "incI32s", "&i32:c8", "𝕨i32"⟩ ⋄ •Show ⊑ ⟨2⟩ F ⟨"helloworld"⟩ +f ↩ "lib.so" •FFI ⟨"", "incI32s", "&i32:c8",">𝕨i32"⟩ ⋄ •Show ⊑ 2 F ⟨"helloworld"⟩ +f ↩ "lib.so" •FFI ⟨"", "incI32s", ">&i32:c8",">𝕨i32"⟩ ⋄ •Show ⊑ 2 F "helloworld" +f ↩ "lib.so" •FFI ⟨"", "incI32s",">𝕨&i32:c8", ">i32"⟩ ⋄ •Show ⊑ "helloworld" F 2 +f ↩ "lib.so" •FFI ⟨"", "incI32s", "&i32:c8", "i32"⟩ ⋄ •Show F ⟨"helloworld", 2⟩ +f ↩ "lib.so" •FFI ⟨"&","incI32s", "&i32:c8", "i32"⟩ ⋄ •Show F ⟨"helloworld", 2⟩ + +Section "# mutate i32*, i16*, i8*" +f ↩ "lib.so" •FFI ⟨"","incInts","&i32", "&i16","&i8"⟩ ⋄ •Show F ⥊¨ 10‿20‿30 +f ↩ "lib.so" •FFI ⟨"","incInts","&i32", "𝕨&i16","&i8"⟩ ⋄ •Show ⟨⥊20⟩ F ⥊¨ 10‿30 +f ↩ "lib.so" •FFI ⟨"","incInts","&i32",">𝕨&i16","&i8"⟩ ⋄ •Show ⟨20⟩ F ⥊¨ 10‿30 + +Section "# u64 tests" +f ↩ "lib.so" •FFI ⟨"u64", "ident_u64",">u64:i32"⟩ ⋄ •Show F 1234‿12 +f ↩ "lib.so" •FFI ⟨"u64", "ident_u64",">u64" ⟩ ⋄ •Show F +´2⋆52‿20 +f ↩ "lib.so" •FFI ⟨"u64:i32","ident_u64",">u64" ⟩ ⋄ •Show F 123456789123456 +f ↩ "lib.so" •FFI ⟨"u64:u1", "ident_u64",">u64:c8" ⟩ ⋄ •Show F "hellowor" + +Section "# malloc test" +f ↩ "lib.so" •FFI "*:i32"‿"malloc"‿">u64" ⋄ •Show (•internal.Info⋈≠) malloc ← F 123 +f ↩ "lib.so" •FFI ""‿"free"‿">*:i32" ⋄ F malloc + +Section "# pick item" +f ↩ "lib.so" •FFI "*:i8"‿"pick_ptr"‿">**:i8"‿">𝕨i32" ⋄ •Show @+0 F "helloworfoobarba"-@ +f ↩ "lib.so" •FFI "*:c8"‿"pick_ptr"‿">**:c8"‿">𝕨i32" ⋄ •Show 0 F "helloworfoobarba" +f ↩ "lib.so" •FFI ⟨"u64:i8","pick_u64",">*u64:i8",">𝕨i32"⟩ ⋄ •Show @+2 F "000000001234560011122100abacabad"-@ +f ↩ "lib.so" •FFI ⟨"u64:i8","pick_u64",">*u64:i8",">𝕨i32"⟩ ⋄ •Show @+3 F "000000001234560011122100abacabad"-@ +f ↩ "lib.so" •FFI ⟨"u64", "pick_u64",">*u64:i8",">𝕨i32"⟩ ⋄ •Show 1 F "000000001234560011122100"-'0' + + +# erroring: + +# "local/lib.so" •FFI ""‿"printArgs"‿"i8"‿"i16:c32"‿"i32"‿"u8"‿"u16"‿"u32"‿"f32"‿"f64" +# "local/lib.so" •FFI ""‿"testArgs"‿"i8:c16"‿"i16"‿"i32"‿"u8"‿"u16"‿"u32"‿"f32"‿"f64" +# "local/lib.so" •FFI ""‿"testArgs"‿"i8:c32"‿"i16"‿"i32"‿"u8"‿"u16"‿"u32"‿"f32"‿"f64" + +# f ↩ "local/lib.so" •FFI "u64"‿"ident_u64"‿">u64:i32" ⋄ •Show F 1234‿12344444 +# f ↩ "local/lib.so" •FFI "u64"‿"ident_u64"‿">u64" ⋄ •Show F +´2⋆53‿20 \ No newline at end of file diff --git a/test/ffi/test.expected b/test/ffi/test.expected new file mode 100644 index 00000000..8455dc3c --- /dev/null +++ b/test/ffi/test.expected @@ -0,0 +1,61 @@ +@ + +# "a" +⟨ 0 10 20 30 40 50 60 70 80 90 ⟩ +127 + +# print args +args: -123 -12323 -212312312 250 50000 3123456789 3.141592741012573242 2.718281828459045091 +@ +@ +args: -123 -12323 -212312312 250 50000 3123456789 3.141592741012573242 2.718281828459045091 +@ +args: -123 -12323 -212312312 250 50000 3123456789 3.141592741012573242 2.718281828459045091 +⟨ ⟨ ¯123 ⟩ ⟨ ¯12323 ⟩ ⟨ ¯212312312 ⟩ ⟨ 250 ⟩ ⟨ 50000 ⟩ ⟨ 3123456789 ⟩ ⟨ 3.141592741012573 ⟩ ⟨ 2.718281828459045 ⟩ ⟩ +726f776f6c6c6568 6161616161616161 3837363534333231 7478657474786574 +12345678 +ff7fdfefefdf7bb4 ff7fdfefefdf7bb4 fefffdfff7ffbffb bffff7fffdfffeff +12345678 + +# read pointers +⟨ 9 8 7 6 5 4 3 2 1 0 ⟩ +10 +120 +55 + +# mutate i32* +⟨ ⟨ 2000000001 2100000001 2200000001 2300000001 2400000001 2500000001 2600000001 2700000001 2800000001 2900000001 ⟩ ⟩ +⟨ 0 1 1 0 1 0 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0 0 1 0 0 0 1 1 1 0 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 1 0 0 ⟩ +"iellpworld" +"iellpworld" +"iellpworld" +"iellpworld" +"iellpworld" +"iellpworld" +"iellpworld" +⟨ "iellpworld" ⟩ +"iellpworld" + +# mutate i32*, i16*, i8* +10 20 30 +⟨ ⟨ 11 ⟩ ⟨ 21 ⟩ ⟨ 31 ⟩ ⟩ +10 20 30 +⟨ ⟨ 11 ⟩ ⟨ 21 ⟩ ⟨ 31 ⟩ ⟩ +10 20 30 +⟨ ⟨ 11 ⟩ ⟨ 21 ⟩ ⟨ 31 ⟩ ⟩ + +# u64 tests +51539608786 +4503599628419072 +⟨ ¯2045800064 28744 ⟩ +⟨ 0 0 0 1 0 1 1 0 1 0 1 0 0 1 1 0 0 0 1 1 0 1 1 0 0 0 1 1 0 1 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 1 1 0 1 1 1 1 0 1 1 0 0 1 0 0 1 1 1 0 ⟩ + +# malloc test +⟨ "fff7: refc:2 type:26=i32arr alloc:128" 2 ⟩ + +# pick item +"hellowor" +"hellowor" +"11122100" +"abacabad" +6618611909121