diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-05-03 12:37:28 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-05-03 12:37:28 -0400 |
commit | cb1a634e495c6f2e3ebd90f25235c6f7d2d639b7 (patch) | |
tree | 92d2e15bee99fd960f566d7e17955770deb71dba | |
parent | 6be24a8a51106e373406081ecd088bd1a2db4040 (diff) |
turns out __cdecl is only for 32-bit. now everything works except for 64-bit arguments
-rw-r--r-- | .gitignore | 7 | ||||
-rw-r--r-- | eval.c | 4 | ||||
-rw-r--r-- | foreign_msvc32.c (renamed from foreign_msvc.c) | 31 | ||||
-rw-r--r-- | test.toc | 22 | ||||
-rw-r--r-- | toc.c | 2 | ||||
-rw-r--r-- | types.c | 2 |
6 files changed, 52 insertions, 16 deletions
@@ -17,3 +17,10 @@ std/*.o *.so README.html docs/*.html +*.dll +*.exp +*.lib +*.pdb +*.ilk +*.obj +*.exe @@ -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; @@ -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); +} @@ -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 @@ -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: |