From e5765b26d44c9add924b64afb3313cea610ca9d1 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 17 Jun 2024 07:07:20 -0700 Subject: [PATCH] Working examples on windows. Add some support for windows x64 ABI. --- build_win.bat | 8 +- examples/sysir/frontend.janet | 1 + examples/sysir/run_samples.bat | 2 +- examples/sysir/samples.janet | 18 ++- src/core/sysir.c | 16 +- src/core/sysir.h | 2 + src/core/sysir_x86.c | 259 ++++++++++++++++++++++----------- 7 files changed, 207 insertions(+), 99 deletions(-) diff --git a/build_win.bat b/build_win.bat index 25f8c011..8ee166f3 100644 --- a/build_win.bat +++ b/build_win.bat @@ -20,11 +20,11 @@ @setlocal @rem Example use asan -@rem set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD /fsanitize=address /Zi -@rem set JANET_LINK=link /nologo clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib +@set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD /fsanitize=address /Zi /DEBUG +@set JANET_LINK=link /nologo clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib /DEBUG -@set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD -@set JANET_LINK=link /nologo +@rem set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD +@rem set JANET_LINK=link /nologo @set JANET_LINK_STATIC=lib /nologo diff --git a/examples/sysir/frontend.janet b/examples/sysir/frontend.janet index 0b99c982..6cd21bcf 100644 --- a/examples/sysir/frontend.janet +++ b/examples/sysir/frontend.janet @@ -57,6 +57,7 @@ (add-prim-type 'long 's64) (add-prim-type 'pointer 'pointer) (add-prim-type 'boolean 'boolean) + (add-prim-type 's16 's16) (sysir/asm ctx into) ctx) diff --git a/examples/sysir/run_samples.bat b/examples/sysir/run_samples.bat index d75243a5..b65536e5 100644 --- a/examples/sysir/run_samples.bat +++ b/examples/sysir/run_samples.bat @@ -1,4 +1,4 @@ janet.exe examples/sysir/samples.janet > temp.nasm nasm -fwin64 temp.nasm -l temp.lst -o temp.o -link temp.o legacy_stdio_definitions.lib msvcrt.lib /out:temp.exe +link /entry:Start /subsystem:windows kernel32.lib user32.lib temp.o /out:temp.exe temp.exe diff --git a/examples/sysir/samples.janet b/examples/sysir/samples.janet index 8a495d00..ec5e09e5 100644 --- a/examples/sysir/samples.janet +++ b/examples/sysir/samples.janet @@ -32,19 +32,27 @@ (return x))) (def main-fn - '(defn WinMain:void [] + '(defn _start:void [] #(syscall 1 1 "Hello, world!\n" 14) (doloop 10 20) (exit (the int 0)) (return))) +(def winmain + '(defn Start:void [] + (MessageBoxExA (the pointer 0) "Hello, world!" "Test" 0 (the s16 0)) + (ExitProcess (the int 0)) + (return))) + + #### #(compile1 square) -(compile1 simple) -(compile1 myprog) -(compile1 doloop) -(compile1 main-fn) +#(compile1 simple) +#(compile1 myprog) +#(compile1 doloop) +#(compile1 main-fn) +(compile1 winmain) #(dump) #(dumpc) (dumpx64) diff --git a/src/core/sysir.c b/src/core/sysir.c index 0ba5b667..9880db12 100644 --- a/src/core/sysir.c +++ b/src/core/sysir.c @@ -71,6 +71,7 @@ const char *prim_to_prim_name[] = { const char *janet_sysop_names[] = { "link-name", /* JANET_SYSOP_LINK_NAME */ "parameter-count", /* JANET_SYSOP_PARAMETER_COUNT */ + "calling-convention", /* JANET_SYSOP_CALLING_CONVENTION */ "move", /* JANET_SYSOP_MOVE */ "cast", /* JANET_SYSOP_CAST */ "add", /* JANET_SYSOP_ADD */ @@ -158,6 +159,7 @@ static const JanetSysInstrName sys_op_names[] = { {"branch-not", JANET_SYSOP_BRANCH_NOT}, {"bxor", JANET_SYSOP_BXOR}, {"call", JANET_SYSOP_CALL}, + {"calling-convention", JANET_SYSOP_CALLING_CONVENTION}, {"cast", JANET_SYSOP_CAST}, {"divide", JANET_SYSOP_DIVIDE}, {"eq", JANET_SYSOP_EQ}, @@ -287,7 +289,7 @@ static uint32_t instr_read_type_operand(Janet x, JanetSysIR *ir, ReadOpMode rmod return (uint32_t) n; } else if (rmode == READ_TYPE_FORWARD_REF) { uint32_t operand = linkage->type_def_count++; - janet_table_put(linkage->type_name_lookup, x, janet_wrap_number(-(int64_t)operand - 1)); + janet_table_put(linkage->type_name_lookup, x, janet_wrap_number(-(double)operand - 1.0)); return operand; } else if (rmode == READ_TYPE_DEFINITION) { uint32_t operand = linkage->type_def_count++; @@ -370,6 +372,7 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction JanetSysInstruction *ir = NULL; JanetTable *labels = out->labels; int found_parameter_count = 0; + int found_calling_convention = 0; /* Parse instructions */ Janet x = janet_wrap_nil(); @@ -436,6 +439,14 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction found_parameter_count = 1; out->parameter_count = janet_getnat(tuple, 1); break; + case JANET_SYSOP_CALLING_CONVENTION: + instr_assert_length(tuple, 2, opvalue); + if (found_calling_convention) { + janet_panic("duplicate calling-convention"); + } + found_calling_convention = 1; + out->calling_convention = instr_read_cc(tuple[1]); + break; case JANET_SYSOP_ADD: case JANET_SYSOP_SUBTRACT: case JANET_SYSOP_MULTIPLY: @@ -1063,6 +1074,7 @@ static void janet_sysir_type_check(JanetSysIR *sysir) { case JANET_SYSOP_ARG: case JANET_SYSOP_LINK_NAME: case JANET_SYSOP_PARAMETER_COUNT: + case JANET_SYSOP_CALLING_CONVENTION: case JANET_SYSOP_JUMP: case JANET_SYSOP_LABEL: break; @@ -1202,6 +1214,7 @@ static void janet_sys_ir_init(JanetSysIR *out, JanetView instructions, JanetSysI ir.parameter_count = 0; ir.link_name = NULL; ir.error_ctx = janet_wrap_nil(); + ir.calling_convention = JANET_SYS_CC_DEFAULT; janet_sysir_init_instructions(&ir, instructions); @@ -1384,6 +1397,7 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) { case JANET_SYSOP_ARG: case JANET_SYSOP_LINK_NAME: case JANET_SYSOP_PARAMETER_COUNT: + case JANET_SYSOP_CALLING_CONVENTION: break; case JANET_SYSOP_LABEL: { janet_formatb(buffer, "\n_label_%u:\n", instruction.label.id); diff --git a/src/core/sysir.h b/src/core/sysir.h index 57d40768..9bceda37 100644 --- a/src/core/sysir.h +++ b/src/core/sysir.h @@ -102,6 +102,7 @@ typedef struct { typedef enum { JANET_SYSOP_LINK_NAME, JANET_SYSOP_PARAMETER_COUNT, + JANET_SYSOP_CALLING_CONVENTION, JANET_SYSOP_MOVE, JANET_SYSOP_CAST, JANET_SYSOP_ADD, @@ -300,6 +301,7 @@ typedef struct { JanetSysConstant *constants; JanetTable *register_name_lookup; JanetTable *labels; + JanetSysCallingConvention calling_convention; Janet error_ctx; /* Temporary for holding error messages */ } JanetSysIR; diff --git a/src/core/sysir_x86.c b/src/core/sysir_x86.c index f70c5756..59d94dde 100644 --- a/src/core/sysir_x86.c +++ b/src/core/sysir_x86.c @@ -91,11 +91,10 @@ typedef struct { JanetSysTypeLayout *layouts; JanetSysTypeLayout *ir_layouts; uint32_t frame_size; - uint32_t restore_count; - uint32_t to_restore[128]; - JanetSysCallingConvention calling_convention; + JanetSysCallingConvention calling_convention; /* Store normalized calling convention of current IR */ int32_t ir_index; uint32_t occupied_registers; + uint32_t clobbered_registers; /* Restore these before returning */ } JanetSysx64Context; /* Get the layout for types */ @@ -167,6 +166,8 @@ void assign_registers(JanetSysx64Context *ctx) { /* TODO - avoid spills inside loops if possible i.e. not all spills are equal */ /* TODO - move into sysir.c and allow reuse for multiple targets */ + JanetSysCallingConvention cc = ctx->calling_convention; + /* Make trivial assigments */ uint32_t next_loc = 16; ctx->regs = janet_smalloc(ctx->ir->register_count * sizeof(x64Reg)); @@ -179,19 +180,28 @@ void assign_registers(JanetSysx64Context *ctx) { ctx->regs[i].kind = get_slot_regkind(ctx, i); if (i < ctx->ir->parameter_count) { /* Assign to rdi, rsi, etc. according to ABI */ - if (i == 0) ctx->regs[i].index = RDI; - if (i == 1) ctx->regs[i].index = RSI; - if (i == 2) ctx->regs[i].index = RDX; - if (i == 3) ctx->regs[i].index = RCX; - if (i == 4) ctx->regs[i].index = 8; - if (i == 5) ctx->regs[i].index = 9; - if (i >= 6) { - janet_panic("nyi"); - ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER; + if (cc == JANET_SYS_CC_X64_SYSV) { + if (i == 0) ctx->regs[i].index = RDI; + if (i == 1) ctx->regs[i].index = RSI; + if (i == 2) ctx->regs[i].index = RDX; + if (i == 3) ctx->regs[i].index = RCX; + if (i == 4) ctx->regs[i].index = 8; + if (i == 5) ctx->regs[i].index = 9; + if (i >= 6) { + janet_panic("nyi parameter count > 6"); + ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER; + } + } else if (cc == JANET_SYS_CC_X64_WINDOWS) { + if (i == 0) ctx->regs[i].index = RCX; + if (i == 1) ctx->regs[i].index = RDX; + if (i == 2) ctx->regs[i].index = 8; + if (i == 3) ctx->regs[i].index = 9; + if (i >= 4) { + ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER; + ctx->regs[i].index = (i - 4) * 8 + 16; + } } else { - ctx->regs[i].storage = JANET_SYSREG_REGISTER; - assigned |= 1 << ctx->regs[i].index; - occupied |= 1 << ctx->regs[i].index; + janet_panic("cannot assign registers for calling convention"); } } else if (assigned < 0xFFFF) { /* Assign to register */ @@ -216,19 +226,24 @@ void assign_registers(JanetSysx64Context *ctx) { ctx->occupied_registers = occupied; /* Mark which registers need restoration before returning */ - ctx->restore_count = 0; - unsigned char seen[16] = {0}; - unsigned char tokeep[] = {3, 6, 7, 12, 13, 14, 15}; - for (uint32_t i = 0; i < ctx->ir->register_count; i++) { - x64Reg reg = ctx->regs[i]; - if (reg.storage != JANET_SYSREG_REGISTER) continue; - for (unsigned int j = 0; j < sizeof(tokeep); j++) { - if (!seen[j] && reg.index == tokeep[j]) { - ctx->to_restore[ctx->restore_count++] = reg.index; - seen[j] = 1; - } - } + uint32_t non_volatile_mask = 0; + if (cc == JANET_SYS_CC_X64_SYSV) { + non_volatile_mask = (1 << RBX) + | (1 << 12) + | (1 << 13) + | (1 << 14) + | (1 << 15); } + if (cc == JANET_SYS_CC_X64_WINDOWS) { + non_volatile_mask = (1 << RBX) + | (RDI << 12) + | (RSI << 12) + | (1 << 12) + | (1 << 13) + | (1 << 14) + | (1 << 15); + } + ctx->clobbered_registers = assigned | non_volatile_mask; } static int operand_isstack(JanetSysx64Context *ctx, uint32_t o) { @@ -372,10 +387,11 @@ static void sysemit_three_inst(JanetSysx64Context *ctx, const char *op, JanetSys static void sysemit_ret(JanetSysx64Context *ctx, uint32_t arg, int has_return) { if (has_return) sysemit_movreg(ctx, RAX, arg); - /* TODO - depends on current calling convention */ - for (uint32_t k = 0; k < ctx->restore_count; k++) { - /* Pop in reverse order */ - janet_formatb(ctx->buffer, "pop %s\n", register_names[ctx->to_restore[ctx->restore_count - k - 1]]); + /* Pop in reverse order */ + for (int32_t k = 31; k >= 0; k--) { + if (ctx->clobbered_registers & (1u << k)) { + janet_formatb(ctx->buffer, "pop %s\n", register_names[k]); + } } janet_formatb(ctx->buffer, "leave\n"); janet_formatb(ctx->buffer, "ret\n"); @@ -404,7 +420,7 @@ static int sysemit_comp(JanetSysx64Context *ctx, uint32_t index, nexti.branch.cond == instruction.three.dest) { /* Combine compare and branch */ int invert = nexti.opcode == JANET_SYSOP_BRANCH_NOT; - janet_formatb(ctx->buffer, "%s label_%d_%u\n", invert ? branch_invert : branch, ctx->ir_index, nexti.branch.to); + janet_formatb(ctx->buffer, "%s label_%d_%u\n", invert ? branch_invert : branch, ctx->ir_index, (uint64_t) nexti.branch.to); /* Skip next branch IR instruction */ return 1; } else { @@ -438,6 +454,100 @@ static void sysemit_cast(JanetSysx64Context *ctx, JanetSysInstruction instructio janet_formatb(ctx->buffer, "; cast nyi\n"); } +static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instruction, uint32_t *args, uint32_t argcount) { + /* Push first 6 arguments to particular registers */ + JanetSysIR *ir = ctx->ir; + JanetBuffer *buffer = ctx->buffer; + int save_rdi = argcount >= 1 || (ctx->occupied_registers & (1 << RDI)); + int save_rsi = argcount >= 2 || (ctx->occupied_registers & (1 << RSI)); + int save_rdx = argcount >= 3 || (ctx->occupied_registers & (1 << RDX)); + int save_rcx = argcount >= 4 || (ctx->occupied_registers & (1 << RCX)); + int save_r8 = argcount >= 5 || (ctx->occupied_registers & (1 << 8)); + int save_r9 = argcount >= 6 || (ctx->occupied_registers & (1 << 9)); + int save_r10 = ctx->occupied_registers & (1 << 10); + int save_r11 = ctx->occupied_registers & (1 << 11); + if (save_rdi && argcount >= 1) sysemit_mov_save(ctx, RDI, args[0]); + if (save_rdi && argcount < 1) sysemit_pushreg(ctx, RDI); + if (save_rsi && argcount >= 2) sysemit_mov_save(ctx, RSI, args[1]); + if (save_rsi && argcount < 2) sysemit_pushreg(ctx, RSI); + if (save_rdx && argcount >= 3) sysemit_mov_save(ctx, RDX, args[2]); + if (save_rdx && argcount < 3) sysemit_pushreg(ctx, RDX); + if (save_rcx && argcount >= 4) sysemit_mov_save(ctx, RCX, args[3]); + if (save_rcx && argcount < 4) sysemit_pushreg(ctx, RCX); + if (save_r8 && argcount >= 5) sysemit_mov_save(ctx, 8, args[4]); + if (save_r8 && argcount < 5) sysemit_pushreg(ctx, 8); + if (save_r9 && argcount >= 6) sysemit_mov_save(ctx, 9, args[5]); + if (save_r9 && argcount < 6) sysemit_pushreg(ctx, 9); + if (save_r10) sysemit_pushreg(ctx, 10); + if (save_r11) sysemit_pushreg(ctx, 11); + for (int32_t argo = argcount - 1; argo >= 6; argo--) { + janet_panic("nyi push sysv args"); + janet_formatb(buffer, "push "); + sysemit_operand(ctx, args[argo], "\n"); + } + if (instruction.opcode == JANET_SYSOP_SYSCALL) { + sysemit_movreg(ctx, RAX, instruction.call.callee); + janet_formatb(buffer, "syscall\n"); + } else { + /* Save RAX to number of floating point args for varags - for now, always 0 :) */ + janet_formatb(buffer, "mov rax, 0\n"); + janet_formatb(buffer, "call "); + sysemit_operand(ctx, instruction.call.callee, "\n"); + } + if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movreg(ctx, RAX, instruction.call.dest); + if (save_r11) sysemit_popreg(ctx, 11); + if (save_r10) sysemit_popreg(ctx, 10); + if (save_r9) sysemit_popreg(ctx, 9); + if (save_r8) sysemit_popreg(ctx, 8); + if (save_rcx) sysemit_popreg(ctx, RCX); + if (save_rdx) sysemit_popreg(ctx, RDX); + if (save_rsi) sysemit_popreg(ctx, RSI); + if (save_rdi) sysemit_popreg(ctx, RDI); +} + +static void sysemit_win64_call(JanetSysx64Context *ctx, JanetSysInstruction instruction, uint32_t *args, uint32_t argcount) { + /* Push first 6 arguments to particular registers */ + JanetSysIR *ir = ctx->ir; + JanetBuffer *buffer = ctx->buffer; + int save_rcx = argcount >= 1 || (ctx->occupied_registers & (1 << RCX)); + int save_rdx = argcount >= 2 || (ctx->occupied_registers & (1 << RDX)); + int save_r8 = argcount >= 3 || (ctx->occupied_registers & (1 << 8)); + int save_r9 = argcount >= 4 || (ctx->occupied_registers & (1 << 9)); + int save_r10 = ctx->occupied_registers & (1 << 10); + int save_r11 = ctx->occupied_registers & (1 << 11); + if (save_rcx && argcount >= 1) sysemit_mov_save(ctx, RCX, args[0]); + if (save_rcx && argcount < 1) sysemit_pushreg(ctx, RCX); + if (save_rdx && argcount >= 2) sysemit_mov_save(ctx, RDX, args[1]); + if (save_rdx && argcount < 2) sysemit_pushreg(ctx, RDX); + if (save_r8 && argcount >= 3) sysemit_mov_save(ctx, 8, args[2]); + if (save_r8 && argcount < 3) sysemit_pushreg(ctx, 8); + if (save_r9 && argcount >= 4) sysemit_mov_save(ctx, 9, args[3]); + if (save_r9 && argcount < 4) sysemit_pushreg(ctx, 9); + if (save_r10) sysemit_pushreg(ctx, 10); + if (save_r11) sysemit_pushreg(ctx, 11); + for (uint32_t argo = 4; argo < argcount; argo++) { + janet_formatb(buffer, "push "); + sysemit_operand(ctx, args[argo], "\n"); + } + if (instruction.opcode == JANET_SYSOP_SYSCALL) { + sysemit_movreg(ctx, RAX, instruction.call.callee); + janet_formatb(buffer, "syscall\n"); + } else { + janet_formatb(buffer, "call "); + sysemit_operand(ctx, instruction.call.callee, "\n"); + } + if (argcount > 4) { + janet_formatb(buffer, "add rsp, %u\n", 8 * (argcount - 4)); + } + if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movreg(ctx, RAX, instruction.call.dest); + if (save_r11) sysemit_popreg(ctx, 11); + if (save_r10) sysemit_popreg(ctx, 10); + if (save_r9) sysemit_popreg(ctx, 9); + if (save_r8) sysemit_popreg(ctx, 8); + if (save_rdx) sysemit_popreg(ctx, RDX); + if (save_rcx) sysemit_popreg(ctx, RCX); +} + void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) { /* Partially setup context */ @@ -480,8 +590,13 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) if (ir->link_name == NULL) { continue; } + ctx.calling_convention = ir->calling_convention; + if (ctx.calling_convention == JANET_SYS_CC_DEFAULT) { + /* Pick default calling convention */ + ctx.calling_convention = JANET_SYS_CC_X64_WINDOWS; + } - /* Setup conttext */ + /* Setup context */ ctx.ir_layouts = janet_smalloc(ir->register_count * sizeof(JanetSysTypeLayout)); for (uint32_t i = 0; i < ir->register_count; i++) { ctx.ir_layouts[i] = ctx.layouts[ir->types[i]]; @@ -497,9 +612,10 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) } janet_formatb(buffer, "push rbp\nmov rbp, rsp\nsub rsp, %u\n", ctx.frame_size); - for (uint32_t k = 0; k < ctx.restore_count; k++) { - /* Pop in reverse order */ - janet_formatb(buffer, "push %s\n", register_names[ctx.to_restore[k]]); + for (uint32_t k = 0; k < 32; k++) { + if (ctx.clobbered_registers & (1u << k)) { + janet_formatb(buffer, "push %s\n", register_names[k]); + } } /* Function body */ @@ -593,64 +709,31 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) break; case JANET_SYSOP_SYSCALL: case JANET_SYSOP_CALL: - ; - /* Push first 6 arguments to particular registers */ - uint32_t argcount = 0; - uint32_t *args = janet_sys_callargs(ir->instructions + j, &argcount); - int save_rdi = argcount >= 1 || (ctx.occupied_registers & (1 << RDI)); - int save_rsi = argcount >= 2 || (ctx.occupied_registers & (1 << RSI)); - int save_rdx = argcount >= 3 || (ctx.occupied_registers & (1 << RDX)); - int save_rcx = argcount >= 4 || (ctx.occupied_registers & (1 << RCX)); - int save_r8 = argcount >= 5 || (ctx.occupied_registers & (1 << 8)); - int save_r9 = argcount >= 6 || (ctx.occupied_registers & (1 << 9)); - int save_r10 = ctx.occupied_registers & (1 << 10); - int save_r11 = ctx.occupied_registers & (1 << 11); - if (save_rdi && argcount >= 1) sysemit_mov_save(&ctx, RDI, args[0]); - if (save_rdi && argcount < 1) sysemit_pushreg(&ctx, RDI); - if (save_rsi && argcount >= 2) sysemit_mov_save(&ctx, RSI, args[1]); - if (save_rsi && argcount < 2) sysemit_pushreg(&ctx, RSI); - if (save_rdx && argcount >= 3) sysemit_mov_save(&ctx, RDX, args[2]); - if (save_rdx && argcount < 3) sysemit_pushreg(&ctx, RDX); - if (save_rcx && argcount >= 4) sysemit_mov_save(&ctx, RCX, args[3]); - if (save_rcx && argcount < 4) sysemit_pushreg(&ctx, RCX); - if (save_r8 && argcount >= 5) sysemit_mov_save(&ctx, 8, args[4]); - if (save_r8 && argcount < 5) sysemit_pushreg(&ctx, 8); - if (save_r9 && argcount >= 6) sysemit_mov_save(&ctx, 9, args[5]); - if (save_r9 && argcount < 6) sysemit_pushreg(&ctx, 9); - if (save_r10) sysemit_pushreg(&ctx, 10); - if (save_r11) sysemit_pushreg(&ctx, 11); - for (int32_t argo = argcount - 1; argo >= 5; argo--) { - janet_panic("nyi"); - janet_formatb(buffer, "push "); - sysemit_operand(&ctx, args[argo], "\n"); + { + uint32_t argcount = 0; + uint32_t *args = janet_sys_callargs(ir->instructions + j, &argcount); + JanetSysCallingConvention cc = instruction.call.calling_convention; + + /* Set default calling convention based on context */ + if (cc == JANET_SYS_CC_DEFAULT) { + cc = JANET_SYS_CC_X64_WINDOWS; + } + + if (cc == JANET_SYS_CC_X64_SYSV) { + sysemit_sysv_call(&ctx, instruction, args, argcount); + } else if (cc == JANET_SYS_CC_X64_WINDOWS) { + sysemit_win64_call(&ctx, instruction, args, argcount); + } + janet_sfree(args); + break; } - janet_sfree(args); - if (instruction.opcode == JANET_SYSOP_SYSCALL) { - sysemit_movreg(&ctx, RAX, instruction.call.callee); - janet_formatb(buffer, "syscall\n"); - } else { - /* Save RAX to number of floating point args for varags - for now, always 0 :) */ - janet_formatb(buffer, "mov rax, 0\n"); - janet_formatb(buffer, "call "); - sysemit_operand(&ctx, instruction.call.callee, "\n"); - } - if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movreg(&ctx, RAX, instruction.call.dest); - if (save_r11) sysemit_popreg(&ctx, 11); - if (save_r10) sysemit_popreg(&ctx, 10); - if (save_r9) sysemit_popreg(&ctx, 9); - if (save_r8) sysemit_popreg(&ctx, 8); - if (save_rcx) sysemit_popreg(&ctx, RCX); - if (save_rdx) sysemit_popreg(&ctx, RDX); - if (save_rsi) sysemit_popreg(&ctx, RSI); - if (save_rdi) sysemit_popreg(&ctx, RDI); - break; // On a comparison, if next instruction is branch that reads from dest, combine into a single op. } } } /* End section .text */ - janet_formatb(buffer, "section .rodata\n\n"); + janet_formatb(buffer, "\nsection .rodata\n"); for (int32_t i = 0; i < linkage->ir_ordered->count; i++) { JanetSysIR *ir = janet_unwrap_pointer(linkage->ir_ordered->data[i]); @@ -658,7 +741,7 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) for (uint32_t j = 0; j < ir->constant_count; j++) { if (janet_checktype(ir->constants[j].value, JANET_STRING)) { JanetString str = janet_unwrap_string(ir->constants[j].value); - janet_formatb(buffer, "\nCONST_%d_%u: db ", i, j); + janet_formatb(buffer, "CONST_%d_%u: db ", i, j); /* Nasm syntax */ int in_string = 0; for (int32_t ci = 0; ci < janet_string_length(str); ci++) {