summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-05-03 12:37:28 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-05-03 12:37:28 -0400
commitcb1a634e495c6f2e3ebd90f25235c6f7d2d639b7 (patch)
tree92d2e15bee99fd960f566d7e17955770deb71dba
parent6be24a8a51106e373406081ecd088bd1a2db4040 (diff)
turns out __cdecl is only for 32-bit. now everything works except for 64-bit arguments
-rw-r--r--.gitignore7
-rw-r--r--eval.c4
-rw-r--r--foreign_msvc32.c (renamed from foreign_msvc.c)31
-rw-r--r--test.toc22
-rw-r--r--toc.c2
-rw-r--r--types.c2
6 files changed, 52 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index 5b905a2..3b26d1a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,10 @@ std/*.o
*.so
README.html
docs/*.html
+*.dll
+*.exp
+*.lib
+*.pdb
+*.ilk
+*.obj
+*.exe
diff --git a/eval.c b/eval.c
index 01f7625..4b7dc40 100644
--- a/eval.c
+++ b/eval.c
@@ -211,7 +211,7 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) {
} break;
case TYPE_ARR: {
fprintf(f, "["); /* @TODO: change? when array initializers are added */
- size_t n = t->arr.n;
+ size_t n = (size_t)t->arr.n;
if (n > 5) n = 5;
for (size_t i = 0; i < n; ++i) {
if (i) fprintf(f, ", ");
@@ -1002,7 +1002,7 @@ static Value val_zero(Type *t) {
val.struc = err_calloc(1, compiler_sizeof(t));
break;
case TYPE_ARR:
- val.arr = err_calloc(t->arr.n, compiler_sizeof(t->arr.of));
+ val.arr = err_calloc((size_t)t->arr.n, compiler_sizeof(t->arr.of));
break;
default:
break;
diff --git a/foreign_msvc.c b/foreign_msvc32.c
index f78f275..d1b38e0 100644
--- a/foreign_msvc.c
+++ b/foreign_msvc32.c
@@ -7,25 +7,37 @@ but I don't think there's any other way that doesn't involve inline assembly
typedef size_t Word;
+#if SIZE_MAX != U32_MAX
+/*
+@TODO
+x64 has its own calling convention
+*/
+#error "Calling #foreign functitons at compile time only works on 32-bit Windows, not 64-bit."
+#endif
+
typedef struct {
HMODULE handle;
} Library;
-
-static Status val_to_word(Value v, Type *t, Location where, Word *w) {
+/* f64s take 2 words */
+static Status val_to_words(Value v, Type *t, Location where, Word *w) {
switch (t->kind) {
case TYPE_BUILTIN:
switch (t->builtin) {
case BUILTIN_I8: *w = (Word)v.i8; break;
case BUILTIN_I16: *w = (Word)v.i16; break;
case BUILTIN_I32: *w = (Word)v.i32; break;
- case BUILTIN_I64: *w = (Word)v.i64; break;
case BUILTIN_U8: *w = (Word)v.u8; break;
case BUILTIN_U16: *w = (Word)v.u16; break;
case BUILTIN_U32: *w = (Word)v.u32; break;
- case BUILTIN_U64: *w = (Word)v.u64; break;
- case BUILTIN_F32: *w = (Word)*(uint32_t *)&v.f32; break;
- case BUILTIN_F64: *w = (Word)*(uint64_t *)&v.f64; break;
+ case BUILTIN_F32: *w = (Word)*(U32 *)&v.f32; break;
+ case BUILTIN_I64:
+ case BUILTIN_U64:
+ case BUILTIN_F64: {
+ Word *ws = (Word *)&v;
+ w[0] = ws[0];
+ w[1] = ws[1];
+ } break;
case BUILTIN_CHAR: *w = (Word)v.charv; break;
case BUILTIN_BOOL: *w = (Word)v.boolv; break;
case BUILTIN_TYPE:
@@ -55,7 +67,7 @@ because of the way the MSVC "cdecl" calling convention works, the only things th
the number of arguments and whether the function returns an integer (or pointer), floating-point number,
or struct (struct return values are not supported yet).
-this means we can get away with these twenty functions--GCC passes most arguments in registers, so there would need to be
+this means we can get away with these twenty functions--GCC/MSVC x64 pass most arguments in registers, so there would need to be
a lot more functions to support different combinations of integer and floating-point arguments (since they use different
registers)
*/
@@ -193,7 +205,7 @@ static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type,
Word words[10];
char *type = (char *)arg_types;
for (size_t i = 0; i < nargs; ++i) {
- val_to_word(args[i], (Type *)type, call_where, &words[i]);
+ val_to_words(args[i], (Type *)type, call_where, &words[i]);
type += arg_types_stride;
}
bool is_float = false;
@@ -241,8 +253,7 @@ static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type,
double d = msvc_callf[nargs](fn_ptr, words);
assert(ret_type->kind == TYPE_BUILTIN);
if (ret_type->builtin == BUILTIN_F32) {
- U64 lower_bits = (U32)*(U64 *)&d;
- ret->f32 = *(float *)&lower_bits;
+ ret->f32 = (F32)d; /* turns out functions just always return doubles */
} else {
assert(ret_type->builtin == BUILTIN_F64);
ret->f64 = d;
diff --git a/test.toc b/test.toc
index 44917ac..f9d135c 100644
--- a/test.toc
+++ b/test.toc
@@ -1,3 +1,5 @@
+/*
+
stdc ::= "msvcrt.dll";
printf ::= #foreign("printf",stdc) fn (#C &"char const", #C ..) #C int;
puti ::= fn(i: i32) i32 {
@@ -5,9 +7,25 @@ puti ::= fn(i: i32) i32 {
printf(&fmt[0], i) as i32
}
// BUG: puti(puti(x))
-sqrtf ::= #foreign("sqrt",stdc) fn(f64) f64;
+//sqrt ::= #foreign("sqrt",stdc) fn(f64) f64;
+sqrtf ::= #foreign("sinf",stdc) fn(f32) f32;
+/*
+putf ::= fn(f: f64) i32 {
+ fmt := "number: %f\n\0";
+ printf(&fmt[0], f) as i32
+}
+*/
main ::= fn() {
- f ::= sqrtf(2.0);
+ sqrtf(3.1);
}
main();
+
+*/
+
+foo ::= #foreign("foo","test.dll") fn(f32) f32;
+printf ::= #foreign("printf", "msvcrt.dll") fn(#C &"const char", #C ..) #C int;
+
+main ::= fn() {
+ x ::= foo(2.7);
+}
diff --git a/toc.c b/toc.c
index bebb9b1..7069205 100644
--- a/toc.c
+++ b/toc.c
@@ -135,7 +135,7 @@ static Location token_location(File *file, Token *t);
#if COMPILE_TIME_FOREIGN_FN_SUPPORT
#if defined _MSC_VER && !defined COMPILE_TIME_FOREIGN_FN_AVCALL
-#include "foreign_msvc.c"
+#include "foreign_msvc32.c"
#else
#include "foreign_avcall.c"
#endif
diff --git a/types.c b/types.c
index 1001e07..7dbfff6 100644
--- a/types.c
+++ b/types.c
@@ -264,7 +264,7 @@ static size_t compiler_sizeof(Type *t) {
case TYPE_PTR:
return sizeof v.ptr;
case TYPE_ARR:
- return t->arr.n * compiler_sizeof(t->arr.of);
+ return (size_t)t->arr.n * compiler_sizeof(t->arr.of);
case TYPE_TUPLE:
return sizeof v.tuple;
case TYPE_SLICE: